xref: /freebsd/contrib/openbsm/libbsm/bsm_control.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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  */
50 static FILE	*fp = NULL;
51 static char	linestr[AU_LINE_MAX];
52 static char	*delim = ":";
53 
54 static char	inacdir = 0;
55 static char	ptrmoved = 0;
56 
57 static 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  */
65 static int
66 getstrfromtype_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  */
111 ssize_t
112 au_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  */
250 int
251 au_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  */
304 static void
305 setac_locked(void)
306 {
307 
308 	ptrmoved = 1;
309 	if (fp != NULL)
310 		fseek(fp, 0, SEEK_SET);
311 }
312 
313 void
314 setac(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  */
325 void
326 endac(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  */
341 int
342 getacdir(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  */
378 int
379 getacmin(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  */
401 int
402 getacfilesz(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  */
441 int
442 getacflg(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  */
468 int
469 getacna(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  */
494 int
495 getacpol(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