1104349Sphk/*-
2104349Sphk * Copyright (c) 2004 Apple Inc.
3104349Sphk * Copyright (c) 2006 Robert N. M. Watson
4104349Sphk * All rights reserved.
5104349Sphk *
6104349Sphk * Redistribution and use in source and binary forms, with or without
7104349Sphk * modification, are permitted provided that the following conditions
8104349Sphk * are met:
9104349Sphk * 1.  Redistributions of source code must retain the above copyright
10104349Sphk *     notice, this list of conditions and the following disclaimer.
11104349Sphk * 2.  Redistributions in binary form must reproduce the above copyright
12104349Sphk *     notice, this list of conditions and the following disclaimer in the
13104349Sphk *     documentation and/or other materials provided with the distribution.
14104349Sphk * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15104349Sphk *     its contributors may be used to endorse or promote products derived
16104349Sphk *     from this software without specific prior written permission.
17104349Sphk *
18104349Sphk * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
19104349Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20104349Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21104349Sphk * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
22104349Sphk * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23104349Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24104349Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25104349Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26104349Sphk * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27104349Sphk * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28104349Sphk * POSSIBILITY OF SUCH DAMAGE.
29104349Sphk */
30104349Sphk
31104349Sphk#include <config/config.h>
32104349Sphk
33104349Sphk#include <bsm/libbsm.h>
34104349Sphk
35104349Sphk#include <string.h>
36104349Sphk#ifdef HAVE_PTHREAD_MUTEX_LOCK
37104349Sphk#include <pthread.h>
38104349Sphk#endif
39104349Sphk#include <stdio.h>
40104349Sphk#include <stdlib.h>
41104349Sphk
42247296Sdelphij#ifndef HAVE_STRLCPY
43247296Sdelphij#include <compat/strlcpy.h>
44247296Sdelphij#endif
45104349Sphk
46104349Sphk/*
47104349Sphk * Parse the contents of the audit_class file to return struct au_class_ent
48104349Sphk * entries.
49104349Sphk */
50104349Sphkstatic FILE		*fp = NULL;
51104349Sphkstatic char		 linestr[AU_LINE_MAX];
52104349Sphkstatic const char	*classdelim = ":";
53104349Sphk
54247296Sdelphij#ifdef HAVE_PTHREAD_MUTEX_LOCK
55247296Sdelphijstatic pthread_mutex_t	mutex = PTHREAD_MUTEX_INITIALIZER;
56247296Sdelphij#endif
57247296Sdelphij
58104349Sphk/*
59104349Sphk * Parse a single line from the audit_class file passed in str to the struct
60104349Sphk * au_class_ent elements; store the result in c.
61104349Sphk */
62104349Sphkstatic struct au_class_ent *
63104349Sphkclassfromstr(char *str, struct au_class_ent *c)
64104349Sphk{
65104349Sphk	char *classname, *classdesc, *classflag;
66104349Sphk	char *last;
67104349Sphk
68104349Sphk	/* Each line contains flag:name:desc. */
69104349Sphk	classflag = strtok_r(str, classdelim, &last);
70247296Sdelphij	classname = strtok_r(NULL, classdelim, &last);
71247296Sdelphij	classdesc = strtok_r(NULL, classdelim, &last);
72247296Sdelphij
73104349Sphk	if ((classflag == NULL) || (classname == NULL) || (classdesc == NULL))
74104349Sphk		return (NULL);
75104349Sphk
76104349Sphk	/*
77104349Sphk	 * Check for very large classnames.
78104349Sphk	 */
79104349Sphk	if (strlen(classname) >= AU_CLASS_NAME_MAX)
80104349Sphk		return (NULL);
81104349Sphk	strlcpy(c->ac_name, classname, AU_CLASS_NAME_MAX);
82104349Sphk
83104349Sphk	/*
84104349Sphk	 * Check for very large class description.
85104349Sphk	 */
86104349Sphk	if (strlen(classdesc) >= AU_CLASS_DESC_MAX)
87104349Sphk		return (NULL);
88104349Sphk	strlcpy(c->ac_desc, classdesc, AU_CLASS_DESC_MAX);
89104349Sphk	c->ac_class = strtoul(classflag, (char **) NULL, 0);
90104349Sphk
91104349Sphk	return (c);
92178848Scokane}
93178848Scokane
94178848Scokane/*
95104349Sphk * Return the next au_class_ent structure from the file setauclass should be
96104349Sphk * called before invoking this function for the first time.
97104349Sphk *
98247296Sdelphij * Must be called with mutex held.
99104349Sphk */
100104349Sphkstatic struct au_class_ent *
101247296Sdelphijgetauclassent_r_locked(struct au_class_ent *c)
102104349Sphk{
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