Deleted Added
full compact
ugidfw.c (101885) ugidfw.c (104038)
1/*-
2 * Copyright (c) 2002 Networks Associates Technology, Inc.
3 * All rights reserved.
4 *
5 * This software was developed for the FreeBSD Project by NAI Labs, the
6 * Security Research Division of Network Associates, Inc. under
7 * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
8 * CHATS research program.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The names of the authors may not be used to endorse or promote
19 * products derived from this software without specific prior written
20 * permission.
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 *
1/*-
2 * Copyright (c) 2002 Networks Associates Technology, Inc.
3 * All rights reserved.
4 *
5 * This software was developed for the FreeBSD Project by NAI Labs, the
6 * Security Research Division of Network Associates, Inc. under
7 * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
8 * CHATS research program.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The names of the authors may not be used to endorse or promote
19 * products derived from this software without specific prior written
20 * permission.
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: head/lib/libugidfw/ugidfw.c 101885 2002-08-14 22:30:07Z rwatson $
34 * $FreeBSD: head/lib/libugidfw/ugidfw.c 104038 2002-09-27 16:35:19Z rwatson $
35 */
36#include <sys/param.h>
37#include <sys/errno.h>
38#include <sys/time.h>
39#include <sys/sysctl.h>
40#include <sys/vnode.h>
41
42#include <security/mac_bsdextended/mac_bsdextended.h>
43
44#include <grp.h>
45#include <pwd.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49
50#include "ugidfw.h"
51
52/*
53 * Text format for rules: rules contain subjectand object elements, mode.
54 * Each element takes the form "[not] [uid number] [gid number]".
55 * The total form is "subject [element] object [element] mode [mode]".
56 * At least * one of a uid or gid entry must be present; both may also be
57 * present.
58 */
59
60#define MIB "security.mac.bsdextended"
61
62int
63bsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf, size_t buflen)
64{
65 struct group *grp;
66 struct passwd *pwd;
67 char *cur;
68 size_t left, len;
69 int anymode, unknownmode, truncated;
70
71 cur = buf;
72 left = buflen;
73 truncated = 0;
74
75 if (rule->mbr_subject.mbi_flags & (MBI_UID_DEFINED |
76 MBI_GID_DEFINED)) {
77 len = snprintf(cur, left, "subject ");
78 if (len < 0 || len > left)
79 goto truncated;
80 left -= len;
81 cur += len;
82
83 if (rule->mbr_subject.mbi_flags & MBI_NEGATED) {
84 len = snprintf(cur, left, "not ");
85 if (len < 0 || len > left)
86 goto truncated;
87 left -= len;
88 cur += len;
89 }
90 if (rule->mbr_subject.mbi_flags & MBI_UID_DEFINED) {
91 pwd = getpwuid(rule->mbr_subject.mbi_uid);
92 if (pwd != NULL) {
93 len = snprintf(cur, left, "uid %s ",
94 pwd->pw_name);
95 if (len < 0 || len > left)
96 goto truncated;
97 left -= len;
98 cur += len;
99 } else {
100 len = snprintf(cur, left, "uid %u ",
101 rule->mbr_subject.mbi_uid);
102 if (len < 0 || len > left)
103 goto truncated;
104 left -= len;
105 cur += len;
106 }
107 }
108 if (rule->mbr_subject.mbi_flags & MBI_GID_DEFINED) {
109 grp = getgrgid(rule->mbr_subject.mbi_gid);
110 if (grp != NULL) {
111 len = snprintf(cur, left, "gid %s ",
112 grp->gr_name);
113 if (len < 0 || len > left)
114 goto truncated;
115 left -= len;
116 cur += len;
117 } else {
118 len = snprintf(cur, left, "gid %u ",
119 rule->mbr_subject.mbi_gid);
120 if (len < 0 || len > left)
121 goto truncated;
122 left -= len;
123 cur += len;
124 }
125 }
126 }
127 if (rule->mbr_object.mbi_flags & (MBI_UID_DEFINED |
128 MBI_GID_DEFINED)) {
129 len = snprintf(cur, left, "object ");
130 if (len < 0 || len > left)
131 goto truncated;
132 left -= len;
133 cur += len;
134
135 if (rule->mbr_object.mbi_flags & MBI_NEGATED) {
136 len = snprintf(cur, left, "not ");
137 if (len < 0 || len > left)
138 goto truncated;
139 left -= len;
140 cur += len;
141 }
142 if (rule->mbr_object.mbi_flags & MBI_UID_DEFINED) {
143 pwd = getpwuid(rule->mbr_object.mbi_uid);
144 if (pwd != NULL) {
145 len = snprintf(cur, left, "uid %s ",
146 pwd->pw_name);
147 if (len < 0 || len > left)
148 goto truncated;
149 left -= len;
150 cur += len;
151 } else {
152 len = snprintf(cur, left, "uid %u ",
153 rule->mbr_object.mbi_uid);
154 left -= len;
155 cur += len;
156 }
157 }
158 if (rule->mbr_object.mbi_flags & MBI_GID_DEFINED) {
159 grp = getgrgid(rule->mbr_object.mbi_gid);
160 if (grp != NULL) {
161 len = snprintf(cur, left, "gid %s ",
162 grp->gr_name);
163 if (len < 0 || len > left)
164 goto truncated;
165 left -= len;
166 cur += len;
167 } else {
168 len = snprintf(cur, left, "gid %u ",
169 rule->mbr_object.mbi_gid);
170 if (len < 0 || len > left)
171 goto truncated;
172 left -= len;
173 cur += len;
174 }
175 }
176 }
177
178 len = snprintf(cur, left, "mode ");
179 if (len < 0 || len > left)
180 goto truncated;
181 left -= len;
182 cur += len;
183
184 anymode = (rule->mbr_mode & VALLPERM);
185 unknownmode = (rule->mbr_mode & ~VALLPERM);
186
187 if (rule->mbr_mode & VADMIN) {
188 len = snprintf(cur, left, "a");
189 if (len < 0 || len > left)
190 goto truncated;
191
192 left -= len;
193 cur += len;
194 }
195 if (rule->mbr_mode & VREAD) {
196 len = snprintf(cur, left, "r");
197 if (len < 0 || len > left)
198 goto truncated;
199
200 left -= len;
201 cur += len;
202 }
203 if (rule->mbr_mode & VSTAT) {
204 len = snprintf(cur, left, "s");
205 if (len < 0 || len > left)
206 goto truncated;
207
208 left -= len;
209 cur += len;
210 }
211 if (rule->mbr_mode & VWRITE) {
212 len = snprintf(cur, left, "w");
213 if (len < 0 || len > left)
214 goto truncated;
215
216 left -= len;
217 cur += len;
218 }
219 if (rule->mbr_mode & VEXEC) {
220 len = snprintf(cur, left, "x");
221 if (len < 0 || len > left)
222 goto truncated;
223
224 left -= len;
225 cur += len;
226 }
227 if (!anymode) {
228 len = snprintf(cur, left, "n");
229 if (len < 0 || len > left)
230 goto truncated;
231
232 left -= len;
233 cur += len;
234 }
235 if (unknownmode) {
236 len = snprintf(cur, left, "?");
237 if (len < 0 || len > left)
238 goto truncated;
239
240 left -= len;
241 cur += len;
242 }
243
244 return (0);
245
246truncated:
247 return (-1);
248}
249
250int
251bsde_parse_identity(int argc, char *argv[],
252 struct mac_bsdextended_identity *identity, size_t buflen, char *errstr)
253{
254 struct group *grp;
255 struct passwd *pwd;
256 int uid_seen, gid_seen, not_seen;
257 int current;
258 char *endp;
259 long value;
260 uid_t uid;
261 gid_t gid;
262 size_t len;
263
264 if (argc == 0) {
265 len = snprintf(errstr, buflen, "Identity must not be empty");
266 return (-1);
267 }
268
269 current = 0;
270
271 /* First element might be "not". */
272 if (strcmp("not", argv[0]) == 0) {
273 not_seen = 1;
274 current++;
275 } else
276 not_seen = 0;
277
278 if (current >= argc) {
279 len = snprintf(errstr, buflen, "Identity short");
280 return (-1);
281 }
282
283 uid_seen = 0;
284 uid = 0;
285 gid_seen = 0;
286 gid = 0;
287
288 /* First phrase: uid [uid] or gid[gid]. */
289 if (strcmp("uid", argv[current]) == 0) {
290 if (current + 2 > argc) {
291 len = snprintf(errstr, buflen, "uid short");
292 return (-1);
293 }
294 pwd = getpwnam(argv[current+1]);
295 if (pwd != NULL)
296 uid = pwd->pw_uid;
297 else {
298 value = strtol(argv[current+1], &endp, 10);
299 if (*endp != '\0') {
300 len = snprintf(errstr, buflen,
301 "invalid uid: '%s'",
302 argv[current+1]);
303 return (-1);
304 }
305 uid = value;
306 }
307 uid_seen = 1;
308 current += 2;
309 } else if (strcmp("gid", argv[current]) == 0) {
310 if (current + 2 > argc) {
311 len = snprintf(errstr, buflen, "gid short");
312 return (-1);
313 }
314 grp = getgrnam(argv[current+1]);
315 if (grp != NULL)
316 gid = grp->gr_gid;
317 else {
318 value = strtol(argv[current+1], &endp, 10);
319 if (*endp != '\0') {
320 len = snprintf(errstr, buflen,
321 "invalid gid: '%s'",
322 argv[current+1]);
323 return (-1);
324 }
325 gid = value;
326 }
327 gid_seen = 1;
328 current += 2;
329 } else {
330 len = snprintf(errstr, buflen, "'%s' not expected",
331 argv[current]);
332 return (-1);
333 }
334
335 /* Onto optional second phrase. */
336 if (current + 1 < argc) {
337 /* Second phrase: uid [uid] or gid [gid], but not a repeat. */
338 if (strcmp("uid", argv[current]) == 0) {
339 if (uid_seen) {
340 len = snprintf(errstr, buflen,
341 "Only one uid permitted per identity clause");
342 return (-1);
343 }
344 if (current + 2 > argc) {
345 len = snprintf(errstr, buflen, "uid short");
346 return (-1);
347 }
348 value = strtol(argv[current+1], &endp, 10);
349 if (*endp != '\0') {
350 len = snprintf(errstr, buflen, "invalid uid: '%s'",
351 argv[current+1]);
352 return (-1);
353 }
354 uid = value;
355 uid_seen = 1;
356 current += 2;
357 } else if (strcmp("gid", argv[current]) == 0) {
358 if (gid_seen) {
359 len = snprintf(errstr, buflen,
360 "Only one gid permitted per identity clause");
361 return (-1);
362 }
363 if (current + 2 > argc) {
364 len = snprintf(errstr, buflen, "gid short");
365 return (-1);
366 }
367 value = strtol(argv[current+1], &endp, 10);
368 if (*endp != '\0') {
369 len = snprintf(errstr, buflen, "invalid gid: '%s'",
370 argv[current+1]);
371 return (-1);
372 }
373 gid = value;
374 gid_seen = 1;
375 current += 2;
376 } else {
377 len = snprintf(errstr, buflen, "'%s' not expected",
378 argv[current]);
379 return (-1);
380 }
381 }
382
383 if (current +1 < argc) {
384 len = snprintf(errstr, buflen, "'%s' not expected",
385 argv[current]);
386 return (-1);
387 }
388
389 /* Fill out the identity. */
390 identity->mbi_flags = 0;
391
392 if (not_seen)
393 identity->mbi_flags |= MBI_NEGATED;
394
395 if (uid_seen) {
396 identity->mbi_flags |= MBI_UID_DEFINED;
397 identity->mbi_uid = uid;
398 } else
399 identity->mbi_uid = 0;
400
401 if (gid_seen) {
402 identity->mbi_flags |= MBI_GID_DEFINED;
403 identity->mbi_gid = gid;
404 } else
405 identity->mbi_gid = 0;
406
407 return (0);
408}
409
410int
411bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
412 char *errstr)
413{
414 size_t len;
415 int i;
416
417 if (argc == 0) {
418 len = snprintf(errstr, buflen, "mode expects mode value");
419 return (-1);
420 }
421
422 if (argc != 1) {
423 len = snprintf(errstr, buflen, "'%s' unexpected", argv[1]);
424 return (-1);
425 }
426
427 *mode = 0;
428 for (i = 0; i < strlen(argv[0]); i++) {
429 switch (argv[0][i]) {
430 case 'a':
431 *mode |= VADMIN;
432 break;
433 case 'r':
434 *mode |= VREAD;
435 break;
436 case 's':
437 *mode |= VSTAT;
438 break;
439 case 'w':
440 *mode |= VWRITE;
441 break;
442 case 'x':
443 *mode |= VEXEC;
444 break;
445 case 'n':
446 /* ignore */
447 break;
448 default:
449 len = snprintf(errstr, buflen, "Unknown mode letter: %c",
450 argv[0][i]);
451 return (-1);
452 }
453 }
454
455 return (0);
456}
457
458int
459bsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule,
460 size_t buflen, char *errstr)
461{
462 int subject, subject_elements, subject_elements_length;
463 int object, object_elements, object_elements_length;
464 int mode, mode_elements, mode_elements_length;
465 int error, i;
466 size_t len;
467
468 bzero(rule, sizeof(*rule));
469
470 if (argc < 1) {
471 len = snprintf(errstr, buflen, "Rule must begin with subject");
472 return (-1);
473 }
474
475 if (strcmp(argv[0], "subject") != 0) {
476 len = snprintf(errstr, buflen, "Rule must begin with subject");
477 return (-1);
478 }
479 subject = 0;
480 subject_elements = 1;
481
482 /* Search forward for object. */
483
484 object = -1;
485 for (i = 1; i < argc; i++)
486 if (strcmp(argv[i], "object") == 0)
487 object = i;
488
489 if (object == -1) {
490 len = snprintf(errstr, buflen, "Rule must contain an object");
491 return (-1);
492 }
493
494 /* Search forward for mode. */
495 mode = -1;
496 for (i = object; i < argc; i++)
497 if (strcmp(argv[i], "mode") == 0)
498 mode = i;
499
500 if (mode == -1) {
501 len = snprintf(errstr, buflen, "Rule must contain mode");
502 return (-1);
503 }
504
505 subject_elements_length = object - subject - 1;
506 object_elements = object + 1;
507 object_elements_length = mode - object_elements;
508 mode_elements = mode + 1;
509 mode_elements_length = argc - mode_elements;
510
511 error = bsde_parse_identity(subject_elements_length,
512 argv + subject_elements, &rule->mbr_subject, buflen, errstr);
513 if (error)
514 return (-1);
515
516 error = bsde_parse_identity(object_elements_length,
517 argv + object_elements, &rule->mbr_object, buflen, errstr);
518 if (error)
519 return (-1);
520
521 error = bsde_parse_mode(mode_elements_length, argv + mode_elements,
522 &rule->mbr_mode, buflen, errstr);
523 if (error)
524 return (-1);
525
526 return (0);
527}
528
529int
530bsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule,
531 size_t buflen, char *errstr)
532{
533 char *stringdup, *stringp, *argv[20], **ap;
534 int argc, error;
535
536 stringp = stringdup = strdup(string);
537 while (*stringp == ' ' || *stringp == '\t')
538 stringp++;
539
540 argc = 0;
541 for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) {
542 argc++;
543 if (**ap != '\0')
544 if (++ap >= &argv[20])
545 break;
546 }
547
548 error = bsde_parse_rule(argc, argv, rule, buflen, errstr);
549
550 free(stringdup);
551
552 return (error);
553}
554
555int
35 */
36#include <sys/param.h>
37#include <sys/errno.h>
38#include <sys/time.h>
39#include <sys/sysctl.h>
40#include <sys/vnode.h>
41
42#include <security/mac_bsdextended/mac_bsdextended.h>
43
44#include <grp.h>
45#include <pwd.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49
50#include "ugidfw.h"
51
52/*
53 * Text format for rules: rules contain subjectand object elements, mode.
54 * Each element takes the form "[not] [uid number] [gid number]".
55 * The total form is "subject [element] object [element] mode [mode]".
56 * At least * one of a uid or gid entry must be present; both may also be
57 * present.
58 */
59
60#define MIB "security.mac.bsdextended"
61
62int
63bsde_rule_to_string(struct mac_bsdextended_rule *rule, char *buf, size_t buflen)
64{
65 struct group *grp;
66 struct passwd *pwd;
67 char *cur;
68 size_t left, len;
69 int anymode, unknownmode, truncated;
70
71 cur = buf;
72 left = buflen;
73 truncated = 0;
74
75 if (rule->mbr_subject.mbi_flags & (MBI_UID_DEFINED |
76 MBI_GID_DEFINED)) {
77 len = snprintf(cur, left, "subject ");
78 if (len < 0 || len > left)
79 goto truncated;
80 left -= len;
81 cur += len;
82
83 if (rule->mbr_subject.mbi_flags & MBI_NEGATED) {
84 len = snprintf(cur, left, "not ");
85 if (len < 0 || len > left)
86 goto truncated;
87 left -= len;
88 cur += len;
89 }
90 if (rule->mbr_subject.mbi_flags & MBI_UID_DEFINED) {
91 pwd = getpwuid(rule->mbr_subject.mbi_uid);
92 if (pwd != NULL) {
93 len = snprintf(cur, left, "uid %s ",
94 pwd->pw_name);
95 if (len < 0 || len > left)
96 goto truncated;
97 left -= len;
98 cur += len;
99 } else {
100 len = snprintf(cur, left, "uid %u ",
101 rule->mbr_subject.mbi_uid);
102 if (len < 0 || len > left)
103 goto truncated;
104 left -= len;
105 cur += len;
106 }
107 }
108 if (rule->mbr_subject.mbi_flags & MBI_GID_DEFINED) {
109 grp = getgrgid(rule->mbr_subject.mbi_gid);
110 if (grp != NULL) {
111 len = snprintf(cur, left, "gid %s ",
112 grp->gr_name);
113 if (len < 0 || len > left)
114 goto truncated;
115 left -= len;
116 cur += len;
117 } else {
118 len = snprintf(cur, left, "gid %u ",
119 rule->mbr_subject.mbi_gid);
120 if (len < 0 || len > left)
121 goto truncated;
122 left -= len;
123 cur += len;
124 }
125 }
126 }
127 if (rule->mbr_object.mbi_flags & (MBI_UID_DEFINED |
128 MBI_GID_DEFINED)) {
129 len = snprintf(cur, left, "object ");
130 if (len < 0 || len > left)
131 goto truncated;
132 left -= len;
133 cur += len;
134
135 if (rule->mbr_object.mbi_flags & MBI_NEGATED) {
136 len = snprintf(cur, left, "not ");
137 if (len < 0 || len > left)
138 goto truncated;
139 left -= len;
140 cur += len;
141 }
142 if (rule->mbr_object.mbi_flags & MBI_UID_DEFINED) {
143 pwd = getpwuid(rule->mbr_object.mbi_uid);
144 if (pwd != NULL) {
145 len = snprintf(cur, left, "uid %s ",
146 pwd->pw_name);
147 if (len < 0 || len > left)
148 goto truncated;
149 left -= len;
150 cur += len;
151 } else {
152 len = snprintf(cur, left, "uid %u ",
153 rule->mbr_object.mbi_uid);
154 left -= len;
155 cur += len;
156 }
157 }
158 if (rule->mbr_object.mbi_flags & MBI_GID_DEFINED) {
159 grp = getgrgid(rule->mbr_object.mbi_gid);
160 if (grp != NULL) {
161 len = snprintf(cur, left, "gid %s ",
162 grp->gr_name);
163 if (len < 0 || len > left)
164 goto truncated;
165 left -= len;
166 cur += len;
167 } else {
168 len = snprintf(cur, left, "gid %u ",
169 rule->mbr_object.mbi_gid);
170 if (len < 0 || len > left)
171 goto truncated;
172 left -= len;
173 cur += len;
174 }
175 }
176 }
177
178 len = snprintf(cur, left, "mode ");
179 if (len < 0 || len > left)
180 goto truncated;
181 left -= len;
182 cur += len;
183
184 anymode = (rule->mbr_mode & VALLPERM);
185 unknownmode = (rule->mbr_mode & ~VALLPERM);
186
187 if (rule->mbr_mode & VADMIN) {
188 len = snprintf(cur, left, "a");
189 if (len < 0 || len > left)
190 goto truncated;
191
192 left -= len;
193 cur += len;
194 }
195 if (rule->mbr_mode & VREAD) {
196 len = snprintf(cur, left, "r");
197 if (len < 0 || len > left)
198 goto truncated;
199
200 left -= len;
201 cur += len;
202 }
203 if (rule->mbr_mode & VSTAT) {
204 len = snprintf(cur, left, "s");
205 if (len < 0 || len > left)
206 goto truncated;
207
208 left -= len;
209 cur += len;
210 }
211 if (rule->mbr_mode & VWRITE) {
212 len = snprintf(cur, left, "w");
213 if (len < 0 || len > left)
214 goto truncated;
215
216 left -= len;
217 cur += len;
218 }
219 if (rule->mbr_mode & VEXEC) {
220 len = snprintf(cur, left, "x");
221 if (len < 0 || len > left)
222 goto truncated;
223
224 left -= len;
225 cur += len;
226 }
227 if (!anymode) {
228 len = snprintf(cur, left, "n");
229 if (len < 0 || len > left)
230 goto truncated;
231
232 left -= len;
233 cur += len;
234 }
235 if (unknownmode) {
236 len = snprintf(cur, left, "?");
237 if (len < 0 || len > left)
238 goto truncated;
239
240 left -= len;
241 cur += len;
242 }
243
244 return (0);
245
246truncated:
247 return (-1);
248}
249
250int
251bsde_parse_identity(int argc, char *argv[],
252 struct mac_bsdextended_identity *identity, size_t buflen, char *errstr)
253{
254 struct group *grp;
255 struct passwd *pwd;
256 int uid_seen, gid_seen, not_seen;
257 int current;
258 char *endp;
259 long value;
260 uid_t uid;
261 gid_t gid;
262 size_t len;
263
264 if (argc == 0) {
265 len = snprintf(errstr, buflen, "Identity must not be empty");
266 return (-1);
267 }
268
269 current = 0;
270
271 /* First element might be "not". */
272 if (strcmp("not", argv[0]) == 0) {
273 not_seen = 1;
274 current++;
275 } else
276 not_seen = 0;
277
278 if (current >= argc) {
279 len = snprintf(errstr, buflen, "Identity short");
280 return (-1);
281 }
282
283 uid_seen = 0;
284 uid = 0;
285 gid_seen = 0;
286 gid = 0;
287
288 /* First phrase: uid [uid] or gid[gid]. */
289 if (strcmp("uid", argv[current]) == 0) {
290 if (current + 2 > argc) {
291 len = snprintf(errstr, buflen, "uid short");
292 return (-1);
293 }
294 pwd = getpwnam(argv[current+1]);
295 if (pwd != NULL)
296 uid = pwd->pw_uid;
297 else {
298 value = strtol(argv[current+1], &endp, 10);
299 if (*endp != '\0') {
300 len = snprintf(errstr, buflen,
301 "invalid uid: '%s'",
302 argv[current+1]);
303 return (-1);
304 }
305 uid = value;
306 }
307 uid_seen = 1;
308 current += 2;
309 } else if (strcmp("gid", argv[current]) == 0) {
310 if (current + 2 > argc) {
311 len = snprintf(errstr, buflen, "gid short");
312 return (-1);
313 }
314 grp = getgrnam(argv[current+1]);
315 if (grp != NULL)
316 gid = grp->gr_gid;
317 else {
318 value = strtol(argv[current+1], &endp, 10);
319 if (*endp != '\0') {
320 len = snprintf(errstr, buflen,
321 "invalid gid: '%s'",
322 argv[current+1]);
323 return (-1);
324 }
325 gid = value;
326 }
327 gid_seen = 1;
328 current += 2;
329 } else {
330 len = snprintf(errstr, buflen, "'%s' not expected",
331 argv[current]);
332 return (-1);
333 }
334
335 /* Onto optional second phrase. */
336 if (current + 1 < argc) {
337 /* Second phrase: uid [uid] or gid [gid], but not a repeat. */
338 if (strcmp("uid", argv[current]) == 0) {
339 if (uid_seen) {
340 len = snprintf(errstr, buflen,
341 "Only one uid permitted per identity clause");
342 return (-1);
343 }
344 if (current + 2 > argc) {
345 len = snprintf(errstr, buflen, "uid short");
346 return (-1);
347 }
348 value = strtol(argv[current+1], &endp, 10);
349 if (*endp != '\0') {
350 len = snprintf(errstr, buflen, "invalid uid: '%s'",
351 argv[current+1]);
352 return (-1);
353 }
354 uid = value;
355 uid_seen = 1;
356 current += 2;
357 } else if (strcmp("gid", argv[current]) == 0) {
358 if (gid_seen) {
359 len = snprintf(errstr, buflen,
360 "Only one gid permitted per identity clause");
361 return (-1);
362 }
363 if (current + 2 > argc) {
364 len = snprintf(errstr, buflen, "gid short");
365 return (-1);
366 }
367 value = strtol(argv[current+1], &endp, 10);
368 if (*endp != '\0') {
369 len = snprintf(errstr, buflen, "invalid gid: '%s'",
370 argv[current+1]);
371 return (-1);
372 }
373 gid = value;
374 gid_seen = 1;
375 current += 2;
376 } else {
377 len = snprintf(errstr, buflen, "'%s' not expected",
378 argv[current]);
379 return (-1);
380 }
381 }
382
383 if (current +1 < argc) {
384 len = snprintf(errstr, buflen, "'%s' not expected",
385 argv[current]);
386 return (-1);
387 }
388
389 /* Fill out the identity. */
390 identity->mbi_flags = 0;
391
392 if (not_seen)
393 identity->mbi_flags |= MBI_NEGATED;
394
395 if (uid_seen) {
396 identity->mbi_flags |= MBI_UID_DEFINED;
397 identity->mbi_uid = uid;
398 } else
399 identity->mbi_uid = 0;
400
401 if (gid_seen) {
402 identity->mbi_flags |= MBI_GID_DEFINED;
403 identity->mbi_gid = gid;
404 } else
405 identity->mbi_gid = 0;
406
407 return (0);
408}
409
410int
411bsde_parse_mode(int argc, char *argv[], mode_t *mode, size_t buflen,
412 char *errstr)
413{
414 size_t len;
415 int i;
416
417 if (argc == 0) {
418 len = snprintf(errstr, buflen, "mode expects mode value");
419 return (-1);
420 }
421
422 if (argc != 1) {
423 len = snprintf(errstr, buflen, "'%s' unexpected", argv[1]);
424 return (-1);
425 }
426
427 *mode = 0;
428 for (i = 0; i < strlen(argv[0]); i++) {
429 switch (argv[0][i]) {
430 case 'a':
431 *mode |= VADMIN;
432 break;
433 case 'r':
434 *mode |= VREAD;
435 break;
436 case 's':
437 *mode |= VSTAT;
438 break;
439 case 'w':
440 *mode |= VWRITE;
441 break;
442 case 'x':
443 *mode |= VEXEC;
444 break;
445 case 'n':
446 /* ignore */
447 break;
448 default:
449 len = snprintf(errstr, buflen, "Unknown mode letter: %c",
450 argv[0][i]);
451 return (-1);
452 }
453 }
454
455 return (0);
456}
457
458int
459bsde_parse_rule(int argc, char *argv[], struct mac_bsdextended_rule *rule,
460 size_t buflen, char *errstr)
461{
462 int subject, subject_elements, subject_elements_length;
463 int object, object_elements, object_elements_length;
464 int mode, mode_elements, mode_elements_length;
465 int error, i;
466 size_t len;
467
468 bzero(rule, sizeof(*rule));
469
470 if (argc < 1) {
471 len = snprintf(errstr, buflen, "Rule must begin with subject");
472 return (-1);
473 }
474
475 if (strcmp(argv[0], "subject") != 0) {
476 len = snprintf(errstr, buflen, "Rule must begin with subject");
477 return (-1);
478 }
479 subject = 0;
480 subject_elements = 1;
481
482 /* Search forward for object. */
483
484 object = -1;
485 for (i = 1; i < argc; i++)
486 if (strcmp(argv[i], "object") == 0)
487 object = i;
488
489 if (object == -1) {
490 len = snprintf(errstr, buflen, "Rule must contain an object");
491 return (-1);
492 }
493
494 /* Search forward for mode. */
495 mode = -1;
496 for (i = object; i < argc; i++)
497 if (strcmp(argv[i], "mode") == 0)
498 mode = i;
499
500 if (mode == -1) {
501 len = snprintf(errstr, buflen, "Rule must contain mode");
502 return (-1);
503 }
504
505 subject_elements_length = object - subject - 1;
506 object_elements = object + 1;
507 object_elements_length = mode - object_elements;
508 mode_elements = mode + 1;
509 mode_elements_length = argc - mode_elements;
510
511 error = bsde_parse_identity(subject_elements_length,
512 argv + subject_elements, &rule->mbr_subject, buflen, errstr);
513 if (error)
514 return (-1);
515
516 error = bsde_parse_identity(object_elements_length,
517 argv + object_elements, &rule->mbr_object, buflen, errstr);
518 if (error)
519 return (-1);
520
521 error = bsde_parse_mode(mode_elements_length, argv + mode_elements,
522 &rule->mbr_mode, buflen, errstr);
523 if (error)
524 return (-1);
525
526 return (0);
527}
528
529int
530bsde_parse_rule_string(const char *string, struct mac_bsdextended_rule *rule,
531 size_t buflen, char *errstr)
532{
533 char *stringdup, *stringp, *argv[20], **ap;
534 int argc, error;
535
536 stringp = stringdup = strdup(string);
537 while (*stringp == ' ' || *stringp == '\t')
538 stringp++;
539
540 argc = 0;
541 for (ap = argv; (*ap = strsep(&stringp, " \t")) != NULL;) {
542 argc++;
543 if (**ap != '\0')
544 if (++ap >= &argv[20])
545 break;
546 }
547
548 error = bsde_parse_rule(argc, argv, rule, buflen, errstr);
549
550 free(stringdup);
551
552 return (error);
553}
554
555int
556bsde_get_mib(const char *string, int *name, int *namelen)
556bsde_get_mib(const char *string, int *name, size_t *namelen)
557{
557{
558 int error, len;
558 size_t len;
559 int error;
559
560 len = *namelen;
561 error = sysctlnametomib(string, name, &len);
562 if (error)
563 return (error);
564
565 *namelen = len;
566 return (0);
567}
568
569int
570bsde_get_rule_count(size_t buflen, char *errstr)
571{
572 size_t len;
573 int error;
574 int rule_count;
575
576 len = sizeof(rule_count);
577 error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, NULL);
578 if (error) {
579 len = snprintf(errstr, buflen, strerror(errno));
580 return (-1);
581 }
582 if (len != sizeof(rule_count)) {
583 len = snprintf(errstr, buflen, "Data error in %s.rule_count",
584 MIB);
585 return (-1);
586 }
587
588 return (rule_count);
589}
590
591int
592bsde_get_rule_slots(size_t buflen, char *errstr)
593{
594 size_t len;
595 int error;
596 int rule_slots;
597
598 len = sizeof(rule_slots);
599 error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL,
600 NULL);
601 if (error) {
602 len = snprintf(errstr, buflen, strerror(errno));
603 return (-1);
604 }
605 if (len != sizeof(rule_slots)) {
606 len = snprintf(errstr, buflen, "Data error in %s.rule_slots",
607 MIB);
608 return (-1);
609 }
610
611 return (rule_slots);
612}
613
614/*
615 * Returns 0 for success;
616 * Returns -1 for failure;
617 * Returns -2 for not present
618 */
619int
620bsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen,
621 char *errstr)
622{
623 int name[10];
624 size_t len, size;
625 int error;
626
627 len = 10;
628 error = bsde_get_mib(MIB ".rules", name, &len);
629 if (error) {
630 len = snprintf(errstr, errlen, "%s: %s", MIB ".rules",
631 strerror(errno));
632 return (-1);
633 }
634
635 size = sizeof(*rule);
636 name[len] = rulenum;
637 len++;
638 error = sysctl(name, len, rule, &size, NULL, 0);
639 if (error == -1 && errno == ENOENT)
640 return (-2);
641 if (error) {
642 len = snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules",
643 rulenum, strerror(errno));
644 return (-1);
645 } else if (size != sizeof(*rule)) {
646 len = snprintf(errstr, errlen, "Data error in %s.%d: %s",
647 MIB ".rules", rulenum, strerror(errno));
648 return (-1);
649 }
650
651 return (0);
652}
653
654int
655bsde_delete_rule(int rulenum, size_t buflen, char *errstr)
656{
657 struct mac_bsdextended_rule rule;
658 int name[10];
659 size_t len, size;
660 int error;
661
662 len = 10;
663 error = bsde_get_mib(MIB ".rules", name, &len);
664 if (error) {
665 len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
666 strerror(errno));
667 return (-1);
668 }
669
670 name[len] = rulenum;
671 len++;
672
673 size = sizeof(rule);
674 error = sysctl(name, len, NULL, NULL, &rule, 0);
675 if (error) {
676 len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
677 rulenum, strerror(errno));
678 return (-1);
679 }
680
681 return (0);
682}
683
684int
685bsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
686 char *errstr)
687{
688 int name[10];
689 size_t len, size;
690 int error;
691
692 len = 10;
693 error = bsde_get_mib(MIB ".rules", name, &len);
694 if (error) {
695 len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
696 strerror(errno));
697 return (-1);
698 }
699
700 name[len] = rulenum;
701 len++;
702
703 size = sizeof(*rule);
704 error = sysctl(name, len, NULL, NULL, rule, size);
705 if (error) {
706 len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
707 rulenum, strerror(errno));
708 return (-1);
709 }
710
711 return (0);
712}
560
561 len = *namelen;
562 error = sysctlnametomib(string, name, &len);
563 if (error)
564 return (error);
565
566 *namelen = len;
567 return (0);
568}
569
570int
571bsde_get_rule_count(size_t buflen, char *errstr)
572{
573 size_t len;
574 int error;
575 int rule_count;
576
577 len = sizeof(rule_count);
578 error = sysctlbyname(MIB ".rule_count", &rule_count, &len, NULL, NULL);
579 if (error) {
580 len = snprintf(errstr, buflen, strerror(errno));
581 return (-1);
582 }
583 if (len != sizeof(rule_count)) {
584 len = snprintf(errstr, buflen, "Data error in %s.rule_count",
585 MIB);
586 return (-1);
587 }
588
589 return (rule_count);
590}
591
592int
593bsde_get_rule_slots(size_t buflen, char *errstr)
594{
595 size_t len;
596 int error;
597 int rule_slots;
598
599 len = sizeof(rule_slots);
600 error = sysctlbyname(MIB ".rule_slots", &rule_slots, &len, NULL,
601 NULL);
602 if (error) {
603 len = snprintf(errstr, buflen, strerror(errno));
604 return (-1);
605 }
606 if (len != sizeof(rule_slots)) {
607 len = snprintf(errstr, buflen, "Data error in %s.rule_slots",
608 MIB);
609 return (-1);
610 }
611
612 return (rule_slots);
613}
614
615/*
616 * Returns 0 for success;
617 * Returns -1 for failure;
618 * Returns -2 for not present
619 */
620int
621bsde_get_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t errlen,
622 char *errstr)
623{
624 int name[10];
625 size_t len, size;
626 int error;
627
628 len = 10;
629 error = bsde_get_mib(MIB ".rules", name, &len);
630 if (error) {
631 len = snprintf(errstr, errlen, "%s: %s", MIB ".rules",
632 strerror(errno));
633 return (-1);
634 }
635
636 size = sizeof(*rule);
637 name[len] = rulenum;
638 len++;
639 error = sysctl(name, len, rule, &size, NULL, 0);
640 if (error == -1 && errno == ENOENT)
641 return (-2);
642 if (error) {
643 len = snprintf(errstr, errlen, "%s.%d: %s", MIB ".rules",
644 rulenum, strerror(errno));
645 return (-1);
646 } else if (size != sizeof(*rule)) {
647 len = snprintf(errstr, errlen, "Data error in %s.%d: %s",
648 MIB ".rules", rulenum, strerror(errno));
649 return (-1);
650 }
651
652 return (0);
653}
654
655int
656bsde_delete_rule(int rulenum, size_t buflen, char *errstr)
657{
658 struct mac_bsdextended_rule rule;
659 int name[10];
660 size_t len, size;
661 int error;
662
663 len = 10;
664 error = bsde_get_mib(MIB ".rules", name, &len);
665 if (error) {
666 len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
667 strerror(errno));
668 return (-1);
669 }
670
671 name[len] = rulenum;
672 len++;
673
674 size = sizeof(rule);
675 error = sysctl(name, len, NULL, NULL, &rule, 0);
676 if (error) {
677 len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
678 rulenum, strerror(errno));
679 return (-1);
680 }
681
682 return (0);
683}
684
685int
686bsde_set_rule(int rulenum, struct mac_bsdextended_rule *rule, size_t buflen,
687 char *errstr)
688{
689 int name[10];
690 size_t len, size;
691 int error;
692
693 len = 10;
694 error = bsde_get_mib(MIB ".rules", name, &len);
695 if (error) {
696 len = snprintf(errstr, buflen, "%s: %s", MIB ".rules",
697 strerror(errno));
698 return (-1);
699 }
700
701 name[len] = rulenum;
702 len++;
703
704 size = sizeof(*rule);
705 error = sysctl(name, len, NULL, NULL, rule, size);
706 if (error) {
707 len = snprintf(errstr, buflen, "%s.%d: %s", MIB ".rules",
708 rulenum, strerror(errno));
709 return (-1);
710 }
711
712 return (0);
713}