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