blob: 8aeecc1bc6934e8f31fd9a9b6b3bb466a005f9c9 [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 *
Daniel Jurgens9fbb3112017-05-22 16:08:24 +030025 * Copyright (C) 2017 Mellanox Technologies Inc.
Joshua Brindle13cd4c82008-08-19 15:30:36 -040026 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
27 * Copyright (C) 2003 - 2005 Tresys Technology, LLC
28 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation, version 2.
32 */
33
34/* FLASK */
35
36/*
37 * checkpolicy
38 *
39 * Load and check a policy configuration.
40 *
41 * A policy configuration is created in a text format,
42 * and then compiled into a binary format for use by
43 * the security server. By default, checkpolicy reads
44 * the text format. If '-b' is specified, then checkpolicy
45 * reads the binary format instead.
46 *
47 * If '-o output_file' is specified, then checkpolicy
48 * writes the binary format version of the configuration
49 * to the specified output file.
50 *
51 * If '-d' is specified, then checkpolicy permits the user
52 * to interactively test the security server functions with
53 * the loaded policy configuration.
54 *
55 * If '-c' is specified, then the supplied parameter is used to
56 * determine which policy version to use for generating binary
57 * policy. This is for compatibility with older kernels. If any
58 * booleans or conditional rules are thrown away a warning is printed.
59 */
60
Nicolas Iooss61f760b2017-01-08 19:45:52 +010061#include <ctype.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -040062#include <getopt.h>
63#include <unistd.h>
64#include <stdlib.h>
65#include <sys/types.h>
66#include <sys/stat.h>
67#include <sys/socket.h>
68#include <netinet/in.h>
Richard Hainesaac93602016-04-24 10:34:47 +010069#ifndef IPPROTO_DCCP
70#define IPPROTO_DCCP 33
71#endif
Joshua Brindle13cd4c82008-08-19 15:30:36 -040072#include <arpa/inet.h>
73#include <fcntl.h>
74#include <stdio.h>
75#include <errno.h>
76#include <sys/mman.h>
77
James Carterb1d94562015-04-01 10:05:04 -040078#include <sepol/module_to_cil.h>
James Carter13c27d62017-03-21 16:00:30 -040079#include <sepol/kernel_to_cil.h>
80#include <sepol/kernel_to_conf.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
Nicolas Ioossef61dd72017-03-05 18:13:01 +0100108static __attribute__((__noreturn__)) void usage(const char *progname)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400109{
110 printf
James Carter13c27d62017-03-21 16:00:30 -0400111 ("usage: %s [-b[F]] [-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 Carter13c27d62017-03-21 16:00:30 -0400394 unsigned int binary = 0, debug = 0, cil = 0, conf = 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'},
James Carter13c27d62017-03-21 16:00:30 -0400417 {"conf",no_argument, NULL, 'F'},
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100418 {"help", no_argument, NULL, 'h'},
419 {NULL, 0, NULL, 0}
420 };
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400421
James Carter13c27d62017-03-21 16:00:30 -0400422 while ((ch = getopt_long(argc, argv, "o:t:dbU:MCFVc:h", long_options, NULL)) != -1) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400423 switch (ch) {
424 case 'o':
425 outfile = optarg;
426 break;
Paul Nuzzi79d10a82009-09-29 10:06:26 -0400427 case 't':
428 if (!strcasecmp(optarg, "Xen"))
429 target = SEPOL_TARGET_XEN;
430 else if (!strcasecmp(optarg, "SELinux"))
431 target = SEPOL_TARGET_SELINUX;
432 else{
433 fprintf(stderr, "%s: Unknown target platform:"
434 "%s\n", argv[0], optarg);
435 exit(1);
436 }
437 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400438 case 'b':
439 binary = 1;
440 file = binfile;
441 break;
442 case 'd':
443 debug = 1;
444 break;
445 case 'V':
446 show_version = 1;
447 break;
448 case 'U':
449 if (!strcasecmp(optarg, "deny")) {
450 handle_unknown = DENY_UNKNOWN;
451 break;
452 }
453 if (!strcasecmp(optarg, "allow")) {
454 handle_unknown = ALLOW_UNKNOWN;
455 break;
456 }
457 if (!strcasecmp(optarg, "reject")) {
458 handle_unknown = REJECT_UNKNOWN;
459 break;
460 }
461 usage(argv[0]);
462 case 'M':
463 mlspol = 1;
464 break;
James Carterb1d94562015-04-01 10:05:04 -0400465 case 'C':
466 cil = 1;
467 break;
James Carter13c27d62017-03-21 16:00:30 -0400468 case 'F':
469 conf = 1;
470 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400471 case 'c':{
Dan Albertb1bbd302014-12-10 11:28:44 -0800472 long int n;
473 errno = 0;
474 n = strtol(optarg, NULL, 10);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400475 if (errno) {
476 fprintf(stderr,
477 "Invalid policyvers specified: %s\n",
478 optarg);
479 usage(argv[0]);
480 exit(1);
481 }
482 if (n < POLICYDB_VERSION_MIN
483 || n > POLICYDB_VERSION_MAX) {
484 fprintf(stderr,
485 "policyvers value %ld not in range %d-%d\n",
486 n, POLICYDB_VERSION_MIN,
487 POLICYDB_VERSION_MAX);
488 usage(argv[0]);
489 exit(1);
490 }
491 if (policyvers != n)
492 policyvers = n;
493 break;
494 }
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100495 case 'h':
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400496 default:
497 usage(argv[0]);
498 }
499 }
500
501 if (show_version) {
502 printf("%d (compatibility range %d-%d)\n", policyvers,
503 POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN);
504 exit(0);
505 }
506
507 if (optind != argc) {
508 file = argv[optind++];
509 if (optind != argc)
510 usage(argv[0]);
511 }
512 printf("%s: loading policy configuration from %s\n", argv[0], file);
513
514 /* Set policydb and sidtab used by libsepol service functions
515 to my structures, so that I can directly populate and
516 manipulate them. */
517 sepol_set_policydb(&policydb);
518 sepol_set_sidtab(&sidtab);
519
James Carter13c27d62017-03-21 16:00:30 -0400520 if (cil && conf) {
521 fprintf(stderr, "Can't convert to CIL and policy.conf at the same time\n");
522 exit(1);
523 }
524
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400525 if (binary) {
526 fd = open(file, O_RDONLY);
527 if (fd < 0) {
528 fprintf(stderr, "Can't open '%s': %s\n",
529 file, strerror(errno));
530 exit(1);
531 }
532 if (fstat(fd, &sb) < 0) {
533 fprintf(stderr, "Can't stat '%s': %s\n",
534 file, strerror(errno));
535 exit(1);
536 }
537 map =
538 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
539 fd, 0);
540 if (map == MAP_FAILED) {
541 fprintf(stderr, "Can't map '%s': %s\n",
542 file, strerror(errno));
543 exit(1);
544 }
545 policy_file_init(&pf);
546 pf.type = PF_USE_MEMORY;
547 pf.data = map;
548 pf.len = sb.st_size;
549 if (policydb_init(&policydb)) {
550 fprintf(stderr, "%s: policydb_init: Out of memory!\n",
551 argv[0]);
552 exit(1);
553 }
554 ret = policydb_read(&policydb, &pf, 1);
555 if (ret) {
556 fprintf(stderr,
557 "%s: error(s) encountered while parsing configuration\n",
558 argv[0]);
559 exit(1);
560 }
561 policydbp = &policydb;
562
563 /* Check Policy Consistency */
564 if (policydbp->mls) {
565 if (!mlspol) {
566 fprintf(stderr, "%s: MLS policy, but non-MLS"
567 " is specified\n", argv[0]);
568 exit(1);
569 }
570 } else {
571 if (mlspol) {
572 fprintf(stderr, "%s: non-MLS policy, but MLS"
573 " is specified\n", argv[0]);
574 exit(1);
575 }
576 }
577 } else {
James Carter13c27d62017-03-21 16:00:30 -0400578 if (conf) {
579 fprintf(stderr, "Can only generate policy.conf from binary policy\n");
580 exit(1);
581 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400582 if (policydb_init(&parse_policy))
583 exit(1);
584 /* We build this as a base policy first since that is all the parser understands */
585 parse_policy.policy_type = POLICY_BASE;
Paul Nuzzi79d10a82009-09-29 10:06:26 -0400586 policydb_set_target_platform(&parse_policy, target);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400587
588 /* Let sepol know if we are dealing with MLS support */
589 parse_policy.mls = mlspol;
590 parse_policy.handle_unknown = handle_unknown;
591
592 policydbp = &parse_policy;
593
594 if (read_source_policy(policydbp, file, "checkpolicy") < 0)
595 exit(1);
596
597 if (hashtab_map(policydbp->p_levels.table, check_level, NULL))
598 exit(1);
599
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400600 /* Linking takes care of optional avrule blocks */
James Carterb1d94562015-04-01 10:05:04 -0400601 if (link_modules(NULL, policydbp, NULL, 0, 0)) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400602 fprintf(stderr, "Error while resolving optionals\n");
603 exit(1);
604 }
605
James Carterb1d94562015-04-01 10:05:04 -0400606 if (!cil) {
607 if (policydb_init(&policydb)) {
608 fprintf(stderr, "%s: policydb_init failed\n", argv[0]);
609 exit(1);
610 }
611 if (expand_module(NULL, policydbp, &policydb, 0, 1)) {
612 fprintf(stderr, "Error while expanding policy\n");
613 exit(1);
614 }
615 policydb_destroy(policydbp);
616 policydbp = &policydb;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400617 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400618 }
619
620 if (policydb_load_isids(&policydb, &sidtab))
621 exit(1);
622
623 printf("%s: policy configuration loaded\n", argv[0]);
624
625 if (outfile) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400626 outfp = fopen(outfile, "w");
627 if (!outfp) {
628 perror(outfile);
629 exit(1);
630 }
631
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400632 policydb.policyvers = policyvers;
633
James Carterb1d94562015-04-01 10:05:04 -0400634 if (!cil) {
James Carter13c27d62017-03-21 16:00:30 -0400635 if (!conf) {
636 printf("%s: writing binary representation (version %d) to %s\n", argv[0], policyvers, outfile);
James Carterb1d94562015-04-01 10:05:04 -0400637
James Carter13c27d62017-03-21 16:00:30 -0400638 policydb.policy_type = POLICY_KERN;
639
640 policy_file_init(&pf);
641 pf.type = PF_USE_STDIO;
642 pf.fp = outfp;
643 ret = policydb_write(&policydb, &pf);
644 } else {
645 printf("%s: writing policy.conf to %s\n",
646 argv[0], outfile);
647 ret = sepol_kernel_policydb_to_conf(outfp, policydbp);
648 }
James Carterb1d94562015-04-01 10:05:04 -0400649 if (ret) {
650 fprintf(stderr, "%s: error writing %s\n",
651 argv[0], outfile);
652 exit(1);
653 }
654 } else {
655 printf("%s: writing CIL to %s\n",argv[0], outfile);
James Carter13c27d62017-03-21 16:00:30 -0400656 if (binary) {
657 ret = sepol_kernel_policydb_to_cil(outfp, policydbp);
658 } else {
659 ret = sepol_module_policydb_to_cil(outfp, policydbp, 1);
660 }
James Carterb1d94562015-04-01 10:05:04 -0400661 if (ret) {
662 fprintf(stderr, "%s: error writing %s\n", argv[0], outfile);
663 exit(1);
664 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400665 }
James Carterb1d94562015-04-01 10:05:04 -0400666
667 if (outfile) {
668 fclose(outfp);
669 }
670 } else if (cil) {
671 fprintf(stderr, "%s: No file to write CIL was specified\n", argv[0]);
672 exit(1);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400673 }
James Carterb1d94562015-04-01 10:05:04 -0400674
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400675 if (!debug) {
676 policydb_destroy(&policydb);
James Carterdd11ab62017-03-17 15:58:29 -0400677 sepol_sidtab_destroy(&sidtab);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400678 exit(0);
679 }
680
681 menu:
682 printf("\nSelect an option:\n");
683 printf("0) Call compute_access_vector\n");
684 printf("1) Call sid_to_context\n");
685 printf("2) Call context_to_sid\n");
686 printf("3) Call transition_sid\n");
687 printf("4) Call member_sid\n");
688 printf("5) Call change_sid\n");
689 printf("6) Call list_sids\n");
690 printf("7) Call load_policy\n");
691 printf("8) Call fs_sid\n");
692 printf("9) Call port_sid\n");
693 printf("a) Call netif_sid\n");
694 printf("b) Call node_sid\n");
695 printf("c) Call fs_use\n");
696 printf("d) Call genfs_sid\n");
697 printf("e) Call get_user_sids\n");
698 printf("f) display conditional bools\n");
699 printf("g) display conditional expressions\n");
700 printf("h) change a boolean value\n");
Richard Hainesab9cbb12013-11-03 19:12:29 +0000701 printf("i) display constraint expressions\n");
702 printf("j) display validatetrans expressions\n");
Daniel Jurgens9fbb3112017-05-22 16:08:24 +0300703 printf("k) Call ibpkey_sid\n");
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400704#ifdef EQUIVTYPES
705 printf("z) Show equivalent types\n");
706#endif
707 printf("m) Show menu again\n");
708 printf("q) Exit\n");
709 while (1) {
710 printf("\nChoose: ");
711 FGETS(ans, sizeof(ans), stdin);
712 switch (ans[0]) {
713 case '0':
714 printf("source sid? ");
715 FGETS(ans, sizeof(ans), stdin);
716 ssid = atoi(ans);
717
718 printf("target sid? ");
719 FGETS(ans, sizeof(ans), stdin);
720 tsid = atoi(ans);
721
722 printf("target class? ");
723 FGETS(ans, sizeof(ans), stdin);
724 if (isdigit(ans[0])) {
725 tclass = atoi(ans);
726 if (!tclass
727 || tclass > policydb.p_classes.nprim) {
728 printf("\nNo such class.\n");
729 break;
730 }
731 cladatum =
732 policydb.class_val_to_struct[tclass - 1];
733 } else {
734 ans[strlen(ans) - 1] = 0;
735 cladatum =
736 (class_datum_t *) hashtab_search(policydb.
737 p_classes.
738 table,
739 ans);
740 if (!cladatum) {
741 printf("\nNo such class\n");
742 break;
743 }
744 tclass = cladatum->s.value;
745 }
746
747 if (!cladatum->comdatum && !cladatum->permissions.nprim) {
748 printf
749 ("\nNo access vector definition for that class\n");
750 break;
751 }
752 ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd);
753 switch (ret) {
754 case 0:
755 printf("\nallowed {");
756 for (i = 1; i <= sizeof(avd.allowed) * 8; i++) {
757 if (avd.allowed & (1 << (i - 1))) {
758 v.val = i;
759 ret =
760 hashtab_map(cladatum->
761 permissions.
762 table,
763 find_perm, &v);
764 if (!ret && cladatum->comdatum) {
765 ret =
766 hashtab_map
767 (cladatum->
768 comdatum->
769 permissions.table,
770 find_perm, &v);
771 }
772 if (ret)
773 printf(" %s", v.name);
774 }
775 }
776 printf(" }\n");
777 break;
778 case -EINVAL:
779 printf("\ninvalid sid\n");
780 break;
781 default:
782 printf("return code 0x%x\n", ret);
783 }
784 break;
785 case '1':
786 printf("sid? ");
787 FGETS(ans, sizeof(ans), stdin);
788 ssid = atoi(ans);
789 ret = sepol_sid_to_context(ssid,
790 &scontext, &scontext_len);
791 switch (ret) {
792 case 0:
793 printf("\nscontext %s\n", scontext);
794 free(scontext);
795 break;
796 case -EINVAL:
797 printf("\ninvalid sid\n");
798 break;
799 case -ENOMEM:
800 printf("\nout of memory\n");
801 break;
802 default:
803 printf("return code 0x%x\n", ret);
804 }
805 break;
806 case '2':
807 printf("scontext? ");
808 FGETS(ans, sizeof(ans), stdin);
809 scontext_len = strlen(ans);
810 ans[scontext_len - 1] = 0;
811 ret = sepol_context_to_sid(ans, scontext_len, &ssid);
812 switch (ret) {
813 case 0:
814 printf("\nsid %d\n", ssid);
815 break;
816 case -EINVAL:
817 printf("\ninvalid context\n");
818 break;
819 case -ENOMEM:
820 printf("\nout of memory\n");
821 break;
822 default:
823 printf("return code 0x%x\n", ret);
824 }
825 break;
826 case '3':
827 case '4':
828 case '5':
829 ch = ans[0];
830
831 printf("source sid? ");
832 FGETS(ans, sizeof(ans), stdin);
833 ssid = atoi(ans);
834 printf("target sid? ");
835 FGETS(ans, sizeof(ans), stdin);
836 tsid = atoi(ans);
837
838 printf("object class? ");
839 FGETS(ans, sizeof(ans), stdin);
840 if (isdigit(ans[0])) {
841 tclass = atoi(ans);
842 if (!tclass
843 || tclass > policydb.p_classes.nprim) {
844 printf("\nNo such class.\n");
845 break;
846 }
847 } else {
848 ans[strlen(ans) - 1] = 0;
849 cladatum =
850 (class_datum_t *) hashtab_search(policydb.
851 p_classes.
852 table,
853 ans);
854 if (!cladatum) {
855 printf("\nNo such class\n");
856 break;
857 }
858 tclass = cladatum->s.value;
859 }
860
861 if (ch == '3')
862 ret =
863 sepol_transition_sid(ssid, tsid, tclass,
864 &ssid);
865 else if (ch == '4')
866 ret =
867 sepol_member_sid(ssid, tsid, tclass, &ssid);
868 else
869 ret =
870 sepol_change_sid(ssid, tsid, tclass, &ssid);
871 switch (ret) {
872 case 0:
873 printf("\nsid %d\n", ssid);
874 break;
875 case -EINVAL:
876 printf("\ninvalid sid\n");
877 break;
878 case -ENOMEM:
879 printf("\nout of memory\n");
880 break;
881 default:
882 printf("return code 0x%x\n", ret);
883 }
884 break;
885 case '6':
886 sepol_sidtab_map(&sidtab, print_sid, 0);
887 break;
888 case '7':
889 printf("pathname? ");
890 FGETS(ans, sizeof(ans), stdin);
891 pathlen = strlen(ans);
892 ans[pathlen - 1] = 0;
893 printf("%s: loading policy configuration from %s\n",
894 argv[0], ans);
895 fd = open(ans, O_RDONLY);
896 if (fd < 0) {
897 fprintf(stderr, "Can't open '%s': %s\n",
898 ans, strerror(errno));
899 break;
900 }
901 if (fstat(fd, &sb) < 0) {
902 fprintf(stderr, "Can't stat '%s': %s\n",
903 ans, strerror(errno));
904 break;
905 }
906 map =
907 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
908 MAP_PRIVATE, fd, 0);
909 if (map == MAP_FAILED) {
910 fprintf(stderr, "Can't map '%s': %s\n",
911 ans, strerror(errno));
912 break;
913 }
914 ret = sepol_load_policy(map, sb.st_size);
915 switch (ret) {
916 case 0:
917 printf("\nsuccess\n");
918 break;
919 case -EINVAL:
920 printf("\ninvalid policy\n");
921 break;
922 case -ENOMEM:
923 printf("\nout of memory\n");
924 break;
925 default:
926 printf("return code 0x%x\n", ret);
927 }
928 break;
929 case '8':
930 printf("fs kdevname? ");
931 FGETS(ans, sizeof(ans), stdin);
932 ans[strlen(ans) - 1] = 0;
933 sepol_fs_sid(ans, &ssid, &tsid);
934 printf("fs_sid %d default_file_sid %d\n", ssid, tsid);
935 break;
936 case '9':
937 printf("protocol? ");
938 FGETS(ans, sizeof(ans), stdin);
939 ans[strlen(ans) - 1] = 0;
940 if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP"))
941 protocol = IPPROTO_TCP;
942 else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP"))
943 protocol = IPPROTO_UDP;
Richard Haines3895fbb2016-04-06 12:44:35 +0100944 else if (!strcmp(ans, "dccp") || !strcmp(ans, "DCCP"))
945 protocol = IPPROTO_DCCP;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400946 else {
947 printf("unknown protocol\n");
948 break;
949 }
950 printf("port? ");
951 FGETS(ans, sizeof(ans), stdin);
952 port = atoi(ans);
953 sepol_port_sid(0, 0, protocol, port, &ssid);
954 printf("sid %d\n", ssid);
955 break;
956 case 'a':
957 printf("netif name? ");
958 FGETS(ans, sizeof(ans), stdin);
959 ans[strlen(ans) - 1] = 0;
960 sepol_netif_sid(ans, &ssid, &tsid);
961 printf("if_sid %d default_msg_sid %d\n", ssid, tsid);
962 break;
963 case 'b':{
964 char *p;
965 int family, len;
966 struct in_addr addr4;
967 struct in6_addr addr6;
968
969 printf("protocol family? ");
970 FGETS(ans, sizeof(ans), stdin);
971 ans[strlen(ans) - 1] = 0;
972 if (!strcasecmp(ans, "ipv4"))
973 family = AF_INET;
974 else if (!strcasecmp(ans, "ipv6"))
975 family = AF_INET6;
976 else {
977 printf("unknown protocol family\n");
978 break;
979 }
980
981 printf("node address? ");
982 FGETS(ans, sizeof(ans), stdin);
983 ans[strlen(ans) - 1] = 0;
984
985 if (family == AF_INET) {
986 p = (char *)&addr4;
987 len = sizeof(addr4);
988 } else {
989 p = (char *)&addr6;
990 len = sizeof(addr6);
991 }
992
993 if (inet_pton(family, ans, p) < 1) {
994 printf("error parsing address\n");
995 break;
996 }
997
998 sepol_node_sid(family, p, len, &ssid);
999 printf("sid %d\n", ssid);
1000 break;
1001 }
1002 case 'c':
1003 printf("fstype? ");
1004 FGETS(ans, sizeof(ans), stdin);
1005 ans[strlen(ans) - 1] = 0;
1006 sepol_fs_use(ans, &uret, &ssid);
1007 switch (uret) {
1008 case SECURITY_FS_USE_XATTR:
1009 printf("use xattr\n");
1010 break;
1011 case SECURITY_FS_USE_TRANS:
1012 printf("use transition SIDs\n");
1013 break;
1014 case SECURITY_FS_USE_TASK:
1015 printf("use task SIDs\n");
1016 break;
1017 case SECURITY_FS_USE_GENFS:
1018 printf("use genfs\n");
1019 break;
1020 case SECURITY_FS_USE_NONE:
1021 printf("no labeling support\n");
1022 break;
1023 }
1024 printf("sid %d\n", ssid);
1025 break;
1026 case 'd':
1027 printf("fstype? ");
1028 FGETS(ans, sizeof(ans), stdin);
1029 ans[strlen(ans) - 1] = 0;
1030 fstype = strdup(ans);
1031 printf("path? ");
1032 FGETS(ans, sizeof(ans), stdin);
1033 ans[strlen(ans) - 1] = 0;
1034 path = strdup(ans);
1035 printf("object class? ");
1036 FGETS(ans, sizeof(ans), stdin);
1037 if (isdigit(ans[0])) {
1038 tclass = atoi(ans);
1039 if (!tclass
1040 || tclass > policydb.p_classes.nprim) {
1041 printf("\nNo such class.\n");
1042 break;
1043 }
1044 } else {
1045 ans[strlen(ans) - 1] = 0;
1046 cladatum =
1047 (class_datum_t *) hashtab_search(policydb.
1048 p_classes.
1049 table,
1050 ans);
1051 if (!cladatum) {
1052 printf("\nNo such class\n");
1053 break;
1054 }
1055 tclass = cladatum->s.value;
1056 }
1057 sepol_genfs_sid(fstype, path, tclass, &ssid);
1058 printf("sid %d\n", ssid);
1059 free(fstype);
1060 free(path);
1061 break;
1062 case 'e':
1063 printf("from SID? ");
1064 FGETS(ans, sizeof(ans), stdin);
1065 ans[strlen(ans) - 1] = 0;
1066 ssid = atoi(ans);
1067
1068 printf("username? ");
1069 FGETS(ans, sizeof(ans), stdin);
1070 ans[strlen(ans) - 1] = 0;
1071
1072 ret = sepol_get_user_sids(ssid, ans, &sids, &nel);
1073 switch (ret) {
1074 case 0:
1075 if (!nel)
1076 printf("\nnone\n");
1077 for (i = 0; i < nel; i++)
1078 print_sid(sids[i], NULL, NULL);
1079 free(sids);
1080 break;
1081 case -ENOMEM:
1082 printf("\nout of memory\n");
1083 break;
1084 case -EINVAL:
1085 printf("\ninvalid argument\n");
1086 break;
1087 default:
1088 printf("\nerror\n");
1089 break;
1090 }
1091 break;
1092 case 'f':
1093 display_bools();
1094 break;
1095 case 'g':
1096 display_cond_expressions();
1097 break;
1098 case 'h':
1099 printf("name? ");
1100 FGETS(ans, sizeof(ans), stdin);
1101 ans[strlen(ans) - 1] = 0;
1102
1103 name = malloc((strlen(ans) + 1) * sizeof(char));
1104 if (name == NULL) {
1105 fprintf(stderr, "couldn't malloc string.\n");
1106 break;
1107 }
1108 strcpy(name, ans);
1109
1110 printf("state? ");
1111 FGETS(ans, sizeof(ans), stdin);
1112 ans[strlen(ans) - 1] = 0;
1113
1114 if (atoi(ans))
1115 state = 1;
1116 else
1117 state = 0;
1118
1119 change_bool(name, state);
1120 free(name);
1121 break;
Richard Hainesab9cbb12013-11-03 19:12:29 +00001122 case 'i':
1123 printf("source sid? ");
1124 FGETS(ans, sizeof(ans), stdin);
1125 ssid = atoi(ans);
1126
1127 printf("target sid? ");
1128 FGETS(ans, sizeof(ans), stdin);
1129 tsid = 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_compute_av_reason_buffer(ssid, tsid,
1158 tclass, 0, &avd, &reason,
1159 &reason_buf, flags)) {
1160 printf("\nconstraint error\n");
1161 break;
1162 }
1163 if (reason_buf) {
1164 printf("\nConstraint expressions:\n%s",
1165 reason_buf);
1166 free(reason_buf);
1167 } else {
1168 printf("\nNo constraints found.\n");
1169 }
1170 break;
1171 case 'j':
1172 printf("old sid? ");
1173 FGETS(ans, sizeof(ans), stdin);
1174 oldsid = atoi(ans);
1175
1176 printf("new sid? ");
1177 FGETS(ans, sizeof(ans), stdin);
1178 newsid = atoi(ans);
1179
1180 printf("task sid? ");
1181 FGETS(ans, sizeof(ans), stdin);
1182 tasksid = atoi(ans);
1183
1184 printf("target class? ");
1185 FGETS(ans, sizeof(ans), stdin);
1186 if (isdigit(ans[0])) {
1187 tclass = atoi(ans);
1188 if (!tclass
1189 || tclass > policydb.p_classes.nprim) {
1190 printf("\nNo such class.\n");
1191 break;
1192 }
1193 cladatum =
1194 policydb.class_val_to_struct[tclass - 1];
1195 } else {
1196 ans[strlen(ans) - 1] = 0;
1197 cladatum =
1198 (class_datum_t *) hashtab_search(policydb.
1199 p_classes.
1200 table,
1201 ans);
1202 if (!cladatum) {
1203 printf("\nNo such class\n");
1204 break;
1205 }
1206 tclass = cladatum->s.value;
1207 }
1208
1209 flags = SHOW_GRANTED;
1210 if (sepol_validate_transition_reason_buffer(oldsid,
1211 newsid, tasksid, tclass,
1212 &reason_buf, flags)) {
1213 printf("\nvalidatetrans error\n");
1214 break;
1215 }
1216 if (reason_buf) {
1217 printf("\nValidatetrans expressions:\n%s",
1218 reason_buf);
1219 free(reason_buf);
1220 } else {
1221 printf(
1222 "\nNo validatetrans expressions found.\n");
1223 }
1224 break;
Daniel Jurgens9fbb3112017-05-22 16:08:24 +03001225 case 'k':
1226 {
1227 char *p;
1228 struct in6_addr addr6;
1229 uint64_t subnet_prefix;
1230 unsigned int pkey;
1231
1232 printf("subnet prefix? ");
1233 FGETS(ans, sizeof(ans), stdin);
1234 ans[strlen(ans) - 1] = 0;
1235 p = (char *)&addr6;
1236
1237 if (inet_pton(AF_INET6, ans, p) < 1) {
1238 printf("error parsing subnet prefix\n");
1239 break;
1240 }
1241
1242 memcpy(&subnet_prefix, p, sizeof(subnet_prefix));
1243 printf("pkey? ");
1244 FGETS(ans, sizeof(ans), stdin);
1245 pkey = atoi(ans);
1246 sepol_ibpkey_sid(subnet_prefix, pkey, &ssid);
1247 printf("sid %d\n", ssid);
1248 }
1249 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -04001250#ifdef EQUIVTYPES
1251 case 'z':
1252 identify_equiv_types();
1253 break;
1254#endif
1255 case 'm':
1256 goto menu;
1257 case 'q':
1258 exit(0);
1259 break;
1260 default:
1261 printf("\nUnknown option %s.\n", ans);
1262 }
1263 }
1264
1265 return 0;
1266}
1267
1268/* FLASK */