]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/openbsm/libbsm/bsm_control.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / contrib / openbsm / libbsm / bsm_control.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }