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