xref: /aosp_15_r20/external/selinux/policycoreutils/secon/secon.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1 
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <assert.h>
5 
6 #include <string.h>
7 
8 #define xstreq(x, y) !strcmp(x, y)
9 
10 #include <err.h>
11 
12 #include <getopt.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 #include <selinux/selinux.h>
16 #include <selinux/context.h>
17 
18 #define TRUE  1
19 #define FALSE 0
20 
21 #define SECON_CONF_PROG_NAME "secon"	/* default program name */
22 #define SECON_OPTS_SM "hVurtscmPRCfLp"	/* small options available, print */
23 #define SECON_OPTS_GO "hVurtlscmPRCf:L:p:"	/* small options available, getopt */
24 
25 #define OPTS_FROM_ARG      0
26 #define OPTS_FROM_FILE     1
27 #define OPTS_FROM_LINK     2
28 #define OPTS_FROM_STDIN    3
29 #define OPTS_FROM_CUR      4
30 #define OPTS_FROM_CUREXE   5
31 #define OPTS_FROM_CURFS    6
32 #define OPTS_FROM_CURKEY   7
33 #define OPTS_FROM_PROC     8
34 #define OPTS_FROM_PROCEXE  9
35 #define OPTS_FROM_PROCFS   10
36 #define OPTS_FROM_PROCKEY  11
37 
38 struct context_color_t {
39 	unsigned int valid;
40 
41 	char *user_fg;
42 	char *user_bg;
43 	char *role_fg;
44 	char *role_bg;
45 	char *type_fg;
46 	char *type_bg;
47 	char *range_fg;
48 	char *range_bg;
49 };
50 
51 struct {
52 	unsigned int disp_user:1;
53 	unsigned int disp_role:1;
54 	unsigned int disp_type:1;
55 	unsigned int disp_sen:1;
56 	unsigned int disp_clr:1;
57 	unsigned int disp_mlsr:1;
58 
59 	unsigned int disp_raw:1;
60 	unsigned int disp_color:1;
61 
62 	unsigned int disp_prompt:1;	/* no return, use : to sep */
63 
64 	unsigned int from_type:8;	/* 16 bits, uses 4 bits */
65 
66 	union {
67 		pid_t pid;
68 		const char *file;
69 		const char *link;
70 		const char *arg;
71 	} f;
72 } opts[1] = { {
73 		FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
74 		    FALSE, FALSE, FALSE, OPTS_FROM_ARG, {0} } };
75 
usage(const char * name,int exit_code)76 static __attribute__((__noreturn__)) void usage(const char *name, int exit_code)
77 {
78 	fprintf(exit_code ? stderr : stdout,
79 		"  Usage: %s [-%s] [ context | - ]\n"
80 		"          --help          -h            Show this message.\n"
81 		"          --version       -V            Show the version.\n"
82 		"          --prompt        -P            Output in a format good for a prompt.\n"
83 		"          --user          -u            Show the user of the context.\n"
84 		"          --role          -r            Show the role of the context.\n"
85 		"          --type          -t            Show the type of the context.\n"
86 		"          --sensitivity   -s            Show the sensitivity level of the context.\n"
87 		"          --clearance     -c            Show the clearance level of the context.\n"
88 		"          --mls-range     -m            Show the sensitivity to clearance range of \n"
89 		"                                        the context.\n"
90 		"          --raw           -R            Show the context in \"raw\" format.\n"
91 		"          --color         -C            Output using ANSI color codes (requires -P).\n"
92 		"          --current,      --self        Get the context for the current process.\n"
93 		"          --current-exec, --self-exec   Get the exec context for the current process.\n"
94 		"          --current-fs,   --self-fs     Get the fs context for the current process.\n"
95 		"          --current-key,  --self-key    Get the key context for the current process.\n"
96 		"          --parent                      Get the context for the parent process.\n"
97 		"          --parent-exec                 Get the exec context for the parent process.\n"
98 		"          --parent-fs                   Get the fs context for the parent process.\n"
99 		"          --parent-key                  Get the key context for the parent process.\n"
100 		"          --pid           -p <arg>      Use the context from the specified pid.\n"
101 		"          --pid-exec      <arg>         Use the exec context from the specified pid.\n"
102 		"          --pid-fs        <arg>         Use the fs context from the specified pid.\n"
103 		"          --pid-key       <arg>         Use the key context from the specified pid.\n"
104 		"          --file          -f <arg>      Use the context from the specified file.\n"
105 		"          --link          -L <arg>      Use the context from the specified link.\n",
106 		name, SECON_OPTS_SM);
107 
108 	exit(exit_code);
109 }
110 
opt_program_name(const char * argv0,const char * def)111 static const char *opt_program_name(const char *argv0, const char *def)
112 {
113 	if (argv0) {
114 		if ((def = strrchr(argv0, '/')))
115 			++def;
116 		else
117 			def = argv0;
118 
119 		/* hack for libtool */
120 		if ((strlen(def) > strlen("lt-"))
121 		    && !memcmp("lt-", def, strlen("lt-")))
122 			def += 3;
123 	}
124 
125 	return (def);
126 }
127 
disp_num(void)128 static int disp_num(void)
129 {
130 	int num = 0;
131 
132 	num += opts->disp_user;
133 	num += opts->disp_role;
134 	num += opts->disp_type;
135 	num += opts->disp_sen;
136 	num += opts->disp_clr;
137 	num += opts->disp_mlsr;
138 
139 	return (num);
140 }
141 
disp_none(void)142 static int disp_none(void)
143 {
144 	return (!disp_num());
145 }
146 
disp_multi(void)147 static int disp_multi(void)
148 {
149 	return (disp_num() > 1);
150 }
151 
cmd_line(int argc,char * argv[])152 static void cmd_line(int argc, char *argv[])
153 {
154 	int optchar = 0;
155 	const char *program_name = NULL;
156 	struct option long_options[] = {
157 		{"help", no_argument, NULL, 'h'},
158 		{"version", no_argument, NULL, 'V'},
159 
160 		{"prompt", no_argument, NULL, 'P'},
161 
162 		{"user", no_argument, NULL, 'u'},
163 		{"role", no_argument, NULL, 'r'},
164 		{"type", no_argument, NULL, 't'},
165 		{"level", no_argument, NULL, 'l'},	/* compat. */
166 		{"sensitivity", no_argument, NULL, 's'},
167 		{"range", no_argument, NULL, 'm'},
168 		{"clearance", no_argument, NULL, 'c'},
169 		{"mls-range", no_argument, NULL, 'm'},
170 
171 		{"raw", no_argument, NULL, 'R'},
172 		{"color", no_argument, NULL, 'C'},
173 
174 		{"current", no_argument, NULL, 1},
175 		{"self", no_argument, NULL, 1},
176 		{"current-exec", no_argument, NULL, 2},
177 		{"self-exec", no_argument, NULL, 2},
178 		{"current-fs", no_argument, NULL, 3},
179 		{"self-fs", no_argument, NULL, 3},
180 		{"current-key", no_argument, NULL, 4},
181 		{"self-key", no_argument, NULL, 4},
182 
183 		{"parent", no_argument, NULL, 5},
184 		{"parent-exec", no_argument, NULL, 6},
185 		{"parent-fs", no_argument, NULL, 7},
186 		{"parent-key", no_argument, NULL, 8},
187 
188 		{"file", required_argument, NULL, 'f'},
189 		{"link", required_argument, NULL, 'L'},
190 		{"pid", required_argument, NULL, 'p'},
191 		{"pid-exec", required_argument, NULL, 9},
192 		{"pid-fs", required_argument, NULL, 10},
193 		{"pid-key", required_argument, NULL, 11},
194 
195 		{NULL, 0, NULL, 0}
196 	};
197 	int done = FALSE;
198 
199 	program_name = opt_program_name(argv[0], SECON_CONF_PROG_NAME);
200 
201 	while ((optchar = getopt_long(argc, argv, SECON_OPTS_GO,
202 				      long_options, NULL)) != -1) {
203 		switch (optchar) {
204 		case '?':
205 			usage(program_name, EXIT_FAILURE);
206 		case 'h':
207 			usage(program_name, EXIT_SUCCESS);
208 		case 'V':
209 			fprintf(stdout,
210 				" %s version %s.\n", program_name, VERSION);
211 			exit(EXIT_SUCCESS);
212 
213 		case 'u':
214 			done = TRUE;
215 			opts->disp_user = !opts->disp_user;
216 			break;
217 		case 'r':
218 			done = TRUE;
219 			opts->disp_role = !opts->disp_role;
220 			break;
221 		case 't':
222 			done = TRUE;
223 			opts->disp_type = !opts->disp_type;
224 			break;
225 		case 'l':
226 			done = TRUE;
227 			opts->disp_sen = !opts->disp_sen;
228 			break;
229 		case 's':
230 			done = TRUE;
231 			opts->disp_sen = !opts->disp_sen;
232 			break;
233 		case 'c':
234 			done = TRUE;
235 			opts->disp_clr = !opts->disp_clr;
236 			break;
237 		case 'm':
238 			done = TRUE;
239 			opts->disp_mlsr = !opts->disp_mlsr;
240 			break;
241 
242 		case 'P':
243 			opts->disp_prompt = !opts->disp_prompt;
244 			break;
245 
246 		case 'R':
247 			opts->disp_raw = !opts->disp_raw;
248 			break;
249 		case 'C':
250 			opts->disp_color = !opts->disp_color;
251 			break;
252 		case 1:
253 			opts->from_type = OPTS_FROM_CUR;
254 			break;
255 		case 2:
256 			opts->from_type = OPTS_FROM_CUREXE;
257 			break;
258 		case 3:
259 			opts->from_type = OPTS_FROM_CURFS;
260 			break;
261 		case 4:
262 			opts->from_type = OPTS_FROM_CURKEY;
263 			break;
264 
265 		case 5:
266 			opts->from_type = OPTS_FROM_PROC;
267 			opts->f.pid = getppid();
268 			break;
269 		case 6:
270 			opts->from_type = OPTS_FROM_PROCEXE;
271 			opts->f.pid = getppid();
272 			break;
273 		case 7:
274 			opts->from_type = OPTS_FROM_PROCFS;
275 			opts->f.pid = getppid();
276 			break;
277 		case 8:
278 			opts->from_type = OPTS_FROM_PROCKEY;
279 			opts->f.pid = getppid();
280 			break;
281 
282 		case 'f':
283 			opts->from_type = OPTS_FROM_FILE;
284 			opts->f.file = optarg;
285 			break;
286 		case 'L':
287 			opts->from_type = OPTS_FROM_LINK;
288 			opts->f.link = optarg;
289 			break;
290 		case 'p':
291 			opts->from_type = OPTS_FROM_PROC;
292 			opts->f.pid = atoi(optarg);
293 			break;
294 		case 9:
295 			opts->from_type = OPTS_FROM_PROCEXE;
296 			opts->f.pid = atoi(optarg);
297 			break;
298 		case 10:
299 			opts->from_type = OPTS_FROM_PROCFS;
300 			opts->f.pid = atoi(optarg);
301 			break;
302 		case 11:
303 			opts->from_type = OPTS_FROM_PROCKEY;
304 			opts->f.pid = atoi(optarg);
305 			break;
306 
307 		default:
308 			assert(FALSE);
309 		}
310 	}
311 
312 	if (!done) {		/* default, if nothing specified */
313 		opts->disp_user = TRUE;
314 		opts->disp_role = TRUE;
315 		opts->disp_type = TRUE;
316 		if (!opts->disp_prompt) {	/* when displaying prompt, just output "normal" by default */
317 			opts->disp_sen = TRUE;
318 			opts->disp_clr = TRUE;
319 		}
320 		opts->disp_mlsr = TRUE;
321 	}
322 
323 	if (disp_none())
324 		err(EXIT_FAILURE, " Nothing to display");
325 
326 	argc -= optind;
327 	argv += optind;
328 
329 	if (!argc && (opts->from_type == OPTS_FROM_ARG)
330 	    && !isatty(STDIN_FILENO))
331 		opts->from_type = OPTS_FROM_STDIN;
332 	if (!argc && (opts->from_type == OPTS_FROM_ARG))
333 		opts->from_type = OPTS_FROM_CUR;
334 
335 	if (opts->from_type == OPTS_FROM_ARG) {
336 		if (!argv[0])
337 			errx(EXIT_FAILURE, "No argument given");
338 
339 		opts->f.arg = argv[0];
340 
341 		if (xstreq(argv[0], "-"))
342 			opts->from_type = OPTS_FROM_STDIN;
343 	} else if (!is_selinux_enabled())
344 		errx(EXIT_FAILURE, "SELinux is not enabled");
345 }
346 
my_getXcon_raw(pid_t pid,char ** con,const char * val)347 static int my_getXcon_raw(pid_t pid, char  **con, const char *val)
348 {
349 	char buf[4096];
350 	FILE *fp = NULL;
351 	const char *ptr = NULL;
352 
353 	snprintf(buf, sizeof(buf), "%s/%ld/attr/%s", "/proc", (long int)pid,
354 		 val);
355 
356 	if (!(fp = fopen(buf, "rb")))
357 		return (-1);
358 
359 	ptr = fgets(buf, sizeof(buf), fp);
360 
361 	fclose(fp);
362 
363 	*con = NULL;
364 	if (ptr) {		/* return *con = NULL, when proc file is empty */
365 		char *tmp = strchr(ptr, '\n');
366 
367 		if (tmp)
368 			*tmp = 0;
369 
370 		if (*ptr && !(*con = strdup(ptr)))
371 			return (-1);
372 	}
373 
374 	return (0);
375 }
376 
my_getpidexeccon_raw(pid_t pid,char ** con)377 static int my_getpidexeccon_raw(pid_t pid, char **con)
378 {
379 	return (my_getXcon_raw(pid, con, "exec"));
380 }
my_getpidfscreatecon_raw(pid_t pid,char ** con)381 static int my_getpidfscreatecon_raw(pid_t pid, char **con)
382 {
383 	return (my_getXcon_raw(pid, con, "fscreate"));
384 }
my_getpidkeycreatecon_raw(pid_t pid,char ** con)385 static int my_getpidkeycreatecon_raw(pid_t pid, char **con)
386 {
387 	return (my_getXcon_raw(pid, con, "keycreate"));
388 }
389 
get_scon(void)390 static char *get_scon(void)
391 {
392 	static char dummy_NIL[1] = "";
393 	char *con = NULL, *con_tmp;
394 	int ret = -1;
395 
396 	switch (opts->from_type) {
397 	case OPTS_FROM_ARG:
398 		if (!(con_tmp = strdup(opts->f.arg)))
399 			err(EXIT_FAILURE,
400 			    " Couldn't allocate security context");
401 		if (selinux_trans_to_raw_context(con_tmp, &con) < 0)
402 			err(EXIT_FAILURE,
403 			    " Couldn't translate security context");
404 		freecon(con_tmp);
405 		break;
406 
407 	case OPTS_FROM_STDIN:
408 		{
409 			char buf[4096] = "";
410 			char *ptr = buf;
411 
412 			while (!*ptr) {
413 				if (!(ptr = fgets(buf, sizeof(buf), stdin)))
414 					err(EXIT_FAILURE,
415 					    " Couldn't read security context");
416 
417 				ptr += strspn(ptr, " \n\t");
418 				ptr[strcspn(ptr, " \n\t")] = 0;
419 			}
420 
421 			if (!(con_tmp = strdup(ptr)))
422 				err(EXIT_FAILURE,
423 				    " Couldn't allocate security context");
424 			if (selinux_trans_to_raw_context(con_tmp, &con) < 0)
425 				err(EXIT_FAILURE,
426 				    " Couldn't translate security context");
427 			freecon(con_tmp);
428 			break;
429 		}
430 
431 	case OPTS_FROM_CUR:
432 		ret = getcon_raw(&con);
433 
434 		if (ret == -1)
435 			err(EXIT_FAILURE,
436 			    " Couldn't get current security context");
437 		break;
438 	case OPTS_FROM_CUREXE:
439 		ret = getexeccon_raw(&con);
440 
441 		if (ret == -1)
442 			err(EXIT_FAILURE,
443 			    " Couldn't get current exec security context");
444 
445 		if (!con)
446 			con = strdup(dummy_NIL);
447 		break;
448 	case OPTS_FROM_CURFS:
449 		ret = getfscreatecon_raw(&con);
450 
451 		if (ret == -1)
452 			err(EXIT_FAILURE,
453 			    " Couldn't get current fs security context");
454 
455 		if (!con)
456 			con = strdup(dummy_NIL);
457 		break;
458 	case OPTS_FROM_CURKEY:
459 		ret = getkeycreatecon_raw(&con);
460 
461 		if (ret == -1)
462 			err(EXIT_FAILURE,
463 			    " Couldn't get current key security context");
464 
465 		if (!con)
466 			con = strdup(dummy_NIL);
467 		break;
468 
469 	case OPTS_FROM_PROC:
470 		ret = getpidcon_raw(opts->f.pid, &con);
471 
472 		if (ret == -1)
473 			err(EXIT_FAILURE,
474 			    " Couldn't get security context for pid %lu",
475 			    (unsigned long)opts->f.pid);
476 		break;
477 	case OPTS_FROM_PROCEXE:
478 		ret = my_getpidexeccon_raw(opts->f.pid, &con);
479 
480 		if (ret == -1)
481 			err(EXIT_FAILURE,
482 			    " Couldn't get security context for pid %lu",
483 			    (unsigned long)opts->f.pid);
484 
485 		if (!con)
486 			con = strdup(dummy_NIL);
487 		break;
488 	case OPTS_FROM_PROCFS:
489 		ret = my_getpidfscreatecon_raw(opts->f.pid, &con);
490 
491 		if (ret == -1)
492 			err(EXIT_FAILURE,
493 			    " Couldn't get security context for pid %lu",
494 			    (unsigned long)opts->f.pid);
495 
496 		if (!con)
497 			con = strdup(dummy_NIL);
498 		/* disabled -- override with normal context ...
499 		   {
500 		   opts->from_type = OPTS_FROM_PROC;
501 		   return (get_scon());
502 		   } */
503 		break;
504 	case OPTS_FROM_PROCKEY:
505 		ret = my_getpidkeycreatecon_raw(opts->f.pid, &con);
506 
507 		if (ret == -1)
508 			err(EXIT_FAILURE,
509 			    " Couldn't get security context for pid %lu",
510 			    (unsigned long)opts->f.pid);
511 
512 		if (!con)
513 			con = strdup(dummy_NIL);
514 		break;
515 
516 	case OPTS_FROM_FILE:
517 		ret = getfilecon_raw(opts->f.file, &con);
518 
519 		if (ret == -1)
520 			err(EXIT_FAILURE,
521 			    " Couldn't get security context for file %s",
522 			    opts->f.file);
523 		break;
524 
525 	case OPTS_FROM_LINK:
526 		ret = lgetfilecon_raw(opts->f.link, &con);
527 
528 		if (ret == -1)
529 			err(EXIT_FAILURE,
530 			    " Couldn't get security context for symlink %s",
531 			    opts->f.link);
532 		break;
533 
534 	default:
535 		assert(FALSE);
536 	}
537 
538 	return (con);
539 }
540 
disp__color_to_ansi(const char * color_str)541 static unsigned int disp__color_to_ansi(const char *color_str)
542 {
543 	int val = 30;
544 
545 	/* NOTE: ansi black is 30 for foreground colors */
546 
547 	/* red */
548 	if (strncasecmp(&color_str[1], "7f", 2) >= 0)
549 		val += 1;
550 	/* green */
551 	if (strncasecmp(&color_str[3], "7f", 2) >= 0)
552 		val += 2;
553 	/* blue */
554 	if (strncasecmp(&color_str[5], "7f", 2) >= 0)
555 		val += 4;
556 
557 	return val;
558 }
559 
disp__con_color_ansi(const char * name,struct context_color_t * color)560 static char *disp__con_color_ansi(const char *name,
561 				  struct context_color_t *color)
562 {
563 	unsigned int fg, bg;
564 	char *ansi;
565 	int ansi_len = strlen("\e[99;99m") + 1;
566 
567 	/* NOTE: ansi background codes are the same as foreground codes +10 */
568 
569 	if (xstreq("user", name)) {
570 		fg = disp__color_to_ansi(color->user_fg);
571 		bg = disp__color_to_ansi(color->user_bg) + 10;
572 	} else if (xstreq("role", name)) {
573 		fg = disp__color_to_ansi(color->role_fg);
574 		bg = disp__color_to_ansi(color->role_bg) + 10;
575 	} else if (xstreq("type", name)) {
576 		fg = disp__color_to_ansi(color->type_fg);
577 		bg = disp__color_to_ansi(color->type_bg) + 10;
578 	} else if (xstreq("sensitivity", name) ||
579 		   xstreq("clearance", name) ||
580 		   xstreq("mls-range", name)) {
581 		fg = disp__color_to_ansi(color->range_fg);
582 		bg = disp__color_to_ansi(color->range_bg) + 10;
583 	} else
584 		err(EXIT_FAILURE, " No color information for context field");
585 
586 	if (!(ansi = malloc(ansi_len)))
587 		err(EXIT_FAILURE, " Unable to allocate memory");
588 	if (snprintf(ansi, ansi_len, "\e[%d;%dm", fg, bg) > ansi_len)
589 		err(EXIT_FAILURE, " Unable to convert colors to ANSI codes");
590 
591 	return ansi;
592 }
593 
disp__con_val(const char * name,const char * val,struct context_color_t * color)594 static void disp__con_val(const char *name, const char *val,
595 			  struct context_color_t *color)
596 {
597 	static int done = FALSE;
598 
599 	assert(name);
600 	assert(color);
601 
602 	if (!val)
603 		val = "";	/* targeted has no "level" etc.,
604 				   any errors should happen at context_new() time */
605 
606 	if (opts->disp_prompt) {
607 		if (xstreq("mls-range", name) && !*val)
608 			return;	/* skip, mls-range if it's empty */
609 
610 		if (opts->disp_color && color->valid) {
611 			char *ansi = disp__con_color_ansi(name, color);
612 			fprintf(stdout, "%s", ansi);
613 			free(ansi);
614 		}
615 		fprintf(stdout, "%s%s", done ? ":" : "", val);
616 		if (opts->disp_color && color->valid)
617 			fprintf(stdout, "\e[0m");
618 	} else if (disp_multi())
619 		fprintf(stdout, "%s: %s\n", name, val);
620 	else
621 		fprintf(stdout, "%s\n", val);
622 
623 	done = TRUE;
624 }
625 
disp_con(const char * scon_raw)626 static void disp_con(const char *scon_raw)
627 {
628 	char *scon_trans;
629 	const char *scon;
630 	context_t con = NULL;
631 	char *color_str = NULL;
632 	struct context_color_t color = { .valid = 0 };
633 
634 	selinux_raw_to_trans_context(scon_raw, &scon_trans);
635 	if (opts->disp_raw)
636 		scon = scon_raw;
637 	else
638 		scon = scon_trans;
639 
640 	if (!*scon) {		/* --self-exec and --self-fs etc. */
641 		if (opts->disp_user)
642 			disp__con_val("user", NULL, &color);
643 		if (opts->disp_role)
644 			disp__con_val("role", NULL, &color);
645 		if (opts->disp_type)
646 			disp__con_val("type", NULL, &color);
647 		if (opts->disp_sen)
648 			disp__con_val("sensitivity", NULL, &color);
649 		if (opts->disp_clr)
650 			disp__con_val("clearance", NULL, &color);
651 		if (opts->disp_mlsr)
652 			disp__con_val("mls-range", NULL, &color);
653 		freecon(scon_trans);
654 		return;
655 	}
656 
657 	if (opts->disp_color) {
658 		if (selinux_raw_context_to_color(scon_raw, &color_str) < 0)
659 			errx(EXIT_FAILURE, "Couldn't determine colors for: %s",
660 			     scon);
661 
662 		color.user_fg = strtok(color_str, " ");
663 		if (!color.user_fg)
664 			errx(EXIT_FAILURE, "Invalid color string");
665 		color.user_bg = strtok(NULL, " ");
666 		if (!color.user_bg)
667 			errx(EXIT_FAILURE, "Invalid color string");
668 
669 		color.role_fg = strtok(NULL, " ");
670 		if (!color.role_fg)
671 			errx(EXIT_FAILURE, "Invalid color string");
672 		color.role_bg = strtok(NULL, " ");
673 		if (!color.role_bg)
674 			errx(EXIT_FAILURE, "Invalid color string");
675 
676 		color.type_fg = strtok(NULL, " ");
677 		if (!color.type_fg)
678 			errx(EXIT_FAILURE, "Invalid color string");
679 		color.type_bg = strtok(NULL, " ");
680 		if (!color.type_bg)
681 			errx(EXIT_FAILURE, "Invalid color string");
682 
683 		color.range_fg = strtok(NULL, " ");
684 		if (!color.range_fg)
685 			errx(EXIT_FAILURE, "Invalid color string");
686 		color.range_bg = strtok(NULL, " ");
687 
688 		color.valid = 1;
689 	}
690 
691 	if (!(con = context_new(scon)))
692 		errx(EXIT_FAILURE, "Couldn't create context from: %s", scon);
693 
694 	if (opts->disp_user) {
695 		disp__con_val("user", context_user_get(con), &color);
696 	}
697 	if (opts->disp_role) {
698 		disp__con_val("role", context_role_get(con), &color);
699 	}
700 	if (opts->disp_type) {
701 		disp__con_val("type", context_type_get(con), &color);
702 	}
703 	if (opts->disp_sen) {
704 		const char *val = NULL;
705 		char *tmp = NULL;
706 
707 		val = context_range_get(con);
708 		if (!val)
709 			val = "";	/* targeted has no "level" etc.,
710 					   any errors should happen at context_new() time */
711 
712 		tmp = strdup(val);
713 		if (!tmp)
714 			errx(EXIT_FAILURE, "Couldn't create context from: %s",
715 			     scon);
716 		if (strchr(tmp, '-'))
717 			*strchr(tmp, '-') = 0;
718 
719 		disp__con_val("sensitivity", tmp, &color);
720 
721 		free(tmp);
722 	}
723 	if (opts->disp_clr) {
724 		const char *val = NULL;
725 		char *tmp = NULL;
726 
727 		val = context_range_get(con);
728 		if (!val)
729 			val = "";	/* targeted has no "level" etc.,
730 					   any errors should happen at context_new() time */
731 
732 		tmp = strdup(val);
733 		if (!tmp)
734 			errx(EXIT_FAILURE, "Couldn't create context from: %s",
735 			     scon);
736 		if (strchr(tmp, '-'))
737 			disp__con_val("clearance", strchr(tmp, '-') + 1, &color);
738 		else
739 			disp__con_val("clearance", tmp, &color);
740 
741 		free(tmp);
742 	}
743 
744 	if (opts->disp_mlsr)
745 		disp__con_val("mls-range", context_range_get(con), &color);
746 
747 	context_free(con);
748 	freecon(scon_trans);
749 	if (color_str)
750 		free(color_str);
751 }
752 
main(int argc,char * argv[])753 int main(int argc, char *argv[])
754 {
755 	char *scon_raw = NULL;
756 
757 	cmd_line(argc, argv);
758 
759 	scon_raw = get_scon();
760 
761 	disp_con(scon_raw);
762 
763 	freecon(scon_raw);
764 
765 	exit(EXIT_SUCCESS);
766 }
767