mac.c revision 106436
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: head/lib/libc/posix1e/mac.c 106436 2002-11-05 01:42:35Z rwatson $
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
50static int	internal_initialized;
51
52/* Default sets of labels for various query operations. */
53static char	*default_file_labels;
54static char	*default_ifnet_labels;
55static char	*default_process_labels;
56
57static void
58mac_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
77static void
78mac_destroy_internal(void)
79{
80
81	mac_destroy_labels();
82
83	internal_initialized = 0;
84}
85
86static int
87mac_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 *argv[ARG_MAX];
101		char *arg, *parse, *statement, *policyname, *modulename;
102		int argc;
103
104		if (line[strlen(line)-1] == '\n')
105			line[strlen(line)-1] = '\0';
106		else {
107			fclose(file);
108			error = EINVAL;
109			goto just_return;
110		}
111
112		parse = line;
113		statement = "";
114		while (parse && statement[0] == '\0')
115			statement = strsep(&parse, " \t");
116
117		/* Blank lines ok. */
118		if (strlen(statement) == 0)
119			continue;
120
121		/* Lines that consist only of comments ok. */
122		if (statement[0] == '#')
123			continue;
124
125		if (strcmp(statement, "default_file_labels") == 0) {
126			if (default_file_labels != NULL) {
127				free(default_file_labels);
128				default_file_labels = NULL;
129			}
130
131			arg = strsep(&parse, "# \t");
132			if (arg != NULL && arg[0] != '\0') {
133				default_file_labels = strdup(arg);
134				if (default_file_labels == NULL) {
135					error = ENOMEM;
136					fclose(file);
137					goto just_return;
138				}
139			}
140		} else if (strcmp(statement, "default_ifnet_labels") == 0) {
141			if (default_ifnet_labels != NULL) {
142				free(default_ifnet_labels);
143				default_ifnet_labels = NULL;
144			}
145
146			arg = strsep(&parse, "# \t");
147			if (arg != NULL && arg[0] != '\0') {
148				default_ifnet_labels = strdup(arg);
149				if (default_ifnet_labels == NULL) {
150					error = ENOMEM;
151					fclose(file);
152					goto just_return;
153				}
154			}
155		} else if (strcmp(statement, "default_process_labels") == 0) {
156			if (default_process_labels != NULL) {
157				free(default_process_labels);
158				default_process_labels = NULL;
159			}
160
161			arg = strsep(&parse, "# \t");
162			if (arg != NULL && arg[0] != '\0') {
163				default_process_labels = strdup(arg);
164				if (default_process_labels == NULL) {
165					error = ENOMEM;
166					fclose(file);
167					goto just_return;
168				}
169			}
170		} else {
171			fclose(file);
172			error = EINVAL;
173			goto just_return;
174		}
175	}
176
177	fclose(file);
178
179	internal_initialized = 1;
180
181just_return:
182	if (error != 0)
183		mac_destroy_internal();
184	return (error);
185}
186
187static int
188mac_maybe_init_internal(void)
189{
190
191	if (!internal_initialized)
192		return (mac_init_internal());
193	else
194		return (0);
195}
196
197int
198mac_reload(void)
199{
200
201	if (internal_initialized)
202		mac_destroy_internal();
203	return (mac_init_internal());
204}
205
206int
207mac_free(struct mac *mac)
208{
209	int error;
210
211	if (mac->m_string != NULL)
212		free(mac->m_string);
213	free(mac);
214
215	return (0);
216}
217
218int
219mac_from_text(struct mac **mac, const char *text)
220{
221	struct mac *temp;
222	char *dup, *element, *search;
223	int count, error;
224
225	*mac = (struct mac *) malloc(sizeof(**mac));
226	if (*mac == NULL)
227		return (ENOMEM);
228
229	(*mac)->m_string = strdup(text);
230	if ((*mac)->m_string == NULL) {
231		free(*mac);
232		*mac = NULL;
233		return (ENOMEM);
234	}
235
236	(*mac)->m_buflen = strlen((*mac)->m_string)+1;
237
238	return (0);
239}
240
241int
242mac_to_text(struct mac *mac, char **text)
243{
244
245	*text = strdup(mac->m_string);
246	if (*text == NULL)
247		return (ENOMEM);
248	return (0);
249}
250
251int
252mac_prepare(struct mac **mac, char *elements)
253{
254	struct mac *temp;
255
256	if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN)
257		return (EINVAL);
258
259	*mac = (struct mac *) malloc(sizeof(**mac));
260	if (*mac == NULL)
261		return (ENOMEM);
262
263	(*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN);
264	if ((*mac)->m_string == NULL) {
265		free(*mac);
266		*mac = NULL;
267		return (ENOMEM);
268	}
269
270	strcpy((*mac)->m_string, elements);
271	(*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN;
272
273	return (0);
274}
275
276int
277mac_prepare_file_label(struct mac **mac)
278{
279	int error;
280
281	error = mac_maybe_init_internal();
282	if (error != 0)
283		return (error);
284
285	if (default_file_labels == NULL)
286		return (mac_prepare(mac, ""));
287
288	return (mac_prepare(mac, default_file_labels));
289}
290
291int
292mac_prepare_ifnet_label(struct mac **mac)
293{
294	int error;
295
296	error = mac_maybe_init_internal();
297	if (error != 0)
298		return (error);
299
300	if (default_ifnet_labels == NULL)
301		return (mac_prepare(mac, ""));
302
303	return (mac_prepare(mac, default_ifnet_labels));
304}
305int
306mac_prepare_process_label(struct mac **mac)
307{
308	int error;
309
310	error = mac_maybe_init_internal();
311	if (error != 0)
312		return (error);
313
314	if (default_process_labels == NULL)
315		return (mac_prepare(mac, ""));
316
317	return (mac_prepare(mac, default_process_labels));
318}
319
320/*
321 * Simply test whether the TrustedBSD/MAC MIB tree is present; if so,
322 * return 1 to indicate that the system has MAC enabled overall or for
323 * a given policy.
324 */
325int
326mac_is_present(const char *policyname)
327{
328	int mib[5];
329	size_t siz;
330	char *mibname;
331	int error;
332
333	if (policyname != NULL) {
334		if (policyname[strcspn(policyname, ".=")] != '\0') {
335			errno = EINVAL;
336			return (-1);
337		}
338		mibname = malloc(sizeof("security.mac.") - 1 +
339		    strlen(policyname) + sizeof(".enabled"));
340		if (mibname == NULL)
341			return (-1);
342		strcpy(mibname, "security.mac.");
343		strcat(mibname, policyname);
344		strcat(mibname, ".enabled");
345		siz = 5;
346		error = sysctlnametomib(mibname, mib, &siz);
347		free(mibname);
348	} else {
349		siz = 3;
350		error = sysctlnametomib("security.mac", mib, &siz);
351	}
352	if (error == -1) {
353		switch (errno) {
354		case ENOTDIR:
355		case ENOENT:
356			return (0);
357		default:
358			return (error);
359		}
360	}
361	return (1);
362}
363