mac.c revision 122868
1105698Srwatson/*
2105698Srwatson * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
3119314Srwatson * Copyright (c) 2002, 2003 Networks Associates Technology, Inc.
4105698Srwatson * All rights reserved.
5105698Srwatson *
6105698Srwatson * This software was developed by Robert Watson for the TrustedBSD Project.
7105698Srwatson *
8106436Srwatson * This software was developed for the FreeBSD Project in part by Network
9106436Srwatson * Associates Laboratories, the Security Research Division of Network
10106436Srwatson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
11106436Srwatson * as part of the DARPA CHATS research program.
12105698Srwatson *
13105698Srwatson * Redistribution and use in source and binary forms, with or without
14105698Srwatson * modification, are permitted provided that the following conditions
15105698Srwatson * are met:
16105698Srwatson * 1. Redistributions of source code must retain the above copyright
17105698Srwatson *    notice, this list of conditions and the following disclaimer.
18105698Srwatson * 2. Redistributions in binary form must reproduce the above copyright
19105698Srwatson *    notice, this list of conditions and the following disclaimer in the
20105698Srwatson *    documentation and/or other materials provided with the distribution.
21105698Srwatson *
22105698Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23105698Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24105698Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25105698Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26105698Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27105698Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28105698Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29105698Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30105698Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31105698Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32105698Srwatson * SUCH DAMAGE.
33105698Srwatson *
34105698Srwatson * $FreeBSD: head/lib/libc/posix1e/mac.c 122868 2003-11-17 19:48:35Z rwatson $
35105698Srwatson */
36105698Srwatson
37105698Srwatson#include <sys/types.h>
38105698Srwatson#include <sys/queue.h>
39105698Srwatson#include <sys/sysctl.h>
40105698Srwatson
41105698Srwatson#include <dlfcn.h>
42105698Srwatson#include <errno.h>
43106053Swollman#include <limits.h>
44105698Srwatson#include <stdio.h>
45105698Srwatson#include <stdlib.h>
46105698Srwatson#include <string.h>
47105698Srwatson
48105698Srwatson#include <sys/mac.h>
49105698Srwatson
50105698Srwatsonstatic int	internal_initialized;
51105698Srwatson
52119314Srwatson/*
53119314Srwatson * Maintain a list of default label preparations for various object
54119314Srwatson * types.  Each name will appear only once in the list.
55119314Srwatson *
56119314Srwatson * XXXMAC: Not thread-safe.
57119314Srwatson */
58122868Srwatsonstatic LIST_HEAD(, label_default) label_default_head;
59119314Srwatsonstruct label_default {
60119314Srwatson	char				*ld_name;
61119314Srwatson	char				*ld_labels;
62119314Srwatson	LIST_ENTRY(label_default)	 ld_entries;
63119314Srwatson};
64105698Srwatson
65105698Srwatsonstatic void
66105698Srwatsonmac_destroy_labels(void)
67105698Srwatson{
68119314Srwatson	struct label_default *ld;
69105698Srwatson
70119314Srwatson	while ((ld = LIST_FIRST(&label_default_head))) {
71119314Srwatson		free(ld->ld_name);
72119314Srwatson		free(ld->ld_labels);
73119314Srwatson		LIST_REMOVE(ld, ld_entries);
74119314Srwatson		free(ld);
75105698Srwatson	}
76105698Srwatson}
77105698Srwatson
78105698Srwatsonstatic void
79105698Srwatsonmac_destroy_internal(void)
80105698Srwatson{
81105698Srwatson
82105698Srwatson	mac_destroy_labels();
83105698Srwatson
84105698Srwatson	internal_initialized = 0;
85105698Srwatson}
86105698Srwatson
87105698Srwatsonstatic int
88119314Srwatsonmac_add_type(const char *name, const char *labels)
89105698Srwatson{
90119314Srwatson	struct label_default *ld, *ld_new;
91119314Srwatson	char *name_dup, *labels_dup;
92119314Srwatson
93119314Srwatson	/*
94119314Srwatson	 * Speculatively allocate all the memory now to avoid allocating
95119314Srwatson	 * later when we will someday hold a mutex.
96119314Srwatson	 */
97119314Srwatson	name_dup = strdup(name);
98119314Srwatson	if (name_dup == NULL) {
99119314Srwatson		errno = ENOMEM;
100119314Srwatson		return (-1);
101119314Srwatson	}
102119314Srwatson	labels_dup = strdup(labels);
103119314Srwatson	if (labels_dup == NULL) {
104119314Srwatson		free(name_dup);
105119314Srwatson		errno = ENOMEM;
106119314Srwatson		return (-1);
107119314Srwatson	}
108119314Srwatson	ld_new = malloc(sizeof(*ld));
109119314Srwatson	if (ld_new == NULL) {
110119314Srwatson		free(name_dup);
111119314Srwatson		free(labels_dup);
112119314Srwatson		errno = ENOMEM;
113119314Srwatson		return (-1);
114119314Srwatson	}
115119314Srwatson
116119314Srwatson	/*
117119314Srwatson	 * If the type is already present, replace the current entry
118119314Srwatson	 * rather than add a new instance.
119119314Srwatson	 */
120119314Srwatson	for (ld = LIST_FIRST(&label_default_head); ld != NULL;
121119314Srwatson	    ld = LIST_NEXT(ld, ld_entries)) {
122119314Srwatson		if (strcmp(name, ld->ld_name) == 0)
123119314Srwatson			break;
124119314Srwatson	}
125119314Srwatson
126119314Srwatson	if (ld != NULL) {
127119314Srwatson		free(ld->ld_labels);
128119314Srwatson		ld->ld_labels = labels_dup;
129119314Srwatson		labels_dup = NULL;
130119314Srwatson	} else {
131119314Srwatson		ld = ld_new;
132119314Srwatson		ld->ld_name = name_dup;
133119314Srwatson		ld->ld_labels = labels_dup;
134119314Srwatson
135119314Srwatson		ld_new = NULL;
136119314Srwatson		name_dup = NULL;
137119314Srwatson		labels_dup = NULL;
138119314Srwatson
139119314Srwatson		LIST_INSERT_HEAD(&label_default_head, ld, ld_entries);
140119314Srwatson	}
141119314Srwatson
142119314Srwatson	if (name_dup != NULL)
143119314Srwatson		free(name_dup);
144119314Srwatson	if (labels_dup != NULL)
145119314Srwatson		free(labels_dup);
146119314Srwatson	if (ld_new != NULL)
147119314Srwatson		free(ld_new);
148119314Srwatson
149119314Srwatson	return (0);
150119314Srwatson}
151119314Srwatson
152119314Srwatsonstatic char *
153119314Srwatsonnext_token(char **string)
154119314Srwatson{
155119314Srwatson	char *token;
156119314Srwatson
157119314Srwatson	token = strsep(string, " \t");
158119314Srwatson	while (token != NULL && *token == '\0')
159119314Srwatson		token = strsep(string, " \t");
160119314Srwatson
161119314Srwatson	return (token);
162119314Srwatson}
163119314Srwatson
164119314Srwatsonstatic int
165119314Srwatsonmac_init_internal(int ignore_errors)
166119314Srwatson{
167119314Srwatson	const char *filename;
168119314Srwatson	char line[LINE_MAX];
169105698Srwatson	FILE *file;
170105698Srwatson	int error;
171105698Srwatson
172105698Srwatson	error = 0;
173105698Srwatson
174119314Srwatson	LIST_INIT(&label_default_head);
175119314Srwatson
176119314Srwatson	if (!issetugid() && getenv("MAC_CONFFILE") != NULL)
177119314Srwatson		filename = getenv("MAC_CONFFILE");
178119314Srwatson	else
179119314Srwatson		filename = MAC_CONFFILE;
180119314Srwatson	file = fopen(filename, "r");
181105698Srwatson	if (file == NULL)
182105698Srwatson		return (0);
183105698Srwatson
184105698Srwatson	while (fgets(line, LINE_MAX, file)) {
185119314Srwatson		char *arg, *comment, *parse, *statement;
186105698Srwatson
187105698Srwatson		if (line[strlen(line)-1] == '\n')
188105698Srwatson			line[strlen(line)-1] = '\0';
189105698Srwatson		else {
190119314Srwatson			if (ignore_errors)
191119314Srwatson				continue;
192105698Srwatson			fclose(file);
193105698Srwatson			error = EINVAL;
194105698Srwatson			goto just_return;
195105698Srwatson		}
196105698Srwatson
197119314Srwatson		/* Remove any comment. */
198119314Srwatson		comment = line;
199119314Srwatson		parse = strsep(&comment, "#");
200105698Srwatson
201119314Srwatson		/* Blank lines OK. */
202119314Srwatson		statement = next_token(&parse);
203119314Srwatson		if (statement == NULL)
204105698Srwatson			continue;
205105698Srwatson
206119314Srwatson		if (strcmp(statement, "default_labels") == 0) {
207119314Srwatson			char *name, *labels;
208105698Srwatson
209119314Srwatson			name = next_token(&parse);
210119314Srwatson			labels = next_token(&parse);
211119314Srwatson			if (name == NULL || labels == NULL ||
212119314Srwatson			    next_token(&parse) != NULL) {
213119314Srwatson				if (ignore_errors)
214119314Srwatson					continue;
215119314Srwatson				error = EINVAL;
216119314Srwatson				fclose(file);
217119314Srwatson				goto just_return;
218105698Srwatson			}
219105698Srwatson
220119314Srwatson			if (mac_add_type(name, labels) == -1) {
221119314Srwatson				if (ignore_errors)
222119314Srwatson					continue;
223119314Srwatson				fclose(file);
224119314Srwatson				goto just_return;
225105698Srwatson			}
226119314Srwatson		} else if (strcmp(statement, "default_ifnet_labels") == 0 ||
227119314Srwatson		    strcmp(statement, "default_file_labels") == 0 ||
228119314Srwatson		    strcmp(statement, "default_process_labels") == 0) {
229119314Srwatson			char *labels, *type;
230105698Srwatson
231119314Srwatson			if (strcmp(statement, "default_ifnet_labels") == 0)
232119314Srwatson				type = "ifnet";
233119314Srwatson			else if (strcmp(statement, "default_file_labels") == 0)
234119314Srwatson				type = "file";
235119314Srwatson			else if (strcmp(statement, "default_process_labels") ==
236119314Srwatson			    0)
237119314Srwatson				type = "process";
238119314Srwatson
239119314Srwatson			labels = next_token(&parse);
240119314Srwatson			if (labels == NULL || next_token(&parse) != NULL) {
241119314Srwatson				if (ignore_errors)
242119314Srwatson					continue;
243119314Srwatson				error = EINVAL;
244119314Srwatson				fclose(file);
245119314Srwatson				goto just_return;
246105698Srwatson			}
247105698Srwatson
248119314Srwatson			if (mac_add_type(type, labels) == -1) {
249119314Srwatson				if (ignore_errors)
250119314Srwatson					continue;
251119314Srwatson				fclose(file);
252119314Srwatson				goto just_return;
253105698Srwatson			}
254105698Srwatson		} else {
255119314Srwatson			if (ignore_errors)
256119314Srwatson				continue;
257105698Srwatson			fclose(file);
258105698Srwatson			error = EINVAL;
259105698Srwatson			goto just_return;
260105698Srwatson		}
261105698Srwatson	}
262105698Srwatson
263105698Srwatson	fclose(file);
264105698Srwatson
265105698Srwatson	internal_initialized = 1;
266105698Srwatson
267105698Srwatsonjust_return:
268105698Srwatson	if (error != 0)
269105698Srwatson		mac_destroy_internal();
270105698Srwatson	return (error);
271105698Srwatson}
272105698Srwatson
273105698Srwatsonstatic int
274105698Srwatsonmac_maybe_init_internal(void)
275105698Srwatson{
276105698Srwatson
277105698Srwatson	if (!internal_initialized)
278119314Srwatson		return (mac_init_internal(1));
279105698Srwatson	else
280105698Srwatson		return (0);
281105698Srwatson}
282105698Srwatson
283105698Srwatsonint
284105698Srwatsonmac_reload(void)
285105698Srwatson{
286105698Srwatson
287105698Srwatson	if (internal_initialized)
288105698Srwatson		mac_destroy_internal();
289119314Srwatson	return (mac_init_internal(0));
290105698Srwatson}
291105698Srwatson
292105698Srwatsonint
293105698Srwatsonmac_free(struct mac *mac)
294105698Srwatson{
295105698Srwatson
296105698Srwatson	if (mac->m_string != NULL)
297105698Srwatson		free(mac->m_string);
298105698Srwatson	free(mac);
299105698Srwatson
300105698Srwatson	return (0);
301105698Srwatson}
302105698Srwatson
303105698Srwatsonint
304105698Srwatsonmac_from_text(struct mac **mac, const char *text)
305105698Srwatson{
306105698Srwatson
307105698Srwatson	*mac = (struct mac *) malloc(sizeof(**mac));
308105698Srwatson	if (*mac == NULL)
309105698Srwatson		return (ENOMEM);
310105698Srwatson
311105698Srwatson	(*mac)->m_string = strdup(text);
312105698Srwatson	if ((*mac)->m_string == NULL) {
313105698Srwatson		free(*mac);
314105698Srwatson		*mac = NULL;
315105698Srwatson		return (ENOMEM);
316105698Srwatson	}
317105698Srwatson
318105698Srwatson	(*mac)->m_buflen = strlen((*mac)->m_string)+1;
319105698Srwatson
320105698Srwatson	return (0);
321105698Srwatson}
322105698Srwatson
323105698Srwatsonint
324105837Schrismac_to_text(struct mac *mac, char **text)
325105837Schris{
326105837Schris
327105837Schris	*text = strdup(mac->m_string);
328105837Schris	if (*text == NULL)
329105837Schris		return (ENOMEM);
330105837Schris	return (0);
331105837Schris}
332105837Schris
333105837Schrisint
334119317Srwatsonmac_prepare(struct mac **mac, const char *elements)
335105698Srwatson{
336105698Srwatson
337105698Srwatson	if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN)
338105698Srwatson		return (EINVAL);
339105698Srwatson
340105698Srwatson	*mac = (struct mac *) malloc(sizeof(**mac));
341105698Srwatson	if (*mac == NULL)
342105698Srwatson		return (ENOMEM);
343105698Srwatson
344105698Srwatson	(*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN);
345105698Srwatson	if ((*mac)->m_string == NULL) {
346105698Srwatson		free(*mac);
347105698Srwatson		*mac = NULL;
348105698Srwatson		return (ENOMEM);
349105698Srwatson	}
350105698Srwatson
351105698Srwatson	strcpy((*mac)->m_string, elements);
352105698Srwatson	(*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN;
353105698Srwatson
354105698Srwatson	return (0);
355105698Srwatson}
356105698Srwatson
357105698Srwatsonint
358119314Srwatsonmac_prepare_type(struct mac **mac, const char *name)
359119314Srwatson{
360119314Srwatson	struct label_default *ld;
361122732Srwatson	int error;
362119314Srwatson
363122732Srwatson	error = mac_maybe_init_internal();
364122732Srwatson	if (error != 0)
365122732Srwatson		return (error);
366122732Srwatson
367119314Srwatson	for (ld = LIST_FIRST(&label_default_head); ld != NULL;
368119314Srwatson	    ld = LIST_NEXT(ld, ld_entries)) {
369119314Srwatson		if (strcmp(name, ld->ld_name) == 0)
370119314Srwatson			return (mac_prepare(mac, ld->ld_labels));
371119314Srwatson	}
372119314Srwatson
373119588Srwatson	errno = ENOENT;
374119588Srwatson	return (-1);		/* XXXMAC: ENOLABEL */
375119314Srwatson}
376119314Srwatson
377119314Srwatsonint
378119314Srwatsonmac_prepare_ifnet_label(struct mac **mac)
379119314Srwatson{
380119314Srwatson
381119314Srwatson	return (mac_prepare_type(mac, "ifnet"));
382119314Srwatson}
383119314Srwatson
384119314Srwatsonint
385105698Srwatsonmac_prepare_file_label(struct mac **mac)
386105698Srwatson{
387105698Srwatson
388119314Srwatson	return (mac_prepare_type(mac, "file"));
389105698Srwatson}
390105698Srwatson
391105698Srwatsonint
392119314Srwatsonmac_prepare_packet_label(struct mac **mac)
393105698Srwatson{
394105698Srwatson
395119314Srwatson	return (mac_prepare_type(mac, "packet"));
396119314Srwatson}
397105698Srwatson
398105698Srwatsonint
399105698Srwatsonmac_prepare_process_label(struct mac **mac)
400105698Srwatson{
401105698Srwatson
402119314Srwatson	return (mac_prepare_type(mac, "process"));
403105698Srwatson}
404105698Srwatson
405105698Srwatson/*
406105698Srwatson * Simply test whether the TrustedBSD/MAC MIB tree is present; if so,
407105698Srwatson * return 1 to indicate that the system has MAC enabled overall or for
408105698Srwatson * a given policy.
409105698Srwatson */
410105698Srwatsonint
411105698Srwatsonmac_is_present(const char *policyname)
412105698Srwatson{
413105698Srwatson	int mib[5];
414105698Srwatson	size_t siz;
415105698Srwatson	char *mibname;
416105698Srwatson	int error;
417105698Srwatson
418105698Srwatson	if (policyname != NULL) {
419105698Srwatson		if (policyname[strcspn(policyname, ".=")] != '\0') {
420105698Srwatson			errno = EINVAL;
421105698Srwatson			return (-1);
422105698Srwatson		}
423105698Srwatson		mibname = malloc(sizeof("security.mac.") - 1 +
424105698Srwatson		    strlen(policyname) + sizeof(".enabled"));
425105698Srwatson		if (mibname == NULL)
426105698Srwatson			return (-1);
427105698Srwatson		strcpy(mibname, "security.mac.");
428105698Srwatson		strcat(mibname, policyname);
429105698Srwatson		strcat(mibname, ".enabled");
430105698Srwatson		siz = 5;
431105698Srwatson		error = sysctlnametomib(mibname, mib, &siz);
432105698Srwatson		free(mibname);
433105698Srwatson	} else {
434105698Srwatson		siz = 3;
435105698Srwatson		error = sysctlnametomib("security.mac", mib, &siz);
436105698Srwatson	}
437105698Srwatson	if (error == -1) {
438105698Srwatson		switch (errno) {
439105698Srwatson		case ENOTDIR:
440105698Srwatson		case ENOENT:
441105698Srwatson			return (0);
442105698Srwatson		default:
443105698Srwatson			return (error);
444105698Srwatson		}
445105698Srwatson	}
446105698Srwatson	return (1);
447105698Srwatson}
448