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