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