2 * Copyright (c) 2004, 2009 Apple Inc.
3 * Copyright (c) 2006, 2016 Robert N. M. Watson
6 * Portions of this software were developed by BAE Systems, the University of
7 * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL
8 * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent
9 * Computing (TC) research program.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
20 * its contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
27 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
36 #include <config/config.h>
38 #include <bsm/libbsm.h>
44 #ifdef HAVE_PTHREAD_MUTEX_LOCK
51 #include <compat/strlcat.h>
54 #include <compat/strlcpy.h>
60 * Parse the contents of the audit_control file to return the audit control
61 * parameters. These static fields are protected by 'mutex'.
63 static FILE *fp = NULL;
64 static char linestr[AU_LINE_MAX];
65 static char *delim = ":";
67 static char inacdir = 0;
68 static char ptrmoved = 0;
70 #ifdef HAVE_PTHREAD_MUTEX_LOCK
71 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
75 * Audit policy string token table for au_poltostr() and au_strtopol().
82 static struct audit_polstr au_polstr[] = {
84 { AUDIT_AHLT, "ahlt" },
85 { AUDIT_ARGV, "argv" },
86 { AUDIT_ARGE, "arge" },
88 { AUDIT_WINDATA, "windata" },
89 { AUDIT_USER, "user" },
90 { AUDIT_GROUP, "group" },
91 { AUDIT_TRAIL, "trail" },
92 { AUDIT_PATH, "path" },
93 { AUDIT_SCNT, "scnt" },
94 { AUDIT_PUBLIC, "public" },
95 { AUDIT_ZONENAME, "zonename" },
96 { AUDIT_PERZONE, "perzone" },
101 * Returns the string value corresponding to the given label from the
102 * configuration file.
104 * Must be called with mutex held.
107 getstrfromtype_locked(const char *name, char **str)
115 if ((fp == NULL) && ((fp = fopen(AUDIT_CONTROL_FILE, "r")) == NULL))
116 return (-1); /* Error */
119 if (fgets(linestr, AU_LINE_MAX, fp) == NULL) {
122 return (0); /* EOF */
125 if (linestr[0] == '#')
128 /* Remove trailing new line character and white space. */
129 nl = strchr(linestr, '\0') - 1;
130 while (nl >= linestr && ('\n' == *nl || ' ' == *nl ||
137 if ((type = strtok_r(tokptr, delim, &last)) != NULL) {
138 if (strcmp(name, type) == 0) {
139 /* Found matching name. */
141 return (0); /* Success */
148 * Convert a given time value with a multiplier (seconds, hours, days, years) to
149 * seconds. Return 0 on success.
152 au_timetosec(time_t *seconds, u_long value, char mult)
160 *seconds = (time_t)value;
165 *seconds = (time_t)value * 60 * 60;
170 *seconds = (time_t)value * 60 * 60 * 24;
174 /* years. Add a day for each 4th (leap) year. */
175 *seconds = (time_t)value * 60 * 60 * 24 * 364 +
176 ((time_t)value / 4) * 60 * 60 * 24;
186 * Convert a given disk space value with a multiplier (bytes, kilobytes,
187 * megabytes, gigabytes) to bytes. Return 0 on success.
190 au_spacetobytes(size_t *bytes, u_long value, char mult)
199 *bytes = (size_t)value;
204 *bytes = (size_t)value * 1024;
209 *bytes = (size_t)value * 1024 * 1024;
214 *bytes = (size_t)value * 1024 * 1024 * 1024;
224 * Convert a policy to a string. Return -1 on failure, or >= 0 representing
225 * the actual size of the string placed in the buffer (excluding terminating
229 au_poltostr(int policy, size_t maxsize, char *buf)
239 if (policy & au_polstr[i].ap_policy) {
240 if (!first && strlcat(buf, ",", maxsize) >= maxsize)
242 if (strlcat(buf, au_polstr[i].ap_str, maxsize) >=
247 } while (NULL != au_polstr[++i].ap_str);
249 return (strlen(buf));
253 * Convert a string to a policy. Return -1 on failure (with errno EINVAL,
254 * ENOMEM) or 0 on success.
257 au_strtopol(const char *polstr, int *policy)
264 buffer = strdup(polstr);
269 while ((string = strsep(&bufp, ",")) != NULL) {
273 if (strcmp(string, au_polstr[i].ap_str) == 0) {
274 *policy |= au_polstr[i].ap_policy;
278 } while (NULL != au_polstr[++i].ap_str);
291 * Rewind the file pointer to beginning.
296 static time_t lastctime = 0;
302 * Check to see if the file on disk has changed. If so,
303 * force a re-read of the file by closing it.
305 if (fstat(fileno(fp), &sbuf) < 0)
307 if (lastctime != sbuf.st_ctime) {
308 lastctime = sbuf.st_ctime;
315 fseek(fp, 0, SEEK_SET);
323 #ifdef HAVE_PTHREAD_MUTEX_LOCK
324 pthread_mutex_lock(&mutex);
327 #ifdef HAVE_PTHREAD_MUTEX_LOCK
328 pthread_mutex_unlock(&mutex);
333 * Close the audit_control file.
339 #ifdef HAVE_PTHREAD_MUTEX_LOCK
340 pthread_mutex_lock(&mutex);
347 #ifdef HAVE_PTHREAD_MUTEX_LOCK
348 pthread_mutex_unlock(&mutex);
353 * Return audit directory information from the audit control file.
356 getacdir(char *name, int len)
362 * Check if another function was called between successive calls to
365 #ifdef HAVE_PTHREAD_MUTEX_LOCK
366 pthread_mutex_lock(&mutex);
368 if (inacdir && ptrmoved) {
371 fseek(fp, 0, SEEK_SET);
374 if (getstrfromtype_locked(DIR_CONTROL_ENTRY, &dir) < 0) {
375 #ifdef HAVE_PTHREAD_MUTEX_LOCK
376 pthread_mutex_unlock(&mutex);
381 #ifdef HAVE_PTHREAD_MUTEX_LOCK
382 pthread_mutex_unlock(&mutex);
386 if (strlen(dir) >= (size_t)len) {
387 #ifdef HAVE_PTHREAD_MUTEX_LOCK
388 pthread_mutex_unlock(&mutex);
392 strlcpy(name, dir, len);
393 #ifdef HAVE_PTHREAD_MUTEX_LOCK
394 pthread_mutex_unlock(&mutex);
400 * Return 1 if dist value is set to 'yes' or 'on'.
401 * Return 0 if dist value is set to something else.
402 * Return negative value on error.
410 #ifdef HAVE_PTHREAD_MUTEX_LOCK
411 pthread_mutex_lock(&mutex);
414 if (getstrfromtype_locked(DIST_CONTROL_ENTRY, &str) < 0) {
415 #ifdef HAVE_PTHREAD_MUTEX_LOCK
416 pthread_mutex_unlock(&mutex);
421 #ifdef HAVE_PTHREAD_MUTEX_LOCK
422 pthread_mutex_unlock(&mutex);
426 if (strcasecmp(str, "on") == 0 || strcasecmp(str, "yes") == 0)
430 #ifdef HAVE_PTHREAD_MUTEX_LOCK
431 pthread_mutex_unlock(&mutex);
437 * Return the minimum free diskspace value from the audit control file.
440 getacmin(int *min_val)
444 #ifdef HAVE_PTHREAD_MUTEX_LOCK
445 pthread_mutex_lock(&mutex);
448 if (getstrfromtype_locked(MINFREE_CONTROL_ENTRY, &min) < 0) {
449 #ifdef HAVE_PTHREAD_MUTEX_LOCK
450 pthread_mutex_unlock(&mutex);
455 #ifdef HAVE_PTHREAD_MUTEX_LOCK
456 pthread_mutex_unlock(&mutex);
460 *min_val = atoi(min);
461 #ifdef HAVE_PTHREAD_MUTEX_LOCK
462 pthread_mutex_unlock(&mutex);
468 * Return the desired trail rotation size from the audit control file.
471 getacfilesz(size_t *filesz_val)
478 #ifdef HAVE_PTHREAD_MUTEX_LOCK
479 pthread_mutex_lock(&mutex);
482 if (getstrfromtype_locked(FILESZ_CONTROL_ENTRY, &str) < 0) {
483 #ifdef HAVE_PTHREAD_MUTEX_LOCK
484 pthread_mutex_unlock(&mutex);
489 #ifdef HAVE_PTHREAD_MUTEX_LOCK
490 pthread_mutex_unlock(&mutex);
496 /* Trim off any leading white space. */
497 while (*str == ' ' || *str == '\t')
500 nparsed = sscanf(str, "%ju%c", (uintmax_t *)&val, &mult);
504 /* If no multiplier then assume 'B' (bytes). */
508 if (au_spacetobytes(filesz_val, val, mult) == 0)
513 #ifdef HAVE_PTHREAD_MUTEX_LOCK
514 pthread_mutex_unlock(&mutex);
520 * The file size must either be 0 or >= MIN_AUDIT_FILE_SIZE. 0
521 * indicates no rotation size.
523 if (*filesz_val < 0 || (*filesz_val > 0 &&
524 *filesz_val < MIN_AUDIT_FILE_SIZE)) {
525 #ifdef HAVE_PTHREAD_MUTEX_LOCK
526 pthread_mutex_unlock(&mutex);
532 #ifdef HAVE_PTHREAD_MUTEX_LOCK
533 pthread_mutex_unlock(&mutex);
539 getaccommon(const char *name, char *auditstr, int len)
543 #ifdef HAVE_PTHREAD_MUTEX_LOCK
544 pthread_mutex_lock(&mutex);
547 if (getstrfromtype_locked(name, &str) < 0) {
548 #ifdef HAVE_PTHREAD_MUTEX_LOCK
549 pthread_mutex_unlock(&mutex);
555 * getstrfromtype_locked() can return NULL for an empty value -- make
556 * sure to handle this by coercing the NULL back into an empty string.
558 if (str != NULL && (strlen(str) >= (size_t)len)) {
559 #ifdef HAVE_PTHREAD_MUTEX_LOCK
560 pthread_mutex_unlock(&mutex);
564 strlcpy(auditstr, str != NULL ? str : "", len);
565 #ifdef HAVE_PTHREAD_MUTEX_LOCK
566 pthread_mutex_unlock(&mutex);
572 * Return the system audit value from the audit contol file.
575 getacflg(char *auditstr, int len)
578 return (getaccommon(FLAGS_CONTROL_ENTRY, auditstr, len));
582 * Return the non attributable flags from the audit contol file.
585 getacna(char *auditstr, int len)
588 return (getaccommon(NA_CONTROL_ENTRY, auditstr, len));
592 * Return the policy field from the audit control file.
595 getacpol(char *auditstr, size_t len)
598 return (getaccommon(POLICY_CONTROL_ENTRY, auditstr, len));
602 getachost(char *auditstr, size_t len)
605 return (getaccommon(HOST_CONTROL_ENTRY, auditstr, len));
609 * Set expiration conditions.
612 setexpirecond(time_t *age, size_t *size, u_long value, char mult)
615 if (isupper(mult) || ' ' == mult)
616 return (au_spacetobytes(size, value, mult));
618 return (au_timetosec(age, value, mult));
622 * Return the expire-after field from the audit control file.
625 getacexpire(int *andflg, time_t *age, size_t *size)
631 char andor[AU_LINE_MAX];
637 #ifdef HAVE_PTHREAD_MUTEX_LOCK
638 pthread_mutex_lock(&mutex);
641 if (getstrfromtype_locked(EXPIRE_AFTER_CONTROL_ENTRY, &str) < 0) {
642 #ifdef HAVE_PTHREAD_MUTEX_LOCK
643 pthread_mutex_unlock(&mutex);
648 #ifdef HAVE_PTHREAD_MUTEX_LOCK
649 pthread_mutex_unlock(&mutex);
654 /* First, trim off any leading white space. */
655 while (*str == ' ' || *str == '\t')
658 nparsed = sscanf(str, "%lu%c%[ \tadnorADNOR]%lu%c", &val1, &mult1,
659 andor, &val2, &mult2);
663 /* If no multiplier then assume 'B' (Bytes). */
667 /* One expiration condition. */
668 if (setexpirecond(age, size, val1, mult1) != 0) {
669 #ifdef HAVE_PTHREAD_MUTEX_LOCK
670 pthread_mutex_unlock(&mutex);
677 /* Two expiration conditions. */
678 if (setexpirecond(age, size, val1, mult1) != 0 ||
679 setexpirecond(age, size, val2, mult2) != 0) {
680 #ifdef HAVE_PTHREAD_MUTEX_LOCK
681 pthread_mutex_unlock(&mutex);
685 if (strcasestr(andor, "and") != NULL)
687 else if (strcasestr(andor, "or") != NULL)
690 #ifdef HAVE_PTHREAD_MUTEX_LOCK
691 pthread_mutex_unlock(&mutex);
698 #ifdef HAVE_PTHREAD_MUTEX_LOCK
699 pthread_mutex_unlock(&mutex);
704 #ifdef HAVE_PTHREAD_MUTEX_LOCK
705 pthread_mutex_unlock(&mutex);
710 * Return the desired queue size from the audit control file.
713 getacqsize(int *qsz_val)
718 #ifdef HAVE_PTHREAD_MUTEX_LOCK
719 pthread_mutex_lock(&mutex);
722 if (getstrfromtype_locked(QSZ_CONTROL_ENTRY, &str) < 0) {
723 #ifdef HAVE_PTHREAD_MUTEX_LOCK
724 pthread_mutex_unlock(&mutex);
729 #ifdef HAVE_PTHREAD_MUTEX_LOCK
730 pthread_mutex_unlock(&mutex);
732 *qsz_val = USE_DEFAULT_QSZ;
736 /* Trim off any leading white space. */
737 while (*str == ' ' || *str == '\t')
740 nparsed = sscanf(str, "%d", (int *)qsz_val);
744 #ifdef HAVE_PTHREAD_MUTEX_LOCK
745 pthread_mutex_unlock(&mutex);
750 /* The queue size must either be 0 or < AQ_MAXHIGH */
751 if (*qsz_val < 0 || *qsz_val > AQ_MAXHIGH) {
752 #ifdef HAVE_PTHREAD_MUTEX_LOCK
753 pthread_mutex_unlock(&mutex);
759 #ifdef HAVE_PTHREAD_MUTEX_LOCK
760 pthread_mutex_unlock(&mutex);