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