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