4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
25 /* Audit daemon server */
27 * These routines make up the audit daemon server. This daemon, called
28 * auditd, handles the user level parts of auditing. It receives buffered
29 * audit records (usually one or more per buffer, potentially less than
30 * one) and passes them to one or more plugins for processing.
32 * The major interrupts are SIGHUP (start over), SIGTERM (start shutting down),
33 * SIGALRM (quit), and SIGUSR1 (start a new audit log file). SIGTERM is also
34 * used for the child to tell the parent that audit is ready.
36 * Configuration data comes from audit service configuration
37 * (AUDITD_FMRI/smf(5)) and the auditon system call.
39 * The major errors are EBUSY (auditing is already in use) and EINTR
40 * (one of the above signals was received). File space errors are
41 * handled by the audit_binfile plugin
44 /* #define DEBUG - define for debug messages to be generated */
45 /* #define MEM_TEST - define to generate core dump on exit */
51 #include <bsm/audit.h>
52 #include <bsm/audit_record.h>
53 #include <bsm/libbsm.h>
67 #include <sys/param.h>
69 #include <sys/statvfs.h>
71 #include <sys/types.h>
76 #include <audit_plugin.h>
77 #include <audit_scf.h>
79 #if !defined(TEXT_DOMAIN)
80 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
83 * After we get a SIGTERM, we want to set a timer for 2 seconds
84 * and let c2audit write as many records as it can until the timer
85 * goes off (at which point it returns to auditd with SIGALRM).
86 * If any other signals are received during that time, we call
87 * __audit_dowarn() to indicate that the queue may not have been fully
91 #define SLEEP_TIME 20 /* # of seconds to sleep in all hard loop */
93 static plugin_t
*binfile
= NULL
;
95 static int turn_audit_on
= AUC_AUDITING
;
96 static int turn_audit_off
= AUC_NOAUDIT
;
98 static int running
= 1;
103 plugin_t
*plugin_head
= NULL
;
104 static thr_data_t main_thr
; /* auditd thread (0) */
105 pthread_mutex_t plugin_mutex
; /* for plugin_t list */
107 static int caught_alrm
= 0; /* number of SIGALRMs pending */
108 static int caught_readc
= 0; /* number of SIGHUPs pending */
109 static int caught_term
= 0; /* number of SIGTERMs pending */
110 static int caught_nextd
= 0; /* number of SIGUSR1s pending */
112 static int reset_list
= 1; /* 1 to re-read audit configuration */
113 static int reset_file
= 1; /* 1 to close/open binary log */
115 static int auditing_set
= 0; /* 1 if auditon(A_SETCOND, on... */
117 static void my_sleep();
118 static void signal_thread();
119 static void loadauditlist();
120 static void block_signals();
121 static int do_sethost();
123 static void conf_to_kernel();
124 static void scf_to_kernel_qctrl();
125 static void scf_to_kernel_policy();
128 * err_exit() - exit function after the unsuccessful call to auditon();
129 * prints_out / saves_via_syslog the necessary error messages.
135 DPRINT((dbfp
, "%s\n", msg
));
136 __audit_syslog("auditd", LOG_PID
| LOG_CONS
| LOG_NOWAIT
,
137 LOG_DAEMON
, LOG_ALERT
, msg
);
140 DPRINT((dbfp
, "the memory allocation failed\n"));
141 __audit_syslog("auditd", LOG_PID
| LOG_CONS
| LOG_NOWAIT
,
142 LOG_DAEMON
, LOG_ALERT
, gettext("no memory"));
144 auditd_thread_close();
148 /* common exit function */
150 auditd_exit(int status
)
153 DPRINT((dbfp
, "mem_test intentional abort (status=%d)\n",
157 DPRINT((dbfp
, "%ld exit status = %d auditing_set = %d\n",
158 getpid(), status
, auditing_set
));
161 (void) auditon(A_SETCOND
, (caddr_t
)&turn_audit_off
,
173 main(int argc
, char *argv
[])
175 auditinfo_addr_t as_null
; /* audit state to set */
186 dbfp
= __auditd_debug_file_open();
191 /* Internationalization */
192 (void) setlocale(LC_ALL
, "");
193 (void) textdomain(TEXT_DOMAIN
);
196 * Set the audit host-id.
198 if (do_sethost() != 0) {
199 __audit_dowarn("nostart", "", 0);
204 * Turn off all auditing for this process.
206 if (getaudit_addr(&as_null
, sizeof (as_null
)) == -1) {
207 __audit_dowarn("nostart", "", 0);
210 as_null
.ai_mask
.as_success
= 0;
211 as_null
.ai_mask
.as_failure
= 0;
212 (void) setaudit_addr(&as_null
, sizeof (as_null
));
214 (void) setauid(&auid
);
216 * Set the audit state flag to AUDITING.
218 if (auditon(A_SETCOND
, (caddr_t
)&turn_audit_on
, sizeof (int)) !=
220 DPRINT((dbfp
, "auditon(A_SETCOND...) failed (exit)\n"));
221 __audit_dowarn("nostart", "", 0);
228 * wait for "ready" signal before exit -- for greenline
232 int signal_caught
= 0;
234 (void) sigemptyset(&set
);
235 (void) sigaddset(&set
, SIGTERM
);
237 while (signal_caught
!= SIGTERM
)
238 signal_caught
= sigwait(&set
);
240 DPRINT((dbfp
, "init complete: parent can now exit\n"));
248 #if DEBUG && MEM_TEST
249 envp
= getenv("UMEM_DEBUG");
251 DPRINT((dbfp
, "UMEM_DEBUG=%s\n", envp
));
252 envp
= getenv("UMEM_LOGGING");
254 DPRINT((dbfp
, "UMEM_LOGGING=%s\n", envp
));
256 DPRINT((dbfp
, "auditd pid=%ld\n", getpid()));
259 (void) pthread_mutex_init(&(main_thr
.thd_mutex
), NULL
);
260 (void) pthread_cond_init(&(main_thr
.thd_cv
), NULL
);
261 (void) pthread_mutex_init(&plugin_mutex
, NULL
);
263 * Set up a separate thread for signal handling.
265 if (pthread_create(&tid
, NULL
, (void *(*)(void *))signal_thread
,
267 (void) fprintf(stderr
, gettext(
268 "auditd can't create a thread\n"));
272 * Set the umask so that only audit or other users in the audit group
273 * can get to the files created by auditd.
277 if (__logpost("")) { /* Cannot unlink pointer to audit.log(4) file */
278 DPRINT((dbfp
, "logpost failed\n"));
282 * Here is the main body of the audit daemon. running == 0 means that
283 * after flushing out the audit queue, it is time to exit in response
288 * Read auditd / auditd plugins related configuration from
289 * smf(5) repository and create plugin lists.
291 * loadauditlist() and auditd_thread_init() are called
292 * while under the plugin_mutex lock to avoid a race
293 * with unload_plugin().
295 if (reset_list
|| reset_file
) {
298 scf_to_kernel_qctrl();
299 scf_to_kernel_policy();
300 (void) pthread_mutex_lock(&plugin_mutex
);
303 (void) pthread_mutex_lock(&plugin_mutex
);
306 if (auditd_thread_init()) {
307 auditd_thread_close();
308 /* continue; wait for audit -s */
310 (void) pthread_mutex_unlock(&plugin_mutex
);
312 if (reset_list
&& reset_file
) {
313 (void) printf(gettext("auditd started\n"));
315 (void) printf(gettext("auditd refreshed\n"));
322 * tell parent I'm running whether or not the initialization
323 * actually worked. The failure case is to wait for an
324 * audit -n or audit -s to fix the problem.
327 (void) kill(pid
, SIGTERM
);
331 * thread_signal() signals main (this thread) when
332 * it has received a signal.
334 DPRINT((dbfp
, "main thread is waiting for signal\n"));
335 (void) pthread_mutex_lock(&(main_thr
.thd_mutex
));
337 if (!(caught_readc
|| caught_term
|| caught_alrm
||
339 (void) pthread_cond_wait(&(main_thr
.thd_cv
),
340 &(main_thr
.thd_mutex
));
341 (void) pthread_mutex_unlock(&(main_thr
.thd_mutex
));
343 * Got here because a signal came in.
344 * Since we may have gotten more than one, we assume a
345 * priority scheme with SIGALRM being the most
350 * We have returned from our timed wait for
351 * c2audit to calm down. We need to really shut
355 running
= 0; /* shut down now */
356 } else if (caught_term
) {
358 * we are going to shut down, but need to
359 * allow time for the audit queues in
360 * c2audit and for the threads to empty.
365 DPRINT((dbfp
, "signalling thread %d\n",
367 (void) pthread_mutex_lock(&(p
->plg_mutex
));
370 if (p
->plg_initialized
)
371 (void) pthread_cond_signal(
374 (void) pthread_mutex_unlock(&(p
->plg_mutex
));
384 "main thread is pausing before exit.\n"));
385 (void) pthread_mutex_lock(&(main_thr
.thd_mutex
));
387 (void) alarm(ALRM_TIME
);
389 (void) pthread_cond_wait(&(main_thr
.thd_cv
),
390 &(main_thr
.thd_mutex
));
392 (void) pthread_mutex_unlock(&(main_thr
.thd_mutex
));
394 running
= 0; /* Close down auditing and exit */
395 } else if (caught_readc
) {
397 * if both hup and usr1 are caught, the logic in
398 * loadauditlist() results in hup winning. The
399 * result will be that the audit file is not rolled
400 * over unless audit configuration actually changed.
402 * They want to reread the audit configuration from
403 * smf(5) repository (AUDITD_FMRI). Set reset_list
404 * which will return us to the main while loop in the
409 } else if (caught_nextd
) {
411 * This is a special case for the binfile plugin.
412 * (audit -n) NULL out kvlist so binfile won't
413 * re-read audit configuration.
417 if (binfile
!= NULL
) {
418 _kva_free(binfile
->plg_kvlist
);
419 binfile
->plg_kvlist
= NULL
;
420 binfile
->plg_reopen
= 1;
423 } /* end while (running) */
424 auditd_thread_close();
431 * my_sleep - sleep for SLEEP_TIME seconds but only accept the signals
432 * that we want to accept. (Premature termination just means the
433 * caller retries more often, not a big deal.)
439 DPRINT((dbfp
, "auditd: sleeping for 20 seconds\n"));
441 * Set timer to "sleep"
443 (void) alarm(SLEEP_TIME
);
445 DPRINT((dbfp
, "main thread is waiting for SIGALRM before exit.\n"));
446 (void) pthread_mutex_lock(&(main_thr
.thd_mutex
));
447 (void) pthread_cond_wait(&(main_thr
.thd_cv
), &(main_thr
.thd_mutex
));
448 (void) pthread_mutex_unlock(&(main_thr
.thd_mutex
));
451 DPRINT((dbfp
, "normal SIGTERM exit\n"));
453 * Exit, as requested.
455 auditd_thread_close();
458 reset_list
= 1; /* Reread the audit configuration */
465 * search for $ISA/ in path and replace it with "" if auditd
466 * is 32 bit, else "sparcv9/" The plugin $ISA must match however
467 * auditd was compiled.
471 isa_ified(char *path
, char **newpath
)
475 if (((p
= strchr(path
, '$')) != NULL
) &&
476 (strncmp("$ISA/", p
, 5) == 0)) {
477 (void) memcpy(*newpath
, path
, p
- path
);
478 q
= *newpath
+ (p
- path
);
479 (void) strcpy(q
, p
+ 5);
485 * init_plugin first searches the existing plugin list to see if the plugin
486 * already has been defined; if not, it creates it and links it into the list.
487 * It returns a pointer to the found or created struct. Note, that
488 * (manual/unsupported) change of path property in audit service configuration
489 * for given plugin will cause a miss.
492 * for 64 bits, the path name can grow 3 bytes (minus 5 for the
493 * removed "$ISA" and plus 8 for the added "sparcv9/"
496 #define ISA_GROW 8 - 5
499 init_plugin(char *name
, kva_t
*list
, int cnt_flag
)
502 char filepath
[MAXPATHLEN
+ 1 + ISA_GROW
];
503 char *path
= filepath
;
506 (void) strcpy(filepath
, "/usr/lib/security/");
507 if (strlcat(filepath
, name
, MAXPATHLEN
) >= MAXPATHLEN
)
510 if (strlen(name
) > MAXPATHLEN
+ ISA_GROW
)
512 isa_ified(name
, &path
);
517 if (p
->plg_path
!= NULL
) {
518 if (strcmp(p
->plg_path
, path
) == 0) {
520 p
->plg_to_be_removed
= 0;
521 p
->plg_cnt
= cnt_flag
;
523 _kva_free(p
->plg_kvlist
);
524 p
->plg_kvlist
= _kva_dup(list
);
525 if (list
!= NULL
&& p
->plg_kvlist
== NULL
) {
529 DPRINT((dbfp
, "reusing %s\n", p
->plg_path
));
536 DPRINT((dbfp
, "creating new plugin structure for %s\n", path
));
538 p
= malloc(sizeof (plugin_t
));
550 p
->plg_initialized
= 0;
554 p
->plg_to_be_removed
= 0;
559 p
->plg_last_seq_out
= 0;
560 p
->plg_path
= strdup(path
);
561 p
->plg_kvlist
= _kva_dup(list
);
562 p
->plg_cnt
= cnt_flag
;
563 p
->plg_retry_time
= SLEEP_TIME
;
565 p
->plg_save_q_copy
= NULL
;
567 if (list
!= NULL
&& p
->plg_kvlist
== NULL
|| p
->plg_path
== NULL
) {
571 DPRINT((dbfp
, "created plugin: %s\n", path
));
576 * loadauditlist() - read the auditd plugin configuration from smf(5) and
577 * prepare appropriate plugin related structures (plugin_t). Set cnt policy here
578 * based on currently active policy settings. (future could have a policy =
579 * {+|-}cnt entry per plugin with auditconfig providing the default)
589 struct au_qctrl kqmax
;
590 scf_plugin_kva_node_t
*plugin_kva_ll
;
591 scf_plugin_kva_node_t
*plugin_kva_ll_head
;
593 if (auditon(A_GETPOLICY
, (char *)&policy
, 0) == -1) {
594 DPRINT((dbfp
, "auditon(A_GETPOLICY...) failed (exit)\n"));
595 __audit_dowarn("auditoff", "", 0);
596 auditd_thread_close();
599 cnt_flag
= ((policy
& AUDIT_CNT
) != 0) ? 1 : 0;
600 DPRINT((dbfp
, "loadauditlist: policy is to %s\n", (cnt_flag
== 1) ?
601 "continue" : "block"));
606 if (auditon(A_GETCOND
, (caddr_t
)&acresult
, sizeof (int)) != 0) {
607 DPRINT((dbfp
, "auditon(A_GETCOND...) failed (exit)\n"));
609 DPRINT((dbfp
, "audit cond = %d (1 is on)\n", acresult
));
614 if (auditon(A_GETQCTRL
, (char *)&kqmax
, sizeof (struct au_qctrl
)) !=
616 DPRINT((dbfp
, "auditon(A_GETQCTRL...) failed (exit)\n"));
617 __audit_dowarn("auditoff", "", 0);
618 auditd_thread_close();
621 kqmax
.aq_hiwater
*= 5; /* RAM is cheaper in userspace */
622 DPRINT((dbfp
, "auditd: reading audit configuration\n"));
626 * two-step on setting p->plg_removed because the input thread
627 * in doorway.c uses p->plg_removed to decide if the plugin is
631 DPRINT((dbfp
, "loadauditlist: %p, %s previously created\n",
632 (void *)p
, p
->plg_path
));
633 p
->plg_to_be_removed
= 1; /* tentative removal */
637 if (!do_getpluginconfig_scf(NULL
, &plugin_kva_ll
)) {
638 DPRINT((dbfp
, "Could not get plugin configuration.\n"));
639 auditd_thread_close();
642 plugin_kva_ll_head
= plugin_kva_ll
;
644 while (plugin_kva_ll
!= NULL
) {
645 DPRINT((dbfp
, "loadauditlist: starting with %s",
646 plugin_kva_ll
->plugin_name
));
648 /* skip inactive plugins */
649 value
= kva_match(plugin_kva_ll
->plugin_kva
, PLUGIN_ACTIVE
);
650 if (strcmp(value
, "1") != 0) {
651 DPRINT((dbfp
, " (inactive:%s) skipping..\n", value
));
652 plugin_kva_ll
= plugin_kva_ll
->next
;
655 DPRINT((dbfp
, " (active)\n"));
657 value
= kva_match(plugin_kva_ll
->plugin_kva
, PLUGIN_PATH
);
658 DPRINT((dbfp
, "loadauditlist: have an entry for %s (%s)\n",
659 plugin_kva_ll
->plugin_name
, value
));
661 p
= init_plugin(value
, plugin_kva_ll
->plugin_kva
, cnt_flag
);
663 DPRINT((dbfp
, "Unsuccessful plugin_t "
664 "initialization.\n"));
669 if (strcmp(plugin_kva_ll
->plugin_name
, "audit_binfile") == 0) {
673 p
->plg_qmax
= kqmax
.aq_hiwater
; /* default */
674 value
= kva_match(plugin_kva_ll
->plugin_kva
, PLUGIN_QSIZE
);
677 tmp
= strtol(value
, &endptr
, 10);
678 if (*endptr
== '\0' && tmp
!= 0) {
682 DPRINT((dbfp
, "%s queue max = %d\n", p
->plg_path
, p
->plg_qmax
));
684 plugin_kva_ll
= plugin_kva_ll
->next
;
689 DPRINT((dbfp
, "loadauditlist: %s remove flag=%d; cnt=%d\n",
690 p
->plg_path
, p
->plg_to_be_removed
, p
->plg_cnt
));
691 p
->plg_removed
= p
->plg_to_be_removed
;
695 plugin_kva_ll_free(plugin_kva_ll_head
);
699 * block signals -- thread-specific blocking of the signals expected
700 * by the main thread.
708 (void) sigfillset(&set
);
709 (void) pthread_sigmask(SIG_BLOCK
, &set
, NULL
);
713 * signal_thread is the designated signal catcher. It wakes up the
714 * main thread whenever it receives a signal and then goes back to
715 * sleep; it does not exit. The global variables caught_* let
716 * the main thread which signal was received.
718 * The thread is created with all signals blocked.
727 DPRINT((dbfp
, "the signal thread is thread %d\n",
730 (void) sigemptyset(&set
);
731 (void) sigaddset(&set
, SIGALRM
);
732 (void) sigaddset(&set
, SIGTERM
);
733 (void) sigaddset(&set
, SIGHUP
);
734 (void) sigaddset(&set
, SIGUSR1
);
737 signal_caught
= sigwait(&set
);
738 switch (signal_caught
) {
741 DPRINT((dbfp
, "caught SIGALRM\n"));
745 DPRINT((dbfp
, "caught SIGTERM\n"));
749 DPRINT((dbfp
, "caught SIGHUP\n"));
753 DPRINT((dbfp
, "caught SIGUSR1\n"));
756 DPRINT((dbfp
, "caught unexpected signal: %d\n",
760 (void) pthread_cond_signal(&(main_thr
.thd_cv
));
765 * do_sethost - do auditon(2) to set the audit host-id.
766 * Returns 0 if success or -1 otherwise.
771 au_tid_addr_t
*termid
;
772 auditinfo_addr_t audit_info
;
775 if (adt_load_hostname(NULL
, (adt_termid_t
**)&termid
) < 0) {
776 (void) snprintf(msg
, sizeof (msg
), "unable to get local "
777 "IP address: %s", strerror(errno
));
780 /* Get current kernel audit info, and fill in the IP address */
781 if (auditon(A_GETKAUDIT
, (caddr_t
)&audit_info
,
782 sizeof (audit_info
)) < 0) {
783 (void) snprintf(msg
, sizeof (msg
), "unable to get kernel "
784 "audit info: %s", strerror(errno
));
788 audit_info
.ai_termid
= *termid
;
790 /* Update the kernel audit info with new IP address */
791 if (auditon(A_SETKAUDIT
, (caddr_t
)&audit_info
,
792 sizeof (audit_info
)) < 0) {
793 (void) snprintf(msg
, sizeof (msg
), "unable to set kernel "
794 "audit info: %s", strerror(errno
));
803 __audit_syslog("auditd", LOG_PID
| LOG_CONS
| LOG_NOWAIT
, LOG_DAEMON
,
809 * conf_to_kernel() - configure the event to class mapping; see also
810 * auditconfig(1M) -conf option.
815 register au_event_ent_t
*evp
;
821 if (auditon(A_GETSTAT
, (caddr_t
)&as
, 0) != 0) {
822 (void) asprintf(&msg
, gettext("Audit module does not appear "
829 while ((evp
= getauevent()) != NULL
) {
830 if (evp
->ae_number
<= as
.as_numevent
) {
832 ec
.ec_number
= evp
->ae_number
;
833 ec
.ec_class
= evp
->ae_class
;
835 if (auditon(A_SETCLASS
, (caddr_t
)&ec
,
837 (void) asprintf(&msg
,
838 gettext("Could not configure kernel audit "
839 "event to class mappings."));
846 DPRINT((dbfp
, "configured %d kernel events.\n", i
));
850 * scf_to_kernel_qctrl() - update the kernel queue control parameters
853 scf_to_kernel_qctrl(void)
855 struct au_qctrl act_qctrl
;
856 struct au_qctrl cfg_qctrl
;
859 if (!do_getqctrl_scf(&cfg_qctrl
)) {
860 (void) asprintf(&msg
, gettext("Unable to gather audit queue "
861 "control parameters from the SMF repository."));
865 DPRINT((dbfp
, "will check and set qctrl parameters:\n"));
866 DPRINT((dbfp
, "\thiwater: %d\n", cfg_qctrl
.aq_hiwater
));
867 DPRINT((dbfp
, "\tlowater: %d\n", cfg_qctrl
.aq_lowater
));
868 DPRINT((dbfp
, "\tbufsz: %d\n", cfg_qctrl
.aq_bufsz
));
869 DPRINT((dbfp
, "\tdelay: %ld\n", cfg_qctrl
.aq_delay
));
871 if (auditon(A_GETQCTRL
, (caddr_t
)&act_qctrl
, 0) != 0) {
872 (void) asprintf(&msg
, gettext("Could not retrieve "
873 "audit queue controls from kernel."));
877 /* overwrite the default (zeros) from the qctrl configuration */
878 if (cfg_qctrl
.aq_hiwater
== 0) {
879 cfg_qctrl
.aq_hiwater
= act_qctrl
.aq_hiwater
;
880 DPRINT((dbfp
, "hiwater changed to active value: %u\n",
881 cfg_qctrl
.aq_hiwater
));
883 if (cfg_qctrl
.aq_lowater
== 0) {
884 cfg_qctrl
.aq_lowater
= act_qctrl
.aq_lowater
;
885 DPRINT((dbfp
, "lowater changed to active value: %u\n",
886 cfg_qctrl
.aq_lowater
));
888 if (cfg_qctrl
.aq_bufsz
== 0) {
889 cfg_qctrl
.aq_bufsz
= act_qctrl
.aq_bufsz
;
890 DPRINT((dbfp
, "bufsz changed to active value: %u\n",
891 cfg_qctrl
.aq_bufsz
));
893 if (cfg_qctrl
.aq_delay
== 0) {
894 cfg_qctrl
.aq_delay
= act_qctrl
.aq_delay
;
895 DPRINT((dbfp
, "delay changed to active value: %ld\n",
896 cfg_qctrl
.aq_delay
));
899 if (auditon(A_SETQCTRL
, (caddr_t
)&cfg_qctrl
, 0) != 0) {
900 (void) asprintf(&msg
,
901 gettext("Could not configure audit queue controls."));
905 DPRINT((dbfp
, "qctrl parameters set\n"));
909 * scf_to_kernel_policy() - update the audit service policies
912 scf_to_kernel_policy(void)
917 if (!do_getpolicy_scf(&policy
)) {
918 (void) asprintf(&msg
, gettext("Unable to get audit policy "
919 "configuration from the SMF repository."));
923 if (auditon(A_SETPOLICY
, (caddr_t
)&policy
, 0) != 0) {
924 (void) asprintf(&msg
,
925 gettext("Could not update active policy settings."));
929 DPRINT((dbfp
, "kernel policy settings updated\n"));