xref: /illumos-gate/usr/src/cmd/auditd/auditd.c (revision 79033acb)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /* Audit daemon server */
30 /*
31  * These routines make up the audit daemon server.  This daemon, called
32  * auditd, handles the user level parts of auditing.  It receives buffered
33  * audit records (usually one or more per buffer, potentially less than
34  * one) and passes them to one or more plugins for processing.
35  *
36  * The major interrupts are AU_SIG_READ_CONTROL (start over),
37  * AU_SIG_DISABLE (start shutting down), SIGALRM (quit), and
38  * AU_SIG_NEXT_DIR (start a new audit log file). SIGTERM (the implementation
39  * value of AU_SIG_DISABLE) is also used for the child to tell the parent
40  * that audit is ready.
41  *
42  * Configuration data comes from /etc/security/audit_control and the auditon
43  * system call.
44  *
45  * The major errors are EBUSY (auditing is already in use) and EINTR
46  * (one of the above signals was received).  File space errors are
47  * handled by the audit_binfile plugin
48  */
49 
50 #define	DEBUG 		0
51 #define	MEM_TEST	0	/* set to one to generate core dump on exit */
52 
53 #include <assert.h>
54 #include <bsm/audit.h>
55 #include <bsm/audit_record.h>
56 #include <bsm/libbsm.h>
57 #include <fcntl.h>
58 #include <libintl.h>
59 #include <locale.h>
60 #include <netdb.h>
61 #include <pwd.h>
62 #include <secdb.h>
63 #include <signal.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <errno.h>
68 #include <sys/file.h>
69 #include <sys/param.h>
70 #include <sys/stat.h>
71 #include <sys/statvfs.h>
72 #include <sys/time.h>
73 #include <sys/types.h>
74 #include <sys/wait.h>
75 #include <termios.h>
76 #include <unistd.h>
77 #include "plugin.h"
78 #include "audit_sig_infc.h"
79 #include <audit_plugin.h>
80 
81 #if !defined(TEXT_DOMAIN)
82 #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
83 #endif
84 /*
85  * After we get a AU_SIG_DISABLE, we want to set a timer for 2 seconds
86  * and let c2audit write as many records as it can until the timer
87  * goes off(at which point it returns to auditd with SIGALRM).  If any
88  * other signals are received during that time, we call
89  * __audit_dowarn() to indicate that the queue may not have been fully
90  * flushed.
91  */
92 #define	ALRM_TIME	2
93 #define	SLEEP_TIME	20	/* # of seconds to sleep in all hard loop */
94 
95 #if DEBUG
96 #define	DPRINT(x) {(void) fprintf x; }
97 static FILE	*dbfp;	/* debug file */
98 #else
99 #define	DPRINT(x)
100 #endif /* DEBUG */
101 
102 static plugin_t	*binfile = NULL;
103 
104 static int	turn_audit_on  = AUC_AUDITING;
105 static int	turn_audit_off = AUC_NOAUDIT;
106 
107 static int	running = 1;
108 
109 /*
110  * GLOBALS:
111  */
112 plugin_t		*plugin_head = NULL;
113 static thr_data_t	main_thr;	/* auditd thread (0) */
114 pthread_mutex_t		plugin_mutex;	/* for plugin_t list */
115 
116 static int	caught_alrm = 0;	/* number of SIGALRMs pending */
117 static int	caught_readc = 0;	/* number of AU_SIG_READ_CONTROLs */
118 static int	caught_term = 0;	/* number of AU_SIG_DISABLEs pending */
119 static int	caught_nextd = 0;	/* number of AU_SIG_NEXT_DIRs pending */
120 
121 static int	reset_list = 1;	/* 1 to re-read audit_control */
122 static int	reset_file = 1; /* 1 to close/open binary log */
123 
124 static int	auditing_set = 0;	/* 1 if auditon(A_SETCOND, on... */
125 
126 static void	my_sleep();
127 static void	signal_thread();
128 static void	loadauditlist();
129 static void	block_signals();
130 static int	do_sethost();
131 
132 /* common exit function */
133 void
134 auditd_exit(int status)
135 {
136 #if MEM_TEST
137 	sigset_t	set;
138 
139 	DPRINT((dbfp, "mem_test intentional abort (status=%d)\n",
140 	    status));
141 	abort();
142 #endif
143 	DPRINT((dbfp, "%ld exit status = %d auditing_set = %d\n",
144 	    getpid(), status, auditing_set));
145 
146 	if (auditing_set)
147 		(void) auditon(A_SETCOND, (caddr_t)&turn_audit_off,
148 		    (int)sizeof (int));
149 
150 	exit(status);
151 }
152 
153 /* ARGSUSED */
154 int
155 main(int argc, char *argv[])
156 {
157 	auditinfo_addr_t	as_null;	/* audit state to set */
158 	au_id_t			auid;
159 	pthread_t		tid;
160 	plugin_t		*p;
161 	pid_t			pid;
162 
163 #if DEBUG
164 	/* LINTED */
165 	char			*envp;
166 	dbfp = __auditd_debug_file_open();
167 #endif
168 	(void) setsid();
169 
170 	/* Internationalization */
171 	(void) setlocale(LC_ALL, "");
172 	(void) textdomain(TEXT_DOMAIN);
173 
174 	/*
175 	 * Set the audit host-id.
176 	 */
177 	if (do_sethost() != 0) {
178 		__audit_dowarn("nostart", "", 0);
179 		auditd_exit(1);
180 	}
181 
182 	/*
183 	 * Turn off all auditing for this process.
184 	 */
185 	if (getaudit_addr(&as_null, sizeof (as_null)) == -1) {
186 		__audit_dowarn("nostart", "", 0);
187 		auditd_exit(2);
188 	}
189 	as_null.ai_mask.as_success = 0;
190 	as_null.ai_mask.as_failure = 0;
191 	(void) setaudit_addr(&as_null, sizeof (as_null));
192 	auid = AU_NOAUDITID;
193 	(void) setauid(&auid);
194 	/*
195 	 * Set the audit state flag to AUDITING.
196 	 */
197 	if (auditon(A_SETCOND, (caddr_t)&turn_audit_on, (int)sizeof (int)) !=
198 	    0) {
199 		DPRINT((dbfp, "auditon(A_SETCOND...) failed (exit)\n"));
200 		__audit_dowarn("nostart", "", 0);
201 		auditd_exit(7);
202 	}
203 
204 	block_signals();
205 
206 #if DEBUG
207 	/* output to dbfp shouldn't be duplicated by parent and child */
208 	(void) fflush(dbfp);
209 #endif
210 	/*
211 	 * wait for "ready" signal before exit -- for greenline
212 	 */
213 	if (fork()) {
214 		sigset_t	set;
215 		int		signal_caught = 0;
216 
217 		(void) sigemptyset(&set);
218 		(void) sigaddset(&set, AU_SIG_DISABLE);
219 
220 		while (signal_caught != AU_SIG_DISABLE)
221 			signal_caught = sigwait(&set);
222 
223 		DPRINT((dbfp, "init complete:  parent can now exit\n"));
224 
225 		auditd_exit(0);
226 	}
227 	pid = getppid();
228 
229 	auditing_set = 1;
230 
231 #if DEBUG && MEM_TEST
232 	envp = getenv("UMEM_DEBUG");
233 	if (envp != NULL)
234 		DPRINT((dbfp, "UMEM_DEBUG=%s\n", envp));
235 	envp = getenv("UMEM_LOGGING");
236 	if (envp != NULL)
237 		DPRINT((dbfp, "UMEM_LOGGING=%s\n", envp));
238 #endif
239 	DPRINT((dbfp, "auditd pid=%ld\n", getpid()));
240 
241 	/* thread 0 sync */
242 	(void) pthread_mutex_init(&(main_thr.thd_mutex), NULL);
243 	(void) pthread_cond_init(&(main_thr.thd_cv), NULL);
244 	(void) pthread_mutex_init(&plugin_mutex, NULL);
245 	/*
246 	 * Set up a separate thread for signal handling.
247 	 */
248 	if (pthread_create(&tid, NULL, (void *(*)(void *))signal_thread,
249 	    NULL)) {
250 		(void) fprintf(stderr, gettext(
251 		    "auditd can't create a thread\n"));
252 		auditd_exit(3);
253 	}
254 	/*
255 	 * Set the umask so that only audit or other users in the audit group
256 	 * can get to the files created by auditd.
257 	 */
258 	(void) umask(007);
259 
260 	if (__logpost("")) {	/* Open the audit_data file. */
261 		DPRINT((dbfp, "logpost failed\n"));
262 		auditd_exit(4);
263 	}
264 	/*
265 	 * Here is the main body of the audit daemon.  running == 0 means that
266 	 * after flushing out the audit queue, it is time to exit in response to
267 	 * AU_SIG_DISABLE
268 	 */
269 	while (running) {
270 		/*
271 		 * Read audit_control and create plugin lists.
272 		 *
273 		 * loadauditlist() and auditd_thread_init() are called
274 		 * while under the plugin_mutex lock to avoid a race
275 		 * with unload_plugin().
276 		 */
277 		if (reset_list || reset_file) {
278 			(void) pthread_mutex_lock(&plugin_mutex);
279 			if (reset_list)
280 				loadauditlist();
281 
282 			if (auditd_thread_init()) {
283 				auditd_thread_close();
284 				/* continue; wait for audit -s */
285 			}
286 			(void) pthread_mutex_unlock(&plugin_mutex);
287 			reset_list = 0;
288 		}
289 		/*
290 		 * tell parent I'm running whether or not the initialization
291 		 * actually worked.  The failure case is to wait for an
292 		 * audit -n or audit -s to fix the problem.
293 		 */
294 		if (pid != 0) {
295 			(void) kill(pid, AU_SIG_DISABLE);
296 			pid = 0;
297 		}
298 		/*
299 		 * thread_signal() signals main (this thread) when
300 		 * it has received a signal.
301 		 */
302 		DPRINT((dbfp, "main thread is waiting\n"));
303 		(void) pthread_mutex_lock(&(main_thr.thd_mutex));
304 
305 		if (!(caught_readc || caught_term || caught_alrm ||
306 		    caught_nextd))
307 			(void) pthread_cond_wait(&(main_thr.thd_cv),
308 			    &(main_thr.thd_mutex));
309 		(void) pthread_mutex_unlock(&(main_thr.thd_mutex));
310 		/*
311 		 * Got here because a signal came in.
312 		 * Since we may have gotten more than one, we assume a
313 		 * priority scheme with SIGALRM being the most
314 		 * significant.
315 		 */
316 		if (caught_alrm) {
317 			/*
318 			 * We have returned from our timed wait for
319 			 * c2audit to calm down.  We need to really shut
320 			 * down here.
321 			 */
322 			caught_alrm = 0;
323 			running = 0;	/* shut down now */
324 		} else if (caught_term) {
325 			/*
326 			 * we are going to shut down, but need to
327 			 * allow time for the audit queues in
328 			 * c2audit and for the threads to empty.
329 			 */
330 
331 			p = plugin_head;
332 			while (p != NULL) {
333 				DPRINT((dbfp, "signalling thread %d\n",
334 				    p->plg_tid));
335 				(void) pthread_mutex_lock(&(p->plg_mutex));
336 				p->plg_removed = 1;
337 
338 				if (p->plg_initialized)
339 					(void) pthread_cond_signal(
340 					    &(p->plg_cv));
341 
342 				(void) pthread_mutex_unlock(&(p->plg_mutex));
343 				p = p->plg_next;
344 			}
345 
346 			caught_alrm = 0;
347 			caught_readc  = 0;
348 			caught_term = 0;
349 			caught_nextd = 0;
350 
351 			DPRINT((dbfp,
352 			    "main thread is pausing before exit.\n"));
353 			(void) pthread_mutex_lock(&(main_thr.thd_mutex));
354 			caught_alrm = 0;
355 			(void) alarm(ALRM_TIME);
356 			while (!caught_alrm)
357 				(void) pthread_cond_wait(&(main_thr.thd_cv),
358 				    &(main_thr.thd_mutex));
359 
360 			(void) pthread_mutex_unlock(&(main_thr.thd_mutex));
361 
362 			running = 0;	/* Close down auditing and exit */
363 		} else if (caught_readc) {
364 			/*
365 			 * if both hup and usr1 are caught, the logic in
366 			 * loadauditlist() results in hup winning.  The
367 			 * result will be that the audit file is not rolled
368 			 * over unless audit_control actually changed.
369 			 *
370 			 * They want to reread the audit_control file.
371 			 * Set reset_list which will return us to the
372 			 * main while loop in the main routine.
373 			 */
374 			caught_readc = 0;
375 			reset_list = 1;
376 		} else if (caught_nextd) {
377 			/*
378 			 * This is a special case for the binfile
379 			 * plugin. (audit -n)  NULL out kvlist
380 			 * so binfile won't re-read audit_control
381 			 */
382 			caught_nextd = 0;
383 			reset_file = 1;
384 			if (binfile != NULL) {
385 				_kva_free(binfile->plg_kvlist);
386 				binfile->plg_kvlist = NULL;
387 				binfile->plg_reopen = 1;
388 			}
389 		}
390 	}	/* end while (running) */
391 	auditd_thread_close();
392 
393 	auditd_exit(0);
394 	return (0);
395 }
396 
397 /*
398  * my_sleep - sleep for SLEEP_TIME seconds but only accept the signals
399  *	that we want to accept.  (Premature termination just means the
400  *	caller retries more often, not a big deal.)
401  */
402 
403 static void
404 my_sleep()
405 {
406 	DPRINT((dbfp, "auditd: sleeping for 20 seconds\n"));
407 	/*
408 	 * Set timer to "sleep"
409 	 */
410 	(void) alarm(SLEEP_TIME);
411 
412 	DPRINT((dbfp, "main thread is waiting for SIGALRM before exit.\n"));
413 	(void) pthread_mutex_lock(&(main_thr.thd_mutex));
414 	(void) pthread_cond_wait(&(main_thr.thd_cv), &(main_thr.thd_mutex));
415 	(void) pthread_mutex_unlock(&(main_thr.thd_mutex));
416 
417 	if (caught_term) {
418 		DPRINT((dbfp, "normal AU_SIG_DISABLE exit\n"));
419 		/*
420 		 * Exit, as requested.
421 		 */
422 		auditd_thread_close();
423 	}
424 	if (caught_readc)
425 		reset_list = 1;		/* Reread the audit_control file */
426 
427 	caught_readc = 0;
428 	caught_nextd = 0;
429 }
430 
431 /*
432  * search for $ISA/ in path and replace it with "" if auditd
433  * is 32 bit, else "sparcv9/"  The plugin $ISA must match however
434  * auditd was compiled.
435  */
436 
437 static void
438 isa_ified(char *path, char **newpath)
439 {
440 	char	*p, *q;
441 
442 	if (((p = strchr(path, '$')) != NULL) &&
443 	    (strncmp("$ISA/", p, 5) == 0)) {
444 		(void) memcpy(*newpath, path, p - path);
445 		q = *newpath + (p - path);
446 #ifdef __sparcv9
447 		q += strlcpy(q, "sparcv9/", avail_length);
448 #endif
449 		(void) strcpy(q, p + 5);
450 	} else
451 		*newpath = path;
452 }
453 
454 /*
455  * init_plugin first searches the existing plugin list to see
456  * if the plugin already has been defined; if not, it creates it
457  * and links it into the list.  It returns a pointer to the found
458  * or created struct.  A change of path in audit_control for a
459  * given plugin will cause a miss.
460  */
461 /*
462  * for 64 bits, the path name can grow 3 bytes (minus 5 for the
463  * removed "$ISA" and plus 8 for the added "sparcv9/"
464  */
465 
466 #define	ISA_GROW	8 - 5
467 
468 static plugin_t *
469 init_plugin(char *name, kva_t *list, int cnt_flag)
470 {
471 	plugin_t	*p, *q;
472 	char		filepath[MAXPATHLEN + 1 + ISA_GROW];
473 	char		*path = filepath;
474 
475 	if (*name != '/') {
476 #ifdef  __sparcv9
477 		(void) strcpy(filepath, "/usr/lib/security/sparcv9/");
478 #else
479 		(void) strcpy(filepath, "/usr/lib/security/");
480 #endif
481 		if (strlcat(filepath, name, MAXPATHLEN) >= MAXPATHLEN)
482 			return (NULL);
483 	} else {
484 		if (strlen(name) > MAXPATHLEN + ISA_GROW)
485 			return (NULL);
486 		isa_ified(name, &path);
487 	}
488 	p = plugin_head;
489 	q = plugin_head;
490 	while (p != NULL) {
491 		if (p->plg_path != NULL) {
492 			if (strcmp(p->plg_path, path) == 0) {
493 				p->plg_removed = 0;
494 				p->plg_to_be_removed = 0;
495 				p->plg_cnt = cnt_flag;
496 
497 				_kva_free(p->plg_kvlist);
498 				p->plg_kvlist = list;
499 				p->plg_reopen = 1;
500 				DPRINT((dbfp, "reusing %s\n", p->plg_path));
501 				return (p);
502 			}
503 		}
504 		q = p;
505 		p = p->plg_next;
506 	}
507 	DPRINT((dbfp, "creating new plugin structure for %s\n", path));
508 
509 	p = malloc(sizeof (plugin_t));
510 
511 	if (p == NULL) {
512 		perror("auditd");
513 		return (NULL);
514 	}
515 	if (q == NULL)
516 		plugin_head = p;
517 	else
518 		q->plg_next = p;
519 
520 	p->plg_next = NULL;
521 	p->plg_initialized = 0;
522 	p->plg_reopen = 1;
523 	p->plg_tid = 0;
524 	p->plg_removed = 0;
525 	p->plg_to_be_removed = 0;
526 	p->plg_tossed = 0;
527 	p->plg_queued = 0;
528 	p->plg_output = 0;
529 	p->plg_sequence = 1;
530 	p->plg_last_seq_out = 0;
531 	p->plg_path = strdup(path);
532 	p->plg_kvlist = list;
533 	p->plg_cnt = cnt_flag;
534 	p->plg_retry_time = SLEEP_TIME;
535 	p->plg_qmax = 0;
536 	p->plg_save_q_copy = NULL;
537 
538 	DPRINT((dbfp, "created plugin:  %s\n", path));
539 	return (p);
540 }
541 
542 /*
543  * loadauditlist - read the directory list from the audit_control file.
544  *		   to determine if a binary file is to be written.
545  *		 - read the plugin entries from the audit_control file
546  *
547  * globals -
548  *
549  *	plugin queues
550  *
551  * success is when at least one plug in is defined.
552  *
553  * set cnt policy here based on auditconfig setting.  future could
554  * have a policy = {+|-}cnt entry per plugin with auditconfig providing the
555  * default.
556  */
557 
558 static void
559 loadauditlist()
560 {
561 	char		buf[MAXPATHLEN];
562 	char		*value;
563 	plugin_t	*p;
564 	int		acresult;
565 	int		wait_count = 0;
566 	kva_t		*kvlist;
567 	long		policy;
568 	int		cnt_flag;
569 	struct au_qctrl	kqmax;
570 	au_acinfo_t	*ach = NULL;
571 	int		got_dir = 0;
572 	int		have_plugin = 0;
573 	char		*endptr;
574 
575 	if (auditon(A_GETPOLICY, (char *)&policy, 0) == -1) {
576 		DPRINT((dbfp, "auditon(A_GETPOLICY...) failed (exit)\n"));
577 		__audit_dowarn("auditoff", "", 0);
578 		auditd_thread_close();
579 		auditd_exit(5);
580 	}
581 	cnt_flag = ((policy & AUDIT_CNT) != 0) ? 1 : 0;
582 	DPRINT((dbfp, "loadauditlist:  policy is to %s\n", (cnt_flag == 1) ?
583 	    "continue" : "block"));
584 
585 #if DEBUG
586 	if (auditon(A_GETCOND, (caddr_t)&acresult, (int)sizeof (int)) !=
587 	    0)
588 		DPRINT((dbfp, "auditon(A_GETCOND...) failed (exit)\n"));
589 #endif
590 	DPRINT((dbfp, "audit cond = %d (1 is on)\n", acresult));
591 
592 
593 	if (auditon(A_GETQCTRL, (char *)&kqmax, sizeof (struct au_qctrl)) !=
594 	    0) {
595 		DPRINT((dbfp, "auditon(A_GETQCTRL...) failed (exit)\n"));
596 		__audit_dowarn("auditoff", "", 0);
597 		auditd_thread_close();
598 		auditd_exit(6);
599 	}
600 	kqmax.aq_hiwater *= 5;		/* RAM is cheaper in userspace */
601 	DPRINT((dbfp, "auditd: reading audit_control\n"));
602 
603 	p = plugin_head;
604 	/*
605 	 * two-step on setting p->plg_removed because the input thread
606 	 * in doorway.c uses p->plg_removed to decide if the plugin is
607 	 * active.
608 	 */
609 	while (p != NULL) {
610 		DPRINT((dbfp, "loadauditlist:  %X, %s previously created\n",
611 		    p, p->plg_path));
612 		p->plg_to_be_removed = 1;	/* tentative removal */
613 		p = p->plg_next;
614 	}
615 	/*
616 	 * have_plugin may over count by one if both a "dir" entry
617 	 * and a "plugin" entry for binfile are found.  All that
618 	 * matters is that it be zero if no plugin or dir entries
619 	 * are found.
620 	 */
621 	have_plugin = 0;
622 	for (;;) {
623 		/* NULL == use standard path for audit_control */
624 		ach = _openac(NULL);
625 		/*
626 		 * loop until a directory entry is found (0) or eof (-1)
627 		 */
628 		while (((acresult = _getacdir(ach, buf, sizeof (buf))) != 0) &&
629 		    acresult != -1) {
630 		}
631 		if (acresult == 0) {
632 			DPRINT((dbfp,
633 			    "loadauditlist: "
634 			    "got binfile via old config syntax\n"));
635 			/*
636 			 * A directory entry was found.
637 			 */
638 			got_dir = 1;
639 			kvlist = _str2kva("name=audit_binfile.so.1",
640 			    "=", ";");
641 
642 			p = init_plugin("audit_binfile.so.1", kvlist, cnt_flag);
643 
644 			if (p != NULL) {
645 				binfile = p;
646 				p->plg_qmax = kqmax.aq_hiwater;
647 				have_plugin++;
648 			}
649 		}
650 		/*
651 		 * collect plugin entries.  If there is an entry for
652 		 * binfile.so.1, the parameters from the plugin line
653 		 * override those set above.  For binfile, p_dir is
654 		 * required only if dir wasn't specified elsewhere in
655 		 * audit_control
656 		 */
657 		_rewindac(ach);
658 		while ((acresult = _getacplug(ach, &kvlist)) == 0) {
659 			value = kva_match(kvlist, "name");
660 			if (value == NULL)
661 				break;
662 			DPRINT((dbfp, "loadauditlist: have an entry for %s\n",
663 			    value));
664 			p = init_plugin(value, kvlist, cnt_flag);
665 			if (p == NULL)
666 				continue;
667 
668 			if (strstr(value, "/audit_binfile.so") != NULL) {
669 				binfile = p;
670 				if (!got_dir &&
671 				    (kva_match(kvlist, "p_dir") ==
672 				    NULL)) {
673 					__audit_dowarn("getacdir", "",
674 					    wait_count);
675 				}
676 			}
677 			p->plg_qmax = kqmax.aq_hiwater; /* default */
678 			value = kva_match(kvlist, "qsize");
679 			if (value != NULL) {
680 				long	tmp;
681 
682 				tmp = strtol(value, &endptr, 10);
683 				if (*endptr == '\0')
684 					p->plg_qmax = tmp;
685 			}
686 			DPRINT((dbfp, "%s queue max = %d\n",
687 				p->plg_path, p->plg_qmax));
688 
689 			have_plugin++;
690 		}
691 		_endac(ach);
692 		if (have_plugin != 0)
693 			break;
694 		/*
695 		 * there was a problem getting the directory
696 		 * list or remote host info from the audit_control file
697 		 */
698 		wait_count++;
699 #if	DEBUG
700 		if (wait_count < 2)
701 			DPRINT((dbfp,
702 			    "auditd: problem getting directory "
703 			    "/ or plugin list from audit_control.\n"));
704 #endif	/* DEBUG */
705 		__audit_dowarn("getacdir", "", wait_count);
706 		/*
707 		 * sleep for SLEEP_TIME seconds.
708 		 */
709 		my_sleep();
710 	}    /* end for(;;) */
711 
712 	p = plugin_head;
713 	while (p != NULL) {
714 		DPRINT((dbfp, "loadauditlist: %s remove flag=%d; cnt=%d\n",
715 		    p->plg_path, p->plg_to_be_removed, p->plg_cnt));
716 		p->plg_removed = p->plg_to_be_removed;
717 		p = p->plg_next;
718 	}
719 }
720 
721 /*
722  * block signals -- thread-specific blocking of the signals expected
723  * by the main thread.
724  */
725 
726 static void
727 block_signals()
728 {
729 	sigset_t	set;
730 
731 	(void) sigfillset(&set);
732 	(void) pthread_sigmask(SIG_BLOCK, &set, NULL);
733 }
734 
735 /*
736  * signal_thread is the designated signal catcher.  It wakes up the
737  * main thread whenever it receives a signal and then goes back to
738  * sleep; it does not exit.  The global variables caught_* let
739  * the main thread which signal was received.
740  *
741  * The thread is created with all signals blocked.
742  */
743 
744 static void
745 signal_thread()
746 {
747 	sigset_t	set;
748 	int		signal_caught;
749 
750 	DPRINT((dbfp, "the signal thread is thread %d\n",
751 	    pthread_self()));
752 
753 	(void) sigemptyset(&set);
754 	(void) sigaddset(&set, SIGALRM);
755 	(void) sigaddset(&set, AU_SIG_DISABLE);
756 	(void) sigaddset(&set, AU_SIG_READ_CONTROL);
757 	(void) sigaddset(&set, AU_SIG_NEXT_DIR);
758 
759 	for (;;) {
760 		signal_caught = sigwait(&set);
761 		switch (signal_caught) {
762 		case SIGALRM:
763 			caught_alrm++;
764 			DPRINT((dbfp, "caught SIGALRM\n"));
765 			break;
766 		case AU_SIG_DISABLE:
767 			caught_term++;
768 			DPRINT((dbfp, "caught AU_SIG_DISABLE\n"));
769 			break;
770 		case AU_SIG_READ_CONTROL:
771 			caught_readc++;
772 			DPRINT((dbfp, "caught AU_SIG_READ_CONTROL\n"));
773 			break;
774 		case AU_SIG_NEXT_DIR:
775 			caught_nextd++;
776 			DPRINT((dbfp, "caught AU_SIG_NEXT_DIR\n"));
777 			break;
778 		default:
779 			DPRINT((dbfp, "caught unexpected signal:  %d\n",
780 			    signal_caught));
781 			break;
782 		}
783 		(void) pthread_cond_signal(&(main_thr.thd_cv));
784 	}
785 }
786 
787 /*
788  * do_sethost - do auditon(2) to set the audit host-id.
789  *		Returns 0 if success, error code or -1 otherwise.
790  */
791 static int
792 do_sethost(void)
793 {
794 	int		err;
795 	char		host_name[MAXHOSTNAMELEN + 1];
796 	auditinfo_addr_t	audit_info;
797 	struct addrinfo	hints;
798 	struct addrinfo	*ai;
799 	int		addr_type;
800 	void		*p;
801 
802 	/* First, get our machine name and convert to IP address */
803 	if ((err = gethostname(host_name, sizeof (host_name)))) {
804 		return (err);
805 	}
806 	(void) memset(&hints, 0, sizeof (hints));
807 	hints.ai_family = PF_INET;
808 	err = getaddrinfo(host_name, NULL, &hints, &ai);
809 	if (err == 0) {
810 		addr_type = AU_IPv4;
811 		/* LINTED */
812 		p = &((struct sockaddr_in *)ai->ai_addr)->sin_addr;
813 	} else {
814 		hints.ai_family = PF_INET6;
815 		err = getaddrinfo(host_name, NULL, &hints, &ai);
816 		if (err != 0) {
817 			return (-1);
818 		}
819 		addr_type = AU_IPv6;
820 		/* LINTED */
821 		p = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
822 	}
823 
824 	/* Get current kernel audit info, and fill in the IP address */
825 	if ((err = auditon(A_GETKAUDIT, (caddr_t)&audit_info,
826 	    sizeof (audit_info))) < 0) {
827 		return (err);
828 	}
829 	audit_info.ai_termid.at_type = addr_type;
830 	(void) memcpy(&audit_info.ai_termid.at_addr[0], p,
831 	    addr_type);
832 
833 	freeaddrinfo(ai);
834 
835 	/* Update the kernel audit info with new IP address */
836 	if ((err = auditon(A_SETKAUDIT, (caddr_t)&audit_info,
837 	    sizeof (audit_info))) < 0) {
838 		return (err);
839 	}
840 
841 	return (0);
842 }
843