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