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
31#include <config/config.h>
32
33#include <bsm/libbsm.h>
34
35#include <string.h>
36#ifdef HAVE_PTHREAD_MUTEX_LOCK
37#include <pthread.h>
38#endif
39#include <stdio.h>
40#include <stdlib.h>
41
42#ifndef HAVE_STRLCPY
43#include <compat/strlcpy.h>
44#endif
45
46/*
47 * Parse the contents of the audit_class file to return struct au_class_ent
48 * entries.
49 */
50static FILE		*fp = NULL;
51static char		 linestr[AU_LINE_MAX];
52static const char	*classdelim = ":";
53
54#ifdef HAVE_PTHREAD_MUTEX_LOCK
55static pthread_mutex_t	mutex = PTHREAD_MUTEX_INITIALIZER;
56#endif
57
58/*
59 * Parse a single line from the audit_class file passed in str to the struct
60 * au_class_ent elements; store the result in c.
61 */
62static struct au_class_ent *
63classfromstr(char *str, struct au_class_ent *c)
64{
65	char *classname, *classdesc, *classflag;
66	char *last;
67
68	/* Each line contains flag:name:desc. */
69	classflag = strtok_r(str, classdelim, &last);
70	classname = strtok_r(NULL, classdelim, &last);
71	classdesc = strtok_r(NULL, classdelim, &last);
72
73	if ((classflag == NULL) || (classname == NULL) || (classdesc == NULL))
74		return (NULL);
75
76	/*
77	 * Check for very large classnames.
78	 */
79	if (strlen(classname) >= AU_CLASS_NAME_MAX)
80		return (NULL);
81	strlcpy(c->ac_name, classname, AU_CLASS_NAME_MAX);
82
83	/*
84	 * Check for very large class description.
85	 */
86	if (strlen(classdesc) >= AU_CLASS_DESC_MAX)
87		return (NULL);
88	strlcpy(c->ac_desc, classdesc, AU_CLASS_DESC_MAX);
89	c->ac_class = strtoul(classflag, (char **) NULL, 0);
90
91	return (c);
92}
93
94/*
95 * Return the next au_class_ent structure from the file setauclass should be
96 * called before invoking this function for the first time.
97 *
98 * Must be called with mutex held.
99 */
100static struct au_class_ent *
101getauclassent_r_locked(struct au_class_ent *c)
102{
103	char *tokptr, *nl;
104
105	if ((fp == NULL) && ((fp = fopen(AUDIT_CLASS_FILE, "r")) == NULL))
106		return (NULL);
107
108	/*
109	 * Read until next non-comment line is found, or EOF.
110	 */
111	while (1) {
112		if (fgets(linestr, AU_LINE_MAX, fp) == NULL)
113			return (NULL);
114
115		/* Skip comments. */
116		if (linestr[0] == '#')
117			continue;
118
119		/* Remove trailing new line character. */
120		if ((nl = strrchr(linestr, '\n')) != NULL)
121			*nl = '\0';
122
123		/* Parse tokptr to au_class_ent components. */
124		tokptr = linestr;
125		if (classfromstr(tokptr, c) == NULL)
126			return (NULL);
127		break;
128	}
129
130	return (c);
131}
132
133struct au_class_ent *
134getauclassent_r(struct au_class_ent *c)
135{
136	struct au_class_ent *cp;
137
138#ifdef HAVE_PTHREAD_MUTEX_LOCK
139	pthread_mutex_lock(&mutex);
140#endif
141	cp = getauclassent_r_locked(c);
142#ifdef HAVE_PTHREAD_MUTEX_LOCK
143	pthread_mutex_unlock(&mutex);
144#endif
145	return (cp);
146}
147
148struct au_class_ent *
149getauclassent(void)
150{
151	static char class_ent_name[AU_CLASS_NAME_MAX];
152	static char class_ent_desc[AU_CLASS_DESC_MAX];
153	static struct au_class_ent c, *cp;
154
155	bzero(&c, sizeof(c));
156	bzero(class_ent_name, sizeof(class_ent_name));
157	bzero(class_ent_desc, sizeof(class_ent_desc));
158	c.ac_name = class_ent_name;
159	c.ac_desc = class_ent_desc;
160
161#ifdef HAVE_PTHREAD_MUTEX_LOCK
162	pthread_mutex_lock(&mutex);
163#endif
164	cp = getauclassent_r_locked(&c);
165#ifdef HAVE_PTHREAD_MUTEX_LOCK
166	pthread_mutex_unlock(&mutex);
167#endif
168	return (cp);
169}
170
171/*
172 * Rewind to the beginning of the enumeration.
173 *
174 * Must be called with mutex held.
175 */
176static void
177setauclass_locked(void)
178{
179
180	if (fp != NULL)
181		fseek(fp, 0, SEEK_SET);
182}
183
184void
185setauclass(void)
186{
187
188#ifdef HAVE_PTHREAD_MUTEX_LOCK
189	pthread_mutex_lock(&mutex);
190#endif
191	setauclass_locked();
192#ifdef HAVE_PTHREAD_MUTEX_LOCK
193	pthread_mutex_unlock(&mutex);
194#endif
195}
196
197/*
198 * Return the next au_class_entry having the given class name.
199 */
200struct au_class_ent *
201getauclassnam_r(struct au_class_ent *c, const char *name)
202{
203	struct au_class_ent *cp;
204
205	if (name == NULL)
206		return (NULL);
207
208#ifdef HAVE_PTHREAD_MUTEX_LOCK
209	pthread_mutex_lock(&mutex);
210#endif
211	setauclass_locked();
212	while ((cp = getauclassent_r_locked(c)) != NULL) {
213		if (strcmp(name, cp->ac_name) == 0) {
214#ifdef HAVE_PTHREAD_MUTEX_LOCK
215			pthread_mutex_unlock(&mutex);
216#endif
217			return (cp);
218		}
219	}
220#ifdef HAVE_PTHREAD_MUTEX_LOCK
221	pthread_mutex_unlock(&mutex);
222#endif
223	return (NULL);
224}
225
226struct au_class_ent *
227getauclassnam(const char *name)
228{
229	static char class_ent_name[AU_CLASS_NAME_MAX];
230	static char class_ent_desc[AU_CLASS_DESC_MAX];
231	static struct au_class_ent c;
232
233	bzero(&c, sizeof(c));
234	bzero(class_ent_name, sizeof(class_ent_name));
235	bzero(class_ent_desc, sizeof(class_ent_desc));
236	c.ac_name = class_ent_name;
237	c.ac_desc = class_ent_desc;
238
239	return (getauclassnam_r(&c, name));
240}
241
242
243/*
244 * Return the next au_class_entry having the given class number.
245 *
246 * OpenBSM extension.
247 */
248struct au_class_ent *
249getauclassnum_r(struct au_class_ent *c, au_class_t class_number)
250{
251	struct au_class_ent *cp;
252
253#ifdef HAVE_PTHREAD_MUTEX_LOCK
254	pthread_mutex_lock(&mutex);
255#endif
256	setauclass_locked();
257	while ((cp = getauclassent_r_locked(c)) != NULL) {
258		if (class_number == cp->ac_class)
259			return (cp);
260	}
261#ifdef HAVE_PTHREAD_MUTEX_LOCK
262	pthread_mutex_unlock(&mutex);
263#endif
264	return (NULL);
265}
266
267struct au_class_ent *
268getauclassnum(au_class_t class_number)
269{
270	static char class_ent_name[AU_CLASS_NAME_MAX];
271	static char class_ent_desc[AU_CLASS_DESC_MAX];
272	static struct au_class_ent c;
273
274	bzero(&c, sizeof(c));
275	bzero(class_ent_name, sizeof(class_ent_name));
276	bzero(class_ent_desc, sizeof(class_ent_desc));
277	c.ac_name = class_ent_name;
278	c.ac_desc = class_ent_desc;
279
280	return (getauclassnum_r(&c, class_number));
281}
282
283/*
284 * audit_class processing is complete; close any open files.
285 */
286void
287endauclass(void)
288{
289
290#ifdef HAVE_PTHREAD_MUTEX_LOCK
291	pthread_mutex_lock(&mutex);
292#endif
293	if (fp != NULL) {
294		fclose(fp);
295		fp = NULL;
296	}
297#ifdef HAVE_PTHREAD_MUTEX_LOCK
298	pthread_mutex_unlock(&mutex);
299#endif
300}
301