blob: b75f2afa2fa29f41b42e2f6fcc98c0368e930418 [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");
Daniel Jurgens118c0cd2017-05-22 16:08:27 +0300704 printf("l) Call ibendport_sid\n");
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400705#ifdef EQUIVTYPES
706 printf("z) Show equivalent types\n");
707#endif
708 printf("m) Show menu again\n");
709 printf("q) Exit\n");
710 while (1) {
711 printf("\nChoose: ");
712 FGETS(ans, sizeof(ans), stdin);
713 switch (ans[0]) {
714 case '0':
715 printf("source sid? ");
716 FGETS(ans, sizeof(ans), stdin);
717 ssid = atoi(ans);
718
719 printf("target sid? ");
720 FGETS(ans, sizeof(ans), stdin);
721 tsid = atoi(ans);
722
723 printf("target class? ");
724 FGETS(ans, sizeof(ans), stdin);
725 if (isdigit(ans[0])) {
726 tclass = atoi(ans);
727 if (!tclass
728 || tclass > policydb.p_classes.nprim) {
729 printf("\nNo such class.\n");
730 break;
731 }
732 cladatum =
733 policydb.class_val_to_struct[tclass - 1];
734 } else {
735 ans[strlen(ans) - 1] = 0;
736 cladatum =
737 (class_datum_t *) hashtab_search(policydb.
738 p_classes.
739 table,
740 ans);
741 if (!cladatum) {
742 printf("\nNo such class\n");
743 break;
744 }
745 tclass = cladatum->s.value;
746 }
747
748 if (!cladatum->comdatum && !cladatum->permissions.nprim) {
749 printf
750 ("\nNo access vector definition for that class\n");
751 break;
752 }
753 ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd);
754 switch (ret) {
755 case 0:
756 printf("\nallowed {");
757 for (i = 1; i <= sizeof(avd.allowed) * 8; i++) {
758 if (avd.allowed & (1 << (i - 1))) {
759 v.val = i;
760 ret =
761 hashtab_map(cladatum->
762 permissions.
763 table,
764 find_perm, &v);
765 if (!ret && cladatum->comdatum) {
766 ret =
767 hashtab_map
768 (cladatum->
769 comdatum->
770 permissions.table,
771 find_perm, &v);
772 }
773 if (ret)
774 printf(" %s", v.name);
775 }
776 }
777 printf(" }\n");
778 break;
779 case -EINVAL:
780 printf("\ninvalid sid\n");
781 break;
782 default:
783 printf("return code 0x%x\n", ret);
784 }
785 break;
786 case '1':
787 printf("sid? ");
788 FGETS(ans, sizeof(ans), stdin);
789 ssid = atoi(ans);
790 ret = sepol_sid_to_context(ssid,
791 &scontext, &scontext_len);
792 switch (ret) {
793 case 0:
794 printf("\nscontext %s\n", scontext);
795 free(scontext);
796 break;
797 case -EINVAL:
798 printf("\ninvalid sid\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 '2':
808 printf("scontext? ");
809 FGETS(ans, sizeof(ans), stdin);
810 scontext_len = strlen(ans);
811 ans[scontext_len - 1] = 0;
812 ret = sepol_context_to_sid(ans, scontext_len, &ssid);
813 switch (ret) {
814 case 0:
815 printf("\nsid %d\n", ssid);
816 break;
817 case -EINVAL:
818 printf("\ninvalid context\n");
819 break;
820 case -ENOMEM:
821 printf("\nout of memory\n");
822 break;
823 default:
824 printf("return code 0x%x\n", ret);
825 }
826 break;
827 case '3':
828 case '4':
829 case '5':
830 ch = ans[0];
831
832 printf("source sid? ");
833 FGETS(ans, sizeof(ans), stdin);
834 ssid = atoi(ans);
835 printf("target sid? ");
836 FGETS(ans, sizeof(ans), stdin);
837 tsid = atoi(ans);
838
839 printf("object class? ");
840 FGETS(ans, sizeof(ans), stdin);
841 if (isdigit(ans[0])) {
842 tclass = atoi(ans);
843 if (!tclass
844 || tclass > policydb.p_classes.nprim) {
845 printf("\nNo such class.\n");
846 break;
847 }
848 } else {
849 ans[strlen(ans) - 1] = 0;
850 cladatum =
851 (class_datum_t *) hashtab_search(policydb.
852 p_classes.
853 table,
854 ans);
855 if (!cladatum) {
856 printf("\nNo such class\n");
857 break;
858 }
859 tclass = cladatum->s.value;
860 }
861
862 if (ch == '3')
863 ret =
864 sepol_transition_sid(ssid, tsid, tclass,
865 &ssid);
866 else if (ch == '4')
867 ret =
868 sepol_member_sid(ssid, tsid, tclass, &ssid);
869 else
870 ret =
871 sepol_change_sid(ssid, tsid, tclass, &ssid);
872 switch (ret) {
873 case 0:
874 printf("\nsid %d\n", ssid);
875 break;
876 case -EINVAL:
877 printf("\ninvalid sid\n");
878 break;
879 case -ENOMEM:
880 printf("\nout of memory\n");
881 break;
882 default:
883 printf("return code 0x%x\n", ret);
884 }
885 break;
886 case '6':
887 sepol_sidtab_map(&sidtab, print_sid, 0);
888 break;
889 case '7':
890 printf("pathname? ");
891 FGETS(ans, sizeof(ans), stdin);
892 pathlen = strlen(ans);
893 ans[pathlen - 1] = 0;
894 printf("%s: loading policy configuration from %s\n",
895 argv[0], ans);
896 fd = open(ans, O_RDONLY);
897 if (fd < 0) {
898 fprintf(stderr, "Can't open '%s': %s\n",
899 ans, strerror(errno));
900 break;
901 }
902 if (fstat(fd, &sb) < 0) {
903 fprintf(stderr, "Can't stat '%s': %s\n",
904 ans, strerror(errno));
905 break;
906 }
907 map =
908 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
909 MAP_PRIVATE, fd, 0);
910 if (map == MAP_FAILED) {
911 fprintf(stderr, "Can't map '%s': %s\n",
912 ans, strerror(errno));
913 break;
914 }
915 ret = sepol_load_policy(map, sb.st_size);
916 switch (ret) {
917 case 0:
918 printf("\nsuccess\n");
919 break;
920 case -EINVAL:
921 printf("\ninvalid policy\n");
922 break;
923 case -ENOMEM:
924 printf("\nout of memory\n");
925 break;
926 default:
927 printf("return code 0x%x\n", ret);
928 }
929 break;
930 case '8':
931 printf("fs kdevname? ");
932 FGETS(ans, sizeof(ans), stdin);
933 ans[strlen(ans) - 1] = 0;
934 sepol_fs_sid(ans, &ssid, &tsid);
935 printf("fs_sid %d default_file_sid %d\n", ssid, tsid);
936 break;
937 case '9':
938 printf("protocol? ");
939 FGETS(ans, sizeof(ans), stdin);
940 ans[strlen(ans) - 1] = 0;
941 if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP"))
942 protocol = IPPROTO_TCP;
943 else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP"))
944 protocol = IPPROTO_UDP;
Richard Haines3895fbb2016-04-06 12:44:35 +0100945 else if (!strcmp(ans, "dccp") || !strcmp(ans, "DCCP"))
946 protocol = IPPROTO_DCCP;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400947 else {
948 printf("unknown protocol\n");
949 break;
950 }
951 printf("port? ");
952 FGETS(ans, sizeof(ans), stdin);
953 port = atoi(ans);
954 sepol_port_sid(0, 0, protocol, port, &ssid);
955 printf("sid %d\n", ssid);
956 break;
957 case 'a':
958 printf("netif name? ");
959 FGETS(ans, sizeof(ans), stdin);
960 ans[strlen(ans) - 1] = 0;
961 sepol_netif_sid(ans, &ssid, &tsid);
962 printf("if_sid %d default_msg_sid %d\n", ssid, tsid);
963 break;
964 case 'b':{
965 char *p;
966 int family, len;
967 struct in_addr addr4;
968 struct in6_addr addr6;
969
970 printf("protocol family? ");
971 FGETS(ans, sizeof(ans), stdin);
972 ans[strlen(ans) - 1] = 0;
973 if (!strcasecmp(ans, "ipv4"))
974 family = AF_INET;
975 else if (!strcasecmp(ans, "ipv6"))
976 family = AF_INET6;
977 else {
978 printf("unknown protocol family\n");
979 break;
980 }
981
982 printf("node address? ");
983 FGETS(ans, sizeof(ans), stdin);
984 ans[strlen(ans) - 1] = 0;
985
986 if (family == AF_INET) {
987 p = (char *)&addr4;
988 len = sizeof(addr4);
989 } else {
990 p = (char *)&addr6;
991 len = sizeof(addr6);
992 }
993
994 if (inet_pton(family, ans, p) < 1) {
995 printf("error parsing address\n");
996 break;
997 }
998
999 sepol_node_sid(family, p, len, &ssid);
1000 printf("sid %d\n", ssid);
1001 break;
1002 }
1003 case 'c':
1004 printf("fstype? ");
1005 FGETS(ans, sizeof(ans), stdin);
1006 ans[strlen(ans) - 1] = 0;
1007 sepol_fs_use(ans, &uret, &ssid);
1008 switch (uret) {
1009 case SECURITY_FS_USE_XATTR:
1010 printf("use xattr\n");
1011 break;
1012 case SECURITY_FS_USE_TRANS:
1013 printf("use transition SIDs\n");
1014 break;
1015 case SECURITY_FS_USE_TASK:
1016 printf("use task SIDs\n");
1017 break;
1018 case SECURITY_FS_USE_GENFS:
1019 printf("use genfs\n");
1020 break;
1021 case SECURITY_FS_USE_NONE:
1022 printf("no labeling support\n");
1023 break;
1024 }
1025 printf("sid %d\n", ssid);
1026 break;
1027 case 'd':
1028 printf("fstype? ");
1029 FGETS(ans, sizeof(ans), stdin);
1030 ans[strlen(ans) - 1] = 0;
1031 fstype = strdup(ans);
1032 printf("path? ");
1033 FGETS(ans, sizeof(ans), stdin);
1034 ans[strlen(ans) - 1] = 0;
1035 path = strdup(ans);
1036 printf("object class? ");
1037 FGETS(ans, sizeof(ans), stdin);
1038 if (isdigit(ans[0])) {
1039 tclass = atoi(ans);
1040 if (!tclass
1041 || tclass > policydb.p_classes.nprim) {
1042 printf("\nNo such class.\n");
1043 break;
1044 }
1045 } else {
1046 ans[strlen(ans) - 1] = 0;
1047 cladatum =
1048 (class_datum_t *) hashtab_search(policydb.
1049 p_classes.
1050 table,
1051 ans);
1052 if (!cladatum) {
1053 printf("\nNo such class\n");
1054 break;
1055 }
1056 tclass = cladatum->s.value;
1057 }
1058 sepol_genfs_sid(fstype, path, tclass, &ssid);
1059 printf("sid %d\n", ssid);
1060 free(fstype);
1061 free(path);
1062 break;
1063 case 'e':
1064 printf("from SID? ");
1065 FGETS(ans, sizeof(ans), stdin);
1066 ans[strlen(ans) - 1] = 0;
1067 ssid = atoi(ans);
1068
1069 printf("username? ");
1070 FGETS(ans, sizeof(ans), stdin);
1071 ans[strlen(ans) - 1] = 0;
1072
1073 ret = sepol_get_user_sids(ssid, ans, &sids, &nel);
1074 switch (ret) {
1075 case 0:
1076 if (!nel)
1077 printf("\nnone\n");
1078 for (i = 0; i < nel; i++)
1079 print_sid(sids[i], NULL, NULL);
1080 free(sids);
1081 break;
1082 case -ENOMEM:
1083 printf("\nout of memory\n");
1084 break;
1085 case -EINVAL:
1086 printf("\ninvalid argument\n");
1087 break;
1088 default:
1089 printf("\nerror\n");
1090 break;
1091 }
1092 break;
1093 case 'f':
1094 display_bools();
1095 break;
1096 case 'g':
1097 display_cond_expressions();
1098 break;
1099 case 'h':
1100 printf("name? ");
1101 FGETS(ans, sizeof(ans), stdin);
1102 ans[strlen(ans) - 1] = 0;
1103
1104 name = malloc((strlen(ans) + 1) * sizeof(char));
1105 if (name == NULL) {
1106 fprintf(stderr, "couldn't malloc string.\n");
1107 break;
1108 }
1109 strcpy(name, ans);
1110
1111 printf("state? ");
1112 FGETS(ans, sizeof(ans), stdin);
1113 ans[strlen(ans) - 1] = 0;
1114
1115 if (atoi(ans))
1116 state = 1;
1117 else
1118 state = 0;
1119
1120 change_bool(name, state);
1121 free(name);
1122 break;
Richard Hainesab9cbb12013-11-03 19:12:29 +00001123 case 'i':
1124 printf("source sid? ");
1125 FGETS(ans, sizeof(ans), stdin);
1126 ssid = atoi(ans);
1127
1128 printf("target sid? ");
1129 FGETS(ans, sizeof(ans), stdin);
1130 tsid = atoi(ans);
1131
1132 printf("target class? ");
1133 FGETS(ans, sizeof(ans), stdin);
1134 if (isdigit(ans[0])) {
1135 tclass = atoi(ans);
1136 if (!tclass
1137 || tclass > policydb.p_classes.nprim) {
1138 printf("\nNo such class.\n");
1139 break;
1140 }
1141 cladatum =
1142 policydb.class_val_to_struct[tclass - 1];
1143 } else {
1144 ans[strlen(ans) - 1] = 0;
1145 cladatum =
1146 (class_datum_t *) hashtab_search(policydb.
1147 p_classes.
1148 table,
1149 ans);
1150 if (!cladatum) {
1151 printf("\nNo such class\n");
1152 break;
1153 }
1154 tclass = cladatum->s.value;
1155 }
1156
1157 flags = SHOW_GRANTED;
1158 if (sepol_compute_av_reason_buffer(ssid, tsid,
1159 tclass, 0, &avd, &reason,
1160 &reason_buf, flags)) {
1161 printf("\nconstraint error\n");
1162 break;
1163 }
1164 if (reason_buf) {
1165 printf("\nConstraint expressions:\n%s",
1166 reason_buf);
1167 free(reason_buf);
1168 } else {
1169 printf("\nNo constraints found.\n");
1170 }
1171 break;
1172 case 'j':
1173 printf("old sid? ");
1174 FGETS(ans, sizeof(ans), stdin);
1175 oldsid = atoi(ans);
1176
1177 printf("new sid? ");
1178 FGETS(ans, sizeof(ans), stdin);
1179 newsid = atoi(ans);
1180
1181 printf("task sid? ");
1182 FGETS(ans, sizeof(ans), stdin);
1183 tasksid = atoi(ans);
1184
1185 printf("target class? ");
1186 FGETS(ans, sizeof(ans), stdin);
1187 if (isdigit(ans[0])) {
1188 tclass = atoi(ans);
1189 if (!tclass
1190 || tclass > policydb.p_classes.nprim) {
1191 printf("\nNo such class.\n");
1192 break;
1193 }
1194 cladatum =
1195 policydb.class_val_to_struct[tclass - 1];
1196 } else {
1197 ans[strlen(ans) - 1] = 0;
1198 cladatum =
1199 (class_datum_t *) hashtab_search(policydb.
1200 p_classes.
1201 table,
1202 ans);
1203 if (!cladatum) {
1204 printf("\nNo such class\n");
1205 break;
1206 }
1207 tclass = cladatum->s.value;
1208 }
1209
1210 flags = SHOW_GRANTED;
1211 if (sepol_validate_transition_reason_buffer(oldsid,
1212 newsid, tasksid, tclass,
1213 &reason_buf, flags)) {
1214 printf("\nvalidatetrans error\n");
1215 break;
1216 }
1217 if (reason_buf) {
1218 printf("\nValidatetrans expressions:\n%s",
1219 reason_buf);
1220 free(reason_buf);
1221 } else {
1222 printf(
1223 "\nNo validatetrans expressions found.\n");
1224 }
1225 break;
Daniel Jurgens9fbb3112017-05-22 16:08:24 +03001226 case 'k':
1227 {
1228 char *p;
1229 struct in6_addr addr6;
1230 uint64_t subnet_prefix;
1231 unsigned int pkey;
1232
1233 printf("subnet prefix? ");
1234 FGETS(ans, sizeof(ans), stdin);
1235 ans[strlen(ans) - 1] = 0;
1236 p = (char *)&addr6;
1237
1238 if (inet_pton(AF_INET6, ans, p) < 1) {
1239 printf("error parsing subnet prefix\n");
1240 break;
1241 }
1242
1243 memcpy(&subnet_prefix, p, sizeof(subnet_prefix));
1244 printf("pkey? ");
1245 FGETS(ans, sizeof(ans), stdin);
1246 pkey = atoi(ans);
1247 sepol_ibpkey_sid(subnet_prefix, pkey, &ssid);
1248 printf("sid %d\n", ssid);
1249 }
1250 break;
Daniel Jurgens118c0cd2017-05-22 16:08:27 +03001251 case 'l':
1252 printf("device name (eg. mlx4_0)? ");
1253 FGETS(ans, sizeof(ans), stdin);
1254 ans[strlen(ans) - 1] = 0;
1255
1256 name = malloc((strlen(ans) + 1) * sizeof(char));
1257 if (!name) {
1258 fprintf(stderr, "couldn't malloc string.\n");
1259 break;
1260 }
1261 strcpy(name, ans);
1262
1263 printf("port? ");
1264 FGETS(ans, sizeof(ans), stdin);
1265 port = atoi(ans);
1266 sepol_ibendport_sid(name, port, &ssid);
1267 printf("sid %d\n", ssid);
1268 free(name);
1269 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -04001270#ifdef EQUIVTYPES
1271 case 'z':
1272 identify_equiv_types();
1273 break;
1274#endif
1275 case 'm':
1276 goto menu;
1277 case 'q':
1278 exit(0);
1279 break;
1280 default:
1281 printf("\nUnknown option %s.\n", ans);
1282 }
1283 }
1284
1285 return 0;
1286}
1287
1288/* FLASK */