source: rtems-libbsd/freebsd/lib/libc/posix1e/mac.c @ 9a3fa15

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 9a3fa15 was cdf6024, checked in by Sebastian Huber <sebastian.huber@…>, on 10/21/13 at 11:57:22

Add MAC support functions

WARNING: They are not thread-safe! This is a known FreeBSD issue.

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