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