1 /*-
2  * Copyright (c) 2004 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#24 $
31  */
32 
33 #include <config/config.h>
34 
35 #include <bsm/libbsm.h>
36 
37 #include <errno.h>
38 #include <string.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 /*
53  * Parse the contents of the audit_control file to return the audit control
54  * parameters.  These static fields are protected by 'mutex'.
55  */
56 static FILE	*fp = NULL;
57 static char	linestr[AU_LINE_MAX];
58 static char	*delim = ":";
59 
60 static char	inacdir = 0;
61 static char	ptrmoved = 0;
62 
63 #ifdef HAVE_PTHREAD_MUTEX_LOCK
64 static pthread_mutex_t	mutex = PTHREAD_MUTEX_INITIALIZER;
65 #endif
66 
67 /*
68  * Returns the string value corresponding to the given label from the
69  * configuration file.
70  *
71  * Must be called with mutex held.
72  */
73 static int
74 getstrfromtype_locked(char *name, char **str)
75 {
76 	char *type, *nl;
77 	char *tokptr;
78 	char *last;
79 
80 	*str = NULL;
81 
82 	if ((fp == NULL) && ((fp = fopen(AUDIT_CONTROL_FILE, "r")) == NULL))
83 		return (-1); /* Error */
84 
85 	while (1) {
86 		if (fgets(linestr, AU_LINE_MAX, fp) == NULL) {
87 			if (ferror(fp))
88 				return (-1);
89 			return (0);	/* EOF */
90 		}
91 
92 		if (linestr[0] == '#')
93 			continue;
94 
95 		/* Remove trailing new line character. */
96 		if ((nl = strrchr(linestr, '\n')) != NULL)
97 			*nl = '\0';
98 
99 		tokptr = linestr;
100 		if ((type = strtok_r(tokptr, delim, &last)) != NULL) {
101 			if (strcmp(name, type) == 0) {
102 				/* Found matching name. */
103 				*str = strtok_r(NULL, delim, &last);
104 				if (*str == NULL) {
105 					errno = EINVAL;
106 					return (-1); /* Parse error in file */
107 				}
108 				return (0); /* Success */
109 			}
110 		}
111 	}
112 }
113 
114 /*
115  * Convert a policy to a string.  Return -1 on failure, or >= 0 representing
116  * the actual size of the string placed in the buffer (excluding terminating
117  * nul).
118  */
119 ssize_t
120 au_poltostr(long policy, size_t maxsize, char *buf)
121 {
122 	int first;
123 
124 	if (maxsize < 1)
125 		return (-1);
126 	first = 1;
127 	buf[0] = '\0';
128 
129 	if (policy & AUDIT_CNT) {
130 		if (strlcat(buf, "cnt", maxsize) >= maxsize)
131 			return (-1);
132 		first = 0;
133 	}
134 	if (policy & AUDIT_AHLT) {
135 		if (!first) {
136 			if (strlcat(buf, ",", maxsize) >= maxsize)
137 				return (-1);
138 		}
139 		if (strlcat(buf, "ahlt", maxsize) >= maxsize)
140 			return (-1);
141 		first = 0;
142 	}
143 	if (policy & AUDIT_ARGV) {
144 		if (!first) {
145 			if (strlcat(buf, ",", maxsize) >= maxsize)
146 				return (-1);
147 		}
148 		if (strlcat(buf, "argv", maxsize) >= maxsize)
149 			return (-1);
150 		first = 0;
151 	}
152 	if (policy & AUDIT_ARGE) {
153 		if (!first) {
154 			if (strlcat(buf, ",", maxsize) >= maxsize)
155 				return (-1);
156 		}
157 		if (strlcat(buf, "arge", maxsize) >= maxsize)
158 			return (-1);
159 		first = 0;
160 	}
161 	if (policy & AUDIT_SEQ) {
162 		if (!first) {
163 			if (strlcat(buf, ",", maxsize) >= maxsize)
164 				return (-1);
165 		}
166 		if (strlcat(buf, "seq", maxsize) >= maxsize)
167 			return (-1);
168 		first = 0;
169 	}
170 	if (policy & AUDIT_WINDATA) {
171 		if (!first) {
172 			if (strlcat(buf, ",", maxsize) >= maxsize)
173 				return (-1);
174 		}
175 		if (strlcat(buf, "windata", maxsize) >= maxsize)
176 			return (-1);
177 		first = 0;
178 	}
179 	if (policy & AUDIT_USER) {
180 		if (!first) {
181 			if (strlcat(buf, ",", maxsize) >= maxsize)
182 				return (-1);
183 		}
184 		if (strlcat(buf, "user", maxsize) >= maxsize)
185 			return (-1);
186 		first = 0;
187 	}
188 	if (policy & AUDIT_GROUP) {
189 		if (!first) {
190 			if (strlcat(buf, ",", maxsize) >= maxsize)
191 				return (-1);
192 		}
193 		if (strlcat(buf, "group", maxsize) >= maxsize)
194 			return (-1);
195 		first = 0;
196 	}
197 	if (policy & AUDIT_TRAIL) {
198 		if (!first) {
199 			if (strlcat(buf, ",", maxsize) >= maxsize)
200 				return (-1);
201 		}
202 		if (strlcat(buf, "trail", maxsize) >= maxsize)
203 			return (-1);
204 		first = 0;
205 	}
206 	if (policy & AUDIT_PATH) {
207 		if (!first) {
208 			if (strlcat(buf, ",", maxsize) >= maxsize)
209 				return (-1);
210 		}
211 		if (strlcat(buf, "path", maxsize) >= maxsize)
212 			return (-1);
213 		first = 0;
214 	}
215 	if (policy & AUDIT_SCNT) {
216 		if (!first) {
217 			if (strlcat(buf, ",", maxsize) >= maxsize)
218 				return (-1);
219 		}
220 		if (strlcat(buf, "scnt", maxsize) >= maxsize)
221 			return (-1);
222 		first = 0;
223 	}
224 	if (policy & AUDIT_PUBLIC) {
225 		if (!first) {
226 			if (strlcat(buf, ",", maxsize) >= maxsize)
227 				return (-1);
228 		}
229 		if (strlcat(buf, "public", maxsize) >= maxsize)
230 			return (-1);
231 		first = 0;
232 	}
233 	if (policy & AUDIT_ZONENAME) {
234 		if (!first) {
235 			if (strlcat(buf, ",", maxsize) >= maxsize)
236 				return (-1);
237 		}
238 		if (strlcat(buf, "zonename", maxsize) >= maxsize)
239 			return (-1);
240 		first = 0;
241 	}
242 	if (policy & AUDIT_PERZONE) {
243 		if (!first) {
244 			if (strlcat(buf, ",", maxsize) >= maxsize)
245 				return (-1);
246 		}
247 		if (strlcat(buf, "perzone", maxsize) >= maxsize)
248 			return (-1);
249 		first = 0;
250 	}
251 	return (strlen(buf));
252 }
253 
254 /*
255  * Convert a string to a policy.  Return -1 on failure (with errno EINVAL,
256  * ENOMEM) or 0 on success.
257  */
258 int
259 au_strtopol(const char *polstr, long *policy)
260 {
261 	char *bufp, *string;
262 	char *buffer;
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 		if (strcmp(string, "cnt") == 0)
272 			*policy |= AUDIT_CNT;
273 		else if (strcmp(string, "ahlt") == 0)
274 			*policy |= AUDIT_AHLT;
275 		else if (strcmp(string, "argv") == 0)
276 			*policy |= AUDIT_ARGV;
277 		else if (strcmp(string, "arge") == 0)
278 			*policy |= AUDIT_ARGE;
279 		else if (strcmp(string, "seq") == 0)
280 			*policy |= AUDIT_SEQ;
281 		else if (strcmp(string, "winau_fstat") == 0)
282 			*policy |= AUDIT_WINDATA;
283 		else if (strcmp(string, "user") == 0)
284 			*policy |= AUDIT_USER;
285 		else if (strcmp(string, "group") == 0)
286 			*policy |= AUDIT_GROUP;
287 		else if (strcmp(string, "trail") == 0)
288 			*policy |= AUDIT_TRAIL;
289 		else if (strcmp(string, "path") == 0)
290 			*policy |= AUDIT_PATH;
291 		else if (strcmp(string, "scnt") == 0)
292 			*policy |= AUDIT_SCNT;
293 		else if (strcmp(string, "public") == 0)
294 			*policy |= AUDIT_PUBLIC;
295 		else if (strcmp(string, "zonename") == 0)
296 			*policy |= AUDIT_ZONENAME;
297 		else if (strcmp(string, "perzone") == 0)
298 			*policy |= AUDIT_PERZONE;
299 		else {
300 			free(buffer);
301 			errno = EINVAL;
302 			return (-1);
303 		}
304 	}
305 	free(buffer);
306 	return (0);
307 }
308 
309 /*
310  * Rewind the file pointer to beginning.
311  */
312 static void
313 setac_locked(void)
314 {
315 
316 	ptrmoved = 1;
317 	if (fp != NULL)
318 		fseek(fp, 0, SEEK_SET);
319 }
320 
321 void
322 setac(void)
323 {
324 
325 #ifdef HAVE_PTHREAD_MUTEX_LOCK
326 	pthread_mutex_lock(&mutex);
327 #endif
328 	setac_locked();
329 #ifdef HAVE_PTHREAD_MUTEX_LOCK
330 	pthread_mutex_unlock(&mutex);
331 #endif
332 }
333 
334 /*
335  * Close the audit_control file.
336  */
337 void
338 endac(void)
339 {
340 
341 #ifdef HAVE_PTHREAD_MUTEX_LOCK
342 	pthread_mutex_lock(&mutex);
343 #endif
344 	ptrmoved = 1;
345 	if (fp != NULL) {
346 		fclose(fp);
347 		fp = NULL;
348 	}
349 #ifdef HAVE_PTHREAD_MUTEX_LOCK
350 	pthread_mutex_unlock(&mutex);
351 #endif
352 }
353 
354 /*
355  * Return audit directory information from the audit control file.
356  */
357 int
358 getacdir(char *name, int len)
359 {
360 	char *dir;
361 	int ret = 0;
362 
363 	/*
364 	 * Check if another function was called between successive calls to
365 	 * getacdir.
366 	 */
367 #ifdef HAVE_PTHREAD_MUTEX_LOCK
368 	pthread_mutex_lock(&mutex);
369 #endif
370 	if (inacdir && ptrmoved) {
371 		ptrmoved = 0;
372 		if (fp != NULL)
373 			fseek(fp, 0, SEEK_SET);
374 		ret = 2;
375 	}
376 	if (getstrfromtype_locked(DIR_CONTROL_ENTRY, &dir) < 0) {
377 #ifdef HAVE_PTHREAD_MUTEX_LOCK
378 		pthread_mutex_unlock(&mutex);
379 #endif
380 		return (-2);
381 	}
382 	if (dir == NULL) {
383 #ifdef HAVE_PTHREAD_MUTEX_LOCK
384 		pthread_mutex_unlock(&mutex);
385 #endif
386 		return (-1);
387 	}
388 	if (strlen(dir) >= (size_t)len) {
389 #ifdef HAVE_PTHREAD_MUTEX_LOCK
390 		pthread_mutex_unlock(&mutex);
391 #endif
392 		return (-3);
393 	}
394 	strlcpy(name, dir, len);
395 #ifdef HAVE_PTHREAD_MUTEX_LOCK
396 	pthread_mutex_unlock(&mutex);
397 #endif
398 	return (ret);
399 }
400 
401 /*
402  * Return the minimum free diskspace value from the audit control file.
403  */
404 int
405 getacmin(int *min_val)
406 {
407 	char *min;
408 
409 #ifdef HAVE_PTHREAD_MUTEX_LOCK
410 	pthread_mutex_lock(&mutex);
411 #endif
412 	setac_locked();
413 	if (getstrfromtype_locked(MINFREE_CONTROL_ENTRY, &min) < 0) {
414 #ifdef HAVE_PTHREAD_MUTEX_LOCK
415 		pthread_mutex_unlock(&mutex);
416 #endif
417 		return (-2);
418 	}
419 	if (min == NULL) {
420 #ifdef HAVE_PTHREAD_MUTEX_LOCK
421 		pthread_mutex_unlock(&mutex);
422 #endif
423 		return (1);
424 	}
425 	*min_val = atoi(min);
426 #ifdef HAVE_PTHREAD_MUTEX_LOCK
427 	pthread_mutex_unlock(&mutex);
428 #endif
429 	return (0);
430 }
431 
432 /*
433  * Return the desired trail rotation size from the audit control file.
434  */
435 int
436 getacfilesz(size_t *filesz_val)
437 {
438 	char *filesz, *dummy;
439 	long long ll;
440 
441 #ifdef HAVE_PTHREAD_MUTEX_LOCK
442 	pthread_mutex_lock(&mutex);
443 #endif
444 	setac_locked();
445 	if (getstrfromtype_locked(FILESZ_CONTROL_ENTRY, &filesz) < 0) {
446 #ifdef HAVE_PTHREAD_MUTEX_LOCK
447 		pthread_mutex_unlock(&mutex);
448 #endif
449 		return (-2);
450 	}
451 	if (filesz == NULL) {
452 #ifdef HAVE_PTHREAD_MUTEX_LOCK
453 		pthread_mutex_unlock(&mutex);
454 #endif
455 		errno = EINVAL;
456 		return (1);
457 	}
458 	ll = strtoll(filesz, &dummy, 10);
459 	if (*dummy != '\0') {
460 #ifdef HAVE_PTHREAD_MUTEX_LOCK
461 		pthread_mutex_unlock(&mutex);
462 #endif
463 		errno = EINVAL;
464 		return (-1);
465 	}
466 	/*
467 	 * The file size must either be 0 or >= MIN_AUDIT_FILE_SIZE.  0
468 	 * indicates no rotation size.
469 	 */
470 	if (ll < 0 || (ll > 0 && ll < MIN_AUDIT_FILE_SIZE)) {
471 #ifdef HAVE_PTHREAD_MUTEX_LOCK
472 		pthread_mutex_unlock(&mutex);
473 #endif
474 		errno = EINVAL;
475 		return (-1);
476 	}
477 	*filesz_val = ll;
478 #ifdef HAVE_PTHREAD_MUTEX_LOCK
479 	pthread_mutex_unlock(&mutex);
480 #endif
481 	return (0);
482 }
483 
484 /*
485  * Return the system audit value from the audit contol file.
486  */
487 int
488 getacflg(char *auditstr, int len)
489 {
490 	char *str;
491 
492 #ifdef HAVE_PTHREAD_MUTEX_LOCK
493 	pthread_mutex_lock(&mutex);
494 #endif
495 	setac_locked();
496 	if (getstrfromtype_locked(FLAGS_CONTROL_ENTRY, &str) < 0) {
497 #ifdef HAVE_PTHREAD_MUTEX_LOCK
498 		pthread_mutex_unlock(&mutex);
499 #endif
500 		return (-2);
501 	}
502 	if (str == NULL) {
503 #ifdef HAVE_PTHREAD_MUTEX_LOCK
504 		pthread_mutex_unlock(&mutex);
505 #endif
506 		return (1);
507 	}
508 	if (strlen(str) >= (size_t)len) {
509 #ifdef HAVE_PTHREAD_MUTEX_LOCK
510 		pthread_mutex_unlock(&mutex);
511 #endif
512 		return (-3);
513 	}
514 	strlcpy(auditstr, str, len);
515 #ifdef HAVE_PTHREAD_MUTEX_LOCK
516 	pthread_mutex_unlock(&mutex);
517 #endif
518 	return (0);
519 }
520 
521 /*
522  * Return the non attributable flags from the audit contol file.
523  */
524 int
525 getacna(char *auditstr, int len)
526 {
527 	char *str;
528 
529 #ifdef HAVE_PTHREAD_MUTEX_LOCK
530 	pthread_mutex_lock(&mutex);
531 #endif
532 	setac_locked();
533 	if (getstrfromtype_locked(NA_CONTROL_ENTRY, &str) < 0) {
534 #ifdef HAVE_PTHREAD_MUTEX_LOCK
535 		pthread_mutex_unlock(&mutex);
536 #endif
537 		return (-2);
538 	}
539 	if (str == NULL) {
540 #ifdef HAVE_PTHREAD_MUTEX_LOCK
541 		pthread_mutex_unlock(&mutex);
542 #endif
543 		return (1);
544 	}
545 	if (strlen(str) >= (size_t)len) {
546 #ifdef HAVE_PTHREAD_MUTEX_LOCK
547 		pthread_mutex_unlock(&mutex);
548 #endif
549 		return (-3);
550 	}
551 	strlcpy(auditstr, str, len);
552 #ifdef HAVE_PTHREAD_MUTEX_LOCK
553 	pthread_mutex_unlock(&mutex);
554 #endif
555 	return (0);
556 }
557 
558 /*
559  * Return the policy field from the audit control file.
560  */
561 int
562 getacpol(char *auditstr, size_t len)
563 {
564 	char *str;
565 
566 #ifdef HAVE_PTHREAD_MUTEX_LOCK
567 	pthread_mutex_lock(&mutex);
568 #endif
569 	setac_locked();
570 	if (getstrfromtype_locked(POLICY_CONTROL_ENTRY, &str) < 0) {
571 #ifdef HAVE_PTHREAD_MUTEX_LOCK
572 		pthread_mutex_unlock(&mutex);
573 #endif
574 		return (-2);
575 	}
576 	if (str == NULL) {
577 #ifdef HAVE_PTHREAD_MUTEX_LOCK
578 		pthread_mutex_unlock(&mutex);
579 #endif
580 		return (-1);
581 	}
582 	if (strlen(str) >= len) {
583 #ifdef HAVE_PTHREAD_MUTEX_LOCK
584 		pthread_mutex_unlock(&mutex);
585 #endif
586 		return (-3);
587 	}
588 	strlcpy(auditstr, str, len);
589 #ifdef HAVE_PTHREAD_MUTEX_LOCK
590 	pthread_mutex_unlock(&mutex);
591 #endif
592 	return (0);
593 }
594 
595 int
596 getachost(char *auditstr, size_t len)
597 {
598 	char *str;
599 
600 #ifdef HAVE_PTHREAD_MUTEX_LOCK
601 	pthread_mutex_lock(&mutex);
602 #endif
603 	setac_locked();
604 	if (getstrfromtype_locked(AUDIT_HOST_CONTROL_ENTRY, &str) < 0) {
605 #ifdef HAVE_PTHREAD_MUTEX_LOCK
606 		pthread_mutex_unlock(&mutex);
607 #endif
608 		return (-2);
609 	}
610 	if (str == NULL) {
611 #ifdef HAVE_PTHREAD_MUTEX_LOCK
612 		pthread_mutex_unlock(&mutex);
613 #endif
614 		return (1);
615 	}
616 	if (strlen(str) >= len) {
617 #ifdef HAVE_PTHREAD_MUTEX_LOCK
618 		pthread_mutex_unlock(&mutex);
619 #endif
620 		return (-3);
621 	}
622 	strcpy(auditstr, str);
623 #ifdef HAVE_PTHREAD_MUTEX_LOCK
624 	pthread_mutex_unlock(&mutex);
625 #endif
626 	return (0);
627 }
628