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