1
2 /*
3 * Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
4 */
5
6 /*
7 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
8 *
9 * Support for enhanced MLS infrastructure.
10 *
11 * Updated: Karl MacMillan <kmacmillan@tresys.com>
12 *
13 * Added conditional policy language extensions
14 *
15 * Updated: James Morris <jmorris@intercode.com.au>
16 *
17 * Added IPv6 support.
18 *
19 * Updated: Joshua Brindle <jbrindle@tresys.com>
20 * Karl MacMillan <kmacmillan@tresys.com>
21 * Jason Tang <jtang@tresys.com>
22 *
23 * Policy Module support.
24 *
25 * Copyright (C) 2017 Mellanox Technologies Inc.
26 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
27 * Copyright (C) 2003 - 2005 Tresys Technology, LLC
28 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation, version 2.
32 */
33
34 /* FLASK */
35
36 /*
37 * checkpolicy
38 *
39 * Load and check a policy configuration.
40 *
41 * A policy configuration is created in a text format,
42 * and then compiled into a binary format for use by
43 * the security server. By default, checkpolicy reads
44 * the text format. If '-b' is specified, then checkpolicy
45 * reads the binary format instead.
46 *
47 * If '-o output_file' is specified, then checkpolicy
48 * writes the binary format version of the configuration
49 * to the specified output file.
50 *
51 * If '-d' is specified, then checkpolicy permits the user
52 * to interactively test the security server functions with
53 * the loaded policy configuration.
54 *
55 * If '-c' is specified, then the supplied parameter is used to
56 * determine which policy version to use for generating binary
57 * policy. This is for compatibility with older kernels. If any
58 * booleans or conditional rules are thrown away a warning is printed.
59 */
60
61 #include <ctype.h>
62 #include <getopt.h>
63 #include <unistd.h>
64 #include <stdlib.h>
65 #include <sys/types.h>
66 #include <sys/stat.h>
67 #include <sys/socket.h>
68 #include <netinet/in.h>
69 #ifndef IPPROTO_DCCP
70 #define IPPROTO_DCCP 33
71 #endif
72 #ifndef IPPROTO_SCTP
73 #define IPPROTO_SCTP 132
74 #endif
75 #include <arpa/inet.h>
76 #include <fcntl.h>
77 #include <stdio.h>
78 #include <errno.h>
79 #include <sys/mman.h>
80
81 #include <sepol/module_to_cil.h>
82 #include <sepol/kernel_to_cil.h>
83 #include <sepol/kernel_to_conf.h>
84 #include <sepol/policydb/policydb.h>
85 #include <sepol/policydb/services.h>
86 #include <sepol/policydb/conditional.h>
87 #include <sepol/policydb/hierarchy.h>
88 #include <sepol/policydb/expand.h>
89 #include <sepol/policydb/link.h>
90
91 #include "queue.h"
92 #include "parse_util.h"
93
94 static policydb_t policydb;
95 static sidtab_t sidtab;
96
97 extern policydb_t *policydbp;
98 extern int mlspol;
99 extern int werror;
100
101 static int handle_unknown = SEPOL_DENY_UNKNOWN;
102 static const char *txtfile = "policy.conf";
103 static const char *binfile = "policy";
104
usage(const char * progname)105 static __attribute__((__noreturn__)) void usage(const char *progname)
106 {
107 printf
108 ("usage: %s [-b[F]] [-C] [-d] [-U handle_unknown (allow,deny,reject)] [-M] "
109 "[-N] [-c policyvers (%d-%d)] [-o output_file|-] [-S] [-O] "
110 "[-t target_platform (selinux,xen)] [-E] [-V] [input_file]\n",
111 progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
112 exit(1);
113 }
114
115 #define FGETS(out, size, in) \
116 do { \
117 if (fgets(out,size,in)==NULL) { \
118 fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, \
119 strerror(errno)); \
120 exit(1);\
121 } \
122 } while (0)
123
print_sid(sepol_security_id_t sid,context_struct_t * context,void * data)124 static int print_sid(sepol_security_id_t sid,
125 context_struct_t * context
126 __attribute__ ((unused)), void *data
127 __attribute__ ((unused)))
128 {
129 sepol_security_context_t scontext;
130 size_t scontext_len;
131 int rc;
132
133 rc = sepol_sid_to_context(sid, &scontext, &scontext_len);
134 if (rc)
135 printf("sid %d -> error %d\n", sid, rc);
136 else {
137 printf("sid %d -> scontext %s\n", sid, scontext);
138 free(scontext);
139 }
140 return 0;
141 }
142
143 struct val_to_name {
144 unsigned int val;
145 char *name;
146 };
147
find_perm(hashtab_key_t key,hashtab_datum_t datum,void * p)148 static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
149 {
150 struct val_to_name *v = p;
151 perm_datum_t *perdatum;
152
153 perdatum = (perm_datum_t *) datum;
154
155 if (v->val == perdatum->s.value) {
156 v->name = key;
157 return 1;
158 }
159
160 return 0;
161 }
162
163 #ifdef EQUIVTYPES
insert_type_rule(avtab_key_t * k,avtab_datum_t * d,struct avtab_node * type_rules)164 static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d,
165 struct avtab_node *type_rules)
166 {
167 struct avtab_node *p, *c, *n;
168
169 for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
170 /*
171 * Find the insertion point, keeping the list
172 * ordered by source type, then target type, then
173 * target class.
174 */
175 if (k->source_type < c->key.source_type)
176 break;
177 if (k->source_type == c->key.source_type &&
178 k->target_type < c->key.target_type)
179 break;
180 if (k->source_type == c->key.source_type &&
181 k->target_type == c->key.target_type &&
182 k->target_class < c->key.target_class)
183 break;
184 }
185
186 /* Insert the rule */
187 n = malloc(sizeof(struct avtab_node));
188 if (!n) {
189 fprintf(stderr, "out of memory\n");
190 exit(1);
191 }
192
193 n->key = *k;
194 n->datum = *d;
195 n->next = p->next;
196 p->next = n;
197 return 0;
198 }
199
create_type_rules(avtab_key_t * k,avtab_datum_t * d,void * args)200 static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args)
201 {
202 struct avtab_node *type_rules = args;
203
204 if (d->specified & AVTAB_ALLOWED) {
205 /*
206 * Insert the rule into the lists for both
207 * the source type and the target type.
208 */
209 if (insert_type_rule(k, d, &type_rules[k->source_type - 1]))
210 return -1;
211 if (insert_type_rule(k, d, &type_rules[k->target_type - 1]))
212 return -1;
213 }
214
215 return 0;
216 }
217
free_type_rules(struct avtab_node * l)218 static void free_type_rules(struct avtab_node *l)
219 {
220 struct avtab_node *tmp;
221
222 while (l) {
223 tmp = l;
224 l = l->next;
225 free(tmp);
226 }
227 }
228
identify_equiv_types(void)229 static int identify_equiv_types(void)
230 {
231 struct avtab_node *type_rules, *l1, *l2;
232 int i, j;
233
234 /*
235 * Create a list of access vector rules for each type
236 * from the access vector table.
237 */
238 type_rules = malloc(sizeof(struct avtab_node) * policydb.p_types.nprim);
239 if (!type_rules) {
240 fprintf(stderr, "out of memory\n");
241 exit(1);
242 }
243 memset(type_rules, 0,
244 sizeof(struct avtab_node) * policydb.p_types.nprim);
245 if (avtab_map(&policydb.te_avtab, create_type_rules, type_rules))
246 exit(1);
247
248 /*
249 * Compare the type lists and identify equivalent types.
250 */
251 for (i = 0; i < policydb.p_types.nprim - 1; i++) {
252 if (!type_rules[i].next)
253 continue;
254 for (j = i + 1; j < policydb.p_types.nprim; j++) {
255 for (l1 = type_rules[i].next, l2 = type_rules[j].next;
256 l1 && l2; l1 = l1->next, l2 = l2->next) {
257 if (l2->key.source_type == (j + 1)) {
258 if (l1->key.source_type != (i + 1))
259 break;
260 } else {
261 if (l1->key.source_type !=
262 l2->key.source_type)
263 break;
264 }
265 if (l2->key.target_type == (j + 1)) {
266 if (l1->key.target_type != (i + 1))
267 break;
268 } else {
269 if (l1->key.target_type !=
270 l2->key.target_type)
271 break;
272 }
273 if (l1->key.target_class != l2->key.target_class
274 || l1->datum.allowed != l2->datum.allowed)
275 break;
276 }
277 if (l1 || l2)
278 continue;
279 free_type_rules(type_rules[j].next);
280 type_rules[j].next = NULL;
281 printf("Types %s and %s are equivalent.\n",
282 policydb.p_type_val_to_name[i],
283 policydb.p_type_val_to_name[j]);
284 }
285 free_type_rules(type_rules[i].next);
286 type_rules[i].next = NULL;
287 }
288
289 free(type_rules);
290 return 0;
291 }
292 #endif
293
display_bools(void)294 static int display_bools(void)
295 {
296 uint32_t i;
297
298 for (i = 0; i < policydbp->p_bools.nprim; i++) {
299 printf("%s : %d\n", policydbp->p_bool_val_to_name[i],
300 policydbp->bool_val_to_struct[i]->state);
301 }
302 return 0;
303 }
304
display_expr(const cond_expr_t * exp)305 static void display_expr(const cond_expr_t * exp)
306 {
307
308 const cond_expr_t *cur;
309 for (cur = exp; cur != NULL; cur = cur->next) {
310 switch (cur->expr_type) {
311 case COND_BOOL:
312 printf("%s ",
313 policydbp->p_bool_val_to_name[cur->boolean - 1]);
314 break;
315 case COND_NOT:
316 printf("! ");
317 break;
318 case COND_OR:
319 printf("|| ");
320 break;
321 case COND_AND:
322 printf("&& ");
323 break;
324 case COND_XOR:
325 printf("^ ");
326 break;
327 case COND_EQ:
328 printf("== ");
329 break;
330 case COND_NEQ:
331 printf("!= ");
332 break;
333 default:
334 printf("error!");
335 break;
336 }
337 }
338 }
339
display_cond_expressions(void)340 static int display_cond_expressions(void)
341 {
342 const cond_node_t *cur;
343
344 for (cur = policydbp->cond_list; cur != NULL; cur = cur->next) {
345 printf("expression: ");
346 display_expr(cur->expr);
347 printf("current state: %d\n", cur->cur_state);
348 }
349 return 0;
350 }
351
change_bool(const char * name,int state)352 static int change_bool(const char *name, int state)
353 {
354 cond_bool_datum_t *boolean;
355
356 boolean = hashtab_search(policydbp->p_bools.table, name);
357 if (boolean == NULL) {
358 printf("Could not find bool %s\n", name);
359 return -1;
360 }
361 boolean->state = state;
362 evaluate_conds(policydbp);
363 return 0;
364 }
365
check_level(hashtab_key_t key,hashtab_datum_t datum,void * arg)366 static int check_level(hashtab_key_t key, hashtab_datum_t datum, void *arg __attribute__ ((unused)))
367 {
368 level_datum_t *levdatum = (level_datum_t *) datum;
369
370 if (!levdatum->isalias && levdatum->notdefined) {
371 fprintf(stderr, "Error: sensitivity %s was not used in a level definition!\n",
372 key);
373 return -1;
374 }
375 return 0;
376 }
377
main(int argc,char ** argv)378 int main(int argc, char **argv)
379 {
380 policydb_t parse_policy;
381 sepol_security_class_t tclass;
382 sepol_security_id_t ssid, tsid, *sids, oldsid, newsid, tasksid;
383 sepol_security_context_t scontext;
384 struct sepol_av_decision avd;
385 class_datum_t *cladatum;
386 const char *file = txtfile;
387 char ans[80 + 1], *path, *fstype;
388 const char *outfile = NULL;
389 size_t scontext_len, pathlen;
390 unsigned int i;
391 unsigned int protocol, port;
392 unsigned int binary = 0, debug = 0, sort = 0, cil = 0, conf = 0, optimize = 0, disable_neverallow = 0;
393 struct val_to_name v;
394 int ret, ch, fd, target = SEPOL_TARGET_SELINUX;
395 unsigned int policyvers = 0;
396 unsigned int nel, uret;
397 struct stat sb;
398 void *map;
399 FILE *outfp = NULL;
400 char *name;
401 int state;
402 int show_version = 0;
403 char *reason_buf = NULL;
404 unsigned int reason;
405 int flags;
406 struct policy_file pf;
407 const struct option long_options[] = {
408 {"output", required_argument, NULL, 'o'},
409 {"target", required_argument, NULL, 't'},
410 {"binary", no_argument, NULL, 'b'},
411 {"debug", no_argument, NULL, 'd'},
412 {"version", no_argument, NULL, 'V'},
413 {"handle-unknown", required_argument, NULL, 'U'},
414 {"mls", no_argument, NULL, 'M'},
415 {"disable-neverallow", no_argument, NULL, 'N'},
416 {"cil", no_argument, NULL, 'C'},
417 {"conf",no_argument, NULL, 'F'},
418 {"sort", no_argument, NULL, 'S'},
419 {"optimize", no_argument, NULL, 'O'},
420 {"werror", no_argument, NULL, 'E'},
421 {"help", no_argument, NULL, 'h'},
422 {NULL, 0, NULL, 0}
423 };
424
425 while ((ch = getopt_long(argc, argv, "o:t:dbU:MNCFSVc:OEh", long_options, NULL)) != -1) {
426 switch (ch) {
427 case 'o':
428 outfile = optarg;
429 break;
430 case 't':
431 if (!strcasecmp(optarg, "Xen"))
432 target = SEPOL_TARGET_XEN;
433 else if (!strcasecmp(optarg, "SELinux"))
434 target = SEPOL_TARGET_SELINUX;
435 else{
436 fprintf(stderr, "%s: Unknown target platform:"
437 "%s\n", argv[0], optarg);
438 exit(1);
439 }
440 break;
441 case 'b':
442 binary = 1;
443 file = binfile;
444 break;
445 case 'd':
446 debug = 1;
447 break;
448 case 'V':
449 show_version = 1;
450 break;
451 case 'U':
452 if (!strcasecmp(optarg, "deny")) {
453 handle_unknown = DENY_UNKNOWN;
454 break;
455 }
456 if (!strcasecmp(optarg, "allow")) {
457 handle_unknown = ALLOW_UNKNOWN;
458 break;
459 }
460 if (!strcasecmp(optarg, "reject")) {
461 handle_unknown = REJECT_UNKNOWN;
462 break;
463 }
464 usage(argv[0]);
465 case 'S':
466 sort = 1;
467 break;
468 case 'O':
469 optimize = 1;
470 break;
471 case 'M':
472 mlspol = 1;
473 break;
474 case 'N':
475 disable_neverallow = 1;
476 break;
477 case 'C':
478 cil = 1;
479 break;
480 case 'F':
481 conf = 1;
482 break;
483 case 'c':{
484 long int n;
485 errno = 0;
486 n = strtol(optarg, NULL, 10);
487 if (errno) {
488 fprintf(stderr,
489 "Invalid policyvers specified: %s\n",
490 optarg);
491 usage(argv[0]);
492 exit(1);
493 }
494 if (n < POLICYDB_VERSION_MIN
495 || n > POLICYDB_VERSION_MAX) {
496 fprintf(stderr,
497 "policyvers value %ld not in range %d-%d\n",
498 n, POLICYDB_VERSION_MIN,
499 POLICYDB_VERSION_MAX);
500 usage(argv[0]);
501 exit(1);
502 }
503 policyvers = n;
504 break;
505 }
506 case 'E':
507 werror = 1;
508 break;
509 case 'h':
510 default:
511 usage(argv[0]);
512 }
513 }
514
515 if (show_version) {
516 printf("%d (compatibility range %d-%d)\n",
517 policyvers ? policyvers : POLICYDB_VERSION_MAX ,
518 POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN);
519 exit(0);
520 }
521
522 if (optind != argc) {
523 file = argv[optind++];
524 if (optind != argc)
525 usage(argv[0]);
526 }
527 /* Set policydb and sidtab used by libsepol service functions
528 to my structures, so that I can directly populate and
529 manipulate them. */
530 sepol_set_policydb(&policydb);
531 sepol_set_sidtab(&sidtab);
532
533 if (cil && conf) {
534 fprintf(stderr, "Can't convert to CIL and policy.conf at the same time\n");
535 exit(1);
536 }
537
538 if (binary) {
539 fd = open(file, O_RDONLY);
540 if (fd < 0) {
541 fprintf(stderr, "Can't open '%s': %s\n",
542 file, strerror(errno));
543 exit(1);
544 }
545 if (fstat(fd, &sb) < 0) {
546 fprintf(stderr, "Can't stat '%s': %s\n",
547 file, strerror(errno));
548 exit(1);
549 }
550 map =
551 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
552 fd, 0);
553 if (map == MAP_FAILED) {
554 fprintf(stderr, "Can't map '%s': %s\n",
555 file, strerror(errno));
556 exit(1);
557 }
558 policy_file_init(&pf);
559 pf.type = PF_USE_MEMORY;
560 pf.data = map;
561 pf.len = sb.st_size;
562 if (policydb_init(&policydb)) {
563 fprintf(stderr, "%s: policydb_init: Out of memory!\n",
564 argv[0]);
565 exit(1);
566 }
567 ret = policydb_read(&policydb, &pf, 1);
568 if (ret) {
569 fprintf(stderr,
570 "%s: error(s) encountered while parsing configuration\n",
571 argv[0]);
572 exit(1);
573 }
574 policydbp = &policydb;
575
576 /* Check Policy Consistency */
577 if (policydbp->mls) {
578 if (!mlspol) {
579 fprintf(stderr, "%s: MLS policy, but non-MLS"
580 " is specified\n", argv[0]);
581 exit(1);
582 }
583 } else {
584 if (mlspol) {
585 fprintf(stderr, "%s: non-MLS policy, but MLS"
586 " is specified\n", argv[0]);
587 exit(1);
588 }
589 }
590
591 if (policydbp->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
592 if (policyvers > policydbp->policyvers) {
593 fprintf(stderr, "Binary policies with version <= %u cannot be upgraded\n", POLICYDB_VERSION_PERMISSIVE);
594 } else if (policyvers) {
595 policydbp->policyvers = policyvers;
596 }
597 } else {
598 policydbp->policyvers = policyvers ? policyvers : POLICYDB_VERSION_MAX;
599 }
600 } else {
601 if (conf) {
602 fprintf(stderr, "Can only generate policy.conf from binary policy\n");
603 exit(1);
604 }
605 if (policydb_init(&parse_policy))
606 exit(1);
607 /* We build this as a base policy first since that is all the parser understands */
608 parse_policy.policy_type = POLICY_BASE;
609 policydb_set_target_platform(&parse_policy, target);
610
611 /* Let sepol know if we are dealing with MLS support */
612 parse_policy.mls = mlspol;
613 parse_policy.handle_unknown = handle_unknown;
614 parse_policy.policyvers = policyvers ? policyvers : POLICYDB_VERSION_MAX;
615
616 policydbp = &parse_policy;
617
618 if (read_source_policy(policydbp, file, "checkpolicy") < 0)
619 exit(1);
620
621 if (hashtab_map(policydbp->p_levels.table, check_level, NULL))
622 exit(1);
623
624 /* Linking takes care of optional avrule blocks */
625 if (link_modules(NULL, policydbp, NULL, 0, 0)) {
626 fprintf(stderr, "Error while resolving optionals\n");
627 exit(1);
628 }
629
630 if (!cil) {
631 if (policydb_init(&policydb)) {
632 fprintf(stderr, "%s: policydb_init failed\n", argv[0]);
633 exit(1);
634 }
635 if (expand_module(NULL, policydbp, &policydb, /*verbose=*/0, !disable_neverallow)) {
636 fprintf(stderr, "Error while expanding policy\n");
637 exit(1);
638 }
639 policydb.policyvers = policyvers ? policyvers : POLICYDB_VERSION_MAX;
640 policydb_destroy(policydbp);
641 policydbp = &policydb;
642 }
643 }
644
645 if (policydb_load_isids(&policydb, &sidtab))
646 exit(1);
647
648 if (optimize && policydbp->policy_type == POLICY_KERN) {
649 ret = policydb_optimize(policydbp);
650 if (ret) {
651 fprintf(stderr, "%s: error optimizing policy\n", argv[0]);
652 exit(1);
653 }
654 }
655
656 if (outfile) {
657 if (!strcmp(outfile, "-")) {
658 outfp = stdout;
659 outfile = "<STDOUT>";
660 } else {
661 outfp = fopen(outfile, "w");
662 if (!outfp) {
663 perror(outfile);
664 exit(1);
665 }
666 }
667
668 if (!cil) {
669 if (!conf) {
670 policydb.policy_type = POLICY_KERN;
671
672 policy_file_init(&pf);
673 pf.type = PF_USE_STDIO;
674 pf.fp = outfp;
675 if (sort) {
676 ret = policydb_sort_ocontexts(&policydb);
677 if (ret) {
678 fprintf(stderr, "%s: error sorting ocontexts\n",
679 argv[0]);
680 exit(1);
681 }
682 }
683 ret = policydb_write(&policydb, &pf);
684 } else {
685 ret = sepol_kernel_policydb_to_conf(outfp, policydbp);
686 }
687 if (ret) {
688 fprintf(stderr, "%s: error writing %s\n",
689 argv[0], outfile);
690 exit(1);
691 }
692 } else {
693 if (binary) {
694 ret = sepol_kernel_policydb_to_cil(outfp, policydbp);
695 } else {
696 ret = sepol_module_policydb_to_cil(outfp, policydbp, 1);
697 }
698 if (ret) {
699 fprintf(stderr, "%s: error writing %s\n", argv[0], outfile);
700 exit(1);
701 }
702 }
703
704 if (outfp != stdout) {
705 if(fclose(outfp)) {
706 fprintf(stderr, "%s: error closing %s: %s\n", argv[0], outfile, strerror(errno));
707 exit(1);
708 }
709 }
710 } else if (cil) {
711 fprintf(stderr, "%s: No file to write CIL was specified\n", argv[0]);
712 exit(1);
713 }
714
715 if (!debug) {
716 policydb_destroy(&policydb);
717 sepol_sidtab_destroy(&sidtab);
718 exit(0);
719 }
720
721 menu:
722 printf("\nSelect an option:\n");
723 printf("0) Call compute_access_vector\n");
724 printf("1) Call sid_to_context\n");
725 printf("2) Call context_to_sid\n");
726 printf("3) Call transition_sid\n");
727 printf("4) Call member_sid\n");
728 printf("5) Call change_sid\n");
729 printf("6) Call list_sids\n");
730 printf("7) Call load_policy\n");
731 printf("8) Call fs_sid\n");
732 printf("9) Call port_sid\n");
733 printf("a) Call netif_sid\n");
734 printf("b) Call node_sid\n");
735 printf("c) Call fs_use\n");
736 printf("d) Call genfs_sid\n");
737 printf("e) Call get_user_sids\n");
738 printf("f) display conditional bools\n");
739 printf("g) display conditional expressions\n");
740 printf("h) change a boolean value\n");
741 printf("i) display constraint expressions\n");
742 printf("j) display validatetrans expressions\n");
743 printf("k) Call ibpkey_sid\n");
744 printf("l) Call ibendport_sid\n");
745 #ifdef EQUIVTYPES
746 printf("z) Show equivalent types\n");
747 #endif
748 printf("m) Show menu again\n");
749 printf("q) Exit\n");
750 while (1) {
751 printf("\nChoose: ");
752 FGETS(ans, sizeof(ans), stdin);
753 switch (ans[0]) {
754 case '0':
755 printf("source sid? ");
756 FGETS(ans, sizeof(ans), stdin);
757 ssid = atoi(ans);
758
759 printf("target sid? ");
760 FGETS(ans, sizeof(ans), stdin);
761 tsid = atoi(ans);
762
763 printf("target class? ");
764 FGETS(ans, sizeof(ans), stdin);
765 if (isdigit(ans[0])) {
766 tclass = atoi(ans);
767 if (!tclass
768 || tclass > policydb.p_classes.nprim) {
769 printf("\nNo such class.\n");
770 break;
771 }
772 cladatum =
773 policydb.class_val_to_struct[tclass - 1];
774 } else {
775 ans[strlen(ans) - 1] = 0;
776 cladatum =
777 (class_datum_t *) hashtab_search(policydb.
778 p_classes.
779 table,
780 ans);
781 if (!cladatum) {
782 printf("\nNo such class\n");
783 break;
784 }
785 tclass = cladatum->s.value;
786 }
787
788 if (!cladatum->comdatum && !cladatum->permissions.nprim) {
789 printf
790 ("\nNo access vector definition for that class\n");
791 break;
792 }
793 ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd);
794 switch (ret) {
795 case 0:
796 printf("\nallowed {");
797 for (i = 1; i <= sizeof(avd.allowed) * 8; i++) {
798 if (avd.allowed & (UINT32_C(1) << (i - 1))) {
799 v.val = i;
800 ret =
801 hashtab_map(cladatum->
802 permissions.
803 table,
804 find_perm, &v);
805 if (!ret && cladatum->comdatum) {
806 ret =
807 hashtab_map
808 (cladatum->
809 comdatum->
810 permissions.table,
811 find_perm, &v);
812 }
813 if (ret)
814 printf(" %s", v.name);
815 }
816 }
817 printf(" }\n");
818 break;
819 case -EINVAL:
820 printf("\ninvalid sid\n");
821 break;
822 default:
823 printf("return code 0x%x\n", ret);
824 }
825 break;
826 case '1':
827 printf("sid? ");
828 FGETS(ans, sizeof(ans), stdin);
829 ssid = atoi(ans);
830 ret = sepol_sid_to_context(ssid,
831 &scontext, &scontext_len);
832 switch (ret) {
833 case 0:
834 printf("\nscontext %s\n", scontext);
835 free(scontext);
836 break;
837 case -EINVAL:
838 printf("\ninvalid sid\n");
839 break;
840 case -ENOMEM:
841 printf("\nout of memory\n");
842 break;
843 default:
844 printf("return code 0x%x\n", ret);
845 }
846 break;
847 case '2':
848 printf("scontext? ");
849 FGETS(ans, sizeof(ans), stdin);
850 scontext_len = strlen(ans);
851 ans[scontext_len - 1] = 0;
852 ret = sepol_context_to_sid(ans, scontext_len, &ssid);
853 switch (ret) {
854 case 0:
855 printf("\nsid %d\n", ssid);
856 break;
857 case -EINVAL:
858 printf("\ninvalid context\n");
859 break;
860 case -ENOMEM:
861 printf("\nout of memory\n");
862 break;
863 default:
864 printf("return code 0x%x\n", ret);
865 }
866 break;
867 case '3':
868 case '4':
869 case '5':
870 ch = ans[0];
871
872 printf("source sid? ");
873 FGETS(ans, sizeof(ans), stdin);
874 ssid = atoi(ans);
875 printf("target sid? ");
876 FGETS(ans, sizeof(ans), stdin);
877 tsid = atoi(ans);
878
879 printf("object class? ");
880 FGETS(ans, sizeof(ans), stdin);
881 if (isdigit(ans[0])) {
882 tclass = atoi(ans);
883 if (!tclass
884 || tclass > policydb.p_classes.nprim) {
885 printf("\nNo such class.\n");
886 break;
887 }
888 } else {
889 ans[strlen(ans) - 1] = 0;
890 cladatum =
891 (class_datum_t *) hashtab_search(policydb.
892 p_classes.
893 table,
894 ans);
895 if (!cladatum) {
896 printf("\nNo such class\n");
897 break;
898 }
899 tclass = cladatum->s.value;
900 }
901
902 if (ch == '3')
903 ret =
904 sepol_transition_sid(ssid, tsid, tclass,
905 &ssid);
906 else if (ch == '4')
907 ret =
908 sepol_member_sid(ssid, tsid, tclass, &ssid);
909 else
910 ret =
911 sepol_change_sid(ssid, tsid, tclass, &ssid);
912 switch (ret) {
913 case 0:
914 printf("\nsid %d\n", ssid);
915 break;
916 case -EINVAL:
917 printf("\ninvalid sid\n");
918 break;
919 case -ENOMEM:
920 printf("\nout of memory\n");
921 break;
922 default:
923 printf("return code 0x%x\n", ret);
924 }
925 break;
926 case '6':
927 sepol_sidtab_map(&sidtab, print_sid, 0);
928 break;
929 case '7':
930 printf("pathname? ");
931 FGETS(ans, sizeof(ans), stdin);
932 pathlen = strlen(ans);
933 ans[pathlen - 1] = 0;
934 fd = open(ans, O_RDONLY);
935 if (fd < 0) {
936 fprintf(stderr, "Can't open '%s': %s\n",
937 ans, strerror(errno));
938 break;
939 }
940 if (fstat(fd, &sb) < 0) {
941 fprintf(stderr, "Can't stat '%s': %s\n",
942 ans, strerror(errno));
943 break;
944 }
945 map =
946 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
947 MAP_PRIVATE, fd, 0);
948 if (map == MAP_FAILED) {
949 fprintf(stderr, "Can't map '%s': %s\n",
950 ans, strerror(errno));
951 break;
952 }
953 ret = sepol_load_policy(map, sb.st_size);
954 switch (ret) {
955 case 0:
956 printf("\nsuccess\n");
957 break;
958 case -EINVAL:
959 printf("\ninvalid policy\n");
960 break;
961 case -ENOMEM:
962 printf("\nout of memory\n");
963 break;
964 default:
965 printf("return code 0x%x\n", ret);
966 }
967 break;
968 case '8':
969 printf("fs kdevname? ");
970 FGETS(ans, sizeof(ans), stdin);
971 ans[strlen(ans) - 1] = 0;
972 ret = sepol_fs_sid(ans, &ssid, &tsid);
973 if (ret) {
974 printf("unknown fs kdevname\n");
975 } else {
976 printf("fs_sid %d default_file_sid %d\n", ssid, tsid);
977 }
978 break;
979 case '9':
980 printf("protocol? ");
981 FGETS(ans, sizeof(ans), stdin);
982 ans[strlen(ans) - 1] = 0;
983 if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP"))
984 protocol = IPPROTO_TCP;
985 else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP"))
986 protocol = IPPROTO_UDP;
987 else if (!strcmp(ans, "dccp") || !strcmp(ans, "DCCP"))
988 protocol = IPPROTO_DCCP;
989 else if (!strcmp(ans, "sctp") || !strcmp(ans, "SCTP"))
990 protocol = IPPROTO_SCTP;
991 else {
992 printf("unknown protocol\n");
993 break;
994 }
995 printf("port? ");
996 FGETS(ans, sizeof(ans), stdin);
997 port = atoi(ans);
998 sepol_port_sid(0, 0, protocol, port, &ssid);
999 printf("sid %d\n", ssid);
1000 break;
1001 case 'a':
1002 printf("netif name? ");
1003 FGETS(ans, sizeof(ans), stdin);
1004 ans[strlen(ans) - 1] = 0;
1005 ret = sepol_netif_sid(ans, &ssid, &tsid);
1006 if (ret) {
1007 printf("unknown name\n");
1008 } else {
1009 printf("if_sid %d default_msg_sid %d\n", ssid, tsid);
1010 }
1011 break;
1012 case 'b':{
1013 char *p;
1014 int family, len;
1015 struct in_addr addr4;
1016 struct in6_addr addr6;
1017
1018 printf("protocol family? ");
1019 FGETS(ans, sizeof(ans), stdin);
1020 ans[strlen(ans) - 1] = 0;
1021 if (!strcasecmp(ans, "ipv4"))
1022 family = AF_INET;
1023 else if (!strcasecmp(ans, "ipv6"))
1024 family = AF_INET6;
1025 else {
1026 printf("unknown protocol family\n");
1027 break;
1028 }
1029
1030 printf("node address? ");
1031 FGETS(ans, sizeof(ans), stdin);
1032 ans[strlen(ans) - 1] = 0;
1033
1034 if (family == AF_INET) {
1035 p = (char *)&addr4;
1036 len = sizeof(addr4);
1037 } else {
1038 p = (char *)&addr6;
1039 len = sizeof(addr6);
1040 }
1041
1042 if (inet_pton(family, ans, p) < 1) {
1043 printf("error parsing address\n");
1044 break;
1045 }
1046
1047 sepol_node_sid(family, p, len, &ssid);
1048 printf("sid %d\n", ssid);
1049 break;
1050 }
1051 case 'c':
1052 printf("fstype? ");
1053 FGETS(ans, sizeof(ans), stdin);
1054 ans[strlen(ans) - 1] = 0;
1055 sepol_fs_use(ans, &uret, &ssid);
1056 switch (uret) {
1057 case SECURITY_FS_USE_XATTR:
1058 printf("use xattr\n");
1059 break;
1060 case SECURITY_FS_USE_TRANS:
1061 printf("use transition SIDs\n");
1062 break;
1063 case SECURITY_FS_USE_TASK:
1064 printf("use task SIDs\n");
1065 break;
1066 case SECURITY_FS_USE_GENFS:
1067 printf("use genfs\n");
1068 break;
1069 case SECURITY_FS_USE_NONE:
1070 printf("no labeling support\n");
1071 break;
1072 }
1073 printf("sid %d\n", ssid);
1074 break;
1075 case 'd':
1076 printf("fstype? ");
1077 FGETS(ans, sizeof(ans), stdin);
1078 ans[strlen(ans) - 1] = 0;
1079 fstype = strdup(ans);
1080 printf("path? ");
1081 FGETS(ans, sizeof(ans), stdin);
1082 ans[strlen(ans) - 1] = 0;
1083 path = strdup(ans);
1084 printf("object class? ");
1085 FGETS(ans, sizeof(ans), stdin);
1086 if (isdigit(ans[0])) {
1087 tclass = atoi(ans);
1088 if (!tclass
1089 || tclass > policydb.p_classes.nprim) {
1090 printf("\nNo such class.\n");
1091 break;
1092 }
1093 } else {
1094 ans[strlen(ans) - 1] = 0;
1095 cladatum =
1096 (class_datum_t *) hashtab_search(policydb.
1097 p_classes.
1098 table,
1099 ans);
1100 if (!cladatum) {
1101 printf("\nNo such class\n");
1102 break;
1103 }
1104 tclass = cladatum->s.value;
1105 }
1106 sepol_genfs_sid(fstype, path, tclass, &ssid);
1107 printf("sid %d\n", ssid);
1108 free(fstype);
1109 free(path);
1110 break;
1111 case 'e':
1112 printf("from SID? ");
1113 FGETS(ans, sizeof(ans), stdin);
1114 ans[strlen(ans) - 1] = 0;
1115 ssid = atoi(ans);
1116
1117 printf("username? ");
1118 FGETS(ans, sizeof(ans), stdin);
1119 ans[strlen(ans) - 1] = 0;
1120
1121 ret = sepol_get_user_sids(ssid, ans, &sids, &nel);
1122 switch (ret) {
1123 case 0:
1124 if (!nel)
1125 printf("\nnone\n");
1126 for (i = 0; i < nel; i++)
1127 print_sid(sids[i], NULL, NULL);
1128 free(sids);
1129 break;
1130 case -ENOMEM:
1131 printf("\nout of memory\n");
1132 break;
1133 case -EINVAL:
1134 printf("\ninvalid argument\n");
1135 break;
1136 default:
1137 printf("\nerror\n");
1138 break;
1139 }
1140 break;
1141 case 'f':
1142 display_bools();
1143 break;
1144 case 'g':
1145 display_cond_expressions();
1146 break;
1147 case 'h':
1148 printf("name? ");
1149 FGETS(ans, sizeof(ans), stdin);
1150 ans[strlen(ans) - 1] = 0;
1151
1152 name = strdup(ans);
1153 if (name == NULL) {
1154 fprintf(stderr, "couldn't strdup string.\n");
1155 break;
1156 }
1157
1158 printf("state? ");
1159 FGETS(ans, sizeof(ans), stdin);
1160 ans[strlen(ans) - 1] = 0;
1161
1162 if (atoi(ans))
1163 state = 1;
1164 else
1165 state = 0;
1166
1167 change_bool(name, state);
1168 free(name);
1169 break;
1170 case 'i':
1171 printf("source sid? ");
1172 FGETS(ans, sizeof(ans), stdin);
1173 ssid = atoi(ans);
1174
1175 printf("target sid? ");
1176 FGETS(ans, sizeof(ans), stdin);
1177 tsid = atoi(ans);
1178
1179 printf("target class? ");
1180 FGETS(ans, sizeof(ans), stdin);
1181 if (isdigit(ans[0])) {
1182 tclass = atoi(ans);
1183 if (!tclass
1184 || tclass > policydb.p_classes.nprim) {
1185 printf("\nNo such class.\n");
1186 break;
1187 }
1188 } else {
1189 ans[strlen(ans) - 1] = 0;
1190 cladatum =
1191 (class_datum_t *) hashtab_search(policydb.
1192 p_classes.
1193 table,
1194 ans);
1195 if (!cladatum) {
1196 printf("\nNo such class\n");
1197 break;
1198 }
1199 tclass = cladatum->s.value;
1200 }
1201
1202 flags = SHOW_GRANTED;
1203 if (sepol_compute_av_reason_buffer(ssid, tsid,
1204 tclass, 0, &avd, &reason,
1205 &reason_buf, flags)) {
1206 printf("\nconstraint error\n");
1207 break;
1208 }
1209 if (reason_buf) {
1210 printf("\nConstraint expressions:\n%s",
1211 reason_buf);
1212 free(reason_buf);
1213 } else {
1214 printf("\nNo constraints found.\n");
1215 }
1216 break;
1217 case 'j':
1218 printf("old sid? ");
1219 FGETS(ans, sizeof(ans), stdin);
1220 oldsid = atoi(ans);
1221
1222 printf("new sid? ");
1223 FGETS(ans, sizeof(ans), stdin);
1224 newsid = atoi(ans);
1225
1226 printf("task sid? ");
1227 FGETS(ans, sizeof(ans), stdin);
1228 tasksid = atoi(ans);
1229
1230 printf("target class? ");
1231 FGETS(ans, sizeof(ans), stdin);
1232 if (isdigit(ans[0])) {
1233 tclass = atoi(ans);
1234 if (!tclass
1235 || tclass > policydb.p_classes.nprim) {
1236 printf("\nNo such class.\n");
1237 break;
1238 }
1239 } else {
1240 ans[strlen(ans) - 1] = 0;
1241 cladatum =
1242 (class_datum_t *) hashtab_search(policydb.
1243 p_classes.
1244 table,
1245 ans);
1246 if (!cladatum) {
1247 printf("\nNo such class\n");
1248 break;
1249 }
1250 tclass = cladatum->s.value;
1251 }
1252
1253 flags = SHOW_GRANTED;
1254 if (sepol_validate_transition_reason_buffer(oldsid,
1255 newsid, tasksid, tclass,
1256 &reason_buf, flags)) {
1257 printf("\nvalidatetrans error\n");
1258 break;
1259 }
1260 if (reason_buf) {
1261 printf("\nValidatetrans expressions:\n%s",
1262 reason_buf);
1263 free(reason_buf);
1264 } else {
1265 printf(
1266 "\nNo validatetrans expressions found.\n");
1267 }
1268 break;
1269 case 'k':
1270 {
1271 char *p;
1272 struct in6_addr addr6;
1273 uint64_t subnet_prefix;
1274 unsigned int pkey;
1275
1276 printf("subnet prefix? ");
1277 FGETS(ans, sizeof(ans), stdin);
1278 ans[strlen(ans) - 1] = 0;
1279 p = (char *)&addr6;
1280
1281 if (inet_pton(AF_INET6, ans, p) < 1) {
1282 printf("error parsing subnet prefix\n");
1283 break;
1284 }
1285
1286 memcpy(&subnet_prefix, p, sizeof(subnet_prefix));
1287 printf("pkey? ");
1288 FGETS(ans, sizeof(ans), stdin);
1289 pkey = atoi(ans);
1290 sepol_ibpkey_sid(subnet_prefix, pkey, &ssid);
1291 printf("sid %d\n", ssid);
1292 }
1293 break;
1294 case 'l':
1295 printf("device name (eg. mlx4_0)? ");
1296 FGETS(ans, sizeof(ans), stdin);
1297 ans[strlen(ans) - 1] = 0;
1298
1299 name = strdup(ans);
1300 if (!name) {
1301 fprintf(stderr, "couldn't strdup string.\n");
1302 break;
1303 }
1304
1305 printf("port? ");
1306 FGETS(ans, sizeof(ans), stdin);
1307 port = atoi(ans);
1308 sepol_ibendport_sid(name, port, &ssid);
1309 printf("sid %d\n", ssid);
1310 free(name);
1311 break;
1312 #ifdef EQUIVTYPES
1313 case 'z':
1314 identify_equiv_types();
1315 break;
1316 #endif
1317 case 'm':
1318 goto menu;
1319 case 'q':
1320 exit(0);
1321 break;
1322 default:
1323 printf("\nUnknown option %s.\n", ans);
1324 }
1325 }
1326
1327 return 0;
1328 }
1329
1330 /* FLASK */
1331