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
35176901Srwatson#include <sys/cdefs.h>
36176901Srwatson__FBSDID("$FreeBSD$");
37176901Srwatson
38105698Srwatson#include <sys/types.h>
39105698Srwatson#include <sys/queue.h>
40105698Srwatson#include <sys/sysctl.h>
41105698Srwatson
42105698Srwatson#include <dlfcn.h>
43105698Srwatson#include <errno.h>
44106053Swollman#include <limits.h>
45105698Srwatson#include <stdio.h>
46105698Srwatson#include <stdlib.h>
47105698Srwatson#include <string.h>
48124174Snectar#include <unistd.h>
49105698Srwatson
50105698Srwatson#include <sys/mac.h>
51105698Srwatson
52105698Srwatsonstatic int	internal_initialized;
53105698Srwatson
54119314Srwatson/*
55119314Srwatson * Maintain a list of default label preparations for various object
56119314Srwatson * types.  Each name will appear only once in the list.
57119314Srwatson *
58119314Srwatson * XXXMAC: Not thread-safe.
59119314Srwatson */
60122868Srwatsonstatic LIST_HEAD(, label_default) label_default_head;
61119314Srwatsonstruct label_default {
62119314Srwatson	char				*ld_name;
63119314Srwatson	char				*ld_labels;
64119314Srwatson	LIST_ENTRY(label_default)	 ld_entries;
65119314Srwatson};
66105698Srwatson
67105698Srwatsonstatic void
68105698Srwatsonmac_destroy_labels(void)
69105698Srwatson{
70119314Srwatson	struct label_default *ld;
71105698Srwatson
72119314Srwatson	while ((ld = LIST_FIRST(&label_default_head))) {
73119314Srwatson		free(ld->ld_name);
74119314Srwatson		free(ld->ld_labels);
75119314Srwatson		LIST_REMOVE(ld, ld_entries);
76119314Srwatson		free(ld);
77105698Srwatson	}
78105698Srwatson}
79105698Srwatson
80105698Srwatsonstatic void
81105698Srwatsonmac_destroy_internal(void)
82105698Srwatson{
83105698Srwatson
84105698Srwatson	mac_destroy_labels();
85105698Srwatson
86105698Srwatson	internal_initialized = 0;
87105698Srwatson}
88105698Srwatson
89105698Srwatsonstatic int
90119314Srwatsonmac_add_type(const char *name, const char *labels)
91105698Srwatson{
92119314Srwatson	struct label_default *ld, *ld_new;
93119314Srwatson	char *name_dup, *labels_dup;
94119314Srwatson
95119314Srwatson	/*
96119314Srwatson	 * Speculatively allocate all the memory now to avoid allocating
97119314Srwatson	 * later when we will someday hold a mutex.
98119314Srwatson	 */
99119314Srwatson	name_dup = strdup(name);
100119314Srwatson	if (name_dup == NULL) {
101119314Srwatson		errno = ENOMEM;
102119314Srwatson		return (-1);
103119314Srwatson	}
104119314Srwatson	labels_dup = strdup(labels);
105119314Srwatson	if (labels_dup == NULL) {
106119314Srwatson		free(name_dup);
107119314Srwatson		errno = ENOMEM;
108119314Srwatson		return (-1);
109119314Srwatson	}
110119314Srwatson	ld_new = malloc(sizeof(*ld));
111119314Srwatson	if (ld_new == NULL) {
112119314Srwatson		free(name_dup);
113119314Srwatson		free(labels_dup);
114119314Srwatson		errno = ENOMEM;
115119314Srwatson		return (-1);
116119314Srwatson	}
117119314Srwatson
118119314Srwatson	/*
119119314Srwatson	 * If the type is already present, replace the current entry
120119314Srwatson	 * rather than add a new instance.
121119314Srwatson	 */
122119314Srwatson	for (ld = LIST_FIRST(&label_default_head); ld != NULL;
123119314Srwatson	    ld = LIST_NEXT(ld, ld_entries)) {
124119314Srwatson		if (strcmp(name, ld->ld_name) == 0)
125119314Srwatson			break;
126119314Srwatson	}
127119314Srwatson
128119314Srwatson	if (ld != NULL) {
129119314Srwatson		free(ld->ld_labels);
130119314Srwatson		ld->ld_labels = labels_dup;
131119314Srwatson		labels_dup = NULL;
132119314Srwatson	} else {
133119314Srwatson		ld = ld_new;
134119314Srwatson		ld->ld_name = name_dup;
135119314Srwatson		ld->ld_labels = labels_dup;
136119314Srwatson
137119314Srwatson		ld_new = NULL;
138119314Srwatson		name_dup = NULL;
139119314Srwatson		labels_dup = NULL;
140119314Srwatson
141119314Srwatson		LIST_INSERT_HEAD(&label_default_head, ld, ld_entries);
142119314Srwatson	}
143119314Srwatson
144119314Srwatson	if (name_dup != NULL)
145119314Srwatson		free(name_dup);
146119314Srwatson	if (labels_dup != NULL)
147119314Srwatson		free(labels_dup);
148119314Srwatson	if (ld_new != NULL)
149119314Srwatson		free(ld_new);
150119314Srwatson
151119314Srwatson	return (0);
152119314Srwatson}
153119314Srwatson
154119314Srwatsonstatic char *
155119314Srwatsonnext_token(char **string)
156119314Srwatson{
157119314Srwatson	char *token;
158119314Srwatson
159119314Srwatson	token = strsep(string, " \t");
160119314Srwatson	while (token != NULL && *token == '\0')
161119314Srwatson		token = strsep(string, " \t");
162119314Srwatson
163119314Srwatson	return (token);
164119314Srwatson}
165119314Srwatson
166119314Srwatsonstatic int
167119314Srwatsonmac_init_internal(int ignore_errors)
168119314Srwatson{
169119314Srwatson	const char *filename;
170119314Srwatson	char line[LINE_MAX];
171105698Srwatson	FILE *file;
172105698Srwatson	int error;
173105698Srwatson
174105698Srwatson	error = 0;
175105698Srwatson
176119314Srwatson	LIST_INIT(&label_default_head);
177119314Srwatson
178119314Srwatson	if (!issetugid() && getenv("MAC_CONFFILE") != NULL)
179119314Srwatson		filename = getenv("MAC_CONFFILE");
180119314Srwatson	else
181119314Srwatson		filename = MAC_CONFFILE;
182119314Srwatson	file = fopen(filename, "r");
183105698Srwatson	if (file == NULL)
184105698Srwatson		return (0);
185105698Srwatson
186105698Srwatson	while (fgets(line, LINE_MAX, file)) {
187124174Snectar		char *comment, *parse, *statement;
188105698Srwatson
189105698Srwatson		if (line[strlen(line)-1] == '\n')
190105698Srwatson			line[strlen(line)-1] = '\0';
191105698Srwatson		else {
192119314Srwatson			if (ignore_errors)
193119314Srwatson				continue;
194105698Srwatson			fclose(file);
195105698Srwatson			error = EINVAL;
196105698Srwatson			goto just_return;
197105698Srwatson		}
198105698Srwatson
199119314Srwatson		/* Remove any comment. */
200119314Srwatson		comment = line;
201119314Srwatson		parse = strsep(&comment, "#");
202105698Srwatson
203119314Srwatson		/* Blank lines OK. */
204119314Srwatson		statement = next_token(&parse);
205119314Srwatson		if (statement == NULL)
206105698Srwatson			continue;
207105698Srwatson
208119314Srwatson		if (strcmp(statement, "default_labels") == 0) {
209119314Srwatson			char *name, *labels;
210105698Srwatson
211119314Srwatson			name = next_token(&parse);
212119314Srwatson			labels = next_token(&parse);
213119314Srwatson			if (name == NULL || labels == NULL ||
214119314Srwatson			    next_token(&parse) != NULL) {
215119314Srwatson				if (ignore_errors)
216119314Srwatson					continue;
217119314Srwatson				error = EINVAL;
218119314Srwatson				fclose(file);
219119314Srwatson				goto just_return;
220105698Srwatson			}
221105698Srwatson
222119314Srwatson			if (mac_add_type(name, labels) == -1) {
223119314Srwatson				if (ignore_errors)
224119314Srwatson					continue;
225119314Srwatson				fclose(file);
226119314Srwatson				goto just_return;
227105698Srwatson			}
228119314Srwatson		} else if (strcmp(statement, "default_ifnet_labels") == 0 ||
229119314Srwatson		    strcmp(statement, "default_file_labels") == 0 ||
230119314Srwatson		    strcmp(statement, "default_process_labels") == 0) {
231119314Srwatson			char *labels, *type;
232105698Srwatson
233119314Srwatson			if (strcmp(statement, "default_ifnet_labels") == 0)
234119314Srwatson				type = "ifnet";
235119314Srwatson			else if (strcmp(statement, "default_file_labels") == 0)
236119314Srwatson				type = "file";
237119314Srwatson			else if (strcmp(statement, "default_process_labels") ==
238119314Srwatson			    0)
239119314Srwatson				type = "process";
240119314Srwatson
241119314Srwatson			labels = next_token(&parse);
242119314Srwatson			if (labels == NULL || next_token(&parse) != NULL) {
243119314Srwatson				if (ignore_errors)
244119314Srwatson					continue;
245119314Srwatson				error = EINVAL;
246119314Srwatson				fclose(file);
247119314Srwatson				goto just_return;
248105698Srwatson			}
249105698Srwatson
250119314Srwatson			if (mac_add_type(type, labels) == -1) {
251119314Srwatson				if (ignore_errors)
252119314Srwatson					continue;
253119314Srwatson				fclose(file);
254119314Srwatson				goto just_return;
255105698Srwatson			}
256105698Srwatson		} else {
257119314Srwatson			if (ignore_errors)
258119314Srwatson				continue;
259105698Srwatson			fclose(file);
260105698Srwatson			error = EINVAL;
261105698Srwatson			goto just_return;
262105698Srwatson		}
263105698Srwatson	}
264105698Srwatson
265105698Srwatson	fclose(file);
266105698Srwatson
267105698Srwatson	internal_initialized = 1;
268105698Srwatson
269105698Srwatsonjust_return:
270105698Srwatson	if (error != 0)
271105698Srwatson		mac_destroy_internal();
272105698Srwatson	return (error);
273105698Srwatson}
274105698Srwatson
275105698Srwatsonstatic int
276105698Srwatsonmac_maybe_init_internal(void)
277105698Srwatson{
278105698Srwatson
279105698Srwatson	if (!internal_initialized)
280119314Srwatson		return (mac_init_internal(1));
281105698Srwatson	else
282105698Srwatson		return (0);
283105698Srwatson}
284105698Srwatson
285105698Srwatsonint
286105698Srwatsonmac_reload(void)
287105698Srwatson{
288105698Srwatson
289105698Srwatson	if (internal_initialized)
290105698Srwatson		mac_destroy_internal();
291119314Srwatson	return (mac_init_internal(0));
292105698Srwatson}
293105698Srwatson
294105698Srwatsonint
295105698Srwatsonmac_free(struct mac *mac)
296105698Srwatson{
297105698Srwatson
298105698Srwatson	if (mac->m_string != NULL)
299105698Srwatson		free(mac->m_string);
300105698Srwatson	free(mac);
301105698Srwatson
302105698Srwatson	return (0);
303105698Srwatson}
304105698Srwatson
305105698Srwatsonint
306105698Srwatsonmac_from_text(struct mac **mac, const char *text)
307105698Srwatson{
308105698Srwatson
309105698Srwatson	*mac = (struct mac *) malloc(sizeof(**mac));
310105698Srwatson	if (*mac == NULL)
311105698Srwatson		return (ENOMEM);
312105698Srwatson
313105698Srwatson	(*mac)->m_string = strdup(text);
314105698Srwatson	if ((*mac)->m_string == NULL) {
315105698Srwatson		free(*mac);
316105698Srwatson		*mac = NULL;
317105698Srwatson		return (ENOMEM);
318105698Srwatson	}
319105698Srwatson
320105698Srwatson	(*mac)->m_buflen = strlen((*mac)->m_string)+1;
321105698Srwatson
322105698Srwatson	return (0);
323105698Srwatson}
324105698Srwatson
325105698Srwatsonint
326105837Schrismac_to_text(struct mac *mac, char **text)
327105837Schris{
328105837Schris
329105837Schris	*text = strdup(mac->m_string);
330105837Schris	if (*text == NULL)
331105837Schris		return (ENOMEM);
332105837Schris	return (0);
333105837Schris}
334105837Schris
335105837Schrisint
336119317Srwatsonmac_prepare(struct mac **mac, const char *elements)
337105698Srwatson{
338105698Srwatson
339105698Srwatson	if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN)
340105698Srwatson		return (EINVAL);
341105698Srwatson
342105698Srwatson	*mac = (struct mac *) malloc(sizeof(**mac));
343105698Srwatson	if (*mac == NULL)
344105698Srwatson		return (ENOMEM);
345105698Srwatson
346105698Srwatson	(*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN);
347105698Srwatson	if ((*mac)->m_string == NULL) {
348105698Srwatson		free(*mac);
349105698Srwatson		*mac = NULL;
350105698Srwatson		return (ENOMEM);
351105698Srwatson	}
352105698Srwatson
353105698Srwatson	strcpy((*mac)->m_string, elements);
354105698Srwatson	(*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN;
355105698Srwatson
356105698Srwatson	return (0);
357105698Srwatson}
358105698Srwatson
359105698Srwatsonint
360119314Srwatsonmac_prepare_type(struct mac **mac, const char *name)
361119314Srwatson{
362119314Srwatson	struct label_default *ld;
363122732Srwatson	int error;
364119314Srwatson
365122732Srwatson	error = mac_maybe_init_internal();
366122732Srwatson	if (error != 0)
367122732Srwatson		return (error);
368122732Srwatson
369119314Srwatson	for (ld = LIST_FIRST(&label_default_head); ld != NULL;
370119314Srwatson	    ld = LIST_NEXT(ld, ld_entries)) {
371119314Srwatson		if (strcmp(name, ld->ld_name) == 0)
372119314Srwatson			return (mac_prepare(mac, ld->ld_labels));
373119314Srwatson	}
374119314Srwatson
375119588Srwatson	errno = ENOENT;
376119588Srwatson	return (-1);		/* XXXMAC: ENOLABEL */
377119314Srwatson}
378119314Srwatson
379119314Srwatsonint
380119314Srwatsonmac_prepare_ifnet_label(struct mac **mac)
381119314Srwatson{
382119314Srwatson
383119314Srwatson	return (mac_prepare_type(mac, "ifnet"));
384119314Srwatson}
385119314Srwatson
386119314Srwatsonint
387105698Srwatsonmac_prepare_file_label(struct mac **mac)
388105698Srwatson{
389105698Srwatson
390119314Srwatson	return (mac_prepare_type(mac, "file"));
391105698Srwatson}
392105698Srwatson
393105698Srwatsonint
394119314Srwatsonmac_prepare_packet_label(struct mac **mac)
395105698Srwatson{
396105698Srwatson
397119314Srwatson	return (mac_prepare_type(mac, "packet"));
398119314Srwatson}
399105698Srwatson
400105698Srwatsonint
401105698Srwatsonmac_prepare_process_label(struct mac **mac)
402105698Srwatson{
403105698Srwatson
404119314Srwatson	return (mac_prepare_type(mac, "process"));
405105698Srwatson}
406105698Srwatson
407105698Srwatson/*
408105698Srwatson * Simply test whether the TrustedBSD/MAC MIB tree is present; if so,
409105698Srwatson * return 1 to indicate that the system has MAC enabled overall or for
410105698Srwatson * a given policy.
411105698Srwatson */
412105698Srwatsonint
413105698Srwatsonmac_is_present(const char *policyname)
414105698Srwatson{
415105698Srwatson	int mib[5];
416105698Srwatson	size_t siz;
417105698Srwatson	char *mibname;
418105698Srwatson	int error;
419105698Srwatson
420105698Srwatson	if (policyname != NULL) {
421105698Srwatson		if (policyname[strcspn(policyname, ".=")] != '\0') {
422105698Srwatson			errno = EINVAL;
423105698Srwatson			return (-1);
424105698Srwatson		}
425105698Srwatson		mibname = malloc(sizeof("security.mac.") - 1 +
426105698Srwatson		    strlen(policyname) + sizeof(".enabled"));
427105698Srwatson		if (mibname == NULL)
428105698Srwatson			return (-1);
429105698Srwatson		strcpy(mibname, "security.mac.");
430105698Srwatson		strcat(mibname, policyname);
431105698Srwatson		strcat(mibname, ".enabled");
432105698Srwatson		siz = 5;
433105698Srwatson		error = sysctlnametomib(mibname, mib, &siz);
434105698Srwatson		free(mibname);
435105698Srwatson	} else {
436105698Srwatson		siz = 3;
437105698Srwatson		error = sysctlnametomib("security.mac", mib, &siz);
438105698Srwatson	}
439105698Srwatson	if (error == -1) {
440105698Srwatson		switch (errno) {
441105698Srwatson		case ENOTDIR:
442105698Srwatson		case ENOENT:
443105698Srwatson			return (0);
444105698Srwatson		default:
445105698Srwatson			return (error);
446105698Srwatson		}
447105698Srwatson	}
448105698Srwatson	return (1);
449105698Srwatson}
450