xref: /freebsd/lib/libc/posix1e/mac.c (revision 4bae1674ce22d73383ff03c86d26b9ceacab8bc9)
1391b1d75SRobert Watson /*
2391b1d75SRobert Watson  * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
3391b1d75SRobert Watson  * Copyright (c) 2002 Networks Associates Technology, Inc.
4391b1d75SRobert Watson  * All rights reserved.
5391b1d75SRobert Watson  *
6391b1d75SRobert Watson  * This software was developed by Robert Watson for the TrustedBSD Project.
7391b1d75SRobert Watson  *
8391b1d75SRobert Watson  * This software was developed for the FreeBSD Project in part by NAI Labs,
9391b1d75SRobert Watson  * the Security Research Division of Network Associates, Inc. under
10391b1d75SRobert Watson  * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
11391b1d75SRobert Watson  * CHATS research program.
12391b1d75SRobert Watson  *
13391b1d75SRobert Watson  * Redistribution and use in source and binary forms, with or without
14391b1d75SRobert Watson  * modification, are permitted provided that the following conditions
15391b1d75SRobert Watson  * are met:
16391b1d75SRobert Watson  * 1. Redistributions of source code must retain the above copyright
17391b1d75SRobert Watson  *    notice, this list of conditions and the following disclaimer.
18391b1d75SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
19391b1d75SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
20391b1d75SRobert Watson  *    documentation and/or other materials provided with the distribution.
21391b1d75SRobert Watson  * 3. The names of the authors may not be used to endorse or promote
22391b1d75SRobert Watson  *    products derived from this software without specific prior written
23391b1d75SRobert Watson  *    permission.
24391b1d75SRobert Watson  *
25391b1d75SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
26391b1d75SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27391b1d75SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28391b1d75SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
29391b1d75SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30391b1d75SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31391b1d75SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32391b1d75SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33391b1d75SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34391b1d75SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35391b1d75SRobert Watson  * SUCH DAMAGE.
36391b1d75SRobert Watson  *
37391b1d75SRobert Watson  * $FreeBSD$
38391b1d75SRobert Watson  */
39391b1d75SRobert Watson 
40391b1d75SRobert Watson #include <sys/types.h>
41391b1d75SRobert Watson #include <sys/queue.h>
42391b1d75SRobert Watson #include <sys/sysctl.h>
43391b1d75SRobert Watson #include <sys/syslimits.h>
44391b1d75SRobert Watson 
45391b1d75SRobert Watson #include <dlfcn.h>
46391b1d75SRobert Watson #include <errno.h>
47391b1d75SRobert Watson #include <stdio.h>
48391b1d75SRobert Watson #include <stdlib.h>
49391b1d75SRobert Watson #include <string.h>
50391b1d75SRobert Watson 
51391b1d75SRobert Watson #include <sys/mac.h>
52391b1d75SRobert Watson 
53391b1d75SRobert Watson static int	internal_initialized;
54391b1d75SRobert Watson 
55391b1d75SRobert Watson /* Default sets of labels for various query operations. */
56391b1d75SRobert Watson static char	*default_file_labels;
57391b1d75SRobert Watson static char	*default_ifnet_labels;
58391b1d75SRobert Watson static char	*default_process_labels;
59391b1d75SRobert Watson 
60391b1d75SRobert Watson static void
61391b1d75SRobert Watson mac_destroy_labels(void)
62391b1d75SRobert Watson {
63391b1d75SRobert Watson 
64391b1d75SRobert Watson 	if (default_file_labels != NULL) {
65391b1d75SRobert Watson 		free(default_file_labels);
66391b1d75SRobert Watson 		default_file_labels = NULL;
67391b1d75SRobert Watson 	}
68391b1d75SRobert Watson 
69391b1d75SRobert Watson 	if (default_ifnet_labels != NULL) {
70391b1d75SRobert Watson 		free(default_ifnet_labels);
71391b1d75SRobert Watson 		default_ifnet_labels = NULL;
72391b1d75SRobert Watson 	}
73391b1d75SRobert Watson 
74391b1d75SRobert Watson 	if (default_process_labels != NULL) {
75391b1d75SRobert Watson 		free(default_process_labels);
76391b1d75SRobert Watson 		default_process_labels = NULL;
77391b1d75SRobert Watson 	}
78391b1d75SRobert Watson }
79391b1d75SRobert Watson 
80391b1d75SRobert Watson static void
81391b1d75SRobert Watson mac_destroy_internal(void)
82391b1d75SRobert Watson {
83391b1d75SRobert Watson 
84391b1d75SRobert Watson 	mac_destroy_labels();
85391b1d75SRobert Watson 
86391b1d75SRobert Watson 	internal_initialized = 0;
87391b1d75SRobert Watson }
88391b1d75SRobert Watson 
89391b1d75SRobert Watson static int
90391b1d75SRobert Watson mac_init_internal(void)
91391b1d75SRobert Watson {
92391b1d75SRobert Watson 	FILE *file;
93391b1d75SRobert Watson 	char line[LINE_MAX];
94391b1d75SRobert Watson 	int error;
95391b1d75SRobert Watson 
96391b1d75SRobert Watson 	error = 0;
97391b1d75SRobert Watson 
98391b1d75SRobert Watson 	file = fopen(MAC_CONFFILE, "r");
99391b1d75SRobert Watson 	if (file == NULL)
100391b1d75SRobert Watson 		return (0);
101391b1d75SRobert Watson 
102391b1d75SRobert Watson 	while (fgets(line, LINE_MAX, file)) {
103391b1d75SRobert Watson 		char *argv[ARG_MAX];
104391b1d75SRobert Watson 		char *arg, *parse, *statement, *policyname, *modulename;
105391b1d75SRobert Watson 		int argc;
106391b1d75SRobert Watson 
107391b1d75SRobert Watson 		if (line[strlen(line)-1] == '\n')
108391b1d75SRobert Watson 			line[strlen(line)-1] = '\0';
109391b1d75SRobert Watson 		else {
110391b1d75SRobert Watson 			fclose(file);
111391b1d75SRobert Watson 			error = EINVAL;
112391b1d75SRobert Watson 			goto just_return;
113391b1d75SRobert Watson 		}
114391b1d75SRobert Watson 
115391b1d75SRobert Watson 		parse = line;
116391b1d75SRobert Watson 		statement = "";
117391b1d75SRobert Watson 		while (parse && statement[0] == '\0')
118391b1d75SRobert Watson 			statement = strsep(&parse, " \t");
119391b1d75SRobert Watson 
120391b1d75SRobert Watson 		/* Blank lines ok. */
121391b1d75SRobert Watson 		if (strlen(statement) == 0)
122391b1d75SRobert Watson 			continue;
123391b1d75SRobert Watson 
124391b1d75SRobert Watson 		/* Lines that consist only of comments ok. */
125391b1d75SRobert Watson 		if (statement[0] == '#')
126391b1d75SRobert Watson 			continue;
127391b1d75SRobert Watson 
128391b1d75SRobert Watson 		if (strcmp(statement, "default_file_labels") == 0) {
129391b1d75SRobert Watson 			if (default_file_labels != NULL) {
130391b1d75SRobert Watson 				free(default_file_labels);
131391b1d75SRobert Watson 				default_file_labels = NULL;
132391b1d75SRobert Watson 			}
133391b1d75SRobert Watson 
134391b1d75SRobert Watson 			arg = strsep(&parse, "# \t");
135391b1d75SRobert Watson 			if (arg != NULL && arg[0] != '\0') {
136391b1d75SRobert Watson 				default_file_labels = strdup(arg);
137391b1d75SRobert Watson 				if (default_file_labels == NULL) {
138391b1d75SRobert Watson 					error = ENOMEM;
139391b1d75SRobert Watson 					fclose(file);
140391b1d75SRobert Watson 					goto just_return;
141391b1d75SRobert Watson 				}
142391b1d75SRobert Watson 			}
143391b1d75SRobert Watson 		} else if (strcmp(statement, "default_ifnet_labels") == 0) {
144391b1d75SRobert Watson 			if (default_ifnet_labels != NULL) {
145391b1d75SRobert Watson 				free(default_ifnet_labels);
146391b1d75SRobert Watson 				default_ifnet_labels = NULL;
147391b1d75SRobert Watson 			}
148391b1d75SRobert Watson 
149391b1d75SRobert Watson 			arg = strsep(&parse, "# \t");
150391b1d75SRobert Watson 			if (arg != NULL && arg[0] != '\0') {
151391b1d75SRobert Watson 				default_ifnet_labels = strdup(arg);
152391b1d75SRobert Watson 				if (default_ifnet_labels == NULL) {
153391b1d75SRobert Watson 					error = ENOMEM;
154391b1d75SRobert Watson 					fclose(file);
155391b1d75SRobert Watson 					goto just_return;
156391b1d75SRobert Watson 				}
157391b1d75SRobert Watson 			}
158391b1d75SRobert Watson 		} else if (strcmp(statement, "default_process_labels") == 0) {
159391b1d75SRobert Watson 			if (default_process_labels != NULL) {
160391b1d75SRobert Watson 				free(default_process_labels);
161391b1d75SRobert Watson 				default_process_labels = NULL;
162391b1d75SRobert Watson 			}
163391b1d75SRobert Watson 
164391b1d75SRobert Watson 			arg = strsep(&parse, "# \t");
165391b1d75SRobert Watson 			if (arg != NULL && arg[0] != '\0') {
166391b1d75SRobert Watson 				default_process_labels = strdup(arg);
167391b1d75SRobert Watson 				if (default_process_labels == NULL) {
168391b1d75SRobert Watson 					error = ENOMEM;
169391b1d75SRobert Watson 					fclose(file);
170391b1d75SRobert Watson 					goto just_return;
171391b1d75SRobert Watson 				}
172391b1d75SRobert Watson 			}
173391b1d75SRobert Watson 		} else {
174391b1d75SRobert Watson 			fclose(file);
175391b1d75SRobert Watson 			error = EINVAL;
176391b1d75SRobert Watson 			goto just_return;
177391b1d75SRobert Watson 		}
178391b1d75SRobert Watson 	}
179391b1d75SRobert Watson 
180391b1d75SRobert Watson 	fclose(file);
181391b1d75SRobert Watson 
182391b1d75SRobert Watson 	internal_initialized = 1;
183391b1d75SRobert Watson 
184391b1d75SRobert Watson just_return:
185391b1d75SRobert Watson 	if (error != 0)
186391b1d75SRobert Watson 		mac_destroy_internal();
187391b1d75SRobert Watson 	return (error);
188391b1d75SRobert Watson }
189391b1d75SRobert Watson 
190391b1d75SRobert Watson static int
191391b1d75SRobert Watson mac_maybe_init_internal(void)
192391b1d75SRobert Watson {
193391b1d75SRobert Watson 
194391b1d75SRobert Watson 	if (!internal_initialized)
195391b1d75SRobert Watson 		return (mac_init_internal());
196391b1d75SRobert Watson 	else
197391b1d75SRobert Watson 		return (0);
198391b1d75SRobert Watson }
199391b1d75SRobert Watson 
200391b1d75SRobert Watson int
201391b1d75SRobert Watson mac_reload(void)
202391b1d75SRobert Watson {
203391b1d75SRobert Watson 
204391b1d75SRobert Watson 	if (internal_initialized)
205391b1d75SRobert Watson 		mac_destroy_internal();
206391b1d75SRobert Watson 	return (mac_init_internal());
207391b1d75SRobert Watson }
208391b1d75SRobert Watson 
209391b1d75SRobert Watson int
210391b1d75SRobert Watson mac_free(struct mac *mac)
211391b1d75SRobert Watson {
212391b1d75SRobert Watson 	int error;
213391b1d75SRobert Watson 
214391b1d75SRobert Watson 	if (mac->m_string != NULL)
215391b1d75SRobert Watson 		free(mac->m_string);
216391b1d75SRobert Watson 	free(mac);
217391b1d75SRobert Watson 
218391b1d75SRobert Watson 	return (0);
219391b1d75SRobert Watson }
220391b1d75SRobert Watson 
221391b1d75SRobert Watson int
222391b1d75SRobert Watson mac_from_text(struct mac **mac, const char *text)
223391b1d75SRobert Watson {
224391b1d75SRobert Watson 	struct mac *temp;
225391b1d75SRobert Watson 	char *dup, *element, *search;
226391b1d75SRobert Watson 	int count, error;
227391b1d75SRobert Watson 
228391b1d75SRobert Watson 	*mac = (struct mac *) malloc(sizeof(**mac));
229391b1d75SRobert Watson 	if (*mac == NULL)
230391b1d75SRobert Watson 		return (ENOMEM);
231391b1d75SRobert Watson 
232391b1d75SRobert Watson 	(*mac)->m_string = strdup(text);
233391b1d75SRobert Watson 	if ((*mac)->m_string == NULL) {
234391b1d75SRobert Watson 		free(*mac);
235391b1d75SRobert Watson 		*mac = NULL;
236391b1d75SRobert Watson 		return (ENOMEM);
237391b1d75SRobert Watson 	}
238391b1d75SRobert Watson 
239391b1d75SRobert Watson 	(*mac)->m_buflen = strlen((*mac)->m_string)+1;
240391b1d75SRobert Watson 
241391b1d75SRobert Watson 	return (0);
242391b1d75SRobert Watson }
243391b1d75SRobert Watson 
244391b1d75SRobert Watson int
2454bae1674SChris Costello mac_to_text(struct mac *mac, char **text)
2464bae1674SChris Costello {
2474bae1674SChris Costello 
2484bae1674SChris Costello 	*text = strdup(mac->m_string);
2494bae1674SChris Costello 	if (*text == NULL)
2504bae1674SChris Costello 		return (ENOMEM);
2514bae1674SChris Costello 	return (0);
2524bae1674SChris Costello }
2534bae1674SChris Costello 
2544bae1674SChris Costello int
255391b1d75SRobert Watson mac_prepare(struct mac **mac, char *elements)
256391b1d75SRobert Watson {
257391b1d75SRobert Watson 	struct mac *temp;
258391b1d75SRobert Watson 
259391b1d75SRobert Watson 	if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN)
260391b1d75SRobert Watson 		return (EINVAL);
261391b1d75SRobert Watson 
262391b1d75SRobert Watson 	*mac = (struct mac *) malloc(sizeof(**mac));
263391b1d75SRobert Watson 	if (*mac == NULL)
264391b1d75SRobert Watson 		return (ENOMEM);
265391b1d75SRobert Watson 
266391b1d75SRobert Watson 	(*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN);
267391b1d75SRobert Watson 	if ((*mac)->m_string == NULL) {
268391b1d75SRobert Watson 		free(*mac);
269391b1d75SRobert Watson 		*mac = NULL;
270391b1d75SRobert Watson 		return (ENOMEM);
271391b1d75SRobert Watson 	}
272391b1d75SRobert Watson 
273391b1d75SRobert Watson 	strcpy((*mac)->m_string, elements);
274391b1d75SRobert Watson 	(*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN;
275391b1d75SRobert Watson 
276391b1d75SRobert Watson 	return (0);
277391b1d75SRobert Watson }
278391b1d75SRobert Watson 
279391b1d75SRobert Watson int
280391b1d75SRobert Watson mac_prepare_file_label(struct mac **mac)
281391b1d75SRobert Watson {
282391b1d75SRobert Watson 	int error;
283391b1d75SRobert Watson 
284391b1d75SRobert Watson 	error = mac_maybe_init_internal();
285391b1d75SRobert Watson 	if (error != 0)
286391b1d75SRobert Watson 		return (error);
287391b1d75SRobert Watson 
288391b1d75SRobert Watson 	if (default_file_labels == NULL)
289391b1d75SRobert Watson 		return (mac_prepare(mac, ""));
290391b1d75SRobert Watson 
291391b1d75SRobert Watson 	return (mac_prepare(mac, default_file_labels));
292391b1d75SRobert Watson }
293391b1d75SRobert Watson 
294391b1d75SRobert Watson int
295391b1d75SRobert Watson mac_prepare_ifnet_label(struct mac **mac)
296391b1d75SRobert Watson {
297391b1d75SRobert Watson 	int error;
298391b1d75SRobert Watson 
299391b1d75SRobert Watson 	error = mac_maybe_init_internal();
300391b1d75SRobert Watson 	if (error != 0)
301391b1d75SRobert Watson 		return (error);
302391b1d75SRobert Watson 
303391b1d75SRobert Watson 	if (default_ifnet_labels == NULL)
304391b1d75SRobert Watson 		return (mac_prepare(mac, ""));
305391b1d75SRobert Watson 
306391b1d75SRobert Watson 	return (mac_prepare(mac, default_ifnet_labels));
307391b1d75SRobert Watson }
308391b1d75SRobert Watson int
309391b1d75SRobert Watson mac_prepare_process_label(struct mac **mac)
310391b1d75SRobert Watson {
311391b1d75SRobert Watson 	int error;
312391b1d75SRobert Watson 
313391b1d75SRobert Watson 	error = mac_maybe_init_internal();
314391b1d75SRobert Watson 	if (error != 0)
315391b1d75SRobert Watson 		return (error);
316391b1d75SRobert Watson 
317391b1d75SRobert Watson 	if (default_process_labels == NULL)
318391b1d75SRobert Watson 		return (mac_prepare(mac, ""));
319391b1d75SRobert Watson 
320391b1d75SRobert Watson 	return (mac_prepare(mac, default_process_labels));
321391b1d75SRobert Watson }
322391b1d75SRobert Watson 
323391b1d75SRobert Watson /*
324391b1d75SRobert Watson  * Simply test whether the TrustedBSD/MAC MIB tree is present; if so,
325391b1d75SRobert Watson  * return 1 to indicate that the system has MAC enabled overall or for
326391b1d75SRobert Watson  * a given policy.
327391b1d75SRobert Watson  */
328391b1d75SRobert Watson int
329391b1d75SRobert Watson mac_is_present(const char *policyname)
330391b1d75SRobert Watson {
331391b1d75SRobert Watson 	int mib[5];
332391b1d75SRobert Watson 	size_t siz;
333391b1d75SRobert Watson 	char *mibname;
334391b1d75SRobert Watson 	int error;
335391b1d75SRobert Watson 
336391b1d75SRobert Watson 	if (policyname != NULL) {
337391b1d75SRobert Watson 		if (policyname[strcspn(policyname, ".=")] != '\0') {
338391b1d75SRobert Watson 			errno = EINVAL;
339391b1d75SRobert Watson 			return (-1);
340391b1d75SRobert Watson 		}
341391b1d75SRobert Watson 		mibname = malloc(sizeof("security.mac.") - 1 +
342391b1d75SRobert Watson 		    strlen(policyname) + sizeof(".enabled"));
343391b1d75SRobert Watson 		if (mibname == NULL)
344391b1d75SRobert Watson 			return (-1);
345391b1d75SRobert Watson 		strcpy(mibname, "security.mac.");
346391b1d75SRobert Watson 		strcat(mibname, policyname);
347391b1d75SRobert Watson 		strcat(mibname, ".enabled");
348391b1d75SRobert Watson 		siz = 5;
349391b1d75SRobert Watson 		error = sysctlnametomib(mibname, mib, &siz);
350391b1d75SRobert Watson 		free(mibname);
351391b1d75SRobert Watson 	} else {
352391b1d75SRobert Watson 		siz = 3;
353391b1d75SRobert Watson 		error = sysctlnametomib("security.mac", mib, &siz);
354391b1d75SRobert Watson 	}
355391b1d75SRobert Watson 	if (error == -1) {
356391b1d75SRobert Watson 		switch (errno) {
357391b1d75SRobert Watson 		case ENOTDIR:
358391b1d75SRobert Watson 		case ENOENT:
359391b1d75SRobert Watson 			return (0);
360391b1d75SRobert Watson 		default:
361391b1d75SRobert Watson 			return (error);
362391b1d75SRobert Watson 		}
363391b1d75SRobert Watson 	}
364391b1d75SRobert Watson 	return (1);
365391b1d75SRobert Watson }
366