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