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

6-freebsd-12
Last change on this file was bb80d9d, checked in by Sebastian Huber <sebastian.huber@…>, on 08/09/18 at 12:02:09

Update to FreeBSD head 2017-12-01

Git mirror commit e724f51f811a4b2bd29447f8b85ab5c2f9b88266.

Update #3472.

  • Property mode set to 100644
File size: 9.2 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3/*-
4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5 *
6 * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
7 * Copyright (c) 2002, 2003 Networks Associates Technology, Inc.
8 * All rights reserved.
9 *
10 * This software was developed by Robert Watson for the TrustedBSD Project.
11 *
12 * This software was developed for the FreeBSD Project in part by Network
13 * Associates Laboratories, the Security Research Division of Network
14 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
15 * as part of the DARPA CHATS research program.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 *    notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 *    notice, this list of conditions and the following disclaimer in the
24 *    documentation and/or other materials provided with the distribution.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD$");
41
42#include <sys/types.h>
43#include <sys/queue.h>
44#include <sys/sysctl.h>
45
46#include <dlfcn.h>
47#include <errno.h>
48#include <limits.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <unistd.h>
53
54#include <sys/mac.h>
55
56static int      internal_initialized;
57
58/*
59 * Maintain a list of default label preparations for various object
60 * types.  Each name will appear only once in the list.
61 *
62 * XXXMAC: Not thread-safe.
63 */
64static LIST_HEAD(, label_default) label_default_head;
65struct label_default {
66        char                            *ld_name;
67        char                            *ld_labels;
68        LIST_ENTRY(label_default)        ld_entries;
69};
70
71static void
72mac_destroy_labels(void)
73{
74        struct label_default *ld;
75
76        while ((ld = LIST_FIRST(&label_default_head))) {
77                free(ld->ld_name);
78                free(ld->ld_labels);
79                LIST_REMOVE(ld, ld_entries);
80                free(ld);
81        }
82}
83
84static void
85mac_destroy_internal(void)
86{
87
88        mac_destroy_labels();
89
90        internal_initialized = 0;
91}
92
93static int
94mac_add_type(const char *name, const char *labels)
95{
96        struct label_default *ld, *ld_new;
97        char *name_dup, *labels_dup;
98
99        /*
100         * Speculatively allocate all the memory now to avoid allocating
101         * later when we will someday hold a mutex.
102         */
103        name_dup = strdup(name);
104        if (name_dup == NULL) {
105                errno = ENOMEM;
106                return (-1);
107        }
108        labels_dup = strdup(labels);
109        if (labels_dup == NULL) {
110                free(name_dup);
111                errno = ENOMEM;
112                return (-1);
113        }
114        ld_new = malloc(sizeof(*ld));
115        if (ld_new == NULL) {
116                free(name_dup);
117                free(labels_dup);
118                errno = ENOMEM;
119                return (-1);
120        }
121
122        /*
123         * If the type is already present, replace the current entry
124         * rather than add a new instance.
125         */
126        for (ld = LIST_FIRST(&label_default_head); ld != NULL;
127            ld = LIST_NEXT(ld, ld_entries)) {
128                if (strcmp(name, ld->ld_name) == 0)
129                        break;
130        }
131
132        if (ld != NULL) {
133                free(ld->ld_labels);
134                ld->ld_labels = labels_dup;
135                labels_dup = NULL;
136        } else {
137                ld = ld_new;
138                ld->ld_name = name_dup;
139                ld->ld_labels = labels_dup;
140
141                ld_new = NULL;
142                name_dup = NULL;
143                labels_dup = NULL;
144
145                LIST_INSERT_HEAD(&label_default_head, ld, ld_entries);
146        }
147
148        if (name_dup != NULL)
149                free(name_dup);
150        if (labels_dup != NULL)
151                free(labels_dup);
152        if (ld_new != NULL)
153                free(ld_new);
154
155        return (0);
156}
157
158static char *
159next_token(char **string)
160{
161        char *token;
162
163        token = strsep(string, " \t");
164        while (token != NULL && *token == '\0')
165                token = strsep(string, " \t");
166
167        return (token);
168}
169
170static int
171mac_init_internal(int ignore_errors)
172{
173        const char *filename;
174        char line[LINE_MAX];
175        FILE *file;
176        int error;
177
178        error = 0;
179
180        LIST_INIT(&label_default_head);
181
182        if (!issetugid() && getenv("MAC_CONFFILE") != NULL)
183                filename = getenv("MAC_CONFFILE");
184        else
185                filename = MAC_CONFFILE;
186        file = fopen(filename, "re");
187        if (file == NULL)
188                return (0);
189
190        while (fgets(line, LINE_MAX, file)) {
191                char *comment, *parse, *statement;
192
193                if (line[strlen(line)-1] == '\n')
194                        line[strlen(line)-1] = '\0';
195                else {
196                        if (ignore_errors)
197                                continue;
198                        fclose(file);
199                        error = EINVAL;
200                        goto just_return;
201                }
202
203                /* Remove any comment. */
204                comment = line;
205                parse = strsep(&comment, "#");
206
207                /* Blank lines OK. */
208                statement = next_token(&parse);
209                if (statement == NULL)
210                        continue;
211
212                if (strcmp(statement, "default_labels") == 0) {
213                        char *name, *labels;
214
215                        name = next_token(&parse);
216                        labels = next_token(&parse);
217                        if (name == NULL || labels == NULL ||
218                            next_token(&parse) != NULL) {
219                                if (ignore_errors)
220                                        continue;
221                                error = EINVAL;
222                                fclose(file);
223                                goto just_return;
224                        }
225
226                        if (mac_add_type(name, labels) == -1) {
227                                if (ignore_errors)
228                                        continue;
229                                fclose(file);
230                                goto just_return;
231                        }
232                } else if (strcmp(statement, "default_ifnet_labels") == 0 ||
233                    strcmp(statement, "default_file_labels") == 0 ||
234                    strcmp(statement, "default_process_labels") == 0) {
235                        char *labels, *type;
236
237                        if (strcmp(statement, "default_ifnet_labels") == 0)
238                                type = "ifnet";
239                        else if (strcmp(statement, "default_file_labels") == 0)
240                                type = "file";
241                        else if (strcmp(statement, "default_process_labels") ==
242                            0)
243                                type = "process";
244
245                        labels = next_token(&parse);
246                        if (labels == NULL || next_token(&parse) != NULL) {
247                                if (ignore_errors)
248                                        continue;
249                                error = EINVAL;
250                                fclose(file);
251                                goto just_return;
252                        }
253
254                        if (mac_add_type(type, labels) == -1) {
255                                if (ignore_errors)
256                                        continue;
257                                fclose(file);
258                                goto just_return;
259                        }
260                } else {
261                        if (ignore_errors)
262                                continue;
263                        fclose(file);
264                        error = EINVAL;
265                        goto just_return;
266                }
267        }
268
269        fclose(file);
270
271        internal_initialized = 1;
272
273just_return:
274        if (error != 0)
275                mac_destroy_internal();
276        return (error);
277}
278
279static int
280mac_maybe_init_internal(void)
281{
282
283        if (!internal_initialized)
284                return (mac_init_internal(1));
285        else
286                return (0);
287}
288
289int
290mac_reload(void)
291{
292
293        if (internal_initialized)
294                mac_destroy_internal();
295        return (mac_init_internal(0));
296}
297
298int
299mac_free(struct mac *mac)
300{
301
302        if (mac->m_string != NULL)
303                free(mac->m_string);
304        free(mac);
305
306        return (0);
307}
308
309int
310mac_from_text(struct mac **mac, const char *text)
311{
312
313        *mac = (struct mac *) malloc(sizeof(**mac));
314        if (*mac == NULL)
315                return (ENOMEM);
316
317        (*mac)->m_string = strdup(text);
318        if ((*mac)->m_string == NULL) {
319                free(*mac);
320                *mac = NULL;
321                return (ENOMEM);
322        }
323
324        (*mac)->m_buflen = strlen((*mac)->m_string)+1;
325
326        return (0);
327}
328
329int
330mac_to_text(struct mac *mac, char **text)
331{
332
333        *text = strdup(mac->m_string);
334        if (*text == NULL)
335                return (ENOMEM);
336        return (0);
337}
338
339int
340mac_prepare(struct mac **mac, const char *elements)
341{
342
343        if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN)
344                return (EINVAL);
345
346        *mac = (struct mac *) malloc(sizeof(**mac));
347        if (*mac == NULL)
348                return (ENOMEM);
349
350        (*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN);
351        if ((*mac)->m_string == NULL) {
352                free(*mac);
353                *mac = NULL;
354                return (ENOMEM);
355        }
356
357        strcpy((*mac)->m_string, elements);
358        (*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN;
359
360        return (0);
361}
362
363int
364mac_prepare_type(struct mac **mac, const char *name)
365{
366        struct label_default *ld;
367        int error;
368
369        error = mac_maybe_init_internal();
370        if (error != 0)
371                return (error);
372
373        for (ld = LIST_FIRST(&label_default_head); ld != NULL;
374            ld = LIST_NEXT(ld, ld_entries)) {
375                if (strcmp(name, ld->ld_name) == 0)
376                        return (mac_prepare(mac, ld->ld_labels));
377        }
378
379        errno = ENOENT;
380        return (-1);            /* XXXMAC: ENOLABEL */
381}
382
383int
384mac_prepare_ifnet_label(struct mac **mac)
385{
386
387        return (mac_prepare_type(mac, "ifnet"));
388}
389
390int
391mac_prepare_file_label(struct mac **mac)
392{
393
394        return (mac_prepare_type(mac, "file"));
395}
396
397int
398mac_prepare_packet_label(struct mac **mac)
399{
400
401        return (mac_prepare_type(mac, "packet"));
402}
403
404int
405mac_prepare_process_label(struct mac **mac)
406{
407
408        return (mac_prepare_type(mac, "process"));
409}
410
411/*
412 * Simply test whether the TrustedBSD/MAC MIB tree is present; if so,
413 * return 1 to indicate that the system has MAC enabled overall or for
414 * a given policy.
415 */
416int
417mac_is_present(const char *policyname)
418{
419        int mib[5];
420        size_t siz;
421        char *mibname;
422        int error;
423
424        if (policyname != NULL) {
425                if (policyname[strcspn(policyname, ".=")] != '\0') {
426                        errno = EINVAL;
427                        return (-1);
428                }
429                mibname = malloc(sizeof("security.mac.") - 1 +
430                    strlen(policyname) + sizeof(".enabled"));
431                if (mibname == NULL)
432                        return (-1);
433                strcpy(mibname, "security.mac.");
434                strcat(mibname, policyname);
435                strcat(mibname, ".enabled");
436                siz = 5;
437                error = sysctlnametomib(mibname, mib, &siz);
438                free(mibname);
439        } else {
440                siz = 3;
441                error = sysctlnametomib("security.mac", mib, &siz);
442        }
443        if (error == -1) {
444                switch (errno) {
445                case ENOTDIR:
446                case ENOENT:
447                        return (0);
448                default:
449                        return (error);
450                }
451        }
452        return (1);
453}
Note: See TracBrowser for help on using the repository browser.