]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/openbsm/libbsm/bsm_control.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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#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  */
59 static FILE     *fp = NULL;
60 static char     linestr[AU_LINE_MAX];
61 static char     *delim = ":";
62
63 static char     inacdir = 0;
64 static char     ptrmoved = 0;
65
66 #ifdef HAVE_PTHREAD_MUTEX_LOCK
67 static pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;
68 #endif
69
70 /*
71  * Audit policy string token table for au_poltostr() and au_strtopol().
72  */
73 struct audit_polstr {
74         long             ap_policy;
75         const char      *ap_str;        
76 };
77
78 static 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  */
102 static int
103 getstrfromtype_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 and white space. */
125                 nl = strchr(linestr, '\0') - 1;
126                 while (nl >= linestr && ('\n' == *nl || ' ' == *nl ||
127                         '\t' == *nl)) {
128                         *nl = '\0';
129                         nl--;
130                 }
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  */
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 the minimum free diskspace value from the audit control file.
401  */
402 int
403 getacmin(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  */
433 int
434 getacfilesz(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  */
504 int
505 getacflg(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  */
541 int
542 getacna(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  */
578 int
579 getacpol(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
612 int
613 getachost(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  */
649 static int
650 setexpirecond(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  */
662 int
663 getacexpire(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 }