blob: 534fc22e70245ce0026356ebebe8baa76d3ce967 [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
Nicolas Iooss61f760b2017-01-08 19:45:52 +010060#include <ctype.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -040061#include <getopt.h>
62#include <unistd.h>
63#include <stdlib.h>
64#include <sys/types.h>
65#include <sys/stat.h>
66#include <sys/socket.h>
67#include <netinet/in.h>
Richard Hainesaac93602016-04-24 10:34:47 +010068#ifndef IPPROTO_DCCP
69#define IPPROTO_DCCP 33
70#endif
Joshua Brindle13cd4c82008-08-19 15:30:36 -040071#include <arpa/inet.h>
72#include <fcntl.h>
73#include <stdio.h>
74#include <errno.h>
75#include <sys/mman.h>
76
James Carterb1d94562015-04-01 10:05:04 -040077#include <sepol/module_to_cil.h>
James Carter13c27d62017-03-21 16:00:30 -040078#include <sepol/kernel_to_cil.h>
79#include <sepol/kernel_to_conf.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -040080#include <sepol/policydb/policydb.h>
81#include <sepol/policydb/services.h>
82#include <sepol/policydb/conditional.h>
83#include <sepol/policydb/hierarchy.h>
84#include <sepol/policydb/flask.h>
85#include <sepol/policydb/expand.h>
86#include <sepol/policydb/link.h>
87
88#include "queue.h"
89#include "checkpolicy.h"
90#include "parse_util.h"
91
92extern char *optarg;
93extern int optind;
94
95static policydb_t policydb;
96static sidtab_t sidtab;
97
98extern policydb_t *policydbp;
99extern int mlspol;
100
101static int handle_unknown = SEPOL_DENY_UNKNOWN;
Nicolas Iooss7dcb7a52014-09-14 23:41:46 +0200102static const char *txtfile = "policy.conf";
103static const char *binfile = "policy";
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400104
105unsigned int policyvers = POLICYDB_VERSION_MAX;
106
Nicolas Ioossef61dd72017-03-05 18:13:01 +0100107static __attribute__((__noreturn__)) void usage(const char *progname)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400108{
109 printf
James Carter13c27d62017-03-21 16:00:30 -0400110 ("usage: %s [-b[F]] [-C] [-d] [-U handle_unknown (allow,deny,reject)] [-M]"
Joshua Brindlef830d962009-10-14 15:49:25 -0400111 "[-c policyvers (%d-%d)] [-o output_file] [-t target_platform (selinux,xen)]"
Paul Nuzzi79d10a82009-09-29 10:06:26 -0400112 "[input_file]\n",
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400113 progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
114 exit(1);
115}
116
117#define FGETS(out, size, in) \
118if (fgets(out,size,in)==NULL) { \
119 fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,\
120 strerror(errno)); \
121 exit(1);\
122}
123static int print_sid(sepol_security_id_t sid,
124 context_struct_t * context
125 __attribute__ ((unused)), void *data
126 __attribute__ ((unused)))
127{
128 sepol_security_context_t scontext;
129 size_t scontext_len;
130 int rc;
131
132 rc = sepol_sid_to_context(sid, &scontext, &scontext_len);
133 if (rc)
134 printf("sid %d -> error %d\n", sid, rc);
135 else {
136 printf("sid %d -> scontext %s\n", sid, scontext);
137 free(scontext);
138 }
139 return 0;
140}
141
142struct val_to_name {
143 unsigned int val;
144 char *name;
145};
146
147static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
148{
149 struct val_to_name *v = p;
150 perm_datum_t *perdatum;
151
152 perdatum = (perm_datum_t *) datum;
153
154 if (v->val == perdatum->s.value) {
155 v->name = key;
156 return 1;
157 }
158
159 return 0;
160}
161
162#ifdef EQUIVTYPES
163static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d,
164 struct avtab_node *type_rules)
165{
166 struct avtab_node *p, *c, *n;
167
168 for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
169 /*
170 * Find the insertion point, keeping the list
171 * ordered by source type, then target type, then
172 * target class.
173 */
174 if (k->source_type < c->key.source_type)
175 break;
176 if (k->source_type == c->key.source_type &&
177 k->target_type < c->key.target_type)
178 break;
179 if (k->source_type == c->key.source_type &&
180 k->target_type == c->key.target_type &&
181 k->target_class < c->key.target_class)
182 break;
183 }
184
185 /* Insert the rule */
186 n = malloc(sizeof(struct avtab_node));
187 if (!n) {
188 fprintf(stderr, "out of memory\n");
189 exit(1);
190 }
191
192 n->key = *k;
193 n->datum = *d;
194 n->next = p->next;
195 p->next = n;
196 return 0;
197}
198
199static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args)
200{
201 struct avtab_node *type_rules = args;
202
203 if (d->specified & AVTAB_ALLOWED) {
204 /*
205 * Insert the rule into the lists for both
206 * the source type and the target type.
207 */
208 if (insert_type_rule(k, d, &type_rules[k->source_type - 1]))
209 return -1;
210 if (insert_type_rule(k, d, &type_rules[k->target_type - 1]))
211 return -1;
212 }
213
214 return 0;
215}
216
217static void free_type_rules(struct avtab_node *l)
218{
219 struct avtab_node *tmp;
220
221 while (l) {
222 tmp = l;
223 l = l->next;
224 free(tmp);
225 }
226}
227
228static int identify_equiv_types(void)
229{
230 struct avtab_node *type_rules, *l1, *l2;
231 int i, j;
232
233 /*
234 * Create a list of access vector rules for each type
235 * from the access vector table.
236 */
237 type_rules = malloc(sizeof(struct avtab_node) * policydb.p_types.nprim);
238 if (!type_rules) {
239 fprintf(stderr, "out of memory\n");
240 exit(1);
241 }
242 memset(type_rules, 0,
243 sizeof(struct avtab_node) * policydb.p_types.nprim);
244 if (avtab_map(&policydb.te_avtab, create_type_rules, type_rules))
245 exit(1);
246
247 /*
248 * Compare the type lists and identify equivalent types.
249 */
250 for (i = 0; i < policydb.p_types.nprim - 1; i++) {
251 if (!type_rules[i].next)
252 continue;
253 for (j = i + 1; j < policydb.p_types.nprim; j++) {
254 for (l1 = type_rules[i].next, l2 = type_rules[j].next;
255 l1 && l2; l1 = l1->next, l2 = l2->next) {
256 if (l2->key.source_type == (j + 1)) {
257 if (l1->key.source_type != (i + 1))
258 break;
259 } else {
260 if (l1->key.source_type !=
261 l2->key.source_type)
262 break;
263 }
264 if (l2->key.target_type == (j + 1)) {
265 if (l1->key.target_type != (i + 1))
266 break;
267 } else {
268 if (l1->key.target_type !=
269 l2->key.target_type)
270 break;
271 }
272 if (l1->key.target_class != l2->key.target_class
273 || l1->datum.allowed != l2->datum.allowed)
274 break;
275 }
276 if (l1 || l2)
277 continue;
278 free_type_rules(type_rules[j].next);
279 type_rules[j].next = NULL;
280 printf("Types %s and %s are equivalent.\n",
281 policydb.p_type_val_to_name[i],
282 policydb.p_type_val_to_name[j]);
283 }
284 free_type_rules(type_rules[i].next);
285 type_rules[i].next = NULL;
286 }
287
288 free(type_rules);
289 return 0;
290}
291#endif
292
293extern char *av_to_string(uint32_t tclass, sepol_access_vector_t av);
294
Nicolas Ioossc4a4a1a2014-09-14 23:41:49 +0200295int display_bools(void)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400296{
Nicolas Iooss581d3eb2014-09-14 23:41:41 +0200297 uint32_t i;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400298
299 for (i = 0; i < policydbp->p_bools.nprim; i++) {
300 printf("%s : %d\n", policydbp->p_bool_val_to_name[i],
301 policydbp->bool_val_to_struct[i]->state);
302 }
303 return 0;
304}
305
306void display_expr(cond_expr_t * exp)
307{
308
309 cond_expr_t *cur;
310 for (cur = exp; cur != NULL; cur = cur->next) {
311 switch (cur->expr_type) {
312 case COND_BOOL:
313 printf("%s ",
314 policydbp->p_bool_val_to_name[cur->bool - 1]);
315 break;
316 case COND_NOT:
317 printf("! ");
318 break;
319 case COND_OR:
320 printf("|| ");
321 break;
322 case COND_AND:
323 printf("&& ");
324 break;
325 case COND_XOR:
326 printf("^ ");
327 break;
328 case COND_EQ:
329 printf("== ");
330 break;
331 case COND_NEQ:
332 printf("!= ");
333 break;
334 default:
335 printf("error!");
336 break;
337 }
338 }
339}
340
Nicolas Ioossc4a4a1a2014-09-14 23:41:49 +0200341int display_cond_expressions(void)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400342{
343 cond_node_t *cur;
344
345 for (cur = policydbp->cond_list; cur != NULL; cur = cur->next) {
346 printf("expression: ");
347 display_expr(cur->expr);
348 printf("current state: %d\n", cur->cur_state);
349 }
350 return 0;
351}
352
353int change_bool(char *name, int state)
354{
355 cond_bool_datum_t *bool;
356
357 bool = hashtab_search(policydbp->p_bools.table, name);
358 if (bool == NULL) {
359 printf("Could not find bool %s\n", name);
360 return -1;
361 }
362 bool->state = state;
363 evaluate_conds(policydbp);
364 return 0;
365}
366
Nicolas Iooss5af8c5a2014-09-14 23:41:50 +0200367static int check_level(hashtab_key_t key, hashtab_datum_t datum, void *arg __attribute__ ((unused)))
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400368{
369 level_datum_t *levdatum = (level_datum_t *) datum;
370
371 if (!levdatum->isalias && !levdatum->defined) {
372 fprintf(stderr,
373 "Error: sensitivity %s was not used in a level definition!\n",
374 key);
375 return -1;
376 }
377 return 0;
378}
379
380int main(int argc, char **argv)
381{
James Carterb1d94562015-04-01 10:05:04 -0400382 policydb_t parse_policy;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400383 sepol_security_class_t tclass;
Richard Hainesab9cbb12013-11-03 19:12:29 +0000384 sepol_security_id_t ssid, tsid, *sids, oldsid, newsid, tasksid;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400385 sepol_security_context_t scontext;
386 struct sepol_av_decision avd;
387 class_datum_t *cladatum;
Nicolas Iooss7dcb7a52014-09-14 23:41:46 +0200388 const char *file = txtfile;
389 char ans[80 + 1], *outfile = NULL, *path, *fstype;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400390 size_t scontext_len, pathlen;
391 unsigned int i;
392 unsigned int protocol, port;
James Carter13c27d62017-03-21 16:00:30 -0400393 unsigned int binary = 0, debug = 0, cil = 0, conf = 0;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400394 struct val_to_name v;
Paul Nuzzi79d10a82009-09-29 10:06:26 -0400395 int ret, ch, fd, target = SEPOL_TARGET_SELINUX;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400396 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;
Richard Hainesab9cbb12013-11-03 19:12:29 +0000403 char *reason_buf = NULL;
404 unsigned int reason;
405 int flags;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400406 struct policy_file pf;
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100407 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'},
Laurent Bigonvillef6a03f12013-07-06 14:32:33 +0200413 {"handle-unknown", required_argument, NULL, 'U'},
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100414 {"mls", no_argument, NULL, 'M'},
James Carterb1d94562015-04-01 10:05:04 -0400415 {"cil", no_argument, NULL, 'C'},
James Carter13c27d62017-03-21 16:00:30 -0400416 {"conf",no_argument, NULL, 'F'},
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 Carter13c27d62017-03-21 16:00:30 -0400421 while ((ch = getopt_long(argc, argv, "o:t:dbU:MCFVc: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;
James Carter13c27d62017-03-21 16:00:30 -0400467 case 'F':
468 conf = 1;
469 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400470 case 'c':{
Dan Albertb1bbd302014-12-10 11:28:44 -0800471 long int n;
472 errno = 0;
473 n = strtol(optarg, NULL, 10);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400474 if (errno) {
475 fprintf(stderr,
476 "Invalid policyvers specified: %s\n",
477 optarg);
478 usage(argv[0]);
479 exit(1);
480 }
481 if (n < POLICYDB_VERSION_MIN
482 || n > POLICYDB_VERSION_MAX) {
483 fprintf(stderr,
484 "policyvers value %ld not in range %d-%d\n",
485 n, POLICYDB_VERSION_MIN,
486 POLICYDB_VERSION_MAX);
487 usage(argv[0]);
488 exit(1);
489 }
490 if (policyvers != n)
491 policyvers = n;
492 break;
493 }
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100494 case 'h':
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400495 default:
496 usage(argv[0]);
497 }
498 }
499
500 if (show_version) {
501 printf("%d (compatibility range %d-%d)\n", policyvers,
502 POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN);
503 exit(0);
504 }
505
506 if (optind != argc) {
507 file = argv[optind++];
508 if (optind != argc)
509 usage(argv[0]);
510 }
511 printf("%s: loading policy configuration from %s\n", argv[0], file);
512
513 /* Set policydb and sidtab used by libsepol service functions
514 to my structures, so that I can directly populate and
515 manipulate them. */
516 sepol_set_policydb(&policydb);
517 sepol_set_sidtab(&sidtab);
518
James Carter13c27d62017-03-21 16:00:30 -0400519 if (cil && conf) {
520 fprintf(stderr, "Can't convert to CIL and policy.conf at the same time\n");
521 exit(1);
522 }
523
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400524 if (binary) {
525 fd = open(file, O_RDONLY);
526 if (fd < 0) {
527 fprintf(stderr, "Can't open '%s': %s\n",
528 file, strerror(errno));
529 exit(1);
530 }
531 if (fstat(fd, &sb) < 0) {
532 fprintf(stderr, "Can't stat '%s': %s\n",
533 file, strerror(errno));
534 exit(1);
535 }
536 map =
537 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
538 fd, 0);
539 if (map == MAP_FAILED) {
540 fprintf(stderr, "Can't map '%s': %s\n",
541 file, strerror(errno));
542 exit(1);
543 }
544 policy_file_init(&pf);
545 pf.type = PF_USE_MEMORY;
546 pf.data = map;
547 pf.len = sb.st_size;
548 if (policydb_init(&policydb)) {
549 fprintf(stderr, "%s: policydb_init: Out of memory!\n",
550 argv[0]);
551 exit(1);
552 }
553 ret = policydb_read(&policydb, &pf, 1);
554 if (ret) {
555 fprintf(stderr,
556 "%s: error(s) encountered while parsing configuration\n",
557 argv[0]);
558 exit(1);
559 }
560 policydbp = &policydb;
561
562 /* Check Policy Consistency */
563 if (policydbp->mls) {
564 if (!mlspol) {
565 fprintf(stderr, "%s: MLS policy, but non-MLS"
566 " is specified\n", argv[0]);
567 exit(1);
568 }
569 } else {
570 if (mlspol) {
571 fprintf(stderr, "%s: non-MLS policy, but MLS"
572 " is specified\n", argv[0]);
573 exit(1);
574 }
575 }
576 } else {
James Carter13c27d62017-03-21 16:00:30 -0400577 if (conf) {
578 fprintf(stderr, "Can only generate policy.conf from binary policy\n");
579 exit(1);
580 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400581 if (policydb_init(&parse_policy))
582 exit(1);
583 /* We build this as a base policy first since that is all the parser understands */
584 parse_policy.policy_type = POLICY_BASE;
Paul Nuzzi79d10a82009-09-29 10:06:26 -0400585 policydb_set_target_platform(&parse_policy, target);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400586
587 /* Let sepol know if we are dealing with MLS support */
588 parse_policy.mls = mlspol;
589 parse_policy.handle_unknown = handle_unknown;
590
591 policydbp = &parse_policy;
592
593 if (read_source_policy(policydbp, file, "checkpolicy") < 0)
594 exit(1);
595
596 if (hashtab_map(policydbp->p_levels.table, check_level, NULL))
597 exit(1);
598
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400599 /* Linking takes care of optional avrule blocks */
James Carterb1d94562015-04-01 10:05:04 -0400600 if (link_modules(NULL, policydbp, NULL, 0, 0)) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400601 fprintf(stderr, "Error while resolving optionals\n");
602 exit(1);
603 }
604
James Carterb1d94562015-04-01 10:05:04 -0400605 if (!cil) {
606 if (policydb_init(&policydb)) {
607 fprintf(stderr, "%s: policydb_init failed\n", argv[0]);
608 exit(1);
609 }
610 if (expand_module(NULL, policydbp, &policydb, 0, 1)) {
611 fprintf(stderr, "Error while expanding policy\n");
612 exit(1);
613 }
614 policydb_destroy(policydbp);
615 policydbp = &policydb;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400616 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400617 }
618
619 if (policydb_load_isids(&policydb, &sidtab))
620 exit(1);
621
622 printf("%s: policy configuration loaded\n", argv[0]);
623
624 if (outfile) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400625 outfp = fopen(outfile, "w");
626 if (!outfp) {
627 perror(outfile);
628 exit(1);
629 }
630
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400631 policydb.policyvers = policyvers;
632
James Carterb1d94562015-04-01 10:05:04 -0400633 if (!cil) {
James Carter13c27d62017-03-21 16:00:30 -0400634 if (!conf) {
635 printf("%s: writing binary representation (version %d) to %s\n", argv[0], policyvers, outfile);
James Carterb1d94562015-04-01 10:05:04 -0400636
James Carter13c27d62017-03-21 16:00:30 -0400637 policydb.policy_type = POLICY_KERN;
638
639 policy_file_init(&pf);
640 pf.type = PF_USE_STDIO;
641 pf.fp = outfp;
642 ret = policydb_write(&policydb, &pf);
643 } else {
644 printf("%s: writing policy.conf to %s\n",
645 argv[0], outfile);
646 ret = sepol_kernel_policydb_to_conf(outfp, policydbp);
647 }
James Carterb1d94562015-04-01 10:05:04 -0400648 if (ret) {
649 fprintf(stderr, "%s: error writing %s\n",
650 argv[0], outfile);
651 exit(1);
652 }
653 } else {
654 printf("%s: writing CIL to %s\n",argv[0], outfile);
James Carter13c27d62017-03-21 16:00:30 -0400655 if (binary) {
656 ret = sepol_kernel_policydb_to_cil(outfp, policydbp);
657 } else {
658 ret = sepol_module_policydb_to_cil(outfp, policydbp, 1);
659 }
James Carterb1d94562015-04-01 10:05:04 -0400660 if (ret) {
661 fprintf(stderr, "%s: error writing %s\n", argv[0], outfile);
662 exit(1);
663 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400664 }
James Carterb1d94562015-04-01 10:05:04 -0400665
666 if (outfile) {
667 fclose(outfp);
668 }
669 } else if (cil) {
670 fprintf(stderr, "%s: No file to write CIL was specified\n", argv[0]);
671 exit(1);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400672 }
James Carterb1d94562015-04-01 10:05:04 -0400673
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400674 if (!debug) {
675 policydb_destroy(&policydb);
James Carterdd11ab62017-03-17 15:58:29 -0400676 sepol_sidtab_destroy(&sidtab);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400677 exit(0);
678 }
679
680 menu:
681 printf("\nSelect an option:\n");
682 printf("0) Call compute_access_vector\n");
683 printf("1) Call sid_to_context\n");
684 printf("2) Call context_to_sid\n");
685 printf("3) Call transition_sid\n");
686 printf("4) Call member_sid\n");
687 printf("5) Call change_sid\n");
688 printf("6) Call list_sids\n");
689 printf("7) Call load_policy\n");
690 printf("8) Call fs_sid\n");
691 printf("9) Call port_sid\n");
692 printf("a) Call netif_sid\n");
693 printf("b) Call node_sid\n");
694 printf("c) Call fs_use\n");
695 printf("d) Call genfs_sid\n");
696 printf("e) Call get_user_sids\n");
697 printf("f) display conditional bools\n");
698 printf("g) display conditional expressions\n");
699 printf("h) change a boolean value\n");
Richard Hainesab9cbb12013-11-03 19:12:29 +0000700 printf("i) display constraint expressions\n");
701 printf("j) display validatetrans expressions\n");
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400702#ifdef EQUIVTYPES
703 printf("z) Show equivalent types\n");
704#endif
705 printf("m) Show menu again\n");
706 printf("q) Exit\n");
707 while (1) {
708 printf("\nChoose: ");
709 FGETS(ans, sizeof(ans), stdin);
710 switch (ans[0]) {
711 case '0':
712 printf("source sid? ");
713 FGETS(ans, sizeof(ans), stdin);
714 ssid = atoi(ans);
715
716 printf("target sid? ");
717 FGETS(ans, sizeof(ans), stdin);
718 tsid = atoi(ans);
719
720 printf("target class? ");
721 FGETS(ans, sizeof(ans), stdin);
722 if (isdigit(ans[0])) {
723 tclass = atoi(ans);
724 if (!tclass
725 || tclass > policydb.p_classes.nprim) {
726 printf("\nNo such class.\n");
727 break;
728 }
729 cladatum =
730 policydb.class_val_to_struct[tclass - 1];
731 } else {
732 ans[strlen(ans) - 1] = 0;
733 cladatum =
734 (class_datum_t *) hashtab_search(policydb.
735 p_classes.
736 table,
737 ans);
738 if (!cladatum) {
739 printf("\nNo such class\n");
740 break;
741 }
742 tclass = cladatum->s.value;
743 }
744
745 if (!cladatum->comdatum && !cladatum->permissions.nprim) {
746 printf
747 ("\nNo access vector definition for that class\n");
748 break;
749 }
750 ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd);
751 switch (ret) {
752 case 0:
753 printf("\nallowed {");
754 for (i = 1; i <= sizeof(avd.allowed) * 8; i++) {
755 if (avd.allowed & (1 << (i - 1))) {
756 v.val = i;
757 ret =
758 hashtab_map(cladatum->
759 permissions.
760 table,
761 find_perm, &v);
762 if (!ret && cladatum->comdatum) {
763 ret =
764 hashtab_map
765 (cladatum->
766 comdatum->
767 permissions.table,
768 find_perm, &v);
769 }
770 if (ret)
771 printf(" %s", v.name);
772 }
773 }
774 printf(" }\n");
775 break;
776 case -EINVAL:
777 printf("\ninvalid sid\n");
778 break;
779 default:
780 printf("return code 0x%x\n", ret);
781 }
782 break;
783 case '1':
784 printf("sid? ");
785 FGETS(ans, sizeof(ans), stdin);
786 ssid = atoi(ans);
787 ret = sepol_sid_to_context(ssid,
788 &scontext, &scontext_len);
789 switch (ret) {
790 case 0:
791 printf("\nscontext %s\n", scontext);
792 free(scontext);
793 break;
794 case -EINVAL:
795 printf("\ninvalid sid\n");
796 break;
797 case -ENOMEM:
798 printf("\nout of memory\n");
799 break;
800 default:
801 printf("return code 0x%x\n", ret);
802 }
803 break;
804 case '2':
805 printf("scontext? ");
806 FGETS(ans, sizeof(ans), stdin);
807 scontext_len = strlen(ans);
808 ans[scontext_len - 1] = 0;
809 ret = sepol_context_to_sid(ans, scontext_len, &ssid);
810 switch (ret) {
811 case 0:
812 printf("\nsid %d\n", ssid);
813 break;
814 case -EINVAL:
815 printf("\ninvalid context\n");
816 break;
817 case -ENOMEM:
818 printf("\nout of memory\n");
819 break;
820 default:
821 printf("return code 0x%x\n", ret);
822 }
823 break;
824 case '3':
825 case '4':
826 case '5':
827 ch = ans[0];
828
829 printf("source sid? ");
830 FGETS(ans, sizeof(ans), stdin);
831 ssid = atoi(ans);
832 printf("target sid? ");
833 FGETS(ans, sizeof(ans), stdin);
834 tsid = atoi(ans);
835
836 printf("object class? ");
837 FGETS(ans, sizeof(ans), stdin);
838 if (isdigit(ans[0])) {
839 tclass = atoi(ans);
840 if (!tclass
841 || tclass > policydb.p_classes.nprim) {
842 printf("\nNo such class.\n");
843 break;
844 }
845 } else {
846 ans[strlen(ans) - 1] = 0;
847 cladatum =
848 (class_datum_t *) hashtab_search(policydb.
849 p_classes.
850 table,
851 ans);
852 if (!cladatum) {
853 printf("\nNo such class\n");
854 break;
855 }
856 tclass = cladatum->s.value;
857 }
858
859 if (ch == '3')
860 ret =
861 sepol_transition_sid(ssid, tsid, tclass,
862 &ssid);
863 else if (ch == '4')
864 ret =
865 sepol_member_sid(ssid, tsid, tclass, &ssid);
866 else
867 ret =
868 sepol_change_sid(ssid, tsid, tclass, &ssid);
869 switch (ret) {
870 case 0:
871 printf("\nsid %d\n", ssid);
872 break;
873 case -EINVAL:
874 printf("\ninvalid sid\n");
875 break;
876 case -ENOMEM:
877 printf("\nout of memory\n");
878 break;
879 default:
880 printf("return code 0x%x\n", ret);
881 }
882 break;
883 case '6':
884 sepol_sidtab_map(&sidtab, print_sid, 0);
885 break;
886 case '7':
887 printf("pathname? ");
888 FGETS(ans, sizeof(ans), stdin);
889 pathlen = strlen(ans);
890 ans[pathlen - 1] = 0;
891 printf("%s: loading policy configuration from %s\n",
892 argv[0], ans);
893 fd = open(ans, O_RDONLY);
894 if (fd < 0) {
895 fprintf(stderr, "Can't open '%s': %s\n",
896 ans, strerror(errno));
897 break;
898 }
899 if (fstat(fd, &sb) < 0) {
900 fprintf(stderr, "Can't stat '%s': %s\n",
901 ans, strerror(errno));
902 break;
903 }
904 map =
905 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
906 MAP_PRIVATE, fd, 0);
907 if (map == MAP_FAILED) {
908 fprintf(stderr, "Can't map '%s': %s\n",
909 ans, strerror(errno));
910 break;
911 }
912 ret = sepol_load_policy(map, sb.st_size);
913 switch (ret) {
914 case 0:
915 printf("\nsuccess\n");
916 break;
917 case -EINVAL:
918 printf("\ninvalid policy\n");
919 break;
920 case -ENOMEM:
921 printf("\nout of memory\n");
922 break;
923 default:
924 printf("return code 0x%x\n", ret);
925 }
926 break;
927 case '8':
928 printf("fs kdevname? ");
929 FGETS(ans, sizeof(ans), stdin);
930 ans[strlen(ans) - 1] = 0;
931 sepol_fs_sid(ans, &ssid, &tsid);
932 printf("fs_sid %d default_file_sid %d\n", ssid, tsid);
933 break;
934 case '9':
935 printf("protocol? ");
936 FGETS(ans, sizeof(ans), stdin);
937 ans[strlen(ans) - 1] = 0;
938 if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP"))
939 protocol = IPPROTO_TCP;
940 else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP"))
941 protocol = IPPROTO_UDP;
Richard Haines3895fbb2016-04-06 12:44:35 +0100942 else if (!strcmp(ans, "dccp") || !strcmp(ans, "DCCP"))
943 protocol = IPPROTO_DCCP;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400944 else {
945 printf("unknown protocol\n");
946 break;
947 }
948 printf("port? ");
949 FGETS(ans, sizeof(ans), stdin);
950 port = atoi(ans);
951 sepol_port_sid(0, 0, protocol, port, &ssid);
952 printf("sid %d\n", ssid);
953 break;
954 case 'a':
955 printf("netif name? ");
956 FGETS(ans, sizeof(ans), stdin);
957 ans[strlen(ans) - 1] = 0;
958 sepol_netif_sid(ans, &ssid, &tsid);
959 printf("if_sid %d default_msg_sid %d\n", ssid, tsid);
960 break;
961 case 'b':{
962 char *p;
963 int family, len;
964 struct in_addr addr4;
965 struct in6_addr addr6;
966
967 printf("protocol family? ");
968 FGETS(ans, sizeof(ans), stdin);
969 ans[strlen(ans) - 1] = 0;
970 if (!strcasecmp(ans, "ipv4"))
971 family = AF_INET;
972 else if (!strcasecmp(ans, "ipv6"))
973 family = AF_INET6;
974 else {
975 printf("unknown protocol family\n");
976 break;
977 }
978
979 printf("node address? ");
980 FGETS(ans, sizeof(ans), stdin);
981 ans[strlen(ans) - 1] = 0;
982
983 if (family == AF_INET) {
984 p = (char *)&addr4;
985 len = sizeof(addr4);
986 } else {
987 p = (char *)&addr6;
988 len = sizeof(addr6);
989 }
990
991 if (inet_pton(family, ans, p) < 1) {
992 printf("error parsing address\n");
993 break;
994 }
995
996 sepol_node_sid(family, p, len, &ssid);
997 printf("sid %d\n", ssid);
998 break;
999 }
1000 case 'c':
1001 printf("fstype? ");
1002 FGETS(ans, sizeof(ans), stdin);
1003 ans[strlen(ans) - 1] = 0;
1004 sepol_fs_use(ans, &uret, &ssid);
1005 switch (uret) {
1006 case SECURITY_FS_USE_XATTR:
1007 printf("use xattr\n");
1008 break;
1009 case SECURITY_FS_USE_TRANS:
1010 printf("use transition SIDs\n");
1011 break;
1012 case SECURITY_FS_USE_TASK:
1013 printf("use task SIDs\n");
1014 break;
1015 case SECURITY_FS_USE_GENFS:
1016 printf("use genfs\n");
1017 break;
1018 case SECURITY_FS_USE_NONE:
1019 printf("no labeling support\n");
1020 break;
1021 }
1022 printf("sid %d\n", ssid);
1023 break;
1024 case 'd':
1025 printf("fstype? ");
1026 FGETS(ans, sizeof(ans), stdin);
1027 ans[strlen(ans) - 1] = 0;
1028 fstype = strdup(ans);
1029 printf("path? ");
1030 FGETS(ans, sizeof(ans), stdin);
1031 ans[strlen(ans) - 1] = 0;
1032 path = strdup(ans);
1033 printf("object class? ");
1034 FGETS(ans, sizeof(ans), stdin);
1035 if (isdigit(ans[0])) {
1036 tclass = atoi(ans);
1037 if (!tclass
1038 || tclass > policydb.p_classes.nprim) {
1039 printf("\nNo such class.\n");
1040 break;
1041 }
1042 } else {
1043 ans[strlen(ans) - 1] = 0;
1044 cladatum =
1045 (class_datum_t *) hashtab_search(policydb.
1046 p_classes.
1047 table,
1048 ans);
1049 if (!cladatum) {
1050 printf("\nNo such class\n");
1051 break;
1052 }
1053 tclass = cladatum->s.value;
1054 }
1055 sepol_genfs_sid(fstype, path, tclass, &ssid);
1056 printf("sid %d\n", ssid);
1057 free(fstype);
1058 free(path);
1059 break;
1060 case 'e':
1061 printf("from SID? ");
1062 FGETS(ans, sizeof(ans), stdin);
1063 ans[strlen(ans) - 1] = 0;
1064 ssid = atoi(ans);
1065
1066 printf("username? ");
1067 FGETS(ans, sizeof(ans), stdin);
1068 ans[strlen(ans) - 1] = 0;
1069
1070 ret = sepol_get_user_sids(ssid, ans, &sids, &nel);
1071 switch (ret) {
1072 case 0:
1073 if (!nel)
1074 printf("\nnone\n");
1075 for (i = 0; i < nel; i++)
1076 print_sid(sids[i], NULL, NULL);
1077 free(sids);
1078 break;
1079 case -ENOMEM:
1080 printf("\nout of memory\n");
1081 break;
1082 case -EINVAL:
1083 printf("\ninvalid argument\n");
1084 break;
1085 default:
1086 printf("\nerror\n");
1087 break;
1088 }
1089 break;
1090 case 'f':
1091 display_bools();
1092 break;
1093 case 'g':
1094 display_cond_expressions();
1095 break;
1096 case 'h':
1097 printf("name? ");
1098 FGETS(ans, sizeof(ans), stdin);
1099 ans[strlen(ans) - 1] = 0;
1100
1101 name = malloc((strlen(ans) + 1) * sizeof(char));
1102 if (name == NULL) {
1103 fprintf(stderr, "couldn't malloc string.\n");
1104 break;
1105 }
1106 strcpy(name, ans);
1107
1108 printf("state? ");
1109 FGETS(ans, sizeof(ans), stdin);
1110 ans[strlen(ans) - 1] = 0;
1111
1112 if (atoi(ans))
1113 state = 1;
1114 else
1115 state = 0;
1116
1117 change_bool(name, state);
1118 free(name);
1119 break;
Richard Hainesab9cbb12013-11-03 19:12:29 +00001120 case 'i':
1121 printf("source sid? ");
1122 FGETS(ans, sizeof(ans), stdin);
1123 ssid = atoi(ans);
1124
1125 printf("target sid? ");
1126 FGETS(ans, sizeof(ans), stdin);
1127 tsid = atoi(ans);
1128
1129 printf("target class? ");
1130 FGETS(ans, sizeof(ans), stdin);
1131 if (isdigit(ans[0])) {
1132 tclass = atoi(ans);
1133 if (!tclass
1134 || tclass > policydb.p_classes.nprim) {
1135 printf("\nNo such class.\n");
1136 break;
1137 }
1138 cladatum =
1139 policydb.class_val_to_struct[tclass - 1];
1140 } else {
1141 ans[strlen(ans) - 1] = 0;
1142 cladatum =
1143 (class_datum_t *) hashtab_search(policydb.
1144 p_classes.
1145 table,
1146 ans);
1147 if (!cladatum) {
1148 printf("\nNo such class\n");
1149 break;
1150 }
1151 tclass = cladatum->s.value;
1152 }
1153
1154 flags = SHOW_GRANTED;
1155 if (sepol_compute_av_reason_buffer(ssid, tsid,
1156 tclass, 0, &avd, &reason,
1157 &reason_buf, flags)) {
1158 printf("\nconstraint error\n");
1159 break;
1160 }
1161 if (reason_buf) {
1162 printf("\nConstraint expressions:\n%s",
1163 reason_buf);
1164 free(reason_buf);
1165 } else {
1166 printf("\nNo constraints found.\n");
1167 }
1168 break;
1169 case 'j':
1170 printf("old sid? ");
1171 FGETS(ans, sizeof(ans), stdin);
1172 oldsid = atoi(ans);
1173
1174 printf("new sid? ");
1175 FGETS(ans, sizeof(ans), stdin);
1176 newsid = atoi(ans);
1177
1178 printf("task sid? ");
1179 FGETS(ans, sizeof(ans), stdin);
1180 tasksid = atoi(ans);
1181
1182 printf("target class? ");
1183 FGETS(ans, sizeof(ans), stdin);
1184 if (isdigit(ans[0])) {
1185 tclass = atoi(ans);
1186 if (!tclass
1187 || tclass > policydb.p_classes.nprim) {
1188 printf("\nNo such class.\n");
1189 break;
1190 }
1191 cladatum =
1192 policydb.class_val_to_struct[tclass - 1];
1193 } else {
1194 ans[strlen(ans) - 1] = 0;
1195 cladatum =
1196 (class_datum_t *) hashtab_search(policydb.
1197 p_classes.
1198 table,
1199 ans);
1200 if (!cladatum) {
1201 printf("\nNo such class\n");
1202 break;
1203 }
1204 tclass = cladatum->s.value;
1205 }
1206
1207 flags = SHOW_GRANTED;
1208 if (sepol_validate_transition_reason_buffer(oldsid,
1209 newsid, tasksid, tclass,
1210 &reason_buf, flags)) {
1211 printf("\nvalidatetrans error\n");
1212 break;
1213 }
1214 if (reason_buf) {
1215 printf("\nValidatetrans expressions:\n%s",
1216 reason_buf);
1217 free(reason_buf);
1218 } else {
1219 printf(
1220 "\nNo validatetrans expressions found.\n");
1221 }
1222 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -04001223#ifdef EQUIVTYPES
1224 case 'z':
1225 identify_equiv_types();
1226 break;
1227#endif
1228 case 'm':
1229 goto menu;
1230 case 'q':
1231 exit(0);
1232 break;
1233 default:
1234 printf("\nUnknown option %s.\n", ans);
1235 }
1236 }
1237
1238 return 0;
1239}
1240
1241/* FLASK */