bsm_control.c revision 186647
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 */
56static FILE	*fp = NULL;
57static char	linestr[AU_LINE_MAX];
58static char	*delim = ":";
59
60static char	inacdir = 0;
61static char	ptrmoved = 0;
62
63#ifdef HAVE_PTHREAD_MUTEX_LOCK
64static 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 */
73static int
74getstrfromtype_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 */
119ssize_t
120au_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 */
258int
259au_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 */
312static void
313setac_locked(void)
314{
315
316	ptrmoved = 1;
317	if (fp != NULL)
318		fseek(fp, 0, SEEK_SET);
319}
320
321void
322setac(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 */
337void
338endac(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 */
357int
358getacdir(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 */
404int
405getacmin(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 */
435int
436getacfilesz(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 */
487int
488getacflg(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 */
524int
525getacna(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 */
561int
562getacpol(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
595int
596getachost(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