Home | History | Annotate | Download | only in auditd
      1 /*
      2  * CDDL HEADER START
      3  *
      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.
      7  *
      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.
     12  *
     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]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  *
     25  */
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 /*
     28  * Threads:
     29  *
     30  * auditd is thread 0 and does signal handling
     31  *
     32  * input() is a door server that receives binary audit records and
     33  * queues them for handling by an instance of process() for conversion to syslog
     34  * message(s).  There is one process thread per plugin.
     35  *
     36  * Queues:
     37  *
     38  * Each plugin has a buffer pool and and queue for feeding the
     39  * the process threads.  The input thread moves buffers from the pool
     40  * to the queue and the process thread puts them back.
     41  *
     42  * Another pool, b_pool, contains buffers referenced by each of the
     43  * process queues; this is to minimize the number of buffer copies
     44  *
     45  */
     46 
     47 #include <arpa/inet.h>
     48 #include <assert.h>
     49 #include <bsm/adt.h>
     50 #include <dlfcn.h>
     51 #include <errno.h>
     52 #include <fcntl.h>
     53 #include <libintl.h>
     54 #include <pthread.h>
     55 #include <secdb.h>
     56 #include <security/auditd.h>
     57 #include <signal.h>
     58 #include <stdio.h>
     59 #include <stdlib.h>
     60 #include <string.h>
     61 #include <syslog.h>
     62 #include <sys/socket.h>
     63 #include <sys/types.h>
     64 #include <sys/stat.h>
     65 #include <unistd.h>
     66 #include <audit_plugin.h>	/* libbsm */
     67 #include "plugin.h"
     68 #include <bsm/audit_door_infc.h>
     69 #include "audit_sig_infc.h"
     70 #include "queue.h"
     71 
     72 #define	DEBUG		0
     73 
     74 #if DEBUG
     75 
     76 static FILE *dbfp;
     77 #define	DUMP(w, x, y, z) dump_state(w, x, y, z)
     78 #define	DPRINT(x) {(void) fprintf x; }
     79 
     80 #else
     81 
     82 #define	DUMP(w, x, y, z)
     83 #define	DPRINT(x)
     84 
     85 #endif
     86 
     87 #define	FATAL_MESSAGE_LEN	256
     88 
     89 #define	MIN_RECORD_SIZE	(size_t)25
     90 
     91 #define	INPUT_MIN		2
     92 #define	THRESHOLD_PCT		75
     93 #define	DEFAULT_BUF_SZ		(size_t)250
     94 #define	BASE_PRIORITY		10	/* 0 - 20 valid for user, time share */
     95 #define	HIGH_PRIORITY		BASE_PRIORITY - 1
     96 
     97 static thr_data_t	in_thr;		/* input thread locks and data */
     98 static int		doorfd = -1;
     99 
    100 static int		largest_queue = INPUT_MIN;
    101 static au_queue_t	b_pool;
    102 static int		b_allocated = 0;
    103 static pthread_mutex_t	b_alloc_lock;
    104 static pthread_mutex_t	b_refcnt_lock;
    105 
    106 static void		input(void *, void *, int, door_desc_t *, int);
    107 static void		process(plugin_t *);
    108 
    109 static audit_q_t	*qpool_withdraw(plugin_t *);
    110 static void		qpool_init(plugin_t *, int);
    111 static void		qpool_return(plugin_t *, audit_q_t *);
    112 static void		qpool_close(plugin_t *);
    113 
    114 static audit_rec_t	*bpool_withdraw(char *, size_t, size_t);
    115 static void		bpool_init();
    116 static void		bpool_return(audit_rec_t *);
    117 
    118 /*
    119  * warn_or_fatal() -- log daemon error and (optionally) exit
    120  */
    121 static void
    122 warn_or_fatal(int fatal, char *parting_shot)
    123 {
    124 	char	*severity;
    125 	char	message[512];
    126 
    127 	if (fatal)
    128 		severity = gettext("fatal error");
    129 	else
    130 		severity = gettext("warning");
    131 
    132 	(void) snprintf(message, 512, "%s:  %s", severity, parting_shot);
    133 
    134 	__audit_syslog("auditd", LOG_PID | LOG_ODELAY | LOG_CONS,
    135 	    LOG_DAEMON, LOG_ALERT, message);
    136 
    137 	DPRINT((dbfp, "auditd warn_or_fatal %s: %s\n", severity, parting_shot));
    138 	if (fatal)
    139 		auditd_exit(1);
    140 }
    141 
    142 /* Internal to doorway.c errors... */
    143 #define	INTERNAL_LOAD_ERROR	-1
    144 #define	INTERNAL_SYS_ERROR	-2
    145 #define	INTERNAL_CONFIG_ERROR	-3
    146 
    147 /*
    148  * report_error -- handle errors returned by plugin
    149  *
    150  * rc is plugin's return code if it is a non-negative value,
    151  * otherwise it is a doorway.c code about a plugin.
    152  */
    153 static void
    154 report_error(auditd_rc_t rc, char *error_text, char *plugin_path)
    155 {
    156 	int		warn = 0;
    157 	char		rcbuf[100]; /* short error name string */
    158 	char		message[FATAL_MESSAGE_LEN];
    159 	int		bad_count = 0;
    160 	char		*name;
    161 	char		empty[] = "..";
    162 
    163 	static int	no_plug = 0;
    164 	static int	no_load = 0;
    165 	static int	no_thread;
    166 	static int	no_memory = 0;
    167 	static int	invalid = 0;
    168 	static int	retry = 0;
    169 	static int	fail = 0;
    170 
    171 	name = plugin_path;
    172 	if (error_text == NULL)
    173 		error_text = empty;
    174 	if (name == NULL)
    175 		name = empty;
    176 
    177 	switch (rc) {
    178 	case INTERNAL_LOAD_ERROR:
    179 		warn = 1;
    180 		bad_count = ++no_load;
    181 		(void) strcpy(rcbuf, "load_error");
    182 		break;
    183 	case INTERNAL_SYS_ERROR:
    184 		warn = 1;
    185 		bad_count = ++no_thread;
    186 		(void) strcpy(rcbuf, "sys_error");
    187 		break;
    188 	case INTERNAL_CONFIG_ERROR:
    189 		warn = 1;
    190 		bad_count = ++no_plug;
    191 		(void) strcpy(rcbuf, "config_error");
    192 		name = strdup("--");
    193 		break;
    194 	case AUDITD_SUCCESS:
    195 		break;
    196 	case AUDITD_NO_MEMORY:	/* no_memory */
    197 		warn = 1;
    198 		bad_count = ++no_memory;
    199 		(void) strcpy(rcbuf, "no_memory");
    200 		break;
    201 	case AUDITD_INVALID:	/* invalid */
    202 		warn = 1;
    203 		bad_count = ++invalid;
    204 		(void) strcpy(rcbuf, "invalid");
    205 		break;
    206 	case AUDITD_RETRY:
    207 		warn = 1;
    208 		bad_count = ++retry;
    209 		(void) strcpy(rcbuf, "retry");
    210 		break;
    211 	case AUDITD_COMM_FAIL:	/* comm_fail */
    212 		(void) strcpy(rcbuf, "comm_fail");
    213 		break;
    214 	case AUDITD_FATAL:	/* failure */
    215 		warn = 1;
    216 		bad_count = ++fail;
    217 		(void) strcpy(rcbuf, "failure");
    218 		break;
    219 	default:
    220 		(void) strcpy(rcbuf, "error");
    221 		break;
    222 	}
    223 	DPRINT((dbfp, "report_error(%d - %s): %s\n\t%s\n",
    224 	    bad_count, name, rcbuf, error_text));
    225 	if (warn)
    226 		__audit_dowarn2("plugin", name, rcbuf, error_text, bad_count);
    227 	else {
    228 		(void) snprintf(message, FATAL_MESSAGE_LEN,
    229 		    gettext("audit plugin %s reported error = \"%s\": %s\n"),
    230 		    name, rcbuf, error_text);
    231 		warn_or_fatal(0, message);
    232 	}
    233 }
    234 
    235 static size_t
    236 getlen(char *buf)
    237 {
    238 	adr_t		adr;
    239 	char		tokenid;
    240 	uint32_t	len;
    241 
    242 	adr.adr_now = buf;
    243 	adr.adr_stream = buf;
    244 
    245 	adrm_char(&adr, &tokenid, 1);
    246 	if ((tokenid == AUT_OHEADER) || (tokenid == AUT_HEADER32) ||
    247 	    (tokenid == AUT_HEADER32_EX) || (tokenid == AUT_HEADER64) ||
    248 	    (tokenid == AUT_HEADER64_EX)) {
    249 		adrm_u_int32(&adr, &len, 1);
    250 
    251 		return (len);
    252 	}
    253 	DPRINT((dbfp, "getlen() is not looking at a header token\n"));
    254 
    255 	return (0);
    256 }
    257 
    258 /*
    259  * load_function - call dlsym() to resolve the function address
    260  */
    261 static int
    262 load_function(plugin_t *p, char *name, auditd_rc_t (**func)())
    263 {
    264 	*func = (auditd_rc_t (*)())dlsym(p->plg_dlptr, name);
    265 	if (*func == NULL) {
    266 		char message[FATAL_MESSAGE_LEN];
    267 		char *errmsg = dlerror();
    268 
    269 		(void) snprintf(message, FATAL_MESSAGE_LEN,
    270 		    gettext("dlsym failed %s: error %s"),
    271 		    name, errmsg != NULL ? errmsg : gettext("Unknown error\n"));
    272 
    273 		warn_or_fatal(0, message);
    274 		return (-1);
    275 	}
    276 	return (0);
    277 }
    278 
    279 /*
    280  * load the auditd plug in
    281  */
    282 static int
    283 load_plugin(plugin_t *p)
    284 {
    285 	struct stat64	stat;
    286 	int		fd;
    287 	int		fail = 0;
    288 
    289 	/*
    290 	 * Stat the file so we can check modes and ownerships
    291 	 */
    292 	if ((fd = open(p->plg_path, O_NONBLOCK | O_RDONLY)) != -1) {
    293 		if ((fstat64(fd, &stat) == -1) || (!S_ISREG(stat.st_mode)))
    294 			fail = 1;
    295 	} else
    296 		fail = 1;
    297 	if (fail) {
    298 		char message[FATAL_MESSAGE_LEN];
    299 
    300 		(void) snprintf(message, FATAL_MESSAGE_LEN,
    301 		    gettext("auditd plugin: stat(%s) failed: %s\n"),
    302 		    p->plg_path, strerror(errno));
    303 
    304 		warn_or_fatal(0, message);
    305 		return (-1);
    306 	}
    307 	/*
    308 	 * Check the ownership of the file
    309 	 */
    310 	if (stat.st_uid != (uid_t)0) {
    311 		char message[FATAL_MESSAGE_LEN];
    312 
    313 		(void) snprintf(message, FATAL_MESSAGE_LEN,
    314 		    gettext(
    315 		    "auditd plugin: Owner of the module %s is not root\n"),
    316 		    p->plg_path);
    317 
    318 		warn_or_fatal(0, message);
    319 		return (-1);
    320 	}
    321 	/*
    322 	 * Check the modes on the file
    323 	 */
    324 	if (stat.st_mode&S_IWGRP) {
    325 		char message[FATAL_MESSAGE_LEN];
    326 
    327 		(void) snprintf(message, FATAL_MESSAGE_LEN,
    328 		    gettext("auditd plugin: module %s writable by group\n"),
    329 		    p->plg_path);
    330 
    331 		warn_or_fatal(0, message);
    332 		return (-1);
    333 	}
    334 	if (stat.st_mode&S_IWOTH) {
    335 		char message[FATAL_MESSAGE_LEN];
    336 
    337 		(void) snprintf(message, FATAL_MESSAGE_LEN,
    338 		    gettext("auditd plugin: module %s writable by world\n"),
    339 		    p->plg_path);
    340 
    341 		warn_or_fatal(0, message);
    342 		return (-1);
    343 	}
    344 	/*
    345 	 * Open the plugin
    346 	 */
    347 	p->plg_dlptr = dlopen(p->plg_path, RTLD_LAZY);
    348 
    349 	if (p->plg_dlptr == NULL) {
    350 		char message[FATAL_MESSAGE_LEN];
    351 		char *errmsg = dlerror();
    352 
    353 		(void) snprintf(message, FATAL_MESSAGE_LEN,
    354 		    gettext("plugin load %s failed: %s\n"),
    355 		    p->plg_path, errmsg != NULL ? errmsg :
    356 		    gettext("Unknown error\n"));
    357 
    358 		warn_or_fatal(0, message);
    359 		return (-1);
    360 	}
    361 	if (load_function(p, "auditd_plugin", &(p->plg_fplugin)))
    362 		return (-1);
    363 
    364 	if (load_function(p, "auditd_plugin_open", &(p->plg_fplugin_open)))
    365 		return (-1);
    366 
    367 	if (load_function(p, "auditd_plugin_close", &(p->plg_fplugin_close)))
    368 		return (-1);
    369 
    370 	return (0);
    371 }
    372 
    373 /*
    374  * unload_plugin() unlinks and frees the plugin_t structure after
    375  * freeing buffers and structures that hang off it.  It also dlcloses
    376  * the referenced plugin.  The return is the next entry, which may be NULL
    377  *
    378  * hold plugin_mutex for this call
    379  */
    380 static plugin_t *
    381 unload_plugin(plugin_t *p)
    382 {
    383 	plugin_t	*q, **r;
    384 
    385 	assert(pthread_mutex_trylock(&plugin_mutex) != 0);
    386 
    387 	DPRINT((dbfp, "unload_plugin: removing %s\n", p->plg_path));
    388 
    389 	_kva_free(p->plg_kvlist);	/* _kva_free accepts NULL */
    390 	qpool_close(p);		/* qpool_close accepts NULL pool, queue */
    391 	DPRINT((dbfp, "unload_plugin: %s structure removed\n", p->plg_path));
    392 
    393 	(void) dlclose(p->plg_dlptr);
    394 
    395 	DPRINT((dbfp, "unload_plugin: %s dlclosed\n", p->plg_path));
    396 	free(p->plg_path);
    397 
    398 	(void) pthread_mutex_destroy(&(p->plg_mutex));
    399 	(void) pthread_cond_destroy(&(p->plg_cv));
    400 
    401 	q = plugin_head;
    402 	r = &plugin_head;
    403 	while (q != NULL) {
    404 		if (q == p) {
    405 			*r = p->plg_next;
    406 			free(p);
    407 			break;
    408 		}
    409 		r = &(q->plg_next);
    410 		q = q->plg_next;
    411 	}
    412 	return (*r);
    413 }
    414 
    415 /*
    416  * process return values from plugin_open
    417  *
    418  * presently no attribute is defined.
    419  */
    420 /* ARGSUSED */
    421 static void
    422 open_return(plugin_t *p, char *attrval)
    423 {
    424 }
    425 
    426 /*
    427  * auditd_thread_init
    428  *	- create threads
    429  *	- load plugins
    430  *
    431  * auditd_thread_init is called at auditd startup with an initial list
    432  * of plugins and again each time audit catches a AU_SIG_READ_CONTROL
    433  * or AU_SIG_NEXT_DIR.
    434  *
    435  */
    436 int
    437 auditd_thread_init()
    438 {
    439 	int		threshold;
    440 	auditd_rc_t	rc;
    441 	plugin_t	*p;
    442 	char		*open_params;
    443 	char		*error_string;
    444 	int		plugin_count = 0;
    445 	static int	threads_ready = 0;
    446 
    447 	if (!threads_ready) {
    448 		struct sched_param	param;
    449 #if DEBUG
    450 		dbfp = __auditd_debug_file_open();
    451 #endif
    452 		doorfd = door_create((void(*)())input, 0,
    453 		    DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
    454 		if (doorfd < 0)
    455 			return (1);	/* can't create door -> fatal */
    456 
    457 		param.sched_priority = BASE_PRIORITY;
    458 		(void) pthread_setschedparam(pthread_self(), SCHED_OTHER,
    459 		    &param);
    460 
    461 		/* input door server */
    462 		(void) pthread_mutex_init(&(in_thr.thd_mutex), NULL);
    463 		(void) pthread_cond_init(&(in_thr.thd_cv), NULL);
    464 		in_thr.thd_waiting = 0;
    465 
    466 		bpool_init();
    467 	}
    468 	p = plugin_head;
    469 	while (p != NULL) {
    470 		if (p->plg_removed) {
    471 			DPRINT((dbfp, "start removing %s\n", p->plg_path));
    472 			/* tell process(p) to exit and dlclose */
    473 			(void) pthread_cond_signal(&(p->plg_cv));
    474 		} else if (!p->plg_initialized) {
    475 			DPRINT((dbfp, "start initial load of %s\n",
    476 			    p->plg_path));
    477 			if (load_plugin(p)) {
    478 				report_error(INTERNAL_LOAD_ERROR,
    479 				    gettext("dynamic load failed"),
    480 				    p->plg_path);
    481 				p = unload_plugin(p);
    482 				continue;
    483 			}
    484 			open_params = NULL;
    485 			error_string = NULL;
    486 			if ((rc = p->plg_fplugin_open(
    487 			    p->plg_kvlist,
    488 			    &open_params, &error_string)) != AUDITD_SUCCESS) {
    489 				report_error(rc, error_string, p->plg_path);
    490 				free(error_string);
    491 				p = unload_plugin(p);
    492 				continue;
    493 			}
    494 			open_return(p, open_params);
    495 			p->plg_reopen = 0;
    496 
    497 			threshold = ((p->plg_qmax * THRESHOLD_PCT) + 99) / 100;
    498 			p->plg_qmin = INPUT_MIN;
    499 
    500 			DPRINT((dbfp,
    501 			    "calling qpool_init for %s with qmax=%d\n",
    502 			    p->plg_path, p->plg_qmax));
    503 
    504 			qpool_init(p, threshold);
    505 			audit_queue_init(&(p->plg_queue));
    506 			p->plg_initialized = 1;
    507 
    508 			(void) pthread_mutex_init(&(p->plg_mutex), NULL);
    509 			(void) pthread_cond_init(&(p->plg_cv), NULL);
    510 			p->plg_waiting = 0;
    511 
    512 			if (pthread_create(&(p->plg_tid), NULL,
    513 			    (void *(*)(void *))process, p)) {
    514 				report_error(INTERNAL_SYS_ERROR,
    515 				    gettext("thread creation failed"),
    516 				    p->plg_path);
    517 				p = unload_plugin(p);
    518 				continue;
    519 			}
    520 		} else if (p->plg_reopen) {
    521 			DPRINT((dbfp, "reopen %s\n", p->plg_path));
    522 			error_string = NULL;
    523 			if ((rc = p->plg_fplugin_open(
    524 			    p->plg_kvlist,
    525 			    &open_params, &error_string)) != AUDITD_SUCCESS) {
    526 
    527 				report_error(rc, error_string, p->plg_path);
    528 				free(error_string);
    529 				p = unload_plugin(p);
    530 				continue;
    531 			}
    532 			open_return(p, open_params);
    533 			p->plg_reopen = 0;
    534 
    535 			DPRINT((dbfp, "%s qmax=%d\n",
    536 			    p->plg_path, p->plg_qmax));
    537 
    538 		}
    539 		p->plg_q_threshold = ((p->plg_qmax * THRESHOLD_PCT) + 99) / 100;
    540 
    541 		p = p->plg_next;
    542 		plugin_count++;
    543 	}
    544 	if (plugin_count == 0) {
    545 		report_error(INTERNAL_CONFIG_ERROR,
    546 		    gettext("No plugins are configured"), NULL);
    547 		return (-1);
    548 	}
    549 	if (!threads_ready) {
    550 		/* unleash the kernel */
    551 		rc = auditdoor(doorfd);
    552 
    553 		DPRINT((dbfp, "%d returned from auditdoor.\n",
    554 		    rc));
    555 		if (rc != 0)
    556 			return (1);	/* fatal */
    557 
    558 		threads_ready = 1;
    559 	}
    560 	return (0);
    561 }
    562 
    563 /*
    564  * Door invocations that are in progress during a
    565  * door_revoke() invocation are allowed to complete normally.
    566  * -- man page for door_revoke()
    567  */
    568 void
    569 auditd_thread_close()
    570 {
    571 	if (doorfd == -1)
    572 		return;
    573 	(void) door_revoke(doorfd);
    574 	doorfd = -1;
    575 }
    576 
    577 /*
    578  * qpool_init() sets up pool for queue entries (audit_q_t)
    579  *
    580  */
    581 static void
    582 qpool_init(plugin_t *p, int threshold)
    583 {
    584 	int		i;
    585 	audit_q_t	*node;
    586 
    587 	audit_queue_init(&(p->plg_pool));
    588 
    589 	DPRINT((dbfp, "qpool_init(%d) max, min, threshhold = %d, %d, %d\n",
    590 	    p->plg_tid, p->plg_qmax, p->plg_qmin, threshold));
    591 
    592 	if (p->plg_qmax > largest_queue)
    593 		largest_queue = p->plg_qmax;
    594 
    595 	p->plg_q_threshold = threshold;
    596 
    597 	for (i = 0; i < p->plg_qmin; i++) {
    598 		node = malloc(sizeof (audit_q_t));
    599 		if (node == NULL)
    600 			warn_or_fatal(1, gettext("no memory\n"));
    601 			/* doesn't return */
    602 
    603 		audit_enqueue(&p->plg_pool, node);
    604 	}
    605 }
    606 
    607 /*
    608  * bpool_init() sets up pool and queue for record entries (audit_rec_t)
    609  *
    610  */
    611 static void
    612 bpool_init()
    613 {
    614 	int		i;
    615 	audit_rec_t	*node;
    616 
    617 	audit_queue_init(&b_pool);
    618 	(void) pthread_mutex_init(&b_alloc_lock, NULL);
    619 	(void) pthread_mutex_init(&b_refcnt_lock, NULL);
    620 
    621 	for (i = 0; i < INPUT_MIN; i++) {
    622 		node = malloc(AUDIT_REC_HEADER + DEFAULT_BUF_SZ);
    623 		if (node == NULL)
    624 			warn_or_fatal(1, gettext("no memory\n"));
    625 			/* doesn't return */
    626 
    627 		node->abq_buf_len = DEFAULT_BUF_SZ;
    628 
    629 		node->abq_data_len = 0;
    630 		audit_enqueue(&b_pool, node);
    631 		(void) pthread_mutex_lock(&b_alloc_lock);
    632 		b_allocated++;
    633 		(void) pthread_mutex_unlock(&b_alloc_lock);
    634 	}
    635 }
    636 
    637 /*
    638  * qpool_close() discard queue and pool for a discontinued plugin
    639  *
    640  * there is no corresponding bpool_close() since it would only
    641  * be called as auditd is going down.
    642  */
    643 static void
    644 qpool_close(plugin_t *p) {
    645 	audit_q_t	*q_node;
    646 	audit_rec_t	*b_node;
    647 
    648 	if (!p->plg_initialized)
    649 		return;
    650 
    651 	while (audit_dequeue(&(p->plg_pool), (void *)&q_node) == 0) {
    652 		free(q_node);
    653 	}
    654 	audit_queue_destroy(&(p->plg_pool));
    655 
    656 	while (audit_dequeue(&(p->plg_queue), (void *)&q_node) == 0) {
    657 		b_node = audit_release(&b_refcnt_lock, q_node->aqq_data);
    658 		if (b_node != NULL)
    659 			audit_enqueue(&b_pool, b_node);
    660 		free(q_node);
    661 	}
    662 	audit_queue_destroy(&(p->plg_queue));
    663 }
    664 
    665 /*
    666  * qpool_withdraw
    667  */
    668 static audit_q_t *
    669 qpool_withdraw(plugin_t *p)
    670 {
    671 	audit_q_t	*node;
    672 	int		rc;
    673 
    674 	/* get a buffer from the pool, if any */
    675 	rc = audit_dequeue(&(p->plg_pool), (void *)&node);
    676 	if (rc == 0)
    677 		return (node);
    678 
    679 	/*
    680 	 * the pool is empty: allocate a new element
    681 	 */
    682 	node = malloc(sizeof (audit_q_t));
    683 
    684 	if (node == NULL)
    685 		warn_or_fatal(1, gettext("no memory\n"));
    686 		/* doesn't return */
    687 
    688 	return (node);
    689 }
    690 
    691 /*
    692  * bpool_withdraw -- gets a buffer and fills it
    693  *
    694  */
    695 static audit_rec_t *
    696 bpool_withdraw(char *buffer, size_t buff_size, size_t request_size)
    697 {
    698 	audit_rec_t	*node;
    699 	int		rc;
    700 	size_t		new_length;
    701 
    702 	new_length = (request_size > DEFAULT_BUF_SZ) ?
    703 	    request_size : DEFAULT_BUF_SZ;
    704 
    705 	/* get a buffer from the pool, if any */
    706 	rc = audit_dequeue(&b_pool, (void *)&node);
    707 
    708 	DPRINT((dbfp, "bpool_withdraw buf length=%d,"
    709 	    " requested size=%d, dequeue rc=%d\n",
    710 	    new_length, request_size, rc));
    711 
    712 	if (rc == 0) {
    713 		DPRINT((dbfp, "bpool_withdraw node=%X (pool=%d)\n", node,
    714 		    audit_queue_size(&b_pool)));
    715 
    716 		if (new_length > node->abq_buf_len) {
    717 			node = realloc(node, AUDIT_REC_HEADER + new_length);
    718 			if (node == NULL)
    719 				warn_or_fatal(1, gettext("no memory\n"));
    720 				/* no return */
    721 		}
    722 	} else {
    723 		/*
    724 		 * the pool is empty: allocate a new element
    725 		 */
    726 		(void) pthread_mutex_lock(&b_alloc_lock);
    727 		if (b_allocated >= largest_queue) {
    728 			(void) pthread_mutex_unlock(&b_alloc_lock);
    729 			DPRINT((dbfp, "bpool_withdraw is over max (pool=%d)\n",
    730 			    audit_queue_size(&b_pool)));
    731 			return (NULL);
    732 		}
    733 		(void) pthread_mutex_unlock(&b_alloc_lock);
    734 
    735 		node = malloc(AUDIT_REC_HEADER + new_length);
    736 
    737 		if (node == NULL)
    738 			warn_or_fatal(1, gettext("no memory\n"));
    739 		/* no return */
    740 
    741 		(void) pthread_mutex_lock(&b_alloc_lock);
    742 		b_allocated++;
    743 		(void) pthread_mutex_unlock(&b_alloc_lock);
    744 		DPRINT((dbfp, "bpool_withdraw node=%X (alloc=%d, pool=%d)\n",
    745 		    node, b_allocated, audit_queue_size(&b_pool)));
    746 	}
    747 	assert(request_size <= new_length);
    748 
    749 	(void) memcpy(node->abq_buffer, buffer, buff_size);
    750 	node->abq_data_len = buff_size;
    751 	node->abq_buf_len = new_length;
    752 	node->abq_ref_count = 0;
    753 
    754 	return (node);
    755 }
    756 
    757 /*
    758  * qpool_return() moves queue nodes back to the pool queue.
    759  *
    760  * if the pool is over max, the node is discarded instead.
    761  */
    762 static void
    763 qpool_return(plugin_t *p, audit_q_t *node)
    764 {
    765 	int	qpool_size;
    766 	int	q_size;
    767 
    768 #if DEBUG
    769 	uint32_t	sequence = node->aqq_sequence;
    770 #endif
    771 	qpool_size = audit_queue_size(&(p->plg_pool));
    772 	q_size = audit_queue_size(&(p->plg_queue));
    773 
    774 	if (qpool_size + q_size > p->plg_qmax)
    775 		free(node);
    776 	else
    777 		audit_enqueue(&(p->plg_pool), node);
    778 
    779 	DPRINT((dbfp,
    780 	    "qpool_return(%d):  seq=%d, q size=%d,"
    781 	    " pool size=%d (total alloc=%d), threshhold=%d\n",
    782 	    p->plg_tid, sequence, q_size, qpool_size,
    783 	    q_size + qpool_size, p->plg_q_threshold));
    784 }
    785 
    786 /*
    787  * bpool_return() moves queue nodes back to the pool queue.
    788  */
    789 static void
    790 bpool_return(audit_rec_t *node)
    791 {
    792 #if DEBUG
    793 	audit_rec_t	*copy = node;
    794 #endif
    795 	node = audit_release(&b_refcnt_lock, node); 	/* decrement ref cnt */
    796 
    797 	if (node != NULL) {	/* NULL if ref cnt is not zero */
    798 		audit_enqueue(&b_pool, node);
    799 		DPRINT((dbfp,
    800 		    "bpool_return: requeue %X (allocated=%d,"
    801 		    " pool size=%d)\n", node, b_allocated,
    802 		    audit_queue_size(&b_pool)));
    803 	}
    804 #if DEBUG
    805 	else {
    806 		DPRINT((dbfp,
    807 		    "bpool_return: decrement count for %X (allocated=%d,"
    808 		    " pool size=%d)\n", copy, b_allocated,
    809 		    audit_queue_size(&b_pool)));
    810 	}
    811 #endif
    812 }
    813 
    814 #if DEBUG
    815 static void
    816 dump_state(char *src, plugin_t *p, int count, char *msg)
    817 {
    818 	struct sched_param	param;
    819 	int			policy;
    820 /*
    821  * count is message sequence
    822  */
    823 	(void) pthread_getschedparam(p->plg_tid, &policy, &param);
    824 	(void) fprintf(dbfp, "%7s(%d/%d) %11s:"
    825 	    " input_in_wait=%d"
    826 	    " priority=%d"
    827 	    " queue size=%d pool size=%d"
    828 	    "\n\t"
    829 	    "process wait=%d"
    830 	    " tossed=%d"
    831 	    " queued=%d"
    832 	    " written=%d"
    833 	    "\n",
    834 	    src, p->plg_tid, count, msg,
    835 	    in_thr.thd_waiting, param.sched_priority,
    836 	    audit_queue_size(&(p->plg_queue)),
    837 	    audit_queue_size(&(p->plg_pool)),
    838 	    p->plg_waiting, p->plg_tossed,
    839 	    p->plg_queued, p->plg_output);
    840 
    841 	(void) fflush(dbfp);
    842 }
    843 #endif
    844 
    845 /*
    846  * policy_is_block: return 1 if the continue policy is off for any active
    847  * plugin, else 0
    848  */
    849 static int
    850 policy_is_block()
    851 {
    852 	plugin_t *p;
    853 
    854 	(void) pthread_mutex_lock(&plugin_mutex);
    855 	p = plugin_head;
    856 
    857 	while (p != NULL) {
    858 		if (p->plg_cnt == 0) {
    859 			(void) pthread_mutex_unlock(&plugin_mutex);
    860 			DPRINT((dbfp,
    861 			    "policy_is_block:  policy is to block\n"));
    862 			return (1);
    863 		}
    864 		p = p->plg_next;
    865 	}
    866 	(void) pthread_mutex_unlock(&plugin_mutex);
    867 	DPRINT((dbfp, "policy_is_block:  policy is to continue\n"));
    868 	return (0);
    869 }
    870 
    871 /*
    872  * policy_update() -- the kernel has received a policy change.
    873  * Presently, the only policy auditd cares about is AUDIT_CNT
    874  */
    875 static void
    876 policy_update(uint32_t newpolicy)
    877 {
    878 	plugin_t *p;
    879 
    880 	DPRINT((dbfp, "policy change:  %X\n", newpolicy));
    881 	(void) pthread_mutex_lock(&plugin_mutex);
    882 	p = plugin_head;
    883 	while (p != NULL) {
    884 		p->plg_cnt = (newpolicy & AUDIT_CNT) ? 1 : 0;
    885 		(void) pthread_cond_signal(&(p->plg_cv));
    886 
    887 		DPRINT((dbfp, "policy changed for thread %d\n", p->plg_tid));
    888 		p = p->plg_next;
    889 	}
    890 	(void) pthread_mutex_unlock(&plugin_mutex);
    891 }
    892 
    893 /*
    894  * queue_buffer() inputs a buffer and queues for each active plugin if
    895  * it represents a complete audit record.  Otherwise it builds a
    896  * larger buffer to hold the record and take successive buffers from
    897  * c2audit to build a complete record; then queues it for each plugin.
    898  *
    899  * return 0 if data is queued (or damaged and tossed).  If resources
    900  * are not available, return 0 if all active plugins have the cnt
    901  * policy set, else 1.  0 is also returned if the input is a control
    902  * message.  (aub_buf is aligned on a 64 bit boundary, so casting
    903  * it to an integer works just fine.)
    904  */
    905 static int
    906 queue_buffer(au_dbuf_t *kl)
    907 {
    908 	plugin_t	*p;
    909 	audit_rec_t	*b_copy;
    910 	audit_q_t	*q_copy;
    911 	boolean_t	referenced = 0;
    912 	static char	*invalid_msg = "invalid audit record discarded";
    913 	static char	*invalid_control = "invalid audit control discarded";
    914 
    915 	static audit_rec_t	*alt_b_copy = NULL;
    916 	static size_t		alt_length;
    917 	static size_t		alt_offset;
    918 
    919 	/*
    920 	 * the buffer may be a kernel -> auditd message.  (only
    921 	 * the policy change message exists so far.)
    922 	 */
    923 
    924 	if ((kl->aub_type & AU_DBUF_NOTIFY) != 0) {
    925 		uint32_t	control;
    926 
    927 		control = kl->aub_type & ~AU_DBUF_NOTIFY;
    928 		switch (control) {
    929 		case AU_DBUF_POLICY:
    930 			/* LINTED */
    931 			policy_update(*(uint32_t *)kl->aub_buf);
    932 			break;
    933 		case AU_DBUF_SHUTDOWN:
    934 			(void) kill(getpid(), AU_SIG_DISABLE);
    935 			DPRINT((dbfp, "AU_DBUF_SHUTDOWN message\n"));
    936 			break;
    937 		default:
    938 			warn_or_fatal(0, gettext(invalid_control));
    939 			break;
    940 		}
    941 		return (0);
    942 	}
    943 	/*
    944 	 * The test for valid continuation/completion may fail. Need to
    945 	 * assume the failure was earlier and that this buffer may
    946 	 * be a valid first or complete buffer after discarding the
    947 	 * incomplete record
    948 	 */
    949 
    950 	if (alt_b_copy != NULL) {
    951 		if ((kl->aub_type == AU_DBUF_FIRST) ||
    952 		    (kl->aub_type == AU_DBUF_COMPLETE)) {
    953 			DPRINT((dbfp, "copy is not null, partial is %d\n",
    954 			    kl->aub_type));
    955 			bpool_return(alt_b_copy);
    956 			warn_or_fatal(0, gettext(invalid_msg));
    957 			alt_b_copy = NULL;
    958 		}
    959 	}
    960 	if (alt_b_copy != NULL) { /* continue collecting a long record */
    961 		if (kl->aub_size + alt_offset > alt_length) {
    962 			bpool_return(alt_b_copy);
    963 			alt_b_copy = NULL;
    964 			warn_or_fatal(0, gettext(invalid_msg));
    965 			return (0);
    966 		}
    967 		(void) memcpy(alt_b_copy->abq_buffer + alt_offset, kl->aub_buf,
    968 		    kl->aub_size);
    969 		alt_offset += kl->aub_size;
    970 		if (kl->aub_type == AU_DBUF_MIDDLE)
    971 			return (0);
    972 		b_copy = alt_b_copy;
    973 		alt_b_copy = NULL;
    974 		b_copy->abq_data_len = alt_length;
    975 	} else if (kl->aub_type == AU_DBUF_FIRST) {
    976 		/* first buffer of a multiple buffer record */
    977 		alt_length = getlen(kl->aub_buf);
    978 		if ((alt_length < MIN_RECORD_SIZE) ||
    979 		    (alt_length <= kl->aub_size)) {
    980 			warn_or_fatal(0, gettext(invalid_msg));
    981 			return (0);
    982 		}
    983 		alt_b_copy = bpool_withdraw(kl->aub_buf, kl->aub_size,
    984 		    alt_length);
    985 
    986 		if (alt_b_copy == NULL)
    987 			return (policy_is_block());
    988 
    989 		alt_offset = kl->aub_size;
    990 		return (0);
    991 	} else { /* one buffer, one record -- the basic case */
    992 		if (kl->aub_type != AU_DBUF_COMPLETE) {
    993 			DPRINT((dbfp, "copy is null, partial is %d\n",
    994 			    kl->aub_type));
    995 			warn_or_fatal(0, gettext(invalid_msg));
    996 			return (0);	/* tossed */
    997 		}
    998 		b_copy = bpool_withdraw(kl->aub_buf, kl->aub_size,
    999 		    kl->aub_size);
   1000 
   1001 		if (b_copy == NULL)
   1002 			return (policy_is_block());
   1003 	}
   1004 
   1005 	(void) pthread_mutex_lock(&plugin_mutex);
   1006 	p = plugin_head;
   1007 	while (p != NULL) {
   1008 		if (!p->plg_removed) {
   1009 			/*
   1010 			 * Link the record buffer to the input queues.
   1011 			 * To avoid a race, it is necessary to wait
   1012 			 * until all reference count increments
   1013 			 * are complete before queueing q_copy.
   1014 			 */
   1015 			audit_incr_ref(&b_refcnt_lock, b_copy);
   1016 
   1017 			q_copy = qpool_withdraw(p);
   1018 			q_copy->aqq_sequence = p->plg_sequence++;
   1019 			q_copy->aqq_data = b_copy;
   1020 
   1021 			p->plg_save_q_copy = q_copy;	/* enqueue below */
   1022 			referenced = 1;
   1023 		} else
   1024 			p->plg_save_q_copy = NULL;
   1025 		p = p->plg_next;
   1026 	}
   1027 	/*
   1028 	 * now that the reference count is updated, queue it.
   1029 	 */
   1030 	if (referenced) {
   1031 		p = plugin_head;
   1032 		while ((p != NULL) && (p->plg_save_q_copy != NULL)) {
   1033 			audit_enqueue(&(p->plg_queue), p->plg_save_q_copy);
   1034 			(void) pthread_cond_signal(&(p->plg_cv));
   1035 			p->plg_queued++;
   1036 			p = p->plg_next;
   1037 		}
   1038 	} else
   1039 		bpool_return(b_copy);
   1040 
   1041 	(void) pthread_mutex_unlock(&plugin_mutex);
   1042 
   1043 	return (0);
   1044 }
   1045 
   1046 /*
   1047  * wait_a_while() -- timed wait in the door server to allow output
   1048  * time to catch up.
   1049  */
   1050 static void
   1051 wait_a_while() {
   1052 	struct timespec delay = {0, 500000000};	/* 1/2 second */;
   1053 
   1054 	(void) pthread_mutex_lock(&(in_thr.thd_mutex));
   1055 	in_thr.thd_waiting = 1;
   1056 	(void) pthread_cond_reltimedwait_np(&(in_thr.thd_cv),
   1057 	    &(in_thr.thd_mutex), &delay);
   1058 	in_thr.thd_waiting = 0;
   1059 	(void) pthread_mutex_unlock(&(in_thr.thd_mutex));
   1060 }
   1061 
   1062 /*
   1063  * adjust_priority() -- check queue and pools and adjust the priority
   1064  * for process() accordingly.  If we're way ahead of output, do a
   1065  * timed wait as well.
   1066  */
   1067 static void
   1068 adjust_priority() {
   1069 	int		queue_near_full;
   1070 	plugin_t	*p;
   1071 	int		queue_size;
   1072 	struct sched_param	param;
   1073 
   1074 	queue_near_full = 0;
   1075 	(void) pthread_mutex_lock(&plugin_mutex);
   1076 	p = plugin_head;
   1077 	while (p != NULL) {
   1078 		queue_size = audit_queue_size(&(p->plg_queue));
   1079 		if (queue_size > p->plg_q_threshold) {
   1080 			if (p->plg_priority != HIGH_PRIORITY) {
   1081 				p->plg_priority =
   1082 				    param.sched_priority =
   1083 				    HIGH_PRIORITY;
   1084 				(void) pthread_setschedparam(p->plg_tid,
   1085 				    SCHED_OTHER, &param);
   1086 			}
   1087 			if (queue_size > p->plg_qmax - p->plg_qmin) {
   1088 				queue_near_full = 1;
   1089 				break;
   1090 			}
   1091 		}
   1092 		p = p->plg_next;
   1093 	}
   1094 	(void) pthread_mutex_unlock(&plugin_mutex);
   1095 
   1096 	if (queue_near_full) {
   1097 		DPRINT((dbfp,
   1098 		    "adjust_priority:  input taking a short break\n"));
   1099 		wait_a_while();
   1100 		DPRINT((dbfp,
   1101 		    "adjust_priority:  input back from my break\n"));
   1102 	}
   1103 }
   1104 
   1105 /*
   1106  * input() is a door server; it blocks if any plugins have full queues
   1107  * with the continue policy off. (auditconfig -policy -cnt)
   1108  *
   1109  * input() is called synchronously from c2audit and is NOT
   1110  * reentrant due to the (unprotected) static variables in
   1111  * queue_buffer().  If multiple clients are created, a context
   1112  * structure will be required for queue_buffer.
   1113  *
   1114  * timedwait is used when input() gets too far ahead of process();
   1115  * the wait terminates either when the set time expires or when
   1116  * process() signals that it has nearly caught up.
   1117  */
   1118 /* ARGSUSED */
   1119 static void
   1120 input(void *cookie, void *argp, int arg_size, door_desc_t *dp,
   1121     int n_descriptors)
   1122 {
   1123 	int		is_blocked;
   1124 	plugin_t	*p;
   1125 #if DEBUG
   1126 	int		loop_count = 0;
   1127 	static int	call_counter = 0;
   1128 #endif
   1129 	if (argp == NULL) {
   1130 		warn_or_fatal(0,
   1131 		    gettext("invalid data received from c2audit\n"));
   1132 		goto input_exit;
   1133 	}
   1134 	DPRINT((dbfp, "%d input new buffer: length=%u, "
   1135 	    "partial=%u, arg_size=%d\n",
   1136 	    ++call_counter, ((au_dbuf_t *)argp)->aub_size,
   1137 	    ((au_dbuf_t *)argp)->aub_type, arg_size));
   1138 
   1139 	if (((au_dbuf_t *)argp)->aub_size < 1) {
   1140 		warn_or_fatal(0,
   1141 		    gettext("invalid data length received from c2audit\n"));
   1142 		goto input_exit;
   1143 	}
   1144 	/*
   1145 	 * is_blocked is true only if one or more plugins have "no
   1146 	 * continue" (-cnt) set and one of those has a full queue.
   1147 	 * All plugins block until success is met.
   1148 	 */
   1149 	for (;;) {
   1150 		DPRINT((dbfp, "%d input is calling queue_buffer\n",
   1151 		    call_counter));
   1152 
   1153 		is_blocked = queue_buffer((au_dbuf_t *)argp);
   1154 
   1155 		if (!is_blocked) {
   1156 			adjust_priority();
   1157 			break;
   1158 		} else {
   1159 			DPRINT((dbfp,
   1160 			    "%d input blocked (loop=%d)\n",
   1161 			    call_counter, loop_count));
   1162 
   1163 			wait_a_while();
   1164 
   1165 			DPRINT((dbfp, "%d input unblocked (loop=%d)\n",
   1166 			    call_counter, loop_count));
   1167 		}
   1168 #if DEBUG
   1169 		loop_count++;
   1170 #endif
   1171 	}
   1172 input_exit:
   1173 	p = plugin_head;
   1174 	while (p != NULL) {
   1175 		(void) pthread_cond_signal(&(p->plg_cv));
   1176 		p = p->plg_next;
   1177 	}
   1178 	((au_dbuf_t *)argp)->aub_size = 0;	/* return code */
   1179 	(void) door_return(argp, sizeof (uint64_t), NULL, 0);
   1180 }
   1181 
   1182 /*
   1183  * process() -- pass a buffer to a plugin
   1184  */
   1185 static void
   1186 process(plugin_t *p)
   1187 {
   1188 	int			rc;
   1189 	audit_rec_t		*b_node;
   1190 	audit_q_t		*q_node;
   1191 	auditd_rc_t		plugrc;
   1192 	char			*error_string;
   1193 	struct timespec 	delay;
   1194 	int			sendsignal;
   1195 	int			queue_len;
   1196 	struct sched_param	param;
   1197 	static boolean_t	once = B_FALSE;
   1198 
   1199 	DPRINT((dbfp, "%s is thread %d\n", p->plg_path, p->plg_tid));
   1200 	p->plg_priority = param.sched_priority = BASE_PRIORITY;
   1201 	(void) pthread_setschedparam(p->plg_tid, SCHED_OTHER, &param);
   1202 
   1203 	delay.tv_nsec = 0;
   1204 
   1205 	for (;;) {
   1206 		while (audit_dequeue(&(p->plg_queue), (void *)&q_node) != 0) {
   1207 			DUMP("process", p, p->plg_last_seq_out, "blocked");
   1208 			(void) pthread_cond_signal(&(in_thr.thd_cv));
   1209 
   1210 			(void) pthread_mutex_lock(&(p->plg_mutex));
   1211 			p->plg_waiting++;
   1212 			(void) pthread_cond_wait(&(p->plg_cv),
   1213 			    &(p->plg_mutex));
   1214 			p->plg_waiting--;
   1215 			(void) pthread_mutex_unlock(&(p->plg_mutex));
   1216 
   1217 			if (p->plg_removed)
   1218 				goto plugin_removed;
   1219 
   1220 			DUMP("process", p, p->plg_last_seq_out, "unblocked");
   1221 		}
   1222 #if DEBUG
   1223 		if (q_node->aqq_sequence != p->plg_last_seq_out + 1)
   1224 			(void) fprintf(dbfp,
   1225 			    "process(%d): buffer sequence=%u but prev=%u\n",
   1226 			    p->plg_tid, q_node->aqq_sequence,
   1227 			    p->plg_last_seq_out);
   1228 #endif
   1229 		error_string = NULL;
   1230 
   1231 		b_node = q_node->aqq_data;
   1232 retry_mode:
   1233 		plugrc = p->plg_fplugin(b_node->abq_buffer,
   1234 		    b_node->abq_data_len, q_node->aqq_sequence, &error_string);
   1235 
   1236 		if (p->plg_removed)
   1237 			goto plugin_removed;
   1238 #if DEBUG
   1239 		p->plg_last_seq_out = q_node->aqq_sequence;
   1240 #endif
   1241 		switch (plugrc) {
   1242 		case AUDITD_RETRY:
   1243 			if (!once) {
   1244 				report_error(plugrc, error_string, p->plg_path);
   1245 				once = B_TRUE;
   1246 			}
   1247 			free(error_string);
   1248 			error_string = NULL;
   1249 
   1250 			DPRINT((dbfp, "process(%d) AUDITD_RETRY returned."
   1251 			    " cnt=%d (if 1, enter retry)\n",
   1252 			    p->plg_tid, p->plg_cnt));
   1253 
   1254 			if (p->plg_cnt)	/* if cnt is on, lose the buffer */
   1255 				break;
   1256 
   1257 			delay.tv_sec = p->plg_retry_time;
   1258 			(void) pthread_mutex_lock(&(p->plg_mutex));
   1259 			p->plg_waiting++;
   1260 			(void) pthread_cond_reltimedwait_np(&(p->plg_cv),
   1261 			    &(p->plg_mutex), &delay);
   1262 			p->plg_waiting--;
   1263 			(void) pthread_mutex_unlock(&(p->plg_mutex));
   1264 
   1265 			DPRINT((dbfp, "left retry mode for %d\n", p->plg_tid));
   1266 			goto retry_mode;
   1267 
   1268 		case AUDITD_SUCCESS:
   1269 			p->plg_output++;
   1270 			once = B_FALSE;
   1271 			break;
   1272 		default:
   1273 			report_error(plugrc, error_string, p->plg_path);
   1274 			free(error_string);
   1275 			error_string = NULL;
   1276 			break;
   1277 		}	/* end switch */
   1278 		bpool_return(b_node);
   1279 		qpool_return(p, q_node);
   1280 
   1281 		sendsignal = 0;
   1282 		queue_len = audit_queue_size(&(p->plg_queue));
   1283 
   1284 		(void) pthread_mutex_lock(&(in_thr.thd_mutex));
   1285 		if (in_thr.thd_waiting && (queue_len > p->plg_qmin) &&
   1286 		    (queue_len < p->plg_q_threshold))
   1287 			sendsignal = 1;
   1288 
   1289 		(void) pthread_mutex_unlock(&(in_thr.thd_mutex));
   1290 
   1291 		if (sendsignal) {
   1292 			(void) pthread_cond_signal(&(in_thr.thd_cv));
   1293 			/*
   1294 			 * sched_yield(); does not help
   1295 			 * performance and in artificial tests
   1296 			 * (high sustained volume) appears to
   1297 			 * hurt by adding wide variability in
   1298 			 * the results.
   1299 			 */
   1300 		} else if ((p->plg_priority < BASE_PRIORITY) &&
   1301 		    (queue_len < p->plg_q_threshold)) {
   1302 			p->plg_priority = param.sched_priority =
   1303 			    BASE_PRIORITY;
   1304 			(void) pthread_setschedparam(p->plg_tid, SCHED_OTHER,
   1305 			    &param);
   1306 		}
   1307 	}	/* end for (;;) */
   1308 plugin_removed:
   1309 	DUMP("process", p, p->plg_last_seq_out, "exit");
   1310 	error_string = NULL;
   1311 	if ((rc = p->plg_fplugin_close(&error_string)) !=
   1312 	    AUDITD_SUCCESS)
   1313 		report_error(rc, error_string, p->plg_path);
   1314 
   1315 	free(error_string);
   1316 
   1317 	(void) pthread_mutex_lock(&plugin_mutex);
   1318 	(void) unload_plugin(p);
   1319 	(void) pthread_mutex_unlock(&plugin_mutex);
   1320 }
   1321