1 /*-
2 * Copyright (c) 2004, 2009 Apple Inc.
3 * Copyright (c) 2006 Robert N. M. Watson
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <config/config.h>
32
33 #include <bsm/libbsm.h>
34
35 #include <ctype.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <strings.h>
39 #ifdef HAVE_PTHREAD_MUTEX_LOCK
40 #include <pthread.h>
41 #endif
42 #include <stdio.h>
43 #include <stdlib.h>
44
45 #ifndef HAVE_STRLCAT
46 #include <compat/strlcat.h>
47 #endif
48 #ifndef HAVE_STRLCPY
49 #include <compat/strlcpy.h>
50 #endif
51
52 #include <sys/stat.h>
53
54 /*
55 * Parse the contents of the audit_control file to return the audit control
56 * parameters. These static fields are protected by 'mutex'.
57 */
58 static FILE *fp = NULL;
59 static char linestr[AU_LINE_MAX];
60 static char *delim = ":";
61
62 static char inacdir = 0;
63 static char ptrmoved = 0;
64
65 #ifdef HAVE_PTHREAD_MUTEX_LOCK
66 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
67 #endif
68
69 /*
70 * Audit policy string token table for au_poltostr() and au_strtopol().
71 */
72 struct audit_polstr {
73 long ap_policy;
74 const char *ap_str;
75 };
76
77 static struct audit_polstr au_polstr[] = {
78 { AUDIT_CNT, "cnt" },
79 { AUDIT_AHLT, "ahlt" },
80 { AUDIT_ARGV, "argv" },
81 { AUDIT_ARGE, "arge" },
82 { AUDIT_SEQ, "seq" },
83 { AUDIT_WINDATA, "windata" },
84 { AUDIT_USER, "user" },
85 { AUDIT_GROUP, "group" },
86 { AUDIT_TRAIL, "trail" },
87 { AUDIT_PATH, "path" },
88 { AUDIT_SCNT, "scnt" },
89 { AUDIT_PUBLIC, "public" },
90 { AUDIT_ZONENAME, "zonename" },
91 { AUDIT_PERZONE, "perzone" },
92 { -1, NULL }
93 };
94
95 /*
96 * Returns the string value corresponding to the given label from the
97 * configuration file.
98 *
99 * Must be called with mutex held.
100 */
101 static int
getstrfromtype_locked(const char * name,char ** str)102 getstrfromtype_locked(const char *name, char **str)
103 {
104 char *type, *nl;
105 char *tokptr;
106 char *last;
107
108 *str = NULL;
109
110 if ((fp == NULL) && ((fp = fopen(AUDIT_CONTROL_FILE, "r")) == NULL))
111 return (-1); /* Error */
112
113 while (1) {
114 if (fgets(linestr, AU_LINE_MAX, fp) == NULL) {
115 if (ferror(fp))
116 return (-1);
117 return (0); /* EOF */
118 }
119
120 if (linestr[0] == '#')
121 continue;
122
123 /* Remove trailing new line character and white space. */
124 nl = strchr(linestr, '\0') - 1;
125 while (nl >= linestr && ('\n' == *nl || ' ' == *nl ||
126 '\t' == *nl)) {
127 *nl = '\0';
128 nl--;
129 }
130
131 tokptr = linestr;
132 if ((type = strtok_r(tokptr, delim, &last)) != NULL) {
133 if (strcmp(name, type) == 0) {
134 /* Found matching name. */
135 *str = strtok_r(NULL, delim, &last);
136 if (*str == NULL) {
137 errno = EINVAL;
138 return (-1); /* Parse error in file */
139 }
140 return (0); /* Success */
141 }
142 }
143 }
144 }
145
146 /*
147 * Convert a given time value with a multiplier (seconds, hours, days, years) to
148 * seconds. Return 0 on success.
149 */
150 static int
au_timetosec(time_t * seconds,u_long value,char mult)151 au_timetosec(time_t *seconds, u_long value, char mult)
152 {
153 if (NULL == seconds)
154 return (-1);
155
156 switch(mult) {
157 case 's':
158 /* seconds */
159 *seconds = (time_t)value;
160 break;
161
162 case 'h':
163 /* hours */
164 *seconds = (time_t)value * 60 * 60;
165 break;
166
167 case 'd':
168 /* days */
169 *seconds = (time_t)value * 60 * 60 * 24;
170 break;
171
172 case 'y':
173 /* years. Add a day for each 4th (leap) year. */
174 *seconds = (time_t)value * 60 * 60 * 24 * 364 +
175 ((time_t)value / 4) * 60 * 60 * 24;
176 break;
177
178 default:
179 return (-1);
180 }
181 return (0);
182 }
183
184 /*
185 * Convert a given disk space value with a multiplier (bytes, kilobytes,
186 * megabytes, gigabytes) to bytes. Return 0 on success.
187 */
188 static int
au_spacetobytes(size_t * bytes,u_long value,char mult)189 au_spacetobytes(size_t *bytes, u_long value, char mult)
190 {
191 if (NULL == bytes)
192 return (-1);
193
194 switch(mult) {
195 case 'B':
196 case ' ':
197 /* Bytes */
198 *bytes = (size_t)value;
199 break;
200
201 case 'K':
202 /* Kilobytes */
203 *bytes = (size_t)value * 1024;
204 break;
205
206 case 'M':
207 /* Megabytes */
208 *bytes = (size_t)value * 1024 * 1024;
209 break;
210
211 case 'G':
212 /* Gigabytes */
213 *bytes = (size_t)value * 1024 * 1024 * 1024;
214 break;
215
216 default:
217 return (-1);
218 }
219 return (0);
220 }
221
222 /*
223 * Convert a policy to a string. Return -1 on failure, or >= 0 representing
224 * the actual size of the string placed in the buffer (excluding terminating
225 * nul).
226 */
227 ssize_t
au_poltostr(int policy,size_t maxsize,char * buf)228 au_poltostr(int policy, size_t maxsize, char *buf)
229 {
230 int first = 1;
231 int i = 0;
232
233 if (maxsize < 1)
234 return (-1);
235 buf[0] = '\0';
236
237 do {
238 if (policy & au_polstr[i].ap_policy) {
239 if (!first && strlcat(buf, ",", maxsize) >= maxsize)
240 return (-1);
241 if (strlcat(buf, au_polstr[i].ap_str, maxsize) >=
242 maxsize)
243 return (-1);
244 first = 0;
245 }
246 } while (NULL != au_polstr[++i].ap_str);
247
248 return (strlen(buf));
249 }
250
251 /*
252 * Convert a string to a policy. Return -1 on failure (with errno EINVAL,
253 * ENOMEM) or 0 on success.
254 */
255 int
au_strtopol(const char * polstr,int * policy)256 au_strtopol(const char *polstr, int *policy)
257 {
258 char *bufp, *string;
259 char *buffer;
260 int i, matched;
261
262 *policy = 0;
263 buffer = strdup(polstr);
264 if (buffer == NULL)
265 return (-1);
266
267 bufp = buffer;
268 while ((string = strsep(&bufp, ",")) != NULL) {
269 matched = i = 0;
270
271 do {
272 if (strcmp(string, au_polstr[i].ap_str) == 0) {
273 *policy |= au_polstr[i].ap_policy;
274 matched = 1;
275 break;
276 }
277 } while (NULL != au_polstr[++i].ap_str);
278
279 if (!matched) {
280 free(buffer);
281 errno = EINVAL;
282 return (-1);
283 }
284 }
285 free(buffer);
286 return (0);
287 }
288
289 /*
290 * Rewind the file pointer to beginning.
291 */
292 static void
setac_locked(void)293 setac_locked(void)
294 {
295 static time_t lastctime = 0;
296 struct stat sbuf;
297
298 ptrmoved = 1;
299 if (fp != NULL) {
300 /*
301 * Check to see if the file on disk has changed. If so,
302 * force a re-read of the file by closing it.
303 */
304 if (fstat(fileno(fp), &sbuf) < 0)
305 goto closefp;
306 if (lastctime != sbuf.st_ctime) {
307 lastctime = sbuf.st_ctime;
308 closefp:
309 fclose(fp);
310 fp = NULL;
311 return;
312 }
313
314 fseek(fp, 0, SEEK_SET);
315 }
316 }
317
318 void
setac(void)319 setac(void)
320 {
321
322 #ifdef HAVE_PTHREAD_MUTEX_LOCK
323 pthread_mutex_lock(&mutex);
324 #endif
325 setac_locked();
326 #ifdef HAVE_PTHREAD_MUTEX_LOCK
327 pthread_mutex_unlock(&mutex);
328 #endif
329 }
330
331 /*
332 * Close the audit_control file.
333 */
334 void
endac(void)335 endac(void)
336 {
337
338 #ifdef HAVE_PTHREAD_MUTEX_LOCK
339 pthread_mutex_lock(&mutex);
340 #endif
341 ptrmoved = 1;
342 if (fp != NULL) {
343 fclose(fp);
344 fp = NULL;
345 }
346 #ifdef HAVE_PTHREAD_MUTEX_LOCK
347 pthread_mutex_unlock(&mutex);
348 #endif
349 }
350
351 /*
352 * Return audit directory information from the audit control file.
353 */
354 int
getacdir(char * name,int len)355 getacdir(char *name, int len)
356 {
357 char *dir;
358 int ret = 0;
359
360 /*
361 * Check if another function was called between successive calls to
362 * getacdir.
363 */
364 #ifdef HAVE_PTHREAD_MUTEX_LOCK
365 pthread_mutex_lock(&mutex);
366 #endif
367 if (inacdir && ptrmoved) {
368 ptrmoved = 0;
369 if (fp != NULL)
370 fseek(fp, 0, SEEK_SET);
371 ret = 2;
372 }
373 if (getstrfromtype_locked(DIR_CONTROL_ENTRY, &dir) < 0) {
374 #ifdef HAVE_PTHREAD_MUTEX_LOCK
375 pthread_mutex_unlock(&mutex);
376 #endif
377 return (-2);
378 }
379 if (dir == NULL) {
380 #ifdef HAVE_PTHREAD_MUTEX_LOCK
381 pthread_mutex_unlock(&mutex);
382 #endif
383 return (-1);
384 }
385 if (strlen(dir) >= (size_t)len) {
386 #ifdef HAVE_PTHREAD_MUTEX_LOCK
387 pthread_mutex_unlock(&mutex);
388 #endif
389 return (-3);
390 }
391 strlcpy(name, dir, len);
392 #ifdef HAVE_PTHREAD_MUTEX_LOCK
393 pthread_mutex_unlock(&mutex);
394 #endif
395 return (ret);
396 }
397
398 /*
399 * Return 1 if dist value is set to 'yes' or 'on'.
400 * Return 0 if dist value is set to something else.
401 * Return negative value on error.
402 */
403 int
getacdist(void)404 getacdist(void)
405 {
406 char *str;
407 int ret;
408
409 #ifdef HAVE_PTHREAD_MUTEX_LOCK
410 pthread_mutex_lock(&mutex);
411 #endif
412 setac_locked();
413 if (getstrfromtype_locked(DIST_CONTROL_ENTRY, &str) < 0) {
414 #ifdef HAVE_PTHREAD_MUTEX_LOCK
415 pthread_mutex_unlock(&mutex);
416 #endif
417 return (-2);
418 }
419 if (str == NULL) {
420 #ifdef HAVE_PTHREAD_MUTEX_LOCK
421 pthread_mutex_unlock(&mutex);
422 #endif
423 return (0);
424 }
425 if (strcasecmp(str, "on") == 0 || strcasecmp(str, "yes") == 0)
426 ret = 1;
427 else
428 ret = 0;
429 #ifdef HAVE_PTHREAD_MUTEX_LOCK
430 pthread_mutex_unlock(&mutex);
431 #endif
432 return (ret);
433 }
434
435 /*
436 * Return the minimum free diskspace value from the audit control file.
437 */
438 int
getacmin(int * min_val)439 getacmin(int *min_val)
440 {
441 char *min;
442
443 #ifdef HAVE_PTHREAD_MUTEX_LOCK
444 pthread_mutex_lock(&mutex);
445 #endif
446 setac_locked();
447 if (getstrfromtype_locked(MINFREE_CONTROL_ENTRY, &min) < 0) {
448 #ifdef HAVE_PTHREAD_MUTEX_LOCK
449 pthread_mutex_unlock(&mutex);
450 #endif
451 return (-2);
452 }
453 if (min == NULL) {
454 #ifdef HAVE_PTHREAD_MUTEX_LOCK
455 pthread_mutex_unlock(&mutex);
456 #endif
457 return (-1);
458 }
459 *min_val = atoi(min);
460 #ifdef HAVE_PTHREAD_MUTEX_LOCK
461 pthread_mutex_unlock(&mutex);
462 #endif
463 return (0);
464 }
465
466 /*
467 * Return the desired trail rotation size from the audit control file.
468 */
469 int
getacfilesz(size_t * filesz_val)470 getacfilesz(size_t *filesz_val)
471 {
472 char *str;
473 size_t val;
474 char mult;
475 int nparsed;
476
477 #ifdef HAVE_PTHREAD_MUTEX_LOCK
478 pthread_mutex_lock(&mutex);
479 #endif
480 setac_locked();
481 if (getstrfromtype_locked(FILESZ_CONTROL_ENTRY, &str) < 0) {
482 #ifdef HAVE_PTHREAD_MUTEX_LOCK
483 pthread_mutex_unlock(&mutex);
484 #endif
485 return (-2);
486 }
487 if (str == NULL) {
488 #ifdef HAVE_PTHREAD_MUTEX_LOCK
489 pthread_mutex_unlock(&mutex);
490 #endif
491 errno = EINVAL;
492 return (-1);
493 }
494
495 /* Trim off any leading white space. */
496 while (*str == ' ' || *str == '\t')
497 str++;
498
499 nparsed = sscanf(str, "%ju%c", (uintmax_t *)&val, &mult);
500
501 switch (nparsed) {
502 case 1:
503 /* If no multiplier then assume 'B' (bytes). */
504 mult = 'B';
505 /* fall through */
506 case 2:
507 if (au_spacetobytes(filesz_val, val, mult) == 0)
508 break;
509 /* fall through */
510 default:
511 errno = EINVAL;
512 #ifdef HAVE_PTHREAD_MUTEX_LOCK
513 pthread_mutex_unlock(&mutex);
514 #endif
515 return (-1);
516 }
517
518 /*
519 * The file size must either be 0 or >= MIN_AUDIT_FILE_SIZE. 0
520 * indicates no rotation size.
521 */
522 if (*filesz_val < 0 || (*filesz_val > 0 &&
523 *filesz_val < MIN_AUDIT_FILE_SIZE)) {
524 #ifdef HAVE_PTHREAD_MUTEX_LOCK
525 pthread_mutex_unlock(&mutex);
526 #endif
527 filesz_val = 0L;
528 errno = EINVAL;
529 return (-1);
530 }
531 #ifdef HAVE_PTHREAD_MUTEX_LOCK
532 pthread_mutex_unlock(&mutex);
533 #endif
534 return (0);
535 }
536
537 static int
getaccommon(const char * name,char * auditstr,int len)538 getaccommon(const char *name, char *auditstr, int len)
539 {
540 char *str;
541
542 #ifdef HAVE_PTHREAD_MUTEX_LOCK
543 pthread_mutex_lock(&mutex);
544 #endif
545 setac_locked();
546 if (getstrfromtype_locked(name, &str) < 0) {
547 #ifdef HAVE_PTHREAD_MUTEX_LOCK
548 pthread_mutex_unlock(&mutex);
549 #endif
550 return (-2);
551 }
552 if (str == NULL) {
553 #ifdef HAVE_PTHREAD_MUTEX_LOCK
554 pthread_mutex_unlock(&mutex);
555 #endif
556 return (-1);
557 }
558 if (strlen(str) >= (size_t)len) {
559 #ifdef HAVE_PTHREAD_MUTEX_LOCK
560 pthread_mutex_unlock(&mutex);
561 #endif
562 return (-3);
563 }
564 strlcpy(auditstr, str, len);
565 #ifdef HAVE_PTHREAD_MUTEX_LOCK
566 pthread_mutex_unlock(&mutex);
567 #endif
568 return (0);
569 }
570
571 /*
572 * Return the system audit value from the audit contol file.
573 */
574 int
getacflg(char * auditstr,int len)575 getacflg(char *auditstr, int len)
576 {
577
578 return (getaccommon(FLAGS_CONTROL_ENTRY, auditstr, len));
579 }
580
581 /*
582 * Return the non attributable flags from the audit contol file.
583 */
584 int
getacna(char * auditstr,int len)585 getacna(char *auditstr, int len)
586 {
587
588 return (getaccommon(NA_CONTROL_ENTRY, auditstr, len));
589 }
590
591 /*
592 * Return the policy field from the audit control file.
593 */
594 int
getacpol(char * auditstr,size_t len)595 getacpol(char *auditstr, size_t len)
596 {
597
598 return (getaccommon(POLICY_CONTROL_ENTRY, auditstr, len));
599 }
600
601 int
getachost(char * auditstr,size_t len)602 getachost(char *auditstr, size_t len)
603 {
604
605 return (getaccommon(HOST_CONTROL_ENTRY, auditstr, len));
606 }
607
608 /*
609 * Set expiration conditions.
610 */
611 static int
setexpirecond(time_t * age,size_t * size,u_long value,char mult)612 setexpirecond(time_t *age, size_t *size, u_long value, char mult)
613 {
614
615 if (isupper(mult) || ' ' == mult)
616 return (au_spacetobytes(size, value, mult));
617 else
618 return (au_timetosec(age, value, mult));
619 }
620
621 /*
622 * Return the expire-after field from the audit control file.
623 */
624 int
getacexpire(int * andflg,time_t * age,size_t * size)625 getacexpire(int *andflg, time_t *age, size_t *size)
626 {
627 char *str;
628 int nparsed;
629 u_long val1, val2;
630 char mult1, mult2;
631 char andor[AU_LINE_MAX];
632
633 *age = 0L;
634 *size = 0LL;
635 *andflg = 0;
636
637 #ifdef HAVE_PTHREAD_MUTEX_LOCK
638 pthread_mutex_lock(&mutex);
639 #endif
640 setac_locked();
641 if (getstrfromtype_locked(EXPIRE_AFTER_CONTROL_ENTRY, &str) < 0) {
642 #ifdef HAVE_PTHREAD_MUTEX_LOCK
643 pthread_mutex_unlock(&mutex);
644 #endif
645 return (-2);
646 }
647 if (str == NULL) {
648 #ifdef HAVE_PTHREAD_MUTEX_LOCK
649 pthread_mutex_unlock(&mutex);
650 #endif
651 return (-1);
652 }
653
654 /* First, trim off any leading white space. */
655 while (*str == ' ' || *str == '\t')
656 str++;
657
658 nparsed = sscanf(str, "%lu%c%[ \tadnorADNOR]%lu%c", &val1, &mult1,
659 andor, &val2, &mult2);
660
661 switch (nparsed) {
662 case 1:
663 /* If no multiplier then assume 'B' (Bytes). */
664 mult1 = 'B';
665 /* fall through */
666 case 2:
667 /* One expiration condition. */
668 if (setexpirecond(age, size, val1, mult1) != 0) {
669 #ifdef HAVE_PTHREAD_MUTEX_LOCK
670 pthread_mutex_unlock(&mutex);
671 #endif
672 return (-1);
673 }
674 break;
675
676 case 5:
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);
682 #endif
683 return (-1);
684 }
685 if (strcasestr(andor, "and") != NULL)
686 *andflg = 1;
687 else if (strcasestr(andor, "or") != NULL)
688 *andflg = 0;
689 else {
690 #ifdef HAVE_PTHREAD_MUTEX_LOCK
691 pthread_mutex_unlock(&mutex);
692 #endif
693 return (-1);
694 }
695 break;
696
697 default:
698 #ifdef HAVE_PTHREAD_MUTEX_LOCK
699 pthread_mutex_unlock(&mutex);
700 #endif
701 return (-1);
702 }
703
704 #ifdef HAVE_PTHREAD_MUTEX_LOCK
705 pthread_mutex_unlock(&mutex);
706 #endif
707 return (0);
708 }
709