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