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