blob: 7947c201e1d9ac429de1a36084b87f621d57ae3e [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>
Richard Hainesaac93602016-04-24 10:34:47 +010067#ifndef IPPROTO_DCCP
68#define IPPROTO_DCCP 33
69#endif
Joshua Brindle13cd4c82008-08-19 15:30:36 -040070#include <arpa/inet.h>
71#include <fcntl.h>
72#include <stdio.h>
73#include <errno.h>
74#include <sys/mman.h>
75
Stephen Smalleyda752ca2012-02-23 10:14:13 -050076#ifdef DARWIN
77#include <ctype.h>
78#endif
79
James Carterb1d94562015-04-01 10:05:04 -040080#include <sepol/module_to_cil.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -040081#include <sepol/policydb/policydb.h>
82#include <sepol/policydb/services.h>
83#include <sepol/policydb/conditional.h>
84#include <sepol/policydb/hierarchy.h>
85#include <sepol/policydb/flask.h>
86#include <sepol/policydb/expand.h>
87#include <sepol/policydb/link.h>
88
89#include "queue.h"
90#include "checkpolicy.h"
91#include "parse_util.h"
92
93extern char *optarg;
94extern int optind;
95
96static policydb_t policydb;
97static sidtab_t sidtab;
98
99extern policydb_t *policydbp;
100extern int mlspol;
101
102static int handle_unknown = SEPOL_DENY_UNKNOWN;
Nicolas Iooss7dcb7a52014-09-14 23:41:46 +0200103static const char *txtfile = "policy.conf";
104static const char *binfile = "policy";
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400105
106unsigned int policyvers = POLICYDB_VERSION_MAX;
107
108void usage(char *progname)
109{
110 printf
James Carterb1d94562015-04-01 10:05:04 -0400111 ("usage: %s [-b] [-C] [-d] [-U handle_unknown (allow,deny,reject)] [-M]"
Joshua Brindlef830d962009-10-14 15:49:25 -0400112 "[-c policyvers (%d-%d)] [-o output_file] [-t target_platform (selinux,xen)]"
Paul Nuzzi79d10a82009-09-29 10:06:26 -0400113 "[input_file]\n",
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400114 progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
115 exit(1);
116}
117
118#define FGETS(out, size, in) \
119if (fgets(out,size,in)==NULL) { \
120 fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,\
121 strerror(errno)); \
122 exit(1);\
123}
124static 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
143struct val_to_name {
144 unsigned int val;
145 char *name;
146};
147
148static 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
164static 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
200static 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
218static 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
229static 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
294extern char *av_to_string(uint32_t tclass, sepol_access_vector_t av);
295
Nicolas Ioossc4a4a1a2014-09-14 23:41:49 +0200296int display_bools(void)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400297{
Nicolas Iooss581d3eb2014-09-14 23:41:41 +0200298 uint32_t i;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400299
300 for (i = 0; i < policydbp->p_bools.nprim; i++) {
301 printf("%s : %d\n", policydbp->p_bool_val_to_name[i],
302 policydbp->bool_val_to_struct[i]->state);
303 }
304 return 0;
305}
306
307void display_expr(cond_expr_t * exp)
308{
309
310 cond_expr_t *cur;
311 for (cur = exp; cur != NULL; cur = cur->next) {
312 switch (cur->expr_type) {
313 case COND_BOOL:
314 printf("%s ",
315 policydbp->p_bool_val_to_name[cur->bool - 1]);
316 break;
317 case COND_NOT:
318 printf("! ");
319 break;
320 case COND_OR:
321 printf("|| ");
322 break;
323 case COND_AND:
324 printf("&& ");
325 break;
326 case COND_XOR:
327 printf("^ ");
328 break;
329 case COND_EQ:
330 printf("== ");
331 break;
332 case COND_NEQ:
333 printf("!= ");
334 break;
335 default:
336 printf("error!");
337 break;
338 }
339 }
340}
341
Nicolas Ioossc4a4a1a2014-09-14 23:41:49 +0200342int display_cond_expressions(void)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400343{
344 cond_node_t *cur;
345
346 for (cur = policydbp->cond_list; cur != NULL; cur = cur->next) {
347 printf("expression: ");
348 display_expr(cur->expr);
349 printf("current state: %d\n", cur->cur_state);
350 }
351 return 0;
352}
353
354int change_bool(char *name, int state)
355{
356 cond_bool_datum_t *bool;
357
358 bool = hashtab_search(policydbp->p_bools.table, name);
359 if (bool == NULL) {
360 printf("Could not find bool %s\n", name);
361 return -1;
362 }
363 bool->state = state;
364 evaluate_conds(policydbp);
365 return 0;
366}
367
Nicolas Iooss5af8c5a2014-09-14 23:41:50 +0200368static int check_level(hashtab_key_t key, hashtab_datum_t datum, void *arg __attribute__ ((unused)))
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400369{
370 level_datum_t *levdatum = (level_datum_t *) datum;
371
372 if (!levdatum->isalias && !levdatum->defined) {
373 fprintf(stderr,
374 "Error: sensitivity %s was not used in a level definition!\n",
375 key);
376 return -1;
377 }
378 return 0;
379}
380
381int main(int argc, char **argv)
382{
James Carterb1d94562015-04-01 10:05:04 -0400383 policydb_t parse_policy;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400384 sepol_security_class_t tclass;
Richard Hainesab9cbb12013-11-03 19:12:29 +0000385 sepol_security_id_t ssid, tsid, *sids, oldsid, newsid, tasksid;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400386 sepol_security_context_t scontext;
387 struct sepol_av_decision avd;
388 class_datum_t *cladatum;
Nicolas Iooss7dcb7a52014-09-14 23:41:46 +0200389 const char *file = txtfile;
390 char ans[80 + 1], *outfile = NULL, *path, *fstype;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400391 size_t scontext_len, pathlen;
392 unsigned int i;
393 unsigned int protocol, port;
James Carterb1d94562015-04-01 10:05:04 -0400394 unsigned int binary = 0, debug = 0, cil = 0;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400395 struct val_to_name v;
Paul Nuzzi79d10a82009-09-29 10:06:26 -0400396 int ret, ch, fd, target = SEPOL_TARGET_SELINUX;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400397 unsigned int nel, uret;
398 struct stat sb;
399 void *map;
400 FILE *outfp = NULL;
401 char *name;
402 int state;
403 int show_version = 0;
Richard Hainesab9cbb12013-11-03 19:12:29 +0000404 char *reason_buf = NULL;
405 unsigned int reason;
406 int flags;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400407 struct policy_file pf;
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100408 struct option long_options[] = {
409 {"output", required_argument, NULL, 'o'},
410 {"target", required_argument, NULL, 't'},
411 {"binary", no_argument, NULL, 'b'},
412 {"debug", no_argument, NULL, 'd'},
413 {"version", no_argument, NULL, 'V'},
Laurent Bigonvillef6a03f12013-07-06 14:32:33 +0200414 {"handle-unknown", required_argument, NULL, 'U'},
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100415 {"mls", no_argument, NULL, 'M'},
James Carterb1d94562015-04-01 10:05:04 -0400416 {"cil", no_argument, NULL, 'C'},
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100417 {"help", no_argument, NULL, 'h'},
418 {NULL, 0, NULL, 0}
419 };
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400420
James Carterb1d94562015-04-01 10:05:04 -0400421 while ((ch = getopt_long(argc, argv, "o:t:dbU:MCVc:h", long_options, NULL)) != -1) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400422 switch (ch) {
423 case 'o':
424 outfile = optarg;
425 break;
Paul Nuzzi79d10a82009-09-29 10:06:26 -0400426 case 't':
427 if (!strcasecmp(optarg, "Xen"))
428 target = SEPOL_TARGET_XEN;
429 else if (!strcasecmp(optarg, "SELinux"))
430 target = SEPOL_TARGET_SELINUX;
431 else{
432 fprintf(stderr, "%s: Unknown target platform:"
433 "%s\n", argv[0], optarg);
434 exit(1);
435 }
436 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400437 case 'b':
438 binary = 1;
439 file = binfile;
440 break;
441 case 'd':
442 debug = 1;
443 break;
444 case 'V':
445 show_version = 1;
446 break;
447 case 'U':
448 if (!strcasecmp(optarg, "deny")) {
449 handle_unknown = DENY_UNKNOWN;
450 break;
451 }
452 if (!strcasecmp(optarg, "allow")) {
453 handle_unknown = ALLOW_UNKNOWN;
454 break;
455 }
456 if (!strcasecmp(optarg, "reject")) {
457 handle_unknown = REJECT_UNKNOWN;
458 break;
459 }
460 usage(argv[0]);
461 case 'M':
462 mlspol = 1;
463 break;
James Carterb1d94562015-04-01 10:05:04 -0400464 case 'C':
465 cil = 1;
466 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400467 case 'c':{
Dan Albertb1bbd302014-12-10 11:28:44 -0800468 long int n;
469 errno = 0;
470 n = strtol(optarg, NULL, 10);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400471 if (errno) {
472 fprintf(stderr,
473 "Invalid policyvers specified: %s\n",
474 optarg);
475 usage(argv[0]);
476 exit(1);
477 }
478 if (n < POLICYDB_VERSION_MIN
479 || n > POLICYDB_VERSION_MAX) {
480 fprintf(stderr,
481 "policyvers value %ld not in range %d-%d\n",
482 n, POLICYDB_VERSION_MIN,
483 POLICYDB_VERSION_MAX);
484 usage(argv[0]);
485 exit(1);
486 }
487 if (policyvers != n)
488 policyvers = n;
489 break;
490 }
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100491 case 'h':
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400492 default:
493 usage(argv[0]);
494 }
495 }
496
497 if (show_version) {
498 printf("%d (compatibility range %d-%d)\n", policyvers,
499 POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN);
500 exit(0);
501 }
502
503 if (optind != argc) {
504 file = argv[optind++];
505 if (optind != argc)
506 usage(argv[0]);
507 }
508 printf("%s: loading policy configuration from %s\n", argv[0], file);
509
510 /* Set policydb and sidtab used by libsepol service functions
511 to my structures, so that I can directly populate and
512 manipulate them. */
513 sepol_set_policydb(&policydb);
514 sepol_set_sidtab(&sidtab);
515
516 if (binary) {
James Carterb1d94562015-04-01 10:05:04 -0400517 if (cil) {
518 fprintf(stderr, "%s: Converting kernel policy to CIL is not supported\n",
519 argv[0]);
520 exit(1);
521 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400522 fd = open(file, O_RDONLY);
523 if (fd < 0) {
524 fprintf(stderr, "Can't open '%s': %s\n",
525 file, strerror(errno));
526 exit(1);
527 }
528 if (fstat(fd, &sb) < 0) {
529 fprintf(stderr, "Can't stat '%s': %s\n",
530 file, strerror(errno));
531 exit(1);
532 }
533 map =
534 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
535 fd, 0);
536 if (map == MAP_FAILED) {
537 fprintf(stderr, "Can't map '%s': %s\n",
538 file, strerror(errno));
539 exit(1);
540 }
541 policy_file_init(&pf);
542 pf.type = PF_USE_MEMORY;
543 pf.data = map;
544 pf.len = sb.st_size;
545 if (policydb_init(&policydb)) {
546 fprintf(stderr, "%s: policydb_init: Out of memory!\n",
547 argv[0]);
548 exit(1);
549 }
550 ret = policydb_read(&policydb, &pf, 1);
551 if (ret) {
552 fprintf(stderr,
553 "%s: error(s) encountered while parsing configuration\n",
554 argv[0]);
555 exit(1);
556 }
557 policydbp = &policydb;
558
559 /* Check Policy Consistency */
560 if (policydbp->mls) {
561 if (!mlspol) {
562 fprintf(stderr, "%s: MLS policy, but non-MLS"
563 " is specified\n", argv[0]);
564 exit(1);
565 }
566 } else {
567 if (mlspol) {
568 fprintf(stderr, "%s: non-MLS policy, but MLS"
569 " is specified\n", argv[0]);
570 exit(1);
571 }
572 }
573 } else {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400574 if (policydb_init(&parse_policy))
575 exit(1);
576 /* We build this as a base policy first since that is all the parser understands */
577 parse_policy.policy_type = POLICY_BASE;
Paul Nuzzi79d10a82009-09-29 10:06:26 -0400578 policydb_set_target_platform(&parse_policy, target);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400579
580 /* Let sepol know if we are dealing with MLS support */
581 parse_policy.mls = mlspol;
582 parse_policy.handle_unknown = handle_unknown;
583
584 policydbp = &parse_policy;
585
586 if (read_source_policy(policydbp, file, "checkpolicy") < 0)
587 exit(1);
588
589 if (hashtab_map(policydbp->p_levels.table, check_level, NULL))
590 exit(1);
591
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400592 /* Linking takes care of optional avrule blocks */
James Carterb1d94562015-04-01 10:05:04 -0400593 if (link_modules(NULL, policydbp, NULL, 0, 0)) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400594 fprintf(stderr, "Error while resolving optionals\n");
595 exit(1);
596 }
597
James Carterb1d94562015-04-01 10:05:04 -0400598 if (!cil) {
599 if (policydb_init(&policydb)) {
600 fprintf(stderr, "%s: policydb_init failed\n", argv[0]);
601 exit(1);
602 }
603 if (expand_module(NULL, policydbp, &policydb, 0, 1)) {
604 fprintf(stderr, "Error while expanding policy\n");
605 exit(1);
606 }
607 policydb_destroy(policydbp);
608 policydbp = &policydb;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400609 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400610 }
611
612 if (policydb_load_isids(&policydb, &sidtab))
613 exit(1);
614
615 printf("%s: policy configuration loaded\n", argv[0]);
616
617 if (outfile) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400618 outfp = fopen(outfile, "w");
619 if (!outfp) {
620 perror(outfile);
621 exit(1);
622 }
623
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400624 policydb.policyvers = policyvers;
625
James Carterb1d94562015-04-01 10:05:04 -0400626 if (!cil) {
627 printf
628 ("%s: writing binary representation (version %d) to %s\n",
629 argv[0], policyvers, outfile);
630 policydb.policy_type = POLICY_KERN;
631
632 policy_file_init(&pf);
633 pf.type = PF_USE_STDIO;
634 pf.fp = outfp;
635 ret = policydb_write(&policydb, &pf);
636 if (ret) {
637 fprintf(stderr, "%s: error writing %s\n",
638 argv[0], outfile);
639 exit(1);
640 }
641 } else {
642 printf("%s: writing CIL to %s\n",argv[0], outfile);
643 ret = sepol_module_policydb_to_cil(outfp, policydbp, 1);
644 if (ret) {
645 fprintf(stderr, "%s: error writing %s\n", argv[0], outfile);
646 exit(1);
647 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400648 }
James Carterb1d94562015-04-01 10:05:04 -0400649
650 if (outfile) {
651 fclose(outfp);
652 }
653 } else if (cil) {
654 fprintf(stderr, "%s: No file to write CIL was specified\n", argv[0]);
655 exit(1);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400656 }
James Carterb1d94562015-04-01 10:05:04 -0400657
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400658 if (!debug) {
659 policydb_destroy(&policydb);
660 exit(0);
661 }
662
663 menu:
664 printf("\nSelect an option:\n");
665 printf("0) Call compute_access_vector\n");
666 printf("1) Call sid_to_context\n");
667 printf("2) Call context_to_sid\n");
668 printf("3) Call transition_sid\n");
669 printf("4) Call member_sid\n");
670 printf("5) Call change_sid\n");
671 printf("6) Call list_sids\n");
672 printf("7) Call load_policy\n");
673 printf("8) Call fs_sid\n");
674 printf("9) Call port_sid\n");
675 printf("a) Call netif_sid\n");
676 printf("b) Call node_sid\n");
677 printf("c) Call fs_use\n");
678 printf("d) Call genfs_sid\n");
679 printf("e) Call get_user_sids\n");
680 printf("f) display conditional bools\n");
681 printf("g) display conditional expressions\n");
682 printf("h) change a boolean value\n");
Richard Hainesab9cbb12013-11-03 19:12:29 +0000683 printf("i) display constraint expressions\n");
684 printf("j) display validatetrans expressions\n");
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400685#ifdef EQUIVTYPES
686 printf("z) Show equivalent types\n");
687#endif
688 printf("m) Show menu again\n");
689 printf("q) Exit\n");
690 while (1) {
691 printf("\nChoose: ");
692 FGETS(ans, sizeof(ans), stdin);
693 switch (ans[0]) {
694 case '0':
695 printf("source sid? ");
696 FGETS(ans, sizeof(ans), stdin);
697 ssid = atoi(ans);
698
699 printf("target sid? ");
700 FGETS(ans, sizeof(ans), stdin);
701 tsid = atoi(ans);
702
703 printf("target class? ");
704 FGETS(ans, sizeof(ans), stdin);
705 if (isdigit(ans[0])) {
706 tclass = atoi(ans);
707 if (!tclass
708 || tclass > policydb.p_classes.nprim) {
709 printf("\nNo such class.\n");
710 break;
711 }
712 cladatum =
713 policydb.class_val_to_struct[tclass - 1];
714 } else {
715 ans[strlen(ans) - 1] = 0;
716 cladatum =
717 (class_datum_t *) hashtab_search(policydb.
718 p_classes.
719 table,
720 ans);
721 if (!cladatum) {
722 printf("\nNo such class\n");
723 break;
724 }
725 tclass = cladatum->s.value;
726 }
727
728 if (!cladatum->comdatum && !cladatum->permissions.nprim) {
729 printf
730 ("\nNo access vector definition for that class\n");
731 break;
732 }
733 ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd);
734 switch (ret) {
735 case 0:
736 printf("\nallowed {");
737 for (i = 1; i <= sizeof(avd.allowed) * 8; i++) {
738 if (avd.allowed & (1 << (i - 1))) {
739 v.val = i;
740 ret =
741 hashtab_map(cladatum->
742 permissions.
743 table,
744 find_perm, &v);
745 if (!ret && cladatum->comdatum) {
746 ret =
747 hashtab_map
748 (cladatum->
749 comdatum->
750 permissions.table,
751 find_perm, &v);
752 }
753 if (ret)
754 printf(" %s", v.name);
755 }
756 }
757 printf(" }\n");
758 break;
759 case -EINVAL:
760 printf("\ninvalid sid\n");
761 break;
762 default:
763 printf("return code 0x%x\n", ret);
764 }
765 break;
766 case '1':
767 printf("sid? ");
768 FGETS(ans, sizeof(ans), stdin);
769 ssid = atoi(ans);
770 ret = sepol_sid_to_context(ssid,
771 &scontext, &scontext_len);
772 switch (ret) {
773 case 0:
774 printf("\nscontext %s\n", scontext);
775 free(scontext);
776 break;
777 case -EINVAL:
778 printf("\ninvalid sid\n");
779 break;
780 case -ENOMEM:
781 printf("\nout of memory\n");
782 break;
783 default:
784 printf("return code 0x%x\n", ret);
785 }
786 break;
787 case '2':
788 printf("scontext? ");
789 FGETS(ans, sizeof(ans), stdin);
790 scontext_len = strlen(ans);
791 ans[scontext_len - 1] = 0;
792 ret = sepol_context_to_sid(ans, scontext_len, &ssid);
793 switch (ret) {
794 case 0:
795 printf("\nsid %d\n", ssid);
796 break;
797 case -EINVAL:
798 printf("\ninvalid context\n");
799 break;
800 case -ENOMEM:
801 printf("\nout of memory\n");
802 break;
803 default:
804 printf("return code 0x%x\n", ret);
805 }
806 break;
807 case '3':
808 case '4':
809 case '5':
810 ch = ans[0];
811
812 printf("source sid? ");
813 FGETS(ans, sizeof(ans), stdin);
814 ssid = atoi(ans);
815 printf("target sid? ");
816 FGETS(ans, sizeof(ans), stdin);
817 tsid = atoi(ans);
818
819 printf("object class? ");
820 FGETS(ans, sizeof(ans), stdin);
821 if (isdigit(ans[0])) {
822 tclass = atoi(ans);
823 if (!tclass
824 || tclass > policydb.p_classes.nprim) {
825 printf("\nNo such class.\n");
826 break;
827 }
828 } else {
829 ans[strlen(ans) - 1] = 0;
830 cladatum =
831 (class_datum_t *) hashtab_search(policydb.
832 p_classes.
833 table,
834 ans);
835 if (!cladatum) {
836 printf("\nNo such class\n");
837 break;
838 }
839 tclass = cladatum->s.value;
840 }
841
842 if (ch == '3')
843 ret =
844 sepol_transition_sid(ssid, tsid, tclass,
845 &ssid);
846 else if (ch == '4')
847 ret =
848 sepol_member_sid(ssid, tsid, tclass, &ssid);
849 else
850 ret =
851 sepol_change_sid(ssid, tsid, tclass, &ssid);
852 switch (ret) {
853 case 0:
854 printf("\nsid %d\n", ssid);
855 break;
856 case -EINVAL:
857 printf("\ninvalid sid\n");
858 break;
859 case -ENOMEM:
860 printf("\nout of memory\n");
861 break;
862 default:
863 printf("return code 0x%x\n", ret);
864 }
865 break;
866 case '6':
867 sepol_sidtab_map(&sidtab, print_sid, 0);
868 break;
869 case '7':
870 printf("pathname? ");
871 FGETS(ans, sizeof(ans), stdin);
872 pathlen = strlen(ans);
873 ans[pathlen - 1] = 0;
874 printf("%s: loading policy configuration from %s\n",
875 argv[0], ans);
876 fd = open(ans, O_RDONLY);
877 if (fd < 0) {
878 fprintf(stderr, "Can't open '%s': %s\n",
879 ans, strerror(errno));
880 break;
881 }
882 if (fstat(fd, &sb) < 0) {
883 fprintf(stderr, "Can't stat '%s': %s\n",
884 ans, strerror(errno));
885 break;
886 }
887 map =
888 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
889 MAP_PRIVATE, fd, 0);
890 if (map == MAP_FAILED) {
891 fprintf(stderr, "Can't map '%s': %s\n",
892 ans, strerror(errno));
893 break;
894 }
895 ret = sepol_load_policy(map, sb.st_size);
896 switch (ret) {
897 case 0:
898 printf("\nsuccess\n");
899 break;
900 case -EINVAL:
901 printf("\ninvalid policy\n");
902 break;
903 case -ENOMEM:
904 printf("\nout of memory\n");
905 break;
906 default:
907 printf("return code 0x%x\n", ret);
908 }
909 break;
910 case '8':
911 printf("fs kdevname? ");
912 FGETS(ans, sizeof(ans), stdin);
913 ans[strlen(ans) - 1] = 0;
914 sepol_fs_sid(ans, &ssid, &tsid);
915 printf("fs_sid %d default_file_sid %d\n", ssid, tsid);
916 break;
917 case '9':
918 printf("protocol? ");
919 FGETS(ans, sizeof(ans), stdin);
920 ans[strlen(ans) - 1] = 0;
921 if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP"))
922 protocol = IPPROTO_TCP;
923 else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP"))
924 protocol = IPPROTO_UDP;
Richard Haines3895fbb2016-04-06 12:44:35 +0100925 else if (!strcmp(ans, "dccp") || !strcmp(ans, "DCCP"))
926 protocol = IPPROTO_DCCP;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400927 else {
928 printf("unknown protocol\n");
929 break;
930 }
931 printf("port? ");
932 FGETS(ans, sizeof(ans), stdin);
933 port = atoi(ans);
934 sepol_port_sid(0, 0, protocol, port, &ssid);
935 printf("sid %d\n", ssid);
936 break;
937 case 'a':
938 printf("netif name? ");
939 FGETS(ans, sizeof(ans), stdin);
940 ans[strlen(ans) - 1] = 0;
941 sepol_netif_sid(ans, &ssid, &tsid);
942 printf("if_sid %d default_msg_sid %d\n", ssid, tsid);
943 break;
944 case 'b':{
945 char *p;
946 int family, len;
947 struct in_addr addr4;
948 struct in6_addr addr6;
949
950 printf("protocol family? ");
951 FGETS(ans, sizeof(ans), stdin);
952 ans[strlen(ans) - 1] = 0;
953 if (!strcasecmp(ans, "ipv4"))
954 family = AF_INET;
955 else if (!strcasecmp(ans, "ipv6"))
956 family = AF_INET6;
957 else {
958 printf("unknown protocol family\n");
959 break;
960 }
961
962 printf("node address? ");
963 FGETS(ans, sizeof(ans), stdin);
964 ans[strlen(ans) - 1] = 0;
965
966 if (family == AF_INET) {
967 p = (char *)&addr4;
968 len = sizeof(addr4);
969 } else {
970 p = (char *)&addr6;
971 len = sizeof(addr6);
972 }
973
974 if (inet_pton(family, ans, p) < 1) {
975 printf("error parsing address\n");
976 break;
977 }
978
979 sepol_node_sid(family, p, len, &ssid);
980 printf("sid %d\n", ssid);
981 break;
982 }
983 case 'c':
984 printf("fstype? ");
985 FGETS(ans, sizeof(ans), stdin);
986 ans[strlen(ans) - 1] = 0;
987 sepol_fs_use(ans, &uret, &ssid);
988 switch (uret) {
989 case SECURITY_FS_USE_XATTR:
990 printf("use xattr\n");
991 break;
992 case SECURITY_FS_USE_TRANS:
993 printf("use transition SIDs\n");
994 break;
995 case SECURITY_FS_USE_TASK:
996 printf("use task SIDs\n");
997 break;
998 case SECURITY_FS_USE_GENFS:
999 printf("use genfs\n");
1000 break;
1001 case SECURITY_FS_USE_NONE:
1002 printf("no labeling support\n");
1003 break;
1004 }
1005 printf("sid %d\n", ssid);
1006 break;
1007 case 'd':
1008 printf("fstype? ");
1009 FGETS(ans, sizeof(ans), stdin);
1010 ans[strlen(ans) - 1] = 0;
1011 fstype = strdup(ans);
1012 printf("path? ");
1013 FGETS(ans, sizeof(ans), stdin);
1014 ans[strlen(ans) - 1] = 0;
1015 path = strdup(ans);
1016 printf("object class? ");
1017 FGETS(ans, sizeof(ans), stdin);
1018 if (isdigit(ans[0])) {
1019 tclass = atoi(ans);
1020 if (!tclass
1021 || tclass > policydb.p_classes.nprim) {
1022 printf("\nNo such class.\n");
1023 break;
1024 }
1025 } else {
1026 ans[strlen(ans) - 1] = 0;
1027 cladatum =
1028 (class_datum_t *) hashtab_search(policydb.
1029 p_classes.
1030 table,
1031 ans);
1032 if (!cladatum) {
1033 printf("\nNo such class\n");
1034 break;
1035 }
1036 tclass = cladatum->s.value;
1037 }
1038 sepol_genfs_sid(fstype, path, tclass, &ssid);
1039 printf("sid %d\n", ssid);
1040 free(fstype);
1041 free(path);
1042 break;
1043 case 'e':
1044 printf("from SID? ");
1045 FGETS(ans, sizeof(ans), stdin);
1046 ans[strlen(ans) - 1] = 0;
1047 ssid = atoi(ans);
1048
1049 printf("username? ");
1050 FGETS(ans, sizeof(ans), stdin);
1051 ans[strlen(ans) - 1] = 0;
1052
1053 ret = sepol_get_user_sids(ssid, ans, &sids, &nel);
1054 switch (ret) {
1055 case 0:
1056 if (!nel)
1057 printf("\nnone\n");
1058 for (i = 0; i < nel; i++)
1059 print_sid(sids[i], NULL, NULL);
1060 free(sids);
1061 break;
1062 case -ENOMEM:
1063 printf("\nout of memory\n");
1064 break;
1065 case -EINVAL:
1066 printf("\ninvalid argument\n");
1067 break;
1068 default:
1069 printf("\nerror\n");
1070 break;
1071 }
1072 break;
1073 case 'f':
1074 display_bools();
1075 break;
1076 case 'g':
1077 display_cond_expressions();
1078 break;
1079 case 'h':
1080 printf("name? ");
1081 FGETS(ans, sizeof(ans), stdin);
1082 ans[strlen(ans) - 1] = 0;
1083
1084 name = malloc((strlen(ans) + 1) * sizeof(char));
1085 if (name == NULL) {
1086 fprintf(stderr, "couldn't malloc string.\n");
1087 break;
1088 }
1089 strcpy(name, ans);
1090
1091 printf("state? ");
1092 FGETS(ans, sizeof(ans), stdin);
1093 ans[strlen(ans) - 1] = 0;
1094
1095 if (atoi(ans))
1096 state = 1;
1097 else
1098 state = 0;
1099
1100 change_bool(name, state);
1101 free(name);
1102 break;
Richard Hainesab9cbb12013-11-03 19:12:29 +00001103 case 'i':
1104 printf("source sid? ");
1105 FGETS(ans, sizeof(ans), stdin);
1106 ssid = atoi(ans);
1107
1108 printf("target sid? ");
1109 FGETS(ans, sizeof(ans), stdin);
1110 tsid = atoi(ans);
1111
1112 printf("target class? ");
1113 FGETS(ans, sizeof(ans), stdin);
1114 if (isdigit(ans[0])) {
1115 tclass = atoi(ans);
1116 if (!tclass
1117 || tclass > policydb.p_classes.nprim) {
1118 printf("\nNo such class.\n");
1119 break;
1120 }
1121 cladatum =
1122 policydb.class_val_to_struct[tclass - 1];
1123 } else {
1124 ans[strlen(ans) - 1] = 0;
1125 cladatum =
1126 (class_datum_t *) hashtab_search(policydb.
1127 p_classes.
1128 table,
1129 ans);
1130 if (!cladatum) {
1131 printf("\nNo such class\n");
1132 break;
1133 }
1134 tclass = cladatum->s.value;
1135 }
1136
1137 flags = SHOW_GRANTED;
1138 if (sepol_compute_av_reason_buffer(ssid, tsid,
1139 tclass, 0, &avd, &reason,
1140 &reason_buf, flags)) {
1141 printf("\nconstraint error\n");
1142 break;
1143 }
1144 if (reason_buf) {
1145 printf("\nConstraint expressions:\n%s",
1146 reason_buf);
1147 free(reason_buf);
1148 } else {
1149 printf("\nNo constraints found.\n");
1150 }
1151 break;
1152 case 'j':
1153 printf("old sid? ");
1154 FGETS(ans, sizeof(ans), stdin);
1155 oldsid = atoi(ans);
1156
1157 printf("new sid? ");
1158 FGETS(ans, sizeof(ans), stdin);
1159 newsid = atoi(ans);
1160
1161 printf("task sid? ");
1162 FGETS(ans, sizeof(ans), stdin);
1163 tasksid = atoi(ans);
1164
1165 printf("target class? ");
1166 FGETS(ans, sizeof(ans), stdin);
1167 if (isdigit(ans[0])) {
1168 tclass = atoi(ans);
1169 if (!tclass
1170 || tclass > policydb.p_classes.nprim) {
1171 printf("\nNo such class.\n");
1172 break;
1173 }
1174 cladatum =
1175 policydb.class_val_to_struct[tclass - 1];
1176 } else {
1177 ans[strlen(ans) - 1] = 0;
1178 cladatum =
1179 (class_datum_t *) hashtab_search(policydb.
1180 p_classes.
1181 table,
1182 ans);
1183 if (!cladatum) {
1184 printf("\nNo such class\n");
1185 break;
1186 }
1187 tclass = cladatum->s.value;
1188 }
1189
1190 flags = SHOW_GRANTED;
1191 if (sepol_validate_transition_reason_buffer(oldsid,
1192 newsid, tasksid, tclass,
1193 &reason_buf, flags)) {
1194 printf("\nvalidatetrans error\n");
1195 break;
1196 }
1197 if (reason_buf) {
1198 printf("\nValidatetrans expressions:\n%s",
1199 reason_buf);
1200 free(reason_buf);
1201 } else {
1202 printf(
1203 "\nNo validatetrans expressions found.\n");
1204 }
1205 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -04001206#ifdef EQUIVTYPES
1207 case 'z':
1208 identify_equiv_types();
1209 break;
1210#endif
1211 case 'm':
1212 goto menu;
1213 case 'q':
1214 exit(0);
1215 break;
1216 default:
1217 printf("\nUnknown option %s.\n", ans);
1218 }
1219 }
1220
1221 return 0;
1222}
1223
1224/* FLASK */