xref: /titanic_50/usr/src/cmd/auditd/doorway.c (revision d321a33cdd896e6b211d113a33698dd76e89b861)
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