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