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