152267f74SRobert Watson /*-
252267f74SRobert Watson * Copyright (c) 2004 Apple Inc.
3ca0716f5SRobert Watson * Copyright (c) 2006 Robert N. M. Watson
4ca0716f5SRobert Watson * All rights reserved.
5ca0716f5SRobert Watson *
6ca0716f5SRobert Watson * Redistribution and use in source and binary forms, with or without
7ca0716f5SRobert Watson * modification, are permitted provided that the following conditions
8ca0716f5SRobert Watson * are met:
9ca0716f5SRobert Watson * 1. Redistributions of source code must retain the above copyright
10ca0716f5SRobert Watson * notice, this list of conditions and the following disclaimer.
11ca0716f5SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright
12ca0716f5SRobert Watson * notice, this list of conditions and the following disclaimer in the
13ca0716f5SRobert Watson * documentation and/or other materials provided with the distribution.
14*aa772005SRobert Watson * 3. Neither the name of Apple Inc. ("Apple") nor the names of
15ca0716f5SRobert Watson * its contributors may be used to endorse or promote products derived
16ca0716f5SRobert Watson * from this software without specific prior written permission.
17ca0716f5SRobert Watson *
18ca0716f5SRobert Watson * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
19ca0716f5SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20ca0716f5SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21ca0716f5SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
22ca0716f5SRobert Watson * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23ca0716f5SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24ca0716f5SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25ca0716f5SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26ca0716f5SRobert Watson * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27ca0716f5SRobert Watson * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28ca0716f5SRobert Watson * POSSIBILITY OF SUCH DAMAGE.
29ca0716f5SRobert Watson */
30ca0716f5SRobert Watson
3152267f74SRobert Watson #include <config/config.h>
3252267f74SRobert Watson
33ca0716f5SRobert Watson #include <bsm/libbsm.h>
34ca0716f5SRobert Watson
35ca0716f5SRobert Watson #include <string.h>
367a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
37ca0716f5SRobert Watson #include <pthread.h>
387a0a89d2SRobert Watson #endif
39ca0716f5SRobert Watson #include <stdio.h>
40ca0716f5SRobert Watson #include <stdlib.h>
41ca0716f5SRobert Watson
4252267f74SRobert Watson #ifndef HAVE_STRLCPY
4352267f74SRobert Watson #include <compat/strlcpy.h>
4452267f74SRobert Watson #endif
4552267f74SRobert Watson
46ca0716f5SRobert Watson /*
47ca0716f5SRobert Watson * Parse the contents of the audit_class file to return struct au_class_ent
48ca0716f5SRobert Watson * entries.
49ca0716f5SRobert Watson */
50ca0716f5SRobert Watson static FILE *fp = NULL;
51ca0716f5SRobert Watson static char linestr[AU_LINE_MAX];
52ca0716f5SRobert Watson static const char *classdelim = ":";
53ca0716f5SRobert Watson
547a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
55ca0716f5SRobert Watson static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
567a0a89d2SRobert Watson #endif
57ca0716f5SRobert Watson
58ca0716f5SRobert Watson /*
59ca0716f5SRobert Watson * Parse a single line from the audit_class file passed in str to the struct
60ca0716f5SRobert Watson * au_class_ent elements; store the result in c.
61ca0716f5SRobert Watson */
62ca0716f5SRobert Watson static struct au_class_ent *
classfromstr(char * str,struct au_class_ent * c)63ca0716f5SRobert Watson classfromstr(char *str, struct au_class_ent *c)
64ca0716f5SRobert Watson {
65ca0716f5SRobert Watson char *classname, *classdesc, *classflag;
66ca0716f5SRobert Watson char *last;
67ca0716f5SRobert Watson
68ca0716f5SRobert Watson /* Each line contains flag:name:desc. */
69ca0716f5SRobert Watson classflag = strtok_r(str, classdelim, &last);
70ca0716f5SRobert Watson classname = strtok_r(NULL, classdelim, &last);
71ca0716f5SRobert Watson classdesc = strtok_r(NULL, classdelim, &last);
72ca0716f5SRobert Watson
73ca0716f5SRobert Watson if ((classflag == NULL) || (classname == NULL) || (classdesc == NULL))
74ca0716f5SRobert Watson return (NULL);
75ca0716f5SRobert Watson
76ca0716f5SRobert Watson /*
77ca0716f5SRobert Watson * Check for very large classnames.
78ca0716f5SRobert Watson */
79ca0716f5SRobert Watson if (strlen(classname) >= AU_CLASS_NAME_MAX)
80ca0716f5SRobert Watson return (NULL);
8152267f74SRobert Watson strlcpy(c->ac_name, classname, AU_CLASS_NAME_MAX);
82ca0716f5SRobert Watson
83ca0716f5SRobert Watson /*
84ca0716f5SRobert Watson * Check for very large class description.
85ca0716f5SRobert Watson */
86ca0716f5SRobert Watson if (strlen(classdesc) >= AU_CLASS_DESC_MAX)
87ca0716f5SRobert Watson return (NULL);
8852267f74SRobert Watson strlcpy(c->ac_desc, classdesc, AU_CLASS_DESC_MAX);
89ca0716f5SRobert Watson c->ac_class = strtoul(classflag, (char **) NULL, 0);
90ca0716f5SRobert Watson
91ca0716f5SRobert Watson return (c);
92ca0716f5SRobert Watson }
93ca0716f5SRobert Watson
94ca0716f5SRobert Watson /*
95ca0716f5SRobert Watson * Return the next au_class_ent structure from the file setauclass should be
96ca0716f5SRobert Watson * called before invoking this function for the first time.
97ca0716f5SRobert Watson *
98ca0716f5SRobert Watson * Must be called with mutex held.
99ca0716f5SRobert Watson */
100ca0716f5SRobert Watson static struct au_class_ent *
getauclassent_r_locked(struct au_class_ent * c)101ca0716f5SRobert Watson getauclassent_r_locked(struct au_class_ent *c)
102ca0716f5SRobert Watson {
103ca0716f5SRobert Watson char *tokptr, *nl;
104ca0716f5SRobert Watson
105ca0716f5SRobert Watson if ((fp == NULL) && ((fp = fopen(AUDIT_CLASS_FILE, "r")) == NULL))
106ca0716f5SRobert Watson return (NULL);
107ca0716f5SRobert Watson
108ca0716f5SRobert Watson /*
109ca0716f5SRobert Watson * Read until next non-comment line is found, or EOF.
110ca0716f5SRobert Watson */
111ca0716f5SRobert Watson while (1) {
112ca0716f5SRobert Watson if (fgets(linestr, AU_LINE_MAX, fp) == NULL)
113ca0716f5SRobert Watson return (NULL);
114ca0716f5SRobert Watson
115ca0716f5SRobert Watson /* Skip comments. */
116ca0716f5SRobert Watson if (linestr[0] == '#')
117ca0716f5SRobert Watson continue;
118ca0716f5SRobert Watson
119ca0716f5SRobert Watson /* Remove trailing new line character. */
120ca0716f5SRobert Watson if ((nl = strrchr(linestr, '\n')) != NULL)
121ca0716f5SRobert Watson *nl = '\0';
122ca0716f5SRobert Watson
123ca0716f5SRobert Watson /* Parse tokptr to au_class_ent components. */
124ca0716f5SRobert Watson tokptr = linestr;
125ca0716f5SRobert Watson if (classfromstr(tokptr, c) == NULL)
126ca0716f5SRobert Watson return (NULL);
127ca0716f5SRobert Watson break;
128ca0716f5SRobert Watson }
129ca0716f5SRobert Watson
130ca0716f5SRobert Watson return (c);
131ca0716f5SRobert Watson }
132ca0716f5SRobert Watson
133ca0716f5SRobert Watson struct au_class_ent *
getauclassent_r(struct au_class_ent * c)134ca0716f5SRobert Watson getauclassent_r(struct au_class_ent *c)
135ca0716f5SRobert Watson {
136ca0716f5SRobert Watson struct au_class_ent *cp;
137ca0716f5SRobert Watson
1387a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
139ca0716f5SRobert Watson pthread_mutex_lock(&mutex);
1407a0a89d2SRobert Watson #endif
141ca0716f5SRobert Watson cp = getauclassent_r_locked(c);
1427a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
143ca0716f5SRobert Watson pthread_mutex_unlock(&mutex);
1447a0a89d2SRobert Watson #endif
145ca0716f5SRobert Watson return (cp);
146ca0716f5SRobert Watson }
147ca0716f5SRobert Watson
148ca0716f5SRobert Watson struct au_class_ent *
getauclassent(void)149ca0716f5SRobert Watson getauclassent(void)
150ca0716f5SRobert Watson {
151ca0716f5SRobert Watson static char class_ent_name[AU_CLASS_NAME_MAX];
152ca0716f5SRobert Watson static char class_ent_desc[AU_CLASS_DESC_MAX];
153ca0716f5SRobert Watson static struct au_class_ent c, *cp;
154ca0716f5SRobert Watson
155ca0716f5SRobert Watson bzero(&c, sizeof(c));
156ca0716f5SRobert Watson bzero(class_ent_name, sizeof(class_ent_name));
157ca0716f5SRobert Watson bzero(class_ent_desc, sizeof(class_ent_desc));
158ca0716f5SRobert Watson c.ac_name = class_ent_name;
159ca0716f5SRobert Watson c.ac_desc = class_ent_desc;
160ca0716f5SRobert Watson
1617a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
162ca0716f5SRobert Watson pthread_mutex_lock(&mutex);
1637a0a89d2SRobert Watson #endif
164ca0716f5SRobert Watson cp = getauclassent_r_locked(&c);
1657a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
166ca0716f5SRobert Watson pthread_mutex_unlock(&mutex);
1677a0a89d2SRobert Watson #endif
168ca0716f5SRobert Watson return (cp);
169ca0716f5SRobert Watson }
170ca0716f5SRobert Watson
171ca0716f5SRobert Watson /*
172ca0716f5SRobert Watson * Rewind to the beginning of the enumeration.
173ca0716f5SRobert Watson *
174ca0716f5SRobert Watson * Must be called with mutex held.
175ca0716f5SRobert Watson */
176ca0716f5SRobert Watson static void
setauclass_locked(void)177ca0716f5SRobert Watson setauclass_locked(void)
178ca0716f5SRobert Watson {
179ca0716f5SRobert Watson
180ca0716f5SRobert Watson if (fp != NULL)
181ca0716f5SRobert Watson fseek(fp, 0, SEEK_SET);
182ca0716f5SRobert Watson }
183ca0716f5SRobert Watson
184ca0716f5SRobert Watson void
setauclass(void)185ca0716f5SRobert Watson setauclass(void)
186ca0716f5SRobert Watson {
187ca0716f5SRobert Watson
1887a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
189ca0716f5SRobert Watson pthread_mutex_lock(&mutex);
1907a0a89d2SRobert Watson #endif
191ca0716f5SRobert Watson setauclass_locked();
1927a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
193ca0716f5SRobert Watson pthread_mutex_unlock(&mutex);
1947a0a89d2SRobert Watson #endif
195ca0716f5SRobert Watson }
196ca0716f5SRobert Watson
197ca0716f5SRobert Watson /*
198ca0716f5SRobert Watson * Return the next au_class_entry having the given class name.
199ca0716f5SRobert Watson */
200ca0716f5SRobert Watson struct au_class_ent *
getauclassnam_r(struct au_class_ent * c,const char * name)201ca0716f5SRobert Watson getauclassnam_r(struct au_class_ent *c, const char *name)
202ca0716f5SRobert Watson {
203ca0716f5SRobert Watson struct au_class_ent *cp;
204ca0716f5SRobert Watson
205ca0716f5SRobert Watson if (name == NULL)
206ca0716f5SRobert Watson return (NULL);
207ca0716f5SRobert Watson
2087a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
209ca0716f5SRobert Watson pthread_mutex_lock(&mutex);
2107a0a89d2SRobert Watson #endif
211ca0716f5SRobert Watson setauclass_locked();
212ca0716f5SRobert Watson while ((cp = getauclassent_r_locked(c)) != NULL) {
213ca0716f5SRobert Watson if (strcmp(name, cp->ac_name) == 0) {
2147a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
215ca0716f5SRobert Watson pthread_mutex_unlock(&mutex);
2167a0a89d2SRobert Watson #endif
217ca0716f5SRobert Watson return (cp);
218ca0716f5SRobert Watson }
219ca0716f5SRobert Watson }
2207a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
221ca0716f5SRobert Watson pthread_mutex_unlock(&mutex);
2227a0a89d2SRobert Watson #endif
223ca0716f5SRobert Watson return (NULL);
224ca0716f5SRobert Watson }
225ca0716f5SRobert Watson
226ca0716f5SRobert Watson struct au_class_ent *
getauclassnam(const char * name)227ca0716f5SRobert Watson getauclassnam(const char *name)
228ca0716f5SRobert Watson {
229ca0716f5SRobert Watson static char class_ent_name[AU_CLASS_NAME_MAX];
230ca0716f5SRobert Watson static char class_ent_desc[AU_CLASS_DESC_MAX];
231ca0716f5SRobert Watson static struct au_class_ent c;
232ca0716f5SRobert Watson
233ca0716f5SRobert Watson bzero(&c, sizeof(c));
234ca0716f5SRobert Watson bzero(class_ent_name, sizeof(class_ent_name));
235ca0716f5SRobert Watson bzero(class_ent_desc, sizeof(class_ent_desc));
236ca0716f5SRobert Watson c.ac_name = class_ent_name;
237ca0716f5SRobert Watson c.ac_desc = class_ent_desc;
238ca0716f5SRobert Watson
239ca0716f5SRobert Watson return (getauclassnam_r(&c, name));
240ca0716f5SRobert Watson }
241ca0716f5SRobert Watson
242ca0716f5SRobert Watson
243ca0716f5SRobert Watson /*
244ca0716f5SRobert Watson * Return the next au_class_entry having the given class number.
245ca0716f5SRobert Watson *
246ca0716f5SRobert Watson * OpenBSM extension.
247ca0716f5SRobert Watson */
248ca0716f5SRobert Watson struct au_class_ent *
getauclassnum_r(struct au_class_ent * c,au_class_t class_number)249ca0716f5SRobert Watson getauclassnum_r(struct au_class_ent *c, au_class_t class_number)
250ca0716f5SRobert Watson {
251ca0716f5SRobert Watson struct au_class_ent *cp;
252ca0716f5SRobert Watson
2537a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
254ca0716f5SRobert Watson pthread_mutex_lock(&mutex);
2557a0a89d2SRobert Watson #endif
256ca0716f5SRobert Watson setauclass_locked();
257ca0716f5SRobert Watson while ((cp = getauclassent_r_locked(c)) != NULL) {
258ca0716f5SRobert Watson if (class_number == cp->ac_class)
259ca0716f5SRobert Watson return (cp);
260ca0716f5SRobert Watson }
2617a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
262ca0716f5SRobert Watson pthread_mutex_unlock(&mutex);
2637a0a89d2SRobert Watson #endif
264ca0716f5SRobert Watson return (NULL);
265ca0716f5SRobert Watson }
266ca0716f5SRobert Watson
267ca0716f5SRobert Watson struct au_class_ent *
getauclassnum(au_class_t class_number)268ca0716f5SRobert Watson getauclassnum(au_class_t class_number)
269ca0716f5SRobert Watson {
270ca0716f5SRobert Watson static char class_ent_name[AU_CLASS_NAME_MAX];
271ca0716f5SRobert Watson static char class_ent_desc[AU_CLASS_DESC_MAX];
272ca0716f5SRobert Watson static struct au_class_ent c;
273ca0716f5SRobert Watson
274ca0716f5SRobert Watson bzero(&c, sizeof(c));
275ca0716f5SRobert Watson bzero(class_ent_name, sizeof(class_ent_name));
276ca0716f5SRobert Watson bzero(class_ent_desc, sizeof(class_ent_desc));
277ca0716f5SRobert Watson c.ac_name = class_ent_name;
278ca0716f5SRobert Watson c.ac_desc = class_ent_desc;
279ca0716f5SRobert Watson
280ca0716f5SRobert Watson return (getauclassnum_r(&c, class_number));
281ca0716f5SRobert Watson }
282ca0716f5SRobert Watson
283ca0716f5SRobert Watson /*
284ca0716f5SRobert Watson * audit_class processing is complete; close any open files.
285ca0716f5SRobert Watson */
286ca0716f5SRobert Watson void
endauclass(void)287ca0716f5SRobert Watson endauclass(void)
288ca0716f5SRobert Watson {
289ca0716f5SRobert Watson
2907a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
291ca0716f5SRobert Watson pthread_mutex_lock(&mutex);
2927a0a89d2SRobert Watson #endif
293ca0716f5SRobert Watson if (fp != NULL) {
294ca0716f5SRobert Watson fclose(fp);
295ca0716f5SRobert Watson fp = NULL;
296ca0716f5SRobert Watson }
2977a0a89d2SRobert Watson #ifdef HAVE_PTHREAD_MUTEX_LOCK
298ca0716f5SRobert Watson pthread_mutex_unlock(&mutex);
2997a0a89d2SRobert Watson #endif
300ca0716f5SRobert Watson }
301