]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/posix1e/mac.c
This commit was generated by cvs2svn to compensate for changes in r175261,
[FreeBSD/FreeBSD.git] / lib / libc / posix1e / mac.c
1 /*
2  * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
3  * Copyright (c) 2002, 2003 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$
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 #include <unistd.h>
48
49 #include <sys/mac.h>
50
51 static int      internal_initialized;
52
53 /*
54  * Maintain a list of default label preparations for various object
55  * types.  Each name will appear only once in the list.
56  *
57  * XXXMAC: Not thread-safe.
58  */
59 static LIST_HEAD(, label_default) label_default_head;
60 struct label_default {
61         char                            *ld_name;
62         char                            *ld_labels;
63         LIST_ENTRY(label_default)        ld_entries;
64 };
65
66 static void
67 mac_destroy_labels(void)
68 {
69         struct label_default *ld;
70
71         while ((ld = LIST_FIRST(&label_default_head))) {
72                 free(ld->ld_name);
73                 free(ld->ld_labels);
74                 LIST_REMOVE(ld, ld_entries);
75                 free(ld);
76         }
77 }
78
79 static void
80 mac_destroy_internal(void)
81 {
82
83         mac_destroy_labels();
84
85         internal_initialized = 0;
86 }
87
88 static int
89 mac_add_type(const char *name, const char *labels)
90 {
91         struct label_default *ld, *ld_new;
92         char *name_dup, *labels_dup;
93
94         /*
95          * Speculatively allocate all the memory now to avoid allocating
96          * later when we will someday hold a mutex.
97          */
98         name_dup = strdup(name);
99         if (name_dup == NULL) {
100                 errno = ENOMEM;
101                 return (-1);
102         }
103         labels_dup = strdup(labels);
104         if (labels_dup == NULL) {
105                 free(name_dup);
106                 errno = ENOMEM;
107                 return (-1);
108         }
109         ld_new = malloc(sizeof(*ld));
110         if (ld_new == NULL) {
111                 free(name_dup);
112                 free(labels_dup);
113                 errno = ENOMEM;
114                 return (-1);
115         }
116
117         /*
118          * If the type is already present, replace the current entry
119          * rather than add a new instance.
120          */
121         for (ld = LIST_FIRST(&label_default_head); ld != NULL;
122             ld = LIST_NEXT(ld, ld_entries)) {
123                 if (strcmp(name, ld->ld_name) == 0)
124                         break;
125         }
126
127         if (ld != NULL) {
128                 free(ld->ld_labels);
129                 ld->ld_labels = labels_dup;
130                 labels_dup = NULL;
131         } else {
132                 ld = ld_new;
133                 ld->ld_name = name_dup;
134                 ld->ld_labels = labels_dup;
135
136                 ld_new = NULL;
137                 name_dup = NULL;
138                 labels_dup = NULL;
139
140                 LIST_INSERT_HEAD(&label_default_head, ld, ld_entries);
141         }
142
143         if (name_dup != NULL)
144                 free(name_dup);
145         if (labels_dup != NULL)
146                 free(labels_dup);
147         if (ld_new != NULL)
148                 free(ld_new);
149
150         return (0);
151 }
152
153 static char *
154 next_token(char **string)
155 {
156         char *token;
157
158         token = strsep(string, " \t");
159         while (token != NULL && *token == '\0')
160                 token = strsep(string, " \t");
161
162         return (token);
163 }
164
165 static int
166 mac_init_internal(int ignore_errors)
167 {
168         const char *filename;
169         char line[LINE_MAX];
170         FILE *file;
171         int error;
172
173         error = 0;
174
175         LIST_INIT(&label_default_head);
176
177         if (!issetugid() && getenv("MAC_CONFFILE") != NULL)
178                 filename = getenv("MAC_CONFFILE");
179         else
180                 filename = MAC_CONFFILE;
181         file = fopen(filename, "r");
182         if (file == NULL)
183                 return (0);
184
185         while (fgets(line, LINE_MAX, file)) {
186                 char *comment, *parse, *statement;
187
188                 if (line[strlen(line)-1] == '\n')
189                         line[strlen(line)-1] = '\0';
190                 else {
191                         if (ignore_errors)
192                                 continue;
193                         fclose(file);
194                         error = EINVAL;
195                         goto just_return;
196                 }
197
198                 /* Remove any comment. */
199                 comment = line;
200                 parse = strsep(&comment, "#");
201
202                 /* Blank lines OK. */
203                 statement = next_token(&parse);
204                 if (statement == NULL)
205                         continue;
206
207                 if (strcmp(statement, "default_labels") == 0) {
208                         char *name, *labels;
209
210                         name = next_token(&parse);
211                         labels = next_token(&parse);
212                         if (name == NULL || labels == NULL ||
213                             next_token(&parse) != NULL) {
214                                 if (ignore_errors)
215                                         continue;
216                                 error = EINVAL;
217                                 fclose(file);
218                                 goto just_return;
219                         }
220
221                         if (mac_add_type(name, labels) == -1) {
222                                 if (ignore_errors)
223                                         continue;
224                                 fclose(file);
225                                 goto just_return;
226                         }
227                 } else if (strcmp(statement, "default_ifnet_labels") == 0 ||
228                     strcmp(statement, "default_file_labels") == 0 ||
229                     strcmp(statement, "default_process_labels") == 0) {
230                         char *labels, *type;
231
232                         if (strcmp(statement, "default_ifnet_labels") == 0)
233                                 type = "ifnet";
234                         else if (strcmp(statement, "default_file_labels") == 0)
235                                 type = "file";
236                         else if (strcmp(statement, "default_process_labels") ==
237                             0)
238                                 type = "process";
239
240                         labels = next_token(&parse);
241                         if (labels == NULL || next_token(&parse) != NULL) {
242                                 if (ignore_errors)
243                                         continue;
244                                 error = EINVAL;
245                                 fclose(file);
246                                 goto just_return;
247                         }
248
249                         if (mac_add_type(type, labels) == -1) {
250                                 if (ignore_errors)
251                                         continue;
252                                 fclose(file);
253                                 goto just_return;
254                         }
255                 } else {
256                         if (ignore_errors)
257                                 continue;
258                         fclose(file);
259                         error = EINVAL;
260                         goto just_return;
261                 }
262         }
263
264         fclose(file);
265
266         internal_initialized = 1;
267
268 just_return:
269         if (error != 0)
270                 mac_destroy_internal();
271         return (error);
272 }
273
274 static int
275 mac_maybe_init_internal(void)
276 {
277
278         if (!internal_initialized)
279                 return (mac_init_internal(1));
280         else
281                 return (0);
282 }
283
284 int
285 mac_reload(void)
286 {
287
288         if (internal_initialized)
289                 mac_destroy_internal();
290         return (mac_init_internal(0));
291 }
292
293 int
294 mac_free(struct mac *mac)
295 {
296
297         if (mac->m_string != NULL)
298                 free(mac->m_string);
299         free(mac);
300
301         return (0);
302 }
303
304 int
305 mac_from_text(struct mac **mac, const char *text)
306 {
307
308         *mac = (struct mac *) malloc(sizeof(**mac));
309         if (*mac == NULL)
310                 return (ENOMEM);
311
312         (*mac)->m_string = strdup(text);
313         if ((*mac)->m_string == NULL) {
314                 free(*mac);
315                 *mac = NULL;
316                 return (ENOMEM);
317         }
318
319         (*mac)->m_buflen = strlen((*mac)->m_string)+1;
320
321         return (0);
322 }
323
324 int
325 mac_to_text(struct mac *mac, char **text)
326 {
327
328         *text = strdup(mac->m_string);
329         if (*text == NULL)
330                 return (ENOMEM);
331         return (0);
332 }
333
334 int
335 mac_prepare(struct mac **mac, const char *elements)
336 {
337
338         if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN)
339                 return (EINVAL);
340
341         *mac = (struct mac *) malloc(sizeof(**mac));
342         if (*mac == NULL)
343                 return (ENOMEM);
344
345         (*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN);
346         if ((*mac)->m_string == NULL) {
347                 free(*mac);
348                 *mac = NULL;
349                 return (ENOMEM);
350         }
351
352         strcpy((*mac)->m_string, elements);
353         (*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN;
354
355         return (0);
356 }
357
358 int
359 mac_prepare_type(struct mac **mac, const char *name)
360 {
361         struct label_default *ld;
362         int error;
363
364         error = mac_maybe_init_internal();
365         if (error != 0)
366                 return (error);
367
368         for (ld = LIST_FIRST(&label_default_head); ld != NULL;
369             ld = LIST_NEXT(ld, ld_entries)) {
370                 if (strcmp(name, ld->ld_name) == 0)
371                         return (mac_prepare(mac, ld->ld_labels));
372         }
373
374         errno = ENOENT;
375         return (-1);            /* XXXMAC: ENOLABEL */
376 }
377
378 int
379 mac_prepare_ifnet_label(struct mac **mac)
380 {
381
382         return (mac_prepare_type(mac, "ifnet"));
383 }
384
385 int
386 mac_prepare_file_label(struct mac **mac)
387 {
388
389         return (mac_prepare_type(mac, "file"));
390 }
391
392 int
393 mac_prepare_packet_label(struct mac **mac)
394 {
395
396         return (mac_prepare_type(mac, "packet"));
397 }
398
399 int
400 mac_prepare_process_label(struct mac **mac)
401 {
402
403         return (mac_prepare_type(mac, "process"));
404 }
405
406 /*
407  * Simply test whether the TrustedBSD/MAC MIB tree is present; if so,
408  * return 1 to indicate that the system has MAC enabled overall or for
409  * a given policy.
410  */
411 int
412 mac_is_present(const char *policyname)
413 {
414         int mib[5];
415         size_t siz;
416         char *mibname;
417         int error;
418
419         if (policyname != NULL) {
420                 if (policyname[strcspn(policyname, ".=")] != '\0') {
421                         errno = EINVAL;
422                         return (-1);
423                 }
424                 mibname = malloc(sizeof("security.mac.") - 1 +
425                     strlen(policyname) + sizeof(".enabled"));
426                 if (mibname == NULL)
427                         return (-1);
428                 strcpy(mibname, "security.mac.");
429                 strcat(mibname, policyname);
430                 strcat(mibname, ".enabled");
431                 siz = 5;
432                 error = sysctlnametomib(mibname, mib, &siz);
433                 free(mibname);
434         } else {
435                 siz = 3;
436                 error = sysctlnametomib("security.mac", mib, &siz);
437         }
438         if (error == -1) {
439                 switch (errno) {
440                 case ENOTDIR:
441                 case ENOENT:
442                         return (0);
443                 default:
444                         return (error);
445                 }
446         }
447         return (1);
448 }