4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28 * auditd is thread 0 and does signal handling
30 * input() is a door server that receives binary audit records and
31 * queues them for handling by an instance of process() for conversion to syslog
32 * message(s). There is one process thread per plugin.
36 * Each plugin has a buffer pool and and queue for feeding the
37 * the process threads. The input thread moves buffers from the pool
38 * to the queue and the process thread puts them back.
40 * Another pool, b_pool, contains buffers referenced by each of the
41 * process queues; this is to minimize the number of buffer copies
45 #include <arpa/inet.h>
54 #include <security/auditd.h>
60 #include <sys/socket.h>
61 #include <sys/types.h>
64 #include <audit_plugin.h> /* libbsm */
66 #include <bsm/audit_door_infc.h>
71 /* gettext() obfuscation routine for lint */
78 #define DUMP(w, x, y, z) dump_state(w, x, y, z)
79 #define DPRINT(x) { (void) fprintf x; }
81 #define DUMP(w, x, y, z)
85 #define FATAL_MESSAGE_LEN 256
87 #define MIN_RECORD_SIZE (size_t)25
90 #define THRESHOLD_PCT 75
91 #define DEFAULT_BUF_SZ (size_t)250
92 #define BASE_PRIORITY 10 /* 0 - 20 valid for user, time share */
93 #define HIGH_PRIORITY BASE_PRIORITY - 1
95 static thr_data_t in_thr
; /* input thread locks and data */
96 static int doorfd
= -1;
98 static int largest_queue
= INPUT_MIN
;
99 static au_queue_t b_pool
;
100 static int b_allocated
= 0;
101 static pthread_mutex_t b_alloc_lock
;
102 static pthread_mutex_t b_refcnt_lock
;
104 static void input(void *, void *, int, door_desc_t
*, int);
105 static void process(plugin_t
*);
107 static audit_q_t
*qpool_withdraw(plugin_t
*);
108 static void qpool_init(plugin_t
*, int);
109 static void qpool_return(plugin_t
*, audit_q_t
*);
110 static void qpool_close(plugin_t
*);
112 static audit_rec_t
*bpool_withdraw(char *, size_t, size_t);
113 static void bpool_init();
114 static void bpool_return(audit_rec_t
*);
117 * warn_or_fatal() -- log daemon error and (optionally) exit
120 warn_or_fatal(int fatal
, char *parting_shot
)
126 severity
= gettext("fatal error");
128 severity
= gettext("warning");
130 (void) snprintf(message
, 512, "%s: %s", severity
, parting_shot
);
132 __audit_syslog("auditd", LOG_PID
| LOG_ODELAY
| LOG_CONS
,
133 LOG_DAEMON
, LOG_ALERT
, message
);
135 DPRINT((dbfp
, "auditd warn_or_fatal %s: %s\n", severity
, parting_shot
));
140 /* Internal to doorway.c errors... */
141 #define INTERNAL_LOAD_ERROR -1
142 #define INTERNAL_SYS_ERROR -2
143 #define INTERNAL_CONFIG_ERROR -3
146 * report_error -- handle errors returned by plugin
148 * rc is plugin's return code if it is a non-negative value,
149 * otherwise it is a doorway.c code about a plugin.
152 report_error(int rc
, char *error_text
, char *plugin_path
)
155 char rcbuf
[100]; /* short error name string */
156 char message
[FATAL_MESSAGE_LEN
];
161 static int no_plug
= 0;
162 static int no_load
= 0;
163 static int no_thread
;
164 static int no_memory
= 0;
165 static int invalid
= 0;
166 static int retry
= 0;
170 if (error_text
== NULL
)
176 case INTERNAL_LOAD_ERROR
:
178 bad_count
= ++no_load
;
179 (void) strcpy(rcbuf
, "load_error");
181 case INTERNAL_SYS_ERROR
:
183 bad_count
= ++no_thread
;
184 (void) strcpy(rcbuf
, "sys_error");
186 case INTERNAL_CONFIG_ERROR
:
188 bad_count
= ++no_plug
;
189 (void) strcpy(rcbuf
, "config_error");
194 case AUDITD_NO_MEMORY
: /* no_memory */
196 bad_count
= ++no_memory
;
197 (void) strcpy(rcbuf
, "no_memory");
199 case AUDITD_INVALID
: /* invalid */
201 bad_count
= ++invalid
;
202 (void) strcpy(rcbuf
, "invalid");
207 (void) strcpy(rcbuf
, "retry");
209 case AUDITD_COMM_FAIL
: /* comm_fail */
210 (void) strcpy(rcbuf
, "comm_fail");
212 case AUDITD_FATAL
: /* failure */
215 (void) strcpy(rcbuf
, "failure");
218 (void) strcpy(rcbuf
, "error");
221 DPRINT((dbfp
, "report_error(%d - %s): %s\n\t%s\n",
222 bad_count
, name
, rcbuf
, error_text
));
224 __audit_dowarn2("plugin", name
, rcbuf
, error_text
, bad_count
);
226 (void) snprintf(message
, FATAL_MESSAGE_LEN
,
227 gettext("audit plugin %s reported error = \"%s\": %s\n"),
228 name
, rcbuf
, error_text
);
229 warn_or_fatal(0, message
);
241 adr
.adr_stream
= buf
;
243 adrm_char(&adr
, &tokenid
, 1);
244 if ((tokenid
== AUT_OHEADER
) || (tokenid
== AUT_HEADER32
) ||
245 (tokenid
== AUT_HEADER32_EX
) || (tokenid
== AUT_HEADER64
) ||
246 (tokenid
== AUT_HEADER64_EX
)) {
247 adrm_u_int32(&adr
, &len
, 1);
251 DPRINT((dbfp
, "getlen() is not looking at a header token\n"));
257 * load_function - call dlsym() to resolve the function address
260 load_function(plugin_t
*p
, char *name
, auditd_rc_t (**func
)())
262 *func
= (auditd_rc_t (*)())dlsym(p
->plg_dlptr
, name
);
264 char message
[FATAL_MESSAGE_LEN
];
265 char *errmsg
= dlerror();
267 (void) snprintf(message
, FATAL_MESSAGE_LEN
,
268 gettext("dlsym failed %s: error %s"),
269 name
, errmsg
!= NULL
? errmsg
: gettext("Unknown error\n"));
271 warn_or_fatal(0, message
);
278 * load the auditd plug in
281 load_plugin(plugin_t
*p
)
288 * Stat the file so we can check modes and ownerships
290 if ((fd
= open(p
->plg_path
, O_NONBLOCK
| O_RDONLY
)) != -1) {
291 if ((fstat64(fd
, &stat
) == -1) || (!S_ISREG(stat
.st_mode
)))
296 char message
[FATAL_MESSAGE_LEN
];
298 (void) snprintf(message
, FATAL_MESSAGE_LEN
,
299 gettext("auditd plugin: stat(%s) failed: %s\n"),
300 p
->plg_path
, strerror(errno
));
302 warn_or_fatal(0, message
);
306 * Check the ownership of the file
308 if (stat
.st_uid
!= (uid_t
)0) {
309 char message
[FATAL_MESSAGE_LEN
];
311 (void) snprintf(message
, FATAL_MESSAGE_LEN
,
313 "auditd plugin: Owner of the module %s is not root\n"),
316 warn_or_fatal(0, message
);
320 * Check the modes on the file
322 if (stat
.st_mode
&S_IWGRP
) {
323 char message
[FATAL_MESSAGE_LEN
];
325 (void) snprintf(message
, FATAL_MESSAGE_LEN
,
326 gettext("auditd plugin: module %s writable by group\n"),
329 warn_or_fatal(0, message
);
332 if (stat
.st_mode
&S_IWOTH
) {
333 char message
[FATAL_MESSAGE_LEN
];
335 (void) snprintf(message
, FATAL_MESSAGE_LEN
,
336 gettext("auditd plugin: module %s writable by world\n"),
339 warn_or_fatal(0, message
);
345 p
->plg_dlptr
= dlopen(p
->plg_path
, RTLD_LAZY
);
347 if (p
->plg_dlptr
== NULL
) {
348 char message
[FATAL_MESSAGE_LEN
];
349 char *errmsg
= dlerror();
351 (void) snprintf(message
, FATAL_MESSAGE_LEN
,
352 gettext("plugin load %s failed: %s\n"),
353 p
->plg_path
, errmsg
!= NULL
? errmsg
:
354 gettext("Unknown error\n"));
356 warn_or_fatal(0, message
);
359 if (load_function(p
, "auditd_plugin", &(p
->plg_fplugin
)))
362 if (load_function(p
, "auditd_plugin_open", &(p
->plg_fplugin_open
)))
365 if (load_function(p
, "auditd_plugin_close", &(p
->plg_fplugin_close
)))
372 * unload_plugin() unlinks and frees the plugin_t structure after
373 * freeing buffers and structures that hang off it. It also dlcloses
374 * the referenced plugin. The return is the next entry, which may be NULL
376 * hold plugin_mutex for this call
379 unload_plugin(plugin_t
*p
)
383 assert(pthread_mutex_trylock(&plugin_mutex
) != 0);
385 DPRINT((dbfp
, "unload_plugin: removing %s\n", p
->plg_path
));
387 _kva_free(p
->plg_kvlist
); /* _kva_free accepts NULL */
388 qpool_close(p
); /* qpool_close accepts NULL pool, queue */
389 DPRINT((dbfp
, "unload_plugin: %s structure removed\n", p
->plg_path
));
391 (void) dlclose(p
->plg_dlptr
);
393 DPRINT((dbfp
, "unload_plugin: %s dlclosed\n", p
->plg_path
));
396 (void) pthread_mutex_destroy(&(p
->plg_mutex
));
397 (void) pthread_cond_destroy(&(p
->plg_cv
));
414 * process return values from plugin_open
416 * presently no attribute is defined.
420 open_return(plugin_t
*p
, char *attrval
)
429 * auditd_thread_init is called at auditd startup with an initial list
430 * of plugins and again each time audit catches a SIGHUP or SIGUSR1.
440 int plugin_count
= 0;
441 static int threads_ready
= 0;
443 if (!threads_ready
) {
444 struct sched_param param
;
446 dbfp
= __auditd_debug_file_open();
448 doorfd
= door_create((void(*)())input
, 0,
449 DOOR_REFUSE_DESC
| DOOR_NO_CANCEL
);
451 return (1); /* can't create door -> fatal */
453 param
.sched_priority
= BASE_PRIORITY
;
454 (void) pthread_setschedparam(pthread_self(), SCHED_OTHER
,
457 /* input door server */
458 (void) pthread_mutex_init(&(in_thr
.thd_mutex
), NULL
);
459 (void) pthread_cond_init(&(in_thr
.thd_cv
), NULL
);
460 in_thr
.thd_waiting
= 0;
466 if (p
->plg_removed
) {
467 DPRINT((dbfp
, "start removing %s\n", p
->plg_path
));
468 /* tell process(p) to exit and dlclose */
469 (void) pthread_cond_signal(&(p
->plg_cv
));
470 } else if (!p
->plg_initialized
) {
471 DPRINT((dbfp
, "start initial load of %s\n",
473 if (load_plugin(p
)) {
474 report_error(INTERNAL_LOAD_ERROR
,
475 gettext("dynamic load failed"),
477 p
= unload_plugin(p
);
482 if ((rc
= p
->plg_fplugin_open(
484 &open_params
, &error_string
)) != AUDITD_SUCCESS
) {
485 report_error(rc
, error_string
, p
->plg_path
);
487 p
= unload_plugin(p
);
490 open_return(p
, open_params
);
493 threshold
= ((p
->plg_qmax
* THRESHOLD_PCT
) + 99) / 100;
494 p
->plg_qmin
= INPUT_MIN
;
497 "calling qpool_init for %s with qmax=%d\n",
498 p
->plg_path
, p
->plg_qmax
));
500 qpool_init(p
, threshold
);
501 audit_queue_init(&(p
->plg_queue
));
502 p
->plg_initialized
= 1;
504 (void) pthread_mutex_init(&(p
->plg_mutex
), NULL
);
505 (void) pthread_cond_init(&(p
->plg_cv
), NULL
);
508 if (pthread_create(&(p
->plg_tid
), NULL
,
509 (void *(*)(void *))process
, p
)) {
510 report_error(INTERNAL_SYS_ERROR
,
511 gettext("thread creation failed"),
513 p
= unload_plugin(p
);
516 } else if (p
->plg_reopen
) {
517 DPRINT((dbfp
, "reopen %s\n", p
->plg_path
));
519 if ((rc
= p
->plg_fplugin_open(p
->plg_kvlist
,
520 &open_params
, &error_string
)) != AUDITD_SUCCESS
) {
521 report_error(rc
, error_string
, p
->plg_path
);
523 p
= unload_plugin(p
);
526 open_return(p
, open_params
);
529 DPRINT((dbfp
, "%s qmax=%d\n",
530 p
->plg_path
, p
->plg_qmax
));
533 p
->plg_q_threshold
= ((p
->plg_qmax
* THRESHOLD_PCT
) + 99) / 100;
538 if (plugin_count
== 0) {
539 report_error(INTERNAL_CONFIG_ERROR
,
540 gettext("No plugins are configured"), NULL
);
543 if (!threads_ready
) {
544 /* unleash the kernel */
545 rc
= auditdoor(doorfd
);
547 DPRINT((dbfp
, "%d returned from auditdoor.\n",
550 return (1); /* fatal */
558 * Door invocations that are in progress during a
559 * door_revoke() invocation are allowed to complete normally.
560 * -- man page for door_revoke()
563 auditd_thread_close()
567 (void) door_revoke(doorfd
);
572 * qpool_init() sets up pool for queue entries (audit_q_t)
576 qpool_init(plugin_t
*p
, int threshold
)
581 audit_queue_init(&(p
->plg_pool
));
583 DPRINT((dbfp
, "qpool_init(%d) max, min, threshhold = %d, %d, %d\n",
584 p
->plg_tid
, p
->plg_qmax
, p
->plg_qmin
, threshold
));
586 if (p
->plg_qmax
> largest_queue
)
587 largest_queue
= p
->plg_qmax
;
589 p
->plg_q_threshold
= threshold
;
591 for (i
= 0; i
< p
->plg_qmin
; i
++) {
592 node
= malloc(sizeof (audit_q_t
));
594 warn_or_fatal(1, gettext("no memory\n"));
597 audit_enqueue(&p
->plg_pool
, node
);
602 * bpool_init() sets up pool and queue for record entries (audit_rec_t)
611 audit_queue_init(&b_pool
);
612 (void) pthread_mutex_init(&b_alloc_lock
, NULL
);
613 (void) pthread_mutex_init(&b_refcnt_lock
, NULL
);
615 for (i
= 0; i
< INPUT_MIN
; i
++) {
616 node
= malloc(AUDIT_REC_HEADER
+ DEFAULT_BUF_SZ
);
618 warn_or_fatal(1, gettext("no memory\n"));
621 node
->abq_buf_len
= DEFAULT_BUF_SZ
;
623 node
->abq_data_len
= 0;
624 audit_enqueue(&b_pool
, node
);
625 (void) pthread_mutex_lock(&b_alloc_lock
);
627 (void) pthread_mutex_unlock(&b_alloc_lock
);
632 * qpool_close() discard queue and pool for a discontinued plugin
634 * there is no corresponding bpool_close() since it would only
635 * be called as auditd is going down.
638 qpool_close(plugin_t
*p
)
643 if (!p
->plg_initialized
)
646 while (audit_dequeue(&(p
->plg_pool
), (void *)&q_node
) == 0) {
649 audit_queue_destroy(&(p
->plg_pool
));
651 while (audit_dequeue(&(p
->plg_queue
), (void *)&q_node
) == 0) {
652 b_node
= audit_release(&b_refcnt_lock
, q_node
->aqq_data
);
654 audit_enqueue(&b_pool
, b_node
);
657 audit_queue_destroy(&(p
->plg_queue
));
664 qpool_withdraw(plugin_t
*p
)
669 /* get a buffer from the pool, if any */
670 rc
= audit_dequeue(&(p
->plg_pool
), (void *)&node
);
675 * the pool is empty: allocate a new element
677 node
= malloc(sizeof (audit_q_t
));
680 warn_or_fatal(1, gettext("no memory\n"));
687 * bpool_withdraw -- gets a buffer and fills it
691 bpool_withdraw(char *buffer
, size_t buff_size
, size_t request_size
)
697 new_length
= (request_size
> DEFAULT_BUF_SZ
) ?
698 request_size
: DEFAULT_BUF_SZ
;
700 /* get a buffer from the pool, if any */
701 rc
= audit_dequeue(&b_pool
, (void *)&node
);
703 DPRINT((dbfp
, "bpool_withdraw buf length=%d,"
704 " requested size=%d, dequeue rc=%d\n",
705 new_length
, request_size
, rc
));
708 DPRINT((dbfp
, "bpool_withdraw node=%p (pool=%d)\n",
709 (void *)node
, audit_queue_size(&b_pool
)));
711 if (new_length
> node
->abq_buf_len
) {
712 node
= realloc(node
, AUDIT_REC_HEADER
+ new_length
);
714 warn_or_fatal(1, gettext("no memory\n"));
719 * the pool is empty: allocate a new element
721 (void) pthread_mutex_lock(&b_alloc_lock
);
722 if (b_allocated
>= largest_queue
) {
723 (void) pthread_mutex_unlock(&b_alloc_lock
);
724 DPRINT((dbfp
, "bpool_withdraw is over max (pool=%d)\n",
725 audit_queue_size(&b_pool
)));
728 (void) pthread_mutex_unlock(&b_alloc_lock
);
730 node
= malloc(AUDIT_REC_HEADER
+ new_length
);
733 warn_or_fatal(1, gettext("no memory\n"));
736 (void) pthread_mutex_lock(&b_alloc_lock
);
738 (void) pthread_mutex_unlock(&b_alloc_lock
);
739 DPRINT((dbfp
, "bpool_withdraw node=%p (alloc=%d, pool=%d)\n",
740 (void *)node
, b_allocated
, audit_queue_size(&b_pool
)));
742 assert(request_size
<= new_length
);
744 (void) memcpy(node
->abq_buffer
, buffer
, buff_size
);
745 node
->abq_data_len
= buff_size
;
746 node
->abq_buf_len
= new_length
;
747 node
->abq_ref_count
= 0;
753 * qpool_return() moves queue nodes back to the pool queue.
755 * if the pool is over max, the node is discarded instead.
758 qpool_return(plugin_t
*p
, audit_q_t
*node
)
764 uint64_t sequence
= node
->aqq_sequence
;
766 qpool_size
= audit_queue_size(&(p
->plg_pool
));
767 q_size
= audit_queue_size(&(p
->plg_queue
));
769 if (qpool_size
+ q_size
> p
->plg_qmax
)
772 audit_enqueue(&(p
->plg_pool
), node
);
775 "qpool_return(%d): seq=%llu, q size=%d,"
776 " pool size=%d (total alloc=%d), threshhold=%d\n",
777 p
->plg_tid
, sequence
, q_size
, qpool_size
,
778 q_size
+ qpool_size
, p
->plg_q_threshold
));
782 * bpool_return() moves queue nodes back to the pool queue.
785 bpool_return(audit_rec_t
*node
)
788 audit_rec_t
*copy
= node
;
790 node
= audit_release(&b_refcnt_lock
, node
); /* decrement ref cnt */
792 if (node
!= NULL
) { /* NULL if ref cnt is not zero */
793 audit_enqueue(&b_pool
, node
);
795 "bpool_return: requeue %p (allocated=%d,"
796 " pool size=%d)\n", (void *)node
, b_allocated
,
797 audit_queue_size(&b_pool
)));
802 "bpool_return: decrement count for %p (allocated=%d,"
803 " pool size=%d)\n", (void *)copy
, b_allocated
,
804 audit_queue_size(&b_pool
)));
811 dump_state(char *src
, plugin_t
*p
, uint64_t count
, char *msg
)
813 struct sched_param param
;
816 * count is message sequence
818 (void) pthread_getschedparam(p
->plg_tid
, &policy
, ¶m
);
819 (void) fprintf(dbfp
, "%7s(%d/%llu) %11s:"
822 " queue size=%d pool size=%d"
829 src
, p
->plg_tid
, count
, msg
,
830 in_thr
.thd_waiting
, param
.sched_priority
,
831 audit_queue_size(&(p
->plg_queue
)),
832 audit_queue_size(&(p
->plg_pool
)),
833 p
->plg_waiting
, p
->plg_tossed
,
834 p
->plg_queued
, p
->plg_output
);
841 * policy_is_block: return 1 if the continue policy is off for any active
849 (void) pthread_mutex_lock(&plugin_mutex
);
853 if (p
->plg_cnt
== 0) {
854 (void) pthread_mutex_unlock(&plugin_mutex
);
856 "policy_is_block: policy is to block\n"));
861 (void) pthread_mutex_unlock(&plugin_mutex
);
862 DPRINT((dbfp
, "policy_is_block: policy is to continue\n"));
867 * policy_update() -- the kernel has received a policy change.
868 * Presently, the only policy auditd cares about is AUDIT_CNT
871 policy_update(uint32_t newpolicy
)
875 DPRINT((dbfp
, "policy change: %X\n", newpolicy
));
876 (void) pthread_mutex_lock(&plugin_mutex
);
879 p
->plg_cnt
= (newpolicy
& AUDIT_CNT
) ? 1 : 0;
880 (void) pthread_cond_signal(&(p
->plg_cv
));
882 DPRINT((dbfp
, "policy changed for thread %d\n", p
->plg_tid
));
885 (void) pthread_mutex_unlock(&plugin_mutex
);
889 * queue_buffer() inputs a buffer and queues for each active plugin if
890 * it represents a complete audit record. Otherwise it builds a
891 * larger buffer to hold the record and take successive buffers from
892 * c2audit to build a complete record; then queues it for each plugin.
894 * return 0 if data is queued (or damaged and tossed). If resources
895 * are not available, return 0 if all active plugins have the cnt
896 * policy set, else 1. 0 is also returned if the input is a control
897 * message. (aub_buf is aligned on a 64 bit boundary, so casting
898 * it to an integer works just fine.)
901 queue_buffer(au_dbuf_t
*kl
)
906 boolean_t referenced
= 0;
907 static char *invalid_msg
= "invalid audit record discarded";
908 static char *invalid_control
= "invalid audit control discarded";
910 static audit_rec_t
*alt_b_copy
= NULL
;
911 static size_t alt_length
;
912 static size_t alt_offset
;
915 * the buffer may be a kernel -> auditd message. (only
916 * the policy change message exists so far.)
919 if ((kl
->aub_type
& AU_DBUF_NOTIFY
) != 0) {
922 control
= kl
->aub_type
& ~AU_DBUF_NOTIFY
;
926 policy_update(*(uint32_t *)kl
->aub_buf
);
928 case AU_DBUF_SHUTDOWN
:
929 (void) kill(getpid(), SIGTERM
);
930 DPRINT((dbfp
, "AU_DBUF_SHUTDOWN message\n"));
933 warn_or_fatal(0, gettext(invalid_control
));
939 * The test for valid continuation/completion may fail. Need to
940 * assume the failure was earlier and that this buffer may
941 * be a valid first or complete buffer after discarding the
945 if (alt_b_copy
!= NULL
) {
946 if ((kl
->aub_type
== AU_DBUF_FIRST
) ||
947 (kl
->aub_type
== AU_DBUF_COMPLETE
)) {
948 DPRINT((dbfp
, "copy is not null, partial is %d\n",
950 bpool_return(alt_b_copy
);
951 warn_or_fatal(0, gettext(invalid_msg
));
955 if (alt_b_copy
!= NULL
) { /* continue collecting a long record */
956 if (kl
->aub_size
+ alt_offset
> alt_length
) {
957 bpool_return(alt_b_copy
);
959 warn_or_fatal(0, gettext(invalid_msg
));
962 (void) memcpy(alt_b_copy
->abq_buffer
+ alt_offset
, kl
->aub_buf
,
964 alt_offset
+= kl
->aub_size
;
965 if (kl
->aub_type
== AU_DBUF_MIDDLE
)
969 b_copy
->abq_data_len
= alt_length
;
970 } else if (kl
->aub_type
== AU_DBUF_FIRST
) {
971 /* first buffer of a multiple buffer record */
972 alt_length
= getlen(kl
->aub_buf
);
973 if ((alt_length
< MIN_RECORD_SIZE
) ||
974 (alt_length
<= kl
->aub_size
)) {
975 warn_or_fatal(0, gettext(invalid_msg
));
978 alt_b_copy
= bpool_withdraw(kl
->aub_buf
, kl
->aub_size
,
981 if (alt_b_copy
== NULL
)
982 return (policy_is_block());
984 alt_offset
= kl
->aub_size
;
986 } else { /* one buffer, one record -- the basic case */
987 if (kl
->aub_type
!= AU_DBUF_COMPLETE
) {
988 DPRINT((dbfp
, "copy is null, partial is %d\n",
990 warn_or_fatal(0, gettext(invalid_msg
));
991 return (0); /* tossed */
993 b_copy
= bpool_withdraw(kl
->aub_buf
, kl
->aub_size
,
997 return (policy_is_block());
1000 (void) pthread_mutex_lock(&plugin_mutex
);
1003 if (!p
->plg_removed
) {
1005 * Link the record buffer to the input queues.
1006 * To avoid a race, it is necessary to wait
1007 * until all reference count increments
1008 * are complete before queueing q_copy.
1010 audit_incr_ref(&b_refcnt_lock
, b_copy
);
1012 q_copy
= qpool_withdraw(p
);
1013 q_copy
->aqq_sequence
= p
->plg_sequence
++;
1014 q_copy
->aqq_data
= b_copy
;
1016 p
->plg_save_q_copy
= q_copy
; /* enqueue below */
1019 p
->plg_save_q_copy
= NULL
;
1023 * now that the reference count is updated, queue it.
1027 while ((p
!= NULL
) && (p
->plg_save_q_copy
!= NULL
)) {
1028 audit_enqueue(&(p
->plg_queue
), p
->plg_save_q_copy
);
1029 (void) pthread_cond_signal(&(p
->plg_cv
));
1034 bpool_return(b_copy
);
1036 (void) pthread_mutex_unlock(&plugin_mutex
);
1042 * wait_a_while() -- timed wait in the door server to allow output
1048 struct timespec delay
= {0, 500000000}; /* 1/2 second */;
1050 (void) pthread_mutex_lock(&(in_thr
.thd_mutex
));
1051 in_thr
.thd_waiting
= 1;
1052 (void) pthread_cond_reltimedwait_np(&(in_thr
.thd_cv
),
1053 &(in_thr
.thd_mutex
), &delay
);
1054 in_thr
.thd_waiting
= 0;
1055 (void) pthread_mutex_unlock(&(in_thr
.thd_mutex
));
1059 * adjust_priority() -- check queue and pools and adjust the priority
1060 * for process() accordingly. If we're way ahead of output, do a
1061 * timed wait as well.
1066 int queue_near_full
;
1069 struct sched_param param
;
1071 queue_near_full
= 0;
1072 (void) pthread_mutex_lock(&plugin_mutex
);
1075 queue_size
= audit_queue_size(&(p
->plg_queue
));
1076 if (queue_size
> p
->plg_q_threshold
) {
1077 if (p
->plg_priority
!= HIGH_PRIORITY
) {
1079 param
.sched_priority
=
1081 (void) pthread_setschedparam(p
->plg_tid
,
1082 SCHED_OTHER
, ¶m
);
1084 if (queue_size
> p
->plg_qmax
- p
->plg_qmin
) {
1085 queue_near_full
= 1;
1091 (void) pthread_mutex_unlock(&plugin_mutex
);
1093 if (queue_near_full
) {
1095 "adjust_priority: input taking a short break\n"));
1098 "adjust_priority: input back from my break\n"));
1103 * input() is a door server; it blocks if any plugins have full queues
1104 * with the continue policy off. (auditconfig -setpolicy -cnt)
1106 * input() is called synchronously from c2audit and is NOT
1107 * reentrant due to the (unprotected) static variables in
1108 * queue_buffer(). If multiple clients are created, a context
1109 * structure will be required for queue_buffer.
1111 * timedwait is used when input() gets too far ahead of process();
1112 * the wait terminates either when the set time expires or when
1113 * process() signals that it has nearly caught up.
1117 input(void *cookie
, void *argp
, int arg_size
, door_desc_t
*dp
,
1124 static int call_counter
= 0;
1128 gettext("invalid data received from c2audit\n"));
1131 DPRINT((dbfp
, "%d input new buffer: length=%u, "
1132 "partial=%u, arg_size=%d\n",
1133 ++call_counter
, ((au_dbuf_t
*)argp
)->aub_size
,
1134 ((au_dbuf_t
*)argp
)->aub_type
, arg_size
));
1136 if (((au_dbuf_t
*)argp
)->aub_size
< 1) {
1138 gettext("invalid data length received from c2audit\n"));
1142 * is_blocked is true only if one or more plugins have "no
1143 * continue" (-cnt) set and one of those has a full queue.
1144 * All plugins block until success is met.
1147 DPRINT((dbfp
, "%d input is calling queue_buffer\n",
1150 is_blocked
= queue_buffer((au_dbuf_t
*)argp
);
1157 "%d input blocked (loop=%d)\n",
1158 call_counter
, loop_count
));
1162 DPRINT((dbfp
, "%d input unblocked (loop=%d)\n",
1163 call_counter
, loop_count
));
1172 (void) pthread_cond_signal(&(p
->plg_cv
));
1175 ((au_dbuf_t
*)argp
)->aub_size
= 0; /* return code */
1176 (void) door_return(argp
, sizeof (uint64_t), NULL
, 0);
1180 * process() -- pass a buffer to a plugin
1183 process(plugin_t
*p
)
1186 audit_rec_t
*b_node
;
1190 struct timespec delay
;
1193 struct sched_param param
;
1194 static boolean_t once
= B_FALSE
;
1196 DPRINT((dbfp
, "%s is thread %d\n", p
->plg_path
, p
->plg_tid
));
1197 p
->plg_priority
= param
.sched_priority
= BASE_PRIORITY
;
1198 (void) pthread_setschedparam(p
->plg_tid
, SCHED_OTHER
, ¶m
);
1203 while (audit_dequeue(&(p
->plg_queue
), (void *)&q_node
) != 0) {
1204 DUMP("process", p
, p
->plg_last_seq_out
, "blocked");
1205 (void) pthread_cond_signal(&(in_thr
.thd_cv
));
1207 (void) pthread_mutex_lock(&(p
->plg_mutex
));
1209 (void) pthread_cond_wait(&(p
->plg_cv
),
1212 (void) pthread_mutex_unlock(&(p
->plg_mutex
));
1215 goto plugin_removed
;
1217 DUMP("process", p
, p
->plg_last_seq_out
, "unblocked");
1220 if (q_node
->aqq_sequence
!= p
->plg_last_seq_out
+ 1)
1221 (void) fprintf(dbfp
,
1222 "process(%d): buffer sequence=%llu but prev=%llu\n",
1223 p
->plg_tid
, q_node
->aqq_sequence
,
1224 p
->plg_last_seq_out
);
1226 error_string
= NULL
;
1228 b_node
= q_node
->aqq_data
;
1230 plugrc
= p
->plg_fplugin(b_node
->abq_buffer
,
1231 b_node
->abq_data_len
, q_node
->aqq_sequence
, &error_string
);
1234 goto plugin_removed
;
1236 p
->plg_last_seq_out
= q_node
->aqq_sequence
;
1241 report_error(plugrc
, error_string
, p
->plg_path
);
1245 error_string
= NULL
;
1247 DPRINT((dbfp
, "process(%d) AUDITD_RETRY returned."
1248 " cnt=%d (if 1, enter retry)\n",
1249 p
->plg_tid
, p
->plg_cnt
));
1251 if (p
->plg_cnt
) /* if cnt is on, lose the buffer */
1254 delay
.tv_sec
= p
->plg_retry_time
;
1255 (void) pthread_mutex_lock(&(p
->plg_mutex
));
1257 (void) pthread_cond_reltimedwait_np(&(p
->plg_cv
),
1258 &(p
->plg_mutex
), &delay
);
1260 (void) pthread_mutex_unlock(&(p
->plg_mutex
));
1262 DPRINT((dbfp
, "left retry mode for %d\n", p
->plg_tid
));
1265 case AUDITD_SUCCESS
:
1270 report_error(plugrc
, error_string
, p
->plg_path
);
1272 error_string
= NULL
;
1275 bpool_return(b_node
);
1276 qpool_return(p
, q_node
);
1279 queue_len
= audit_queue_size(&(p
->plg_queue
));
1281 (void) pthread_mutex_lock(&(in_thr
.thd_mutex
));
1282 if (in_thr
.thd_waiting
&& (queue_len
> p
->plg_qmin
) &&
1283 (queue_len
< p
->plg_q_threshold
))
1286 (void) pthread_mutex_unlock(&(in_thr
.thd_mutex
));
1289 (void) pthread_cond_signal(&(in_thr
.thd_cv
));
1291 * sched_yield(); does not help
1292 * performance and in artificial tests
1293 * (high sustained volume) appears to
1294 * hurt by adding wide variability in
1297 } else if ((p
->plg_priority
< BASE_PRIORITY
) &&
1298 (queue_len
< p
->plg_q_threshold
)) {
1299 p
->plg_priority
= param
.sched_priority
=
1301 (void) pthread_setschedparam(p
->plg_tid
, SCHED_OTHER
,
1304 } /* end for (;;) */
1306 DUMP("process", p
, p
->plg_last_seq_out
, "exit");
1307 error_string
= NULL
;
1308 if ((rc
= p
->plg_fplugin_close(&error_string
)) !=
1310 report_error(rc
, error_string
, p
->plg_path
);
1314 (void) pthread_mutex_lock(&plugin_mutex
);
1315 (void) unload_plugin(p
);
1316 (void) pthread_mutex_unlock(&plugin_mutex
);