]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/openbsm/libbsm/bsm_control.c
MFV r337014:
[FreeBSD/FreeBSD.git] / contrib / openbsm / libbsm / bsm_control.c
1 /*-
2  * Copyright (c) 2004, 2009 Apple Inc.
3  * Copyright (c) 2006, 2016 Robert N. M. Watson
4  * All rights reserved.
5  *
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.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
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.
22  *
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.
34  */
35
36 #include <config/config.h>
37
38 #include <bsm/libbsm.h>
39
40 #include <ctype.h>
41 #include <errno.h>
42 #include <string.h>
43 #include <strings.h>
44 #ifdef HAVE_PTHREAD_MUTEX_LOCK
45 #include <pthread.h>
46 #endif
47 #include <stdio.h>
48 #include <stdlib.h>
49
50 #ifndef HAVE_STRLCAT
51 #include <compat/strlcat.h>
52 #endif
53 #ifndef HAVE_STRLCPY
54 #include <compat/strlcpy.h>
55 #endif
56
57 #include <sys/stat.h>
58
59 /*
60  * Parse the contents of the audit_control file to return the audit control
61  * parameters.  These static fields are protected by 'mutex'.
62  */
63 static FILE     *fp = NULL;
64 static char     linestr[AU_LINE_MAX];
65 static char     *delim = ":";
66
67 static char     inacdir = 0;
68 static char     ptrmoved = 0;
69
70 #ifdef HAVE_PTHREAD_MUTEX_LOCK
71 static pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;
72 #endif
73
74 /*
75  * Audit policy string token table for au_poltostr() and au_strtopol().
76  */
77 struct audit_polstr {
78         long             ap_policy;
79         const char      *ap_str;
80 };
81
82 static struct audit_polstr au_polstr[] = {
83         { AUDIT_CNT,            "cnt"           },
84         { AUDIT_AHLT,           "ahlt"          },
85         { AUDIT_ARGV,           "argv"          },
86         { AUDIT_ARGE,           "arge"          },
87         { AUDIT_SEQ,            "seq"           },
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"       },
97         { -1,                   NULL            }
98 };
99
100 /*
101  * Returns the string value corresponding to the given label from the
102  * configuration file.
103  *
104  * Must be called with mutex held.
105  */
106 static int
107 getstrfromtype_locked(const char *name, char **str)
108 {
109         char *type, *nl;
110         char *tokptr;
111         char *last;
112
113         *str = NULL;
114
115         if ((fp == NULL) && ((fp = fopen(AUDIT_CONTROL_FILE, "r")) == NULL))
116                 return (-1); /* Error */
117
118         while (1) {
119                 if (fgets(linestr, AU_LINE_MAX, fp) == NULL) {
120                         if (ferror(fp))
121                                 return (-1);
122                         return (0);     /* EOF */
123                 }
124
125                 if (linestr[0] == '#')
126                         continue;
127
128                 /* Remove trailing new line character and white space. */
129                 nl = strchr(linestr, '\0') - 1;
130                 while (nl >= linestr && ('\n' == *nl || ' ' == *nl ||
131                         '\t' == *nl)) {
132                         *nl = '\0';
133                         nl--;
134                 }
135
136                 tokptr = linestr;
137                 if ((type = strtok_r(tokptr, delim, &last)) != NULL) {
138                         if (strcmp(name, type) == 0) {
139                                 /* Found matching name. */
140                                 *str = last;
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  */
151 static int
152 au_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  */
189 static int
190 au_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  */
228 ssize_t
229 au_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  */
256 int
257 au_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  */
293 static void
294 setac_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;
309 closefp:
310                         fclose(fp);
311                         fp = NULL;
312                         return;
313                 }
314
315                 fseek(fp, 0, SEEK_SET);
316         }
317 }
318
319 void
320 setac(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  */
335 void
336 endac(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  */
355 int
356 getacdir(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 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.
403  */
404 int
405 getacdist(void)
406 {
407         char *str;
408         int ret;
409
410 #ifdef HAVE_PTHREAD_MUTEX_LOCK
411         pthread_mutex_lock(&mutex);
412 #endif
413         setac_locked();
414         if (getstrfromtype_locked(DIST_CONTROL_ENTRY, &str) < 0) {
415 #ifdef HAVE_PTHREAD_MUTEX_LOCK
416                 pthread_mutex_unlock(&mutex);
417 #endif
418                 return (-2);
419         }
420         if (str == NULL) {
421 #ifdef HAVE_PTHREAD_MUTEX_LOCK
422                 pthread_mutex_unlock(&mutex);
423 #endif
424                 return (0);
425         }
426         if (strcasecmp(str, "on") == 0 || strcasecmp(str, "yes") == 0)
427                 ret = 1;
428         else
429                 ret = 0;
430 #ifdef HAVE_PTHREAD_MUTEX_LOCK
431         pthread_mutex_unlock(&mutex);
432 #endif
433         return (ret);
434 }
435
436 /*
437  * Return the minimum free diskspace value from the audit control file.
438  */
439 int
440 getacmin(int *min_val)
441 {
442         char *min;
443
444 #ifdef HAVE_PTHREAD_MUTEX_LOCK
445         pthread_mutex_lock(&mutex);
446 #endif
447         setac_locked();
448         if (getstrfromtype_locked(MINFREE_CONTROL_ENTRY, &min) < 0) {
449 #ifdef HAVE_PTHREAD_MUTEX_LOCK
450                 pthread_mutex_unlock(&mutex);
451 #endif
452                 return (-2);
453         }
454         if (min == NULL) {
455 #ifdef HAVE_PTHREAD_MUTEX_LOCK
456                 pthread_mutex_unlock(&mutex);
457 #endif
458                 return (-1);
459         }
460         *min_val = atoi(min);
461 #ifdef HAVE_PTHREAD_MUTEX_LOCK
462         pthread_mutex_unlock(&mutex);
463 #endif
464         return (0);
465 }
466
467 /*
468  * Return the desired trail rotation size from the audit control file.
469  */
470 int
471 getacfilesz(size_t *filesz_val)
472 {
473         char *str;
474         size_t val;
475         char mult;
476         int nparsed;
477
478 #ifdef HAVE_PTHREAD_MUTEX_LOCK
479         pthread_mutex_lock(&mutex);
480 #endif
481         setac_locked();
482         if (getstrfromtype_locked(FILESZ_CONTROL_ENTRY, &str) < 0) {
483 #ifdef HAVE_PTHREAD_MUTEX_LOCK
484                 pthread_mutex_unlock(&mutex);
485 #endif
486                 return (-2);
487         }
488         if (str == NULL) {
489 #ifdef HAVE_PTHREAD_MUTEX_LOCK
490                 pthread_mutex_unlock(&mutex);
491 #endif
492                 errno = EINVAL;
493                 return (-1);
494         }
495
496         /* Trim off any leading white space. */
497         while (*str == ' ' || *str == '\t')
498                 str++;
499
500         nparsed = sscanf(str, "%ju%c", (uintmax_t *)&val, &mult);
501
502         switch (nparsed) {
503         case 1:
504                 /* If no multiplier then assume 'B' (bytes). */
505                 mult = 'B';
506                 /* fall through */
507         case 2:
508                 if (au_spacetobytes(filesz_val, val, mult) == 0)
509                         break;
510                 /* fall through */
511         default:
512                 errno = EINVAL;
513 #ifdef HAVE_PTHREAD_MUTEX_LOCK
514                 pthread_mutex_unlock(&mutex);
515 #endif
516                 return (-1);
517         }
518
519         /*
520          * The file size must either be 0 or >= MIN_AUDIT_FILE_SIZE.  0
521          * indicates no rotation size.
522          */
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);
527 #endif
528                 filesz_val = 0L;
529                 errno = EINVAL;
530                 return (-1);
531         }
532 #ifdef HAVE_PTHREAD_MUTEX_LOCK
533         pthread_mutex_unlock(&mutex);
534 #endif
535         return (0);
536 }
537
538 static int
539 getaccommon(const char *name, char *auditstr, int len)
540 {
541         char *str;
542
543 #ifdef HAVE_PTHREAD_MUTEX_LOCK
544         pthread_mutex_lock(&mutex);
545 #endif
546         setac_locked();
547         if (getstrfromtype_locked(name, &str) < 0) {
548 #ifdef HAVE_PTHREAD_MUTEX_LOCK
549                 pthread_mutex_unlock(&mutex);
550 #endif
551                 return (-2);
552         }
553
554         /*
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.
557          */
558         if (str != NULL && (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 != NULL ? 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
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
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
595 getacpol(char *auditstr, size_t len)
596 {
597
598         return (getaccommon(POLICY_CONTROL_ENTRY, auditstr, len));
599 }
600
601 int
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
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
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 /*
710  * Return the desired queue size from the audit control file.
711  */
712 int
713 getacqsize(int *qsz_val)
714 {
715         char *str;
716         int nparsed;
717
718 #ifdef HAVE_PTHREAD_MUTEX_LOCK
719         pthread_mutex_lock(&mutex);
720 #endif
721         setac_locked();
722         if (getstrfromtype_locked(QSZ_CONTROL_ENTRY, &str) < 0) {
723 #ifdef HAVE_PTHREAD_MUTEX_LOCK
724                 pthread_mutex_unlock(&mutex);
725 #endif
726                 return (-2);
727         }
728         if (str == NULL) {
729 #ifdef HAVE_PTHREAD_MUTEX_LOCK
730                 pthread_mutex_unlock(&mutex);
731 #endif
732                 *qsz_val = USE_DEFAULT_QSZ;
733                 return (0);
734         }
735
736         /* Trim off any leading white space. */
737         while (*str == ' ' || *str == '\t')
738                 str++;
739
740         nparsed = sscanf(str, "%d", (int *)qsz_val);
741
742         if (nparsed != 1) {
743                 errno = EINVAL;
744 #ifdef HAVE_PTHREAD_MUTEX_LOCK
745                 pthread_mutex_unlock(&mutex);
746 #endif
747                 return (-1);
748         }
749
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);
754 #endif
755                 qsz_val = 0L;
756                 errno = EINVAL;
757                 return (-1);
758         }
759 #ifdef HAVE_PTHREAD_MUTEX_LOCK
760         pthread_mutex_unlock(&mutex);
761 #endif
762         return (0);
763 }