xref: /freebsd/lib/libc/posix1e/mac.c (revision f9218d3d4fd34f082473b3a021c6d4d109fb47cf)
1 /*
2  * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
3  * Copyright (c) 2002 Networks Associates Technology, Inc.
4  * All rights reserved.
5  *
6  * This software was developed by Robert Watson for the TrustedBSD Project.
7  *
8  * This software was developed for the FreeBSD Project in part by Network
9  * Associates Laboratories, the Security Research Division of Network
10  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
11  * as part of the DARPA CHATS research program.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $FreeBSD$
35  */
36 
37 #include <sys/types.h>
38 #include <sys/queue.h>
39 #include <sys/sysctl.h>
40 
41 #include <dlfcn.h>
42 #include <errno.h>
43 #include <limits.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 
48 #include <sys/mac.h>
49 
50 static int	internal_initialized;
51 
52 /* Default sets of labels for various query operations. */
53 static char	*default_file_labels;
54 static char	*default_ifnet_labels;
55 static char	*default_process_labels;
56 
57 static void
58 mac_destroy_labels(void)
59 {
60 
61 	if (default_file_labels != NULL) {
62 		free(default_file_labels);
63 		default_file_labels = NULL;
64 	}
65 
66 	if (default_ifnet_labels != NULL) {
67 		free(default_ifnet_labels);
68 		default_ifnet_labels = NULL;
69 	}
70 
71 	if (default_process_labels != NULL) {
72 		free(default_process_labels);
73 		default_process_labels = NULL;
74 	}
75 }
76 
77 static void
78 mac_destroy_internal(void)
79 {
80 
81 	mac_destroy_labels();
82 
83 	internal_initialized = 0;
84 }
85 
86 static int
87 mac_init_internal(void)
88 {
89 	FILE *file;
90 	char line[LINE_MAX];
91 	int error;
92 
93 	error = 0;
94 
95 	file = fopen(MAC_CONFFILE, "r");
96 	if (file == NULL)
97 		return (0);
98 
99 	while (fgets(line, LINE_MAX, file)) {
100 		char *arg, *parse, *statement;
101 
102 		if (line[strlen(line)-1] == '\n')
103 			line[strlen(line)-1] = '\0';
104 		else {
105 			fclose(file);
106 			error = EINVAL;
107 			goto just_return;
108 		}
109 
110 		parse = line;
111 		statement = "";
112 		while (parse && statement[0] == '\0')
113 			statement = strsep(&parse, " \t");
114 
115 		/* Blank lines ok. */
116 		if (strlen(statement) == 0)
117 			continue;
118 
119 		/* Lines that consist only of comments ok. */
120 		if (statement[0] == '#')
121 			continue;
122 
123 		if (strcmp(statement, "default_file_labels") == 0) {
124 			if (default_file_labels != NULL) {
125 				free(default_file_labels);
126 				default_file_labels = NULL;
127 			}
128 
129 			arg = strsep(&parse, "# \t");
130 			if (arg != NULL && arg[0] != '\0') {
131 				default_file_labels = strdup(arg);
132 				if (default_file_labels == NULL) {
133 					error = ENOMEM;
134 					fclose(file);
135 					goto just_return;
136 				}
137 			}
138 		} else if (strcmp(statement, "default_ifnet_labels") == 0) {
139 			if (default_ifnet_labels != NULL) {
140 				free(default_ifnet_labels);
141 				default_ifnet_labels = NULL;
142 			}
143 
144 			arg = strsep(&parse, "# \t");
145 			if (arg != NULL && arg[0] != '\0') {
146 				default_ifnet_labels = strdup(arg);
147 				if (default_ifnet_labels == NULL) {
148 					error = ENOMEM;
149 					fclose(file);
150 					goto just_return;
151 				}
152 			}
153 		} else if (strcmp(statement, "default_process_labels") == 0) {
154 			if (default_process_labels != NULL) {
155 				free(default_process_labels);
156 				default_process_labels = NULL;
157 			}
158 
159 			arg = strsep(&parse, "# \t");
160 			if (arg != NULL && arg[0] != '\0') {
161 				default_process_labels = strdup(arg);
162 				if (default_process_labels == NULL) {
163 					error = ENOMEM;
164 					fclose(file);
165 					goto just_return;
166 				}
167 			}
168 		} else {
169 			fclose(file);
170 			error = EINVAL;
171 			goto just_return;
172 		}
173 	}
174 
175 	fclose(file);
176 
177 	internal_initialized = 1;
178 
179 just_return:
180 	if (error != 0)
181 		mac_destroy_internal();
182 	return (error);
183 }
184 
185 static int
186 mac_maybe_init_internal(void)
187 {
188 
189 	if (!internal_initialized)
190 		return (mac_init_internal());
191 	else
192 		return (0);
193 }
194 
195 int
196 mac_reload(void)
197 {
198 
199 	if (internal_initialized)
200 		mac_destroy_internal();
201 	return (mac_init_internal());
202 }
203 
204 int
205 mac_free(struct mac *mac)
206 {
207 
208 	if (mac->m_string != NULL)
209 		free(mac->m_string);
210 	free(mac);
211 
212 	return (0);
213 }
214 
215 int
216 mac_from_text(struct mac **mac, const char *text)
217 {
218 
219 	*mac = (struct mac *) malloc(sizeof(**mac));
220 	if (*mac == NULL)
221 		return (ENOMEM);
222 
223 	(*mac)->m_string = strdup(text);
224 	if ((*mac)->m_string == NULL) {
225 		free(*mac);
226 		*mac = NULL;
227 		return (ENOMEM);
228 	}
229 
230 	(*mac)->m_buflen = strlen((*mac)->m_string)+1;
231 
232 	return (0);
233 }
234 
235 int
236 mac_to_text(struct mac *mac, char **text)
237 {
238 
239 	*text = strdup(mac->m_string);
240 	if (*text == NULL)
241 		return (ENOMEM);
242 	return (0);
243 }
244 
245 int
246 mac_prepare(struct mac **mac, char *elements)
247 {
248 
249 	if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN)
250 		return (EINVAL);
251 
252 	*mac = (struct mac *) malloc(sizeof(**mac));
253 	if (*mac == NULL)
254 		return (ENOMEM);
255 
256 	(*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN);
257 	if ((*mac)->m_string == NULL) {
258 		free(*mac);
259 		*mac = NULL;
260 		return (ENOMEM);
261 	}
262 
263 	strcpy((*mac)->m_string, elements);
264 	(*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN;
265 
266 	return (0);
267 }
268 
269 int
270 mac_prepare_file_label(struct mac **mac)
271 {
272 	int error;
273 
274 	error = mac_maybe_init_internal();
275 	if (error != 0)
276 		return (error);
277 
278 	if (default_file_labels == NULL)
279 		return (mac_prepare(mac, ""));
280 
281 	return (mac_prepare(mac, default_file_labels));
282 }
283 
284 int
285 mac_prepare_ifnet_label(struct mac **mac)
286 {
287 	int error;
288 
289 	error = mac_maybe_init_internal();
290 	if (error != 0)
291 		return (error);
292 
293 	if (default_ifnet_labels == NULL)
294 		return (mac_prepare(mac, ""));
295 
296 	return (mac_prepare(mac, default_ifnet_labels));
297 }
298 int
299 mac_prepare_process_label(struct mac **mac)
300 {
301 	int error;
302 
303 	error = mac_maybe_init_internal();
304 	if (error != 0)
305 		return (error);
306 
307 	if (default_process_labels == NULL)
308 		return (mac_prepare(mac, ""));
309 
310 	return (mac_prepare(mac, default_process_labels));
311 }
312 
313 /*
314  * Simply test whether the TrustedBSD/MAC MIB tree is present; if so,
315  * return 1 to indicate that the system has MAC enabled overall or for
316  * a given policy.
317  */
318 int
319 mac_is_present(const char *policyname)
320 {
321 	int mib[5];
322 	size_t siz;
323 	char *mibname;
324 	int error;
325 
326 	if (policyname != NULL) {
327 		if (policyname[strcspn(policyname, ".=")] != '\0') {
328 			errno = EINVAL;
329 			return (-1);
330 		}
331 		mibname = malloc(sizeof("security.mac.") - 1 +
332 		    strlen(policyname) + sizeof(".enabled"));
333 		if (mibname == NULL)
334 			return (-1);
335 		strcpy(mibname, "security.mac.");
336 		strcat(mibname, policyname);
337 		strcat(mibname, ".enabled");
338 		siz = 5;
339 		error = sysctlnametomib(mibname, mib, &siz);
340 		free(mibname);
341 	} else {
342 		siz = 3;
343 		error = sysctlnametomib("security.mac", mib, &siz);
344 	}
345 	if (error == -1) {
346 		switch (errno) {
347 		case ENOTDIR:
348 		case ENOENT:
349 			return (0);
350 		default:
351 			return (error);
352 		}
353 	}
354 	return (1);
355 }
356