1159248Srwatson/*-
2159248Srwatson * Copyright (c) 2006 Robert N. M. Watson
3159248Srwatson * All rights reserved.
4159248Srwatson *
5159248Srwatson * This software was developed by Robert Watson for the TrustedBSD Project.
6159248Srwatson *
7159248Srwatson * Redistribution and use in source and binary forms, with or without
8159248Srwatson * modification, are permitted provided that the following conditions
9159248Srwatson * are met:
10159248Srwatson * 1. Redistributions of source code must retain the above copyright
11159248Srwatson *    notice, this list of conditions and the following disclaimer.
12159248Srwatson * 2. Redistributions in binary form must reproduce the above copyright
13159248Srwatson *    notice, this list of conditions and the following disclaimer in the
14159248Srwatson *    documentation and/or other materials provided with the distribution.
15159248Srwatson *
16159248Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17159248Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18159248Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19159248Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20159248Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21159248Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22159248Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23159248Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24159248Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25159248Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26159248Srwatson * SUCH DAMAGE.
27159248Srwatson *
28161630Srwatson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditfilterd/auditfilterd_conf.c#5 $
29159248Srwatson */
30159248Srwatson
31159248Srwatson/*
32159248Srwatson * Configuration file parser for auditfilterd.  The configuration file is a
33159248Srwatson * very simple format, similar to other BSM configuration files, consisting
34159248Srwatson * of configuration entries of one line each.  The configuration function is
35159248Srwatson * aware of previous runs, and will update the current configuration as
36159248Srwatson * needed.
37159248Srwatson *
38159248Srwatson * Modules are in one of two states: attached, or detached.  If attach fails,
39159248Srwatson * detach is not called because it was not attached.  If a module is attached
40159248Srwatson * and a call to its reinit method fails, we will detach it.
41161630Srwatson *
42161630Srwatson * Modules are passed a (void *) reference to their configuration state so
43161630Srwatson * that they may pass this into any common APIs we provide which may rely on
44161630Srwatson * that state.  Currently, the only such API is the cookie API, which allows
45161630Srwatson * per-instance state to be maintained by a module.  In the future, this will
46161630Srwatson * also be used to support per-instance preselection state.
47159248Srwatson */
48159248Srwatson
49159248Srwatson#include <sys/types.h>
50159248Srwatson
51159248Srwatson#include <config/config.h>
52159248Srwatson#ifdef HAVE_FULL_QUEUE_H
53159248Srwatson#include <sys/queue.h>
54159248Srwatson#else
55159248Srwatson#include <compat/queue.h>
56159248Srwatson#endif
57159248Srwatson
58159248Srwatson#include <bsm/libbsm.h>
59159248Srwatson#include <bsm/audit_filter.h>
60159248Srwatson
61159248Srwatson#include <dlfcn.h>
62159248Srwatson#include <err.h>
63159248Srwatson#include <errno.h>
64159248Srwatson#include <limits.h>
65159248Srwatson#include <stdio.h>
66159248Srwatson#include <stdlib.h>
67159248Srwatson#include <string.h>
68159248Srwatson
69159248Srwatson#include "auditfilterd.h"
70159248Srwatson
71159248Srwatson/*
72159248Srwatson * Free an individual auditfilter_module structure.  Will not shut down the
73159248Srwatson * module, just frees the memory.  Does so conditional on pointers being
74159248Srwatson * non-NULL so that it can be used on partially allocated structures.
75159248Srwatson */
76159248Srwatsonstatic void
77159248Srwatsonauditfilter_module_free(struct auditfilter_module *am)
78159248Srwatson{
79159248Srwatson
80159248Srwatson	if (am->am_modulename != NULL)
81159248Srwatson		free(am->am_modulename);
82159248Srwatson	if (am->am_arg_buffer != NULL)
83159248Srwatson		free(am->am_arg_buffer);
84159248Srwatson	if (am->am_argv != NULL)
85159248Srwatson		free(am->am_argv);
86159248Srwatson}
87159248Srwatson
88159248Srwatson/*
89159248Srwatson * Free all memory associated with an auditfilter_module list.  Does not
90159248Srwatson * dlclose() or shut down the modules, just free the memory.  Use
91159248Srwatson * auditfilter_module_list_detach() for that, if required.
92159248Srwatson */
93159248Srwatsonstatic void
94159248Srwatsonauditfilter_module_list_free(struct auditfilter_module_list *list)
95159248Srwatson{
96159248Srwatson	struct auditfilter_module *am;
97159248Srwatson
98159248Srwatson	while (!(TAILQ_EMPTY(list))) {
99159248Srwatson		am = TAILQ_FIRST(list);
100159248Srwatson		TAILQ_REMOVE(list, am, am_list);
101159248Srwatson		auditfilter_module_free(am);
102159248Srwatson	}
103159248Srwatson}
104159248Srwatson
105159248Srwatson/*
106159248Srwatson * Detach an attached module from an auditfilter_module structure.  Does not
107159248Srwatson * free the data structure itself.
108159248Srwatson */
109159248Srwatsonstatic void
110159248Srwatsonauditfilter_module_detach(struct auditfilter_module *am)
111159248Srwatson{
112159248Srwatson
113159248Srwatson	if (am->am_detach != NULL)
114161630Srwatson		am->am_detach(am);
115161630Srwatson	am->am_cookie = NULL;
116159248Srwatson	(void)dlclose(am->am_dlhandle);
117159248Srwatson	am->am_dlhandle = NULL;
118159248Srwatson}
119159248Srwatson
120159248Srwatson/*
121159248Srwatson * Walk an auditfilter_module list, detaching each module.  Intended to be
122159248Srwatson * combined with auditfilter_module_list_free().
123159248Srwatson */
124159248Srwatsonstatic void
125159248Srwatsonauditfilter_module_list_detach(struct auditfilter_module_list *list)
126159248Srwatson{
127159248Srwatson	struct auditfilter_module *am;
128159248Srwatson
129159248Srwatson	TAILQ_FOREACH(am, list, am_list)
130159248Srwatson		auditfilter_module_detach(am);
131159248Srwatson}
132159248Srwatson
133159248Srwatson/*
134159248Srwatson * Given a filled out auditfilter_module, use dlopen() and dlsym() to attach
135159248Srwatson * the module.  If we fail, leave fields in the state we found them.
136159248Srwatson *
137159248Srwatson * XXXRW: Need a better way to report errors.
138159248Srwatson */
139159248Srwatsonstatic int
140159248Srwatsonauditfilter_module_attach(struct auditfilter_module *am)
141159248Srwatson{
142159248Srwatson
143159248Srwatson	am->am_dlhandle = dlopen(am->am_modulename, RTLD_NOW);
144159248Srwatson	if (am->am_dlhandle == NULL) {
145159248Srwatson		warnx("auditfilter_module_attach: %s: %s", am->am_modulename,
146159248Srwatson		    dlerror());
147159248Srwatson		return (-1);
148159248Srwatson	}
149159248Srwatson
150159248Srwatson	/*
151159248Srwatson	 * Not implementing these is not considered a failure condition,
152159248Srwatson	 * although we might want to consider warning if obvious stuff is
153159248Srwatson	 * not implemented, such as am_record.
154159248Srwatson	 */
155159248Srwatson	am->am_attach = dlsym(am->am_dlhandle, AUDIT_FILTER_ATTACH_STRING);
156159248Srwatson	am->am_reinit = dlsym(am->am_dlhandle, AUDIT_FILTER_REINIT_STRING);
157159248Srwatson	am->am_record = dlsym(am->am_dlhandle, AUDIT_FILTER_RECORD_STRING);
158161630Srwatson	am->am_rawrecord = dlsym(am->am_dlhandle,
159161630Srwatson	    AUDIT_FILTER_RAWRECORD_STRING);
160159248Srwatson	am->am_detach = dlsym(am->am_dlhandle, AUDIT_FILTER_DETACH_STRING);
161159248Srwatson
162159248Srwatson	if (am->am_attach != NULL) {
163161630Srwatson		if (am->am_attach(am, am->am_argc, am->am_argv)
164159248Srwatson		    != AUDIT_FILTER_SUCCESS) {
165159248Srwatson			warnx("auditfilter_module_attach: %s: failed",
166159248Srwatson			    am->am_modulename);
167159248Srwatson			dlclose(am->am_dlhandle);
168159248Srwatson			am->am_dlhandle = NULL;
169161630Srwatson			am->am_cookie = NULL;
170159248Srwatson			am->am_attach = NULL;
171159248Srwatson			am->am_reinit = NULL;
172159248Srwatson			am->am_record = NULL;
173161630Srwatson			am->am_rawrecord = NULL;
174159248Srwatson			am->am_detach = NULL;
175159248Srwatson			return (-1);
176159248Srwatson		}
177159248Srwatson	}
178159248Srwatson
179159248Srwatson	return (0);
180159248Srwatson}
181159248Srwatson
182159248Srwatson/*
183159248Srwatson * When the arguments for a module are changed, we notify the module through
184159248Srwatson * a call to its reinit method, if any.  Return 0 on success, or -1 on
185159248Srwatson * failure.
186159248Srwatson */
187159248Srwatsonstatic int
188159248Srwatsonauditfilter_module_reinit(struct auditfilter_module *am)
189159248Srwatson{
190159248Srwatson
191159248Srwatson	if (am->am_reinit == NULL)
192159248Srwatson		return (0);
193159248Srwatson
194161630Srwatson	if (am->am_reinit(am, am->am_argc, am->am_argv) !=
195159248Srwatson	    AUDIT_FILTER_SUCCESS) {
196159248Srwatson		warnx("auditfilter_module_reinit: %s: failed",
197159248Srwatson		    am->am_modulename);
198159248Srwatson		return (-1);
199159248Srwatson	}
200159248Srwatson
201159248Srwatson	return (0);
202159248Srwatson}
203159248Srwatson
204159248Srwatson/*
205159248Srwatson * Given a configuration line, generate an auditfilter_module structure that
206159248Srwatson * describes it; caller will not pass comments in, so they are not looked
207159248Srwatson * for.  Do not attempt to instantiate it.  Will destroy the contents of
208159248Srwatson * 'buffer'.
209159248Srwatson *
210159248Srwatson * Configuration lines consist of two parts: the module name and arguments
211159248Srwatson * separated by a ':', and then a ','-delimited list of arguments.
212159248Srwatson *
213159248Srwatson * XXXRW: Need to decide where to send the warning output -- stderr for now.
214159248Srwatson */
215159248Srwatsonstruct auditfilter_module *
216159248Srwatsonauditfilter_module_parse(const char *filename, int linenumber, char *buffer)
217159248Srwatson{
218159248Srwatson	char *arguments, *module, **ap;
219159248Srwatson	struct auditfilter_module *am;
220159248Srwatson
221159248Srwatson	am = malloc(sizeof(*am));
222159248Srwatson	if (am == NULL) {
223159248Srwatson		warn("auditfilter_module_parse: %s:%d", filename, linenumber);
224159248Srwatson		return (NULL);
225159248Srwatson	}
226159248Srwatson	bzero(am, sizeof(*am));
227159248Srwatson
228159248Srwatson	/*
229159248Srwatson	 * First, break out the module and arguments strings.  We look for
230159248Srwatson	 * one extra argument to make sure there are no more :'s in the line.
231159248Srwatson	 * That way, we prevent modules from using argument strings that, in
232159248Srwatson	 * the future, may cause problems for adding additional columns.
233159248Srwatson	 */
234159248Srwatson	arguments = buffer;
235159248Srwatson	module = strsep(&arguments, ":");
236159248Srwatson	if (module == NULL || arguments == NULL) {
237159248Srwatson		warnx("auditfilter_module_parse: %s:%d: parse error",
238159248Srwatson		    filename, linenumber);
239159248Srwatson		return (NULL);
240159248Srwatson	}
241159248Srwatson
242159248Srwatson	am->am_modulename = strdup(module);
243159248Srwatson	if (am->am_modulename == NULL) {
244159248Srwatson		warn("auditfilter_module_parse: %s:%d", filename, linenumber);
245159248Srwatson		auditfilter_module_free(am);
246159248Srwatson		return (NULL);
247159248Srwatson	}
248159248Srwatson
249159248Srwatson	am->am_arg_buffer = strdup(buffer);
250159248Srwatson	if (am->am_arg_buffer == NULL) {
251159248Srwatson		warn("auditfilter_module_parse: %s:%d", filename, linenumber);
252159248Srwatson		auditfilter_module_free(am);
253159248Srwatson		return (NULL);
254159248Srwatson	}
255159248Srwatson
256159248Srwatson	/*
257159248Srwatson	 * Now, break out the arguments string into a series of arguments.
258159248Srwatson	 * This is a bit more complicated, and requires cleanup if things go
259159248Srwatson	 * wrong.
260159248Srwatson	 */
261159248Srwatson	am->am_argv = malloc(sizeof(char *) * AUDITFILTERD_CONF_MAXARGS);
262159248Srwatson	if (am->am_argv == NULL) {
263159248Srwatson		warn("auditfilter_module_parse: %s:%d", filename, linenumber);
264159248Srwatson		auditfilter_module_free(am);
265159248Srwatson		return (NULL);
266159248Srwatson	}
267159248Srwatson	bzero(am->am_argv, sizeof(char *) * AUDITFILTERD_CONF_MAXARGS);
268159248Srwatson	am->am_argc = 0;
269159248Srwatson	for (ap = am->am_argv; (*ap = strsep(&arguments, " \t")) != NULL;) {
270159248Srwatson		if (**ap != '\0') {
271159248Srwatson			am->am_argc++;
272159248Srwatson			if (++ap >= &am->am_argv[AUDITFILTERD_CONF_MAXARGS])
273159248Srwatson				break;
274159248Srwatson		}
275159248Srwatson	}
276159248Srwatson	if (ap >= &am->am_argv[AUDITFILTERD_CONF_MAXARGS]) {
277159248Srwatson		warnx("auditfilter_module_parse: %s:%d: too many arguments",
278159248Srwatson		    filename, linenumber);
279159248Srwatson		auditfilter_module_free(am);
280159248Srwatson		return (NULL);
281159248Srwatson	}
282159248Srwatson
283159248Srwatson	return (am);
284159248Srwatson}
285159248Srwatson
286159248Srwatson/*
287159248Srwatson * Read a configuration file, and populate 'list' with the configuration
288159248Srwatson * lines.  Does not attempt to instantiate the configuration, just read it
289159248Srwatson * into a useful set of data structures.
290159248Srwatson */
291159248Srwatsonstatic int
292159248Srwatsonauditfilterd_conf_read(const char *filename, FILE *fp,
293159248Srwatson    struct auditfilter_module_list *list)
294159248Srwatson{
295159248Srwatson	int error, linenumber, syntaxerror;
296159248Srwatson	struct auditfilter_module *am;
297159248Srwatson	char buffer[LINE_MAX];
298159248Srwatson
299159248Srwatson	syntaxerror = 0;
300159248Srwatson	linenumber = 0;
301159248Srwatson	while (!feof(fp) && !ferror(fp)) {
302159248Srwatson		if (fgets(buffer, LINE_MAX, fp) == NULL)
303159248Srwatson			break;
304159248Srwatson		linenumber++;
305159248Srwatson		if (buffer[0] == '#' || strlen(buffer) < 1)
306159248Srwatson			continue;
307159248Srwatson		buffer[strlen(buffer)-1] = '\0';
308159248Srwatson		am = auditfilter_module_parse(filename, linenumber, buffer);
309159248Srwatson		if (am == NULL) {
310159248Srwatson			syntaxerror = 1;
311159248Srwatson			break;
312159248Srwatson		}
313159248Srwatson		TAILQ_INSERT_HEAD(list, am, am_list);
314159248Srwatson	}
315159248Srwatson
316159248Srwatson	/*
317159248Srwatson	 * File I/O error.
318159248Srwatson	 */
319159248Srwatson	if (ferror(fp)) {
320159248Srwatson		error = errno;
321159248Srwatson		auditfilter_module_list_free(list);
322159248Srwatson		errno = error;
323159248Srwatson		return (-1);
324159248Srwatson	}
325159248Srwatson
326159248Srwatson	/*
327159248Srwatson	 * Syntax error.
328159248Srwatson	 */
329159248Srwatson	if (syntaxerror) {
330159248Srwatson		auditfilter_module_list_free(list);
331159248Srwatson		errno = EINVAL;
332159248Srwatson		return (-1);
333159248Srwatson	}
334159248Srwatson	return (0);
335159248Srwatson}
336159248Srwatson
337159248Srwatson/*
338159248Srwatson * Apply changes necessary to bring a new configuration into force.  The new
339159248Srwatson * configuration data is passed in, and the current configuration is updated
340159248Srwatson * to match it.  The contents of 'list' are freed or otherwise disposed of
341159248Srwatson * before return.
342159248Srwatson *
343159248Srwatson * The algorithms here are not very efficient, but this is an infrequent
344159248Srwatson * operation on very short lists.
345159248Srwatson */
346159248Srwatsonstatic void
347159248Srwatsonauditfilterd_conf_apply(struct auditfilter_module_list *list)
348159248Srwatson{
349159248Srwatson	struct auditfilter_module *am1, *am2, *am_tmp;
350159248Srwatson	int argc_tmp, found;
351159248Srwatson	char **argv_tmp;
352159248Srwatson
353159248Srwatson	/*
354159248Srwatson	 * First, remove remove and detach any entries that appear in the
355159248Srwatson	 * current configuration, but not the new configuration.
356159248Srwatson	 */
357159248Srwatson	TAILQ_FOREACH_SAFE(am1, &filter_list, am_list, am_tmp) {
358159248Srwatson		found = 0;
359159248Srwatson		TAILQ_FOREACH(am2, list, am_list) {
360159248Srwatson			if (strcmp(am1->am_modulename, am2->am_modulename)
361159248Srwatson			    == 0) {
362159248Srwatson				found = 1;
363159248Srwatson				break;
364159248Srwatson			}
365159248Srwatson		}
366159248Srwatson		if (found)
367159248Srwatson			continue;
368159248Srwatson
369159248Srwatson		/*
370159248Srwatson		 * am1 appears in filter_list, but not the new list, detach
371159248Srwatson		 * and free the module.
372159248Srwatson		 */
373159248Srwatson		warnx("detaching module %s", am1->am_modulename);
374159248Srwatson		TAILQ_REMOVE(&filter_list, am1, am_list);
375159248Srwatson		auditfilter_module_detach(am1);
376159248Srwatson		auditfilter_module_free(am1);
377159248Srwatson	}
378159248Srwatson
379159248Srwatson	/*
380159248Srwatson	 * Next, update the configuration of any modules that appear in both
381159248Srwatson	 * lists.  We do this by swapping the two argc and argv values and
382159248Srwatson	 * freeing the new one, rather than detaching the old one and
383159248Srwatson	 * attaching the new one.  That way module state is preserved.
384159248Srwatson	 */
385159248Srwatson	TAILQ_FOREACH(am1, &filter_list, am_list) {
386159248Srwatson		found = 0;
387159248Srwatson		TAILQ_FOREACH(am2, list, am_list) {
388159248Srwatson			if (strcmp(am1->am_modulename, am2->am_modulename)
389159248Srwatson			    == 0) {
390159248Srwatson				found = 1;
391159248Srwatson				break;
392159248Srwatson			}
393159248Srwatson		}
394159248Srwatson		if (!found)
395159248Srwatson			continue;
396159248Srwatson
397159248Srwatson		/*
398159248Srwatson		 * Swap the arguments.
399159248Srwatson		 */
400159248Srwatson		argc_tmp = am1->am_argc;
401159248Srwatson		argv_tmp = am1->am_argv;
402159248Srwatson		am1->am_argc = am2->am_argc;
403159248Srwatson		am1->am_argv = am2->am_argv;
404159248Srwatson		am2->am_argc = argc_tmp;
405159248Srwatson		am2->am_argv = argv_tmp;
406159248Srwatson
407159248Srwatson		/*
408159248Srwatson		 * The reinit is a bit tricky: if reinit fails, we actually
409159248Srwatson		 * remove the old entry and detach that, as we don't allow
410159248Srwatson		 * running modules to be out of sync with the configuration
411159248Srwatson		 * file.
412159248Srwatson		 */
413159248Srwatson		warnx("reiniting module %s", am1->am_modulename);
414159248Srwatson		if (auditfilter_module_reinit(am1) != 0) {
415159248Srwatson			warnx("reinit failed for module %s, detaching",
416159248Srwatson			    am1->am_modulename);
417159248Srwatson			TAILQ_REMOVE(&filter_list, am1, am_list);
418159248Srwatson			auditfilter_module_detach(am1);
419159248Srwatson			auditfilter_module_free(am1);
420159248Srwatson		}
421159248Srwatson
422159248Srwatson		/*
423159248Srwatson		 * Free the entry from the new list, which will discard the
424159248Srwatson		 * old arguments.  No need to detach, as it was never
425159248Srwatson		 * attached in the first place.
426159248Srwatson		 */
427159248Srwatson		TAILQ_REMOVE(list, am2, am_list);
428159248Srwatson		auditfilter_module_free(am2);
429159248Srwatson	}
430159248Srwatson
431159248Srwatson	/*
432159248Srwatson	 * Finally, attach any new entries that don't appear in the old
433159248Srwatson	 * configuration, and if they attach successfully, move them to the
434159248Srwatson	 * real configuration list.
435159248Srwatson	 */
436159248Srwatson	TAILQ_FOREACH(am1, list, am_list) {
437159248Srwatson		found = 0;
438159248Srwatson		TAILQ_FOREACH(am2, &filter_list, am_list) {
439159248Srwatson			if (strcmp(am1->am_modulename, am2->am_modulename)
440159248Srwatson			    == 0) {
441159248Srwatson				found = 1;
442159248Srwatson				break;
443159248Srwatson			}
444159248Srwatson		}
445159248Srwatson		if (found)
446159248Srwatson			continue;
447159248Srwatson		/*
448159248Srwatson		 * Attach the entry.  If it succeeds, add to filter_list,
449159248Srwatson		 * otherwise, free.  No need to detach if attach failed.
450159248Srwatson		 */
451159248Srwatson		warnx("attaching module %s", am1->am_modulename);
452159248Srwatson		TAILQ_REMOVE(list, am1, am_list);
453159248Srwatson		if (auditfilter_module_attach(am1) != 0) {
454159248Srwatson			warnx("attaching module %s failed",
455159248Srwatson			    am1->am_modulename);
456159248Srwatson			auditfilter_module_free(am1);
457159248Srwatson		} else
458159248Srwatson			TAILQ_INSERT_HEAD(&filter_list, am1, am_list);
459159248Srwatson	}
460159248Srwatson
461159248Srwatson	if (TAILQ_FIRST(list) != NULL)
462159248Srwatson		warnx("auditfilterd_conf_apply: new list not empty\n");
463159248Srwatson}
464159248Srwatson
465159248Srwatson/*
466159248Srwatson * Read the new configuration file into a local list.  If the configuration
467159248Srwatson * file is parsed OK, then apply the changes.
468159248Srwatson */
469159248Srwatsonint
470159248Srwatsonauditfilterd_conf(const char *filename, FILE *fp)
471159248Srwatson{
472159248Srwatson	struct auditfilter_module_list list;
473159248Srwatson
474159248Srwatson	TAILQ_INIT(&list);
475159248Srwatson	if (auditfilterd_conf_read(filename, fp, &list) < 0)
476159248Srwatson		return (-1);
477159248Srwatson
478159248Srwatson	auditfilterd_conf_apply(&list);
479159248Srwatson
480159248Srwatson	return (0);
481159248Srwatson}
482159248Srwatson
483159248Srwatson/*
484159248Srwatson * Detach and free all active filter modules for daemon shutdown.
485159248Srwatson */
486159248Srwatsonvoid
487159248Srwatsonauditfilterd_conf_shutdown(void)
488159248Srwatson{
489159248Srwatson
490159248Srwatson	auditfilter_module_list_detach(&filter_list);
491159248Srwatson	auditfilter_module_list_free(&filter_list);
492159248Srwatson}
493161630Srwatson
494161630Srwatson/*
495161630Srwatson * APIs to allow modules to query and set their per-instance cookie.
496161630Srwatson */
497161630Srwatsonvoid
498161630Srwatsonaudit_filter_getcookie(void *instance, void **cookie)
499161630Srwatson{
500161630Srwatson	struct auditfilter_module *am;
501161630Srwatson
502161630Srwatson	am = (struct auditfilter_module *)instance;
503161630Srwatson	*cookie = am->am_cookie;
504161630Srwatson}
505161630Srwatson
506161630Srwatsonvoid
507161630Srwatsonaudit_filter_setcookie(void *instance, void *cookie)
508161630Srwatson{
509161630Srwatson	struct auditfilter_module *am;
510161630Srwatson
511161630Srwatson	am = (struct auditfilter_module *)instance;
512161630Srwatson	am->am_cookie = cookie;
513161630Srwatson}
514