bsm_user.c revision 186647
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 * $P4: //depot/projects/trustedbsd/openbsm/libbsm/bsm_user.c#19 $
31 */
32
33#include <config/config.h>
34
35#include <bsm/libbsm.h>
36
37#include <string.h>
38#ifdef HAVE_PTHREAD_MUTEX_LOCK
39#include <pthread.h>
40#endif
41#include <stdio.h>
42#include <stdlib.h>
43
44#ifndef HAVE_STRLCPY
45#include <compat/strlcpy.h>
46#endif
47
48/*
49 * Parse the contents of the audit_user file into au_user_ent structures.
50 */
51
52static FILE		*fp = NULL;
53static char		 linestr[AU_LINE_MAX];
54static const char	*user_delim = ":";
55
56#ifdef HAVE_PTHREAD_MUTEX_LOCK
57static pthread_mutex_t	mutex = PTHREAD_MUTEX_INITIALIZER;
58#endif
59
60/*
61 * Parse one line from the audit_user file into the au_user_ent structure.
62 */
63static struct au_user_ent *
64userfromstr(char *str, struct au_user_ent *u)
65{
66	char *username, *always, *never;
67	char *last;
68
69	username = strtok_r(str, user_delim, &last);
70	always = strtok_r(NULL, user_delim, &last);
71	never = strtok_r(NULL, user_delim, &last);
72
73	if ((username == NULL) || (always == NULL) || (never == NULL))
74		return (NULL);
75
76	if (strlen(username) >= AU_USER_NAME_MAX)
77		return (NULL);
78
79	strlcpy(u->au_name, username, AU_USER_NAME_MAX);
80	if (getauditflagsbin(always, &(u->au_always)) == -1)
81		return (NULL);
82
83	if (getauditflagsbin(never, &(u->au_never)) == -1)
84		return (NULL);
85
86	return (u);
87}
88
89/*
90 * Rewind to beginning of the file
91 */
92static void
93setauuser_locked(void)
94{
95
96	if (fp != NULL)
97		fseek(fp, 0, SEEK_SET);
98}
99
100void
101setauuser(void)
102{
103
104#ifdef HAVE_PTHREAD_MUTEX_LOCK
105	pthread_mutex_lock(&mutex);
106#endif
107	setauuser_locked();
108#ifdef HAVE_PTHREAD_MUTEX_LOCK
109	pthread_mutex_unlock(&mutex);
110#endif
111}
112
113/*
114 * Close the file descriptor
115 */
116void
117endauuser(void)
118{
119
120#ifdef HAVE_PTHREAD_MUTEX_LOCK
121	pthread_mutex_lock(&mutex);
122#endif
123	if (fp != NULL) {
124		fclose(fp);
125		fp = NULL;
126	}
127#ifdef HAVE_PTHREAD_MUTEX_LOCK
128	pthread_mutex_unlock(&mutex);
129#endif
130}
131
132/*
133 * Enumerate the au_user_ent structures from the file
134 */
135static struct au_user_ent *
136getauuserent_r_locked(struct au_user_ent *u)
137{
138	char *nl;
139
140	if ((fp == NULL) && ((fp = fopen(AUDIT_USER_FILE, "r")) == NULL))
141		return (NULL);
142
143	while (1) {
144		if (fgets(linestr, AU_LINE_MAX, fp) == NULL)
145			return (NULL);
146
147		/* Remove new lines. */
148		if ((nl = strrchr(linestr, '\n')) != NULL)
149			*nl = '\0';
150
151		/* Skip comments. */
152		if (linestr[0] == '#')
153			continue;
154
155		/* Get the next structure. */
156		if (userfromstr(linestr, u) == NULL)
157			return (NULL);
158		break;
159	}
160
161	return (u);
162}
163
164struct au_user_ent *
165getauuserent_r(struct au_user_ent *u)
166{
167	struct au_user_ent *up;
168
169#ifdef HAVE_PTHREAD_MUTEX_LOCK
170	pthread_mutex_lock(&mutex);
171#endif
172	up = getauuserent_r_locked(u);
173#ifdef HAVE_PTHREAD_MUTEX_LOCK
174	pthread_mutex_unlock(&mutex);
175#endif
176	return (up);
177}
178
179struct au_user_ent *
180getauuserent(void)
181{
182	static char user_ent_name[AU_USER_NAME_MAX];
183	static struct au_user_ent u;
184
185	bzero(&u, sizeof(u));
186	bzero(user_ent_name, sizeof(user_ent_name));
187	u.au_name = user_ent_name;
188
189	return (getauuserent_r(&u));
190}
191
192/*
193 * Find a au_user_ent structure matching the given user name.
194 */
195struct au_user_ent *
196getauusernam_r(struct au_user_ent *u, const char *name)
197{
198	struct au_user_ent *up;
199
200	if (name == NULL)
201		return (NULL);
202
203#ifdef HAVE_PTHREAD_MUTEX_LOCK
204	pthread_mutex_lock(&mutex);
205#endif
206
207	setauuser_locked();
208	while ((up = getauuserent_r_locked(u)) != NULL) {
209		if (strcmp(name, u->au_name) == 0) {
210#ifdef HAVE_PTHREAD_MUTEX_LOCK
211			pthread_mutex_unlock(&mutex);
212#endif
213			return (u);
214		}
215	}
216
217#ifdef HAVE_PTHREAD_MUTEX_LOCK
218	pthread_mutex_unlock(&mutex);
219#endif
220	return (NULL);
221
222}
223
224struct au_user_ent *
225getauusernam(const char *name)
226{
227	static char user_ent_name[AU_USER_NAME_MAX];
228	static struct au_user_ent u;
229
230	bzero(&u, sizeof(u));
231	bzero(user_ent_name, sizeof(user_ent_name));
232	u.au_name = user_ent_name;
233
234	return (getauusernam_r(&u, name));
235}
236
237/*
238 * Read the default system wide audit classes from audit_control, combine with
239 * the per-user audit class and update the binary preselection mask.
240 */
241int
242au_user_mask(char *username, au_mask_t *mask_p)
243{
244	char auditstring[MAX_AUDITSTRING_LEN + 1];
245	char user_ent_name[AU_USER_NAME_MAX];
246	struct au_user_ent u, *up;
247
248	bzero(&u, sizeof(u));
249	bzero(user_ent_name, sizeof(user_ent_name));
250	u.au_name = user_ent_name;
251
252	/* Get user mask. */
253	if ((up = getauusernam_r(&u, username)) != NULL) {
254		if (-1 == getfauditflags(&up->au_always, &up->au_never,
255		    mask_p))
256			return (-1);
257		return (0);
258	}
259
260	/* Read the default system mask. */
261	if (getacflg(auditstring, MAX_AUDITSTRING_LEN) == 0) {
262		if (-1 == getauditflagsbin(auditstring, mask_p))
263			return (-1);
264		return (0);
265	}
266
267	/* No masks defined. */
268	return (-1);
269}
270
271/*
272 * Generate the process audit state by combining the audit masks passed as
273 * parameters with the system audit masks.
274 */
275int
276getfauditflags(au_mask_t *usremask, au_mask_t *usrdmask, au_mask_t *lastmask)
277{
278	char auditstring[MAX_AUDITSTRING_LEN + 1];
279
280	if ((usremask == NULL) || (usrdmask == NULL) || (lastmask == NULL))
281		return (-1);
282
283	lastmask->am_success = 0;
284	lastmask->am_failure = 0;
285
286	/* Get the system mask. */
287	if (getacflg(auditstring, MAX_AUDITSTRING_LEN) == 0) {
288		if (getauditflagsbin(auditstring, lastmask) != 0)
289			return (-1);
290	}
291
292	ADDMASK(lastmask, usremask);
293	SUBMASK(lastmask, usrdmask);
294
295	return (0);
296}
297