| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <assert.h> |
| |
| #include <string.h> |
| |
| #define xstreq(x, y) !strcmp(x, y) |
| |
| #include <err.h> |
| |
| #include <getopt.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| #include <selinux/selinux.h> |
| #include <selinux/context.h> |
| |
| #define TRUE 1 |
| #define FALSE 0 |
| |
| #define SECON_CONF_PROG_NAME "secon" /* default program name */ |
| #define SECON_OPTS_SM "hVurtscmPRCfLp" /* small options available, print */ |
| #define SECON_OPTS_GO "hVurtlscmPRCf:L:p:" /* small options available, getopt */ |
| |
| #define OPTS_FROM_ARG 0 |
| #define OPTS_FROM_FILE 1 |
| #define OPTS_FROM_LINK 2 |
| #define OPTS_FROM_STDIN 3 |
| #define OPTS_FROM_CUR 4 |
| #define OPTS_FROM_CUREXE 5 |
| #define OPTS_FROM_CURFS 6 |
| #define OPTS_FROM_CURKEY 7 |
| #define OPTS_FROM_PROC 8 |
| #define OPTS_FROM_PROCEXE 9 |
| #define OPTS_FROM_PROCFS 10 |
| #define OPTS_FROM_PROCKEY 11 |
| |
| struct context_color_t { |
| unsigned int valid; |
| |
| char *user_fg; |
| char *user_bg; |
| char *role_fg; |
| char *role_bg; |
| char *type_fg; |
| char *type_bg; |
| char *range_fg; |
| char *range_bg; |
| }; |
| |
| struct { |
| unsigned int disp_user:1; |
| unsigned int disp_role:1; |
| unsigned int disp_type:1; |
| unsigned int disp_sen:1; |
| unsigned int disp_clr:1; |
| unsigned int disp_mlsr:1; |
| |
| unsigned int disp_raw:1; |
| unsigned int disp_color:1; |
| |
| unsigned int disp_prompt:1; /* no return, use : to sep */ |
| |
| unsigned int from_type:8; /* 16 bits, uses 4 bits */ |
| |
| union { |
| pid_t pid; |
| const char *file; |
| const char *link; |
| const char *arg; |
| } f; |
| } opts[1] = { { |
| FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, |
| FALSE, FALSE, FALSE, OPTS_FROM_ARG, {0} } }; |
| |
| static __attribute__((__noreturn__)) void usage(const char *name, int exit_code) |
| { |
| fprintf(exit_code ? stderr : stdout, |
| " Usage: %s [-%s] [ context | - ]\n" |
| " --help -h Show this message.\n" |
| " --version -V Show the version.\n" |
| " --prompt -P Output in a format good for a prompt.\n" |
| " --user -u Show the user of the context.\n" |
| " --role -r Show the role of the context.\n" |
| " --type -t Show the type of the context.\n" |
| " --sensitivity -s Show the sensitivity level of the context.\n" |
| " --clearance -c Show the clearance level of the context.\n" |
| " --mls-range -m Show the sensitivity to clearance range of \n" |
| " the context.\n" |
| " --raw -R Show the context in \"raw\" format.\n" |
| " --color -C Output using ANSI color codes (requires -P).\n" |
| " --current, --self Get the context for the current process.\n" |
| " --current-exec, --self-exec Get the exec context for the current process.\n" |
| " --current-fs, --self-fs Get the fs context for the current process.\n" |
| " --current-key, --self-key Get the key context for the current process.\n" |
| " --parent Get the context for the parent process.\n" |
| " --parent-exec Get the exec context for the parent process.\n" |
| " --parent-fs Get the fs context for the parent process.\n" |
| " --parent-key Get the key context for the parent process.\n" |
| " --pid -p <arg> Use the context from the specified pid.\n" |
| " --pid-exec <arg> Use the exec context from the specified pid.\n" |
| " --pid-fs <arg> Use the fs context from the specified pid.\n" |
| " --pid-key <arg> Use the key context from the specified pid.\n" |
| " --file -f <arg> Use the context from the specified file.\n" |
| " --link -L <arg> Use the context from the specified link.\n", |
| name, SECON_OPTS_SM); |
| |
| exit(exit_code); |
| } |
| |
| static const char *opt_program_name(const char *argv0, const char *def) |
| { |
| if (argv0) { |
| if ((def = strrchr(argv0, '/'))) |
| ++def; |
| else |
| def = argv0; |
| |
| /* hack for libtool */ |
| if ((strlen(def) > strlen("lt-")) |
| && !memcmp("lt-", def, strlen("lt-"))) |
| def += 3; |
| } |
| |
| return (def); |
| } |
| |
| static int disp_num(void) |
| { |
| int num = 0; |
| |
| num += opts->disp_user; |
| num += opts->disp_role; |
| num += opts->disp_type; |
| num += opts->disp_sen; |
| num += opts->disp_clr; |
| num += opts->disp_mlsr; |
| |
| return (num); |
| } |
| |
| static int disp_none(void) |
| { |
| return (!disp_num()); |
| } |
| |
| static int disp_multi(void) |
| { |
| return (disp_num() > 1); |
| } |
| |
| static void cmd_line(int argc, char *argv[]) |
| { |
| int optchar = 0; |
| const char *program_name = NULL; |
| struct option long_options[] = { |
| {"help", no_argument, NULL, 'h'}, |
| {"version", no_argument, NULL, 'V'}, |
| |
| {"prompt", no_argument, NULL, 'P'}, |
| |
| {"user", no_argument, NULL, 'u'}, |
| {"role", no_argument, NULL, 'r'}, |
| {"type", no_argument, NULL, 't'}, |
| {"level", no_argument, NULL, 'l'}, /* compat. */ |
| {"sensitivity", no_argument, NULL, 's'}, |
| {"range", no_argument, NULL, 'm'}, |
| {"clearance", no_argument, NULL, 'c'}, |
| {"mls-range", no_argument, NULL, 'm'}, |
| |
| {"raw", no_argument, NULL, 'R'}, |
| {"color", no_argument, NULL, 'C'}, |
| |
| {"current", no_argument, NULL, 1}, |
| {"self", no_argument, NULL, 1}, |
| {"current-exec", no_argument, NULL, 2}, |
| {"self-exec", no_argument, NULL, 2}, |
| {"current-fs", no_argument, NULL, 3}, |
| {"self-fs", no_argument, NULL, 3}, |
| {"current-key", no_argument, NULL, 4}, |
| {"self-key", no_argument, NULL, 4}, |
| |
| {"parent", no_argument, NULL, 5}, |
| {"parent-exec", no_argument, NULL, 6}, |
| {"parent-fs", no_argument, NULL, 7}, |
| {"parent-key", no_argument, NULL, 8}, |
| |
| {"file", required_argument, NULL, 'f'}, |
| {"link", required_argument, NULL, 'L'}, |
| {"pid", required_argument, NULL, 'p'}, |
| {"pid-exec", required_argument, NULL, 9}, |
| {"pid-fs", required_argument, NULL, 10}, |
| {"pid-key", required_argument, NULL, 11}, |
| |
| {NULL, 0, NULL, 0} |
| }; |
| int done = FALSE; |
| |
| program_name = opt_program_name(argv[0], SECON_CONF_PROG_NAME); |
| |
| while ((optchar = getopt_long(argc, argv, SECON_OPTS_GO, |
| long_options, NULL)) != -1) { |
| switch (optchar) { |
| case '?': |
| usage(program_name, EXIT_FAILURE); |
| case 'h': |
| usage(program_name, EXIT_SUCCESS); |
| case 'V': |
| fprintf(stdout, |
| " %s version %s.\n", program_name, VERSION); |
| exit(EXIT_SUCCESS); |
| |
| case 'u': |
| done = TRUE; |
| opts->disp_user = !opts->disp_user; |
| break; |
| case 'r': |
| done = TRUE; |
| opts->disp_role = !opts->disp_role; |
| break; |
| case 't': |
| done = TRUE; |
| opts->disp_type = !opts->disp_type; |
| break; |
| case 'l': |
| done = TRUE; |
| opts->disp_sen = !opts->disp_sen; |
| break; |
| case 's': |
| done = TRUE; |
| opts->disp_sen = !opts->disp_sen; |
| break; |
| case 'c': |
| done = TRUE; |
| opts->disp_clr = !opts->disp_clr; |
| break; |
| case 'm': |
| done = TRUE; |
| opts->disp_mlsr = !opts->disp_mlsr; |
| break; |
| |
| case 'P': |
| opts->disp_prompt = !opts->disp_prompt; |
| break; |
| |
| case 'R': |
| opts->disp_raw = !opts->disp_raw; |
| break; |
| case 'C': |
| opts->disp_color = !opts->disp_color; |
| break; |
| case 1: |
| opts->from_type = OPTS_FROM_CUR; |
| break; |
| case 2: |
| opts->from_type = OPTS_FROM_CUREXE; |
| break; |
| case 3: |
| opts->from_type = OPTS_FROM_CURFS; |
| break; |
| case 4: |
| opts->from_type = OPTS_FROM_CURKEY; |
| break; |
| |
| case 5: |
| opts->from_type = OPTS_FROM_PROC; |
| opts->f.pid = getppid(); |
| break; |
| case 6: |
| opts->from_type = OPTS_FROM_PROCEXE; |
| opts->f.pid = getppid(); |
| break; |
| case 7: |
| opts->from_type = OPTS_FROM_PROCFS; |
| opts->f.pid = getppid(); |
| break; |
| case 8: |
| opts->from_type = OPTS_FROM_PROCKEY; |
| opts->f.pid = getppid(); |
| break; |
| |
| case 'f': |
| opts->from_type = OPTS_FROM_FILE; |
| opts->f.file = optarg; |
| break; |
| case 'L': |
| opts->from_type = OPTS_FROM_LINK; |
| opts->f.link = optarg; |
| break; |
| case 'p': |
| opts->from_type = OPTS_FROM_PROC; |
| opts->f.pid = atoi(optarg); |
| break; |
| case 9: |
| opts->from_type = OPTS_FROM_PROCEXE; |
| opts->f.pid = atoi(optarg); |
| break; |
| case 10: |
| opts->from_type = OPTS_FROM_PROCFS; |
| opts->f.pid = atoi(optarg); |
| break; |
| case 11: |
| opts->from_type = OPTS_FROM_PROCKEY; |
| opts->f.pid = atoi(optarg); |
| break; |
| |
| default: |
| assert(FALSE); |
| } |
| } |
| |
| if (!done) { /* default, if nothing specified */ |
| opts->disp_user = TRUE; |
| opts->disp_role = TRUE; |
| opts->disp_type = TRUE; |
| if (!opts->disp_prompt) { /* when displaying prompt, just output "normal" by default */ |
| opts->disp_sen = TRUE; |
| opts->disp_clr = TRUE; |
| } |
| opts->disp_mlsr = TRUE; |
| } |
| |
| if (disp_none()) |
| err(EXIT_FAILURE, " Nothing to display"); |
| |
| argc -= optind; |
| argv += optind; |
| |
| if (!argc && (opts->from_type == OPTS_FROM_ARG) |
| && !isatty(STDIN_FILENO)) |
| opts->from_type = OPTS_FROM_STDIN; |
| if (!argc && (opts->from_type == OPTS_FROM_ARG)) |
| opts->from_type = OPTS_FROM_CUR; |
| |
| if (opts->from_type == OPTS_FROM_ARG) { |
| if (!argv[0]) |
| errx(EXIT_FAILURE, "No argument given"); |
| |
| opts->f.arg = argv[0]; |
| |
| if (xstreq(argv[0], "-")) |
| opts->from_type = OPTS_FROM_STDIN; |
| } else if (!is_selinux_enabled()) |
| errx(EXIT_FAILURE, "SELinux is not enabled"); |
| } |
| |
| static int my_getXcon_raw(pid_t pid, char **con, const char *val) |
| { |
| char buf[4096]; |
| FILE *fp = NULL; |
| const char *ptr = NULL; |
| |
| snprintf(buf, sizeof(buf), "%s/%ld/attr/%s", "/proc", (long int)pid, |
| val); |
| |
| if (!(fp = fopen(buf, "rb"))) |
| return (-1); |
| |
| ptr = fgets(buf, sizeof(buf), fp); |
| |
| fclose(fp); |
| |
| *con = NULL; |
| if (ptr) { /* return *con = NULL, when proc file is empty */ |
| char *tmp = strchr(ptr, '\n'); |
| |
| if (tmp) |
| *tmp = 0; |
| |
| if (*ptr && !(*con = strdup(ptr))) |
| return (-1); |
| } |
| |
| return (0); |
| } |
| |
| static int my_getpidexeccon_raw(pid_t pid, char **con) |
| { |
| return (my_getXcon_raw(pid, con, "exec")); |
| } |
| static int my_getpidfscreatecon_raw(pid_t pid, char **con) |
| { |
| return (my_getXcon_raw(pid, con, "fscreate")); |
| } |
| static int my_getpidkeycreatecon_raw(pid_t pid, char **con) |
| { |
| return (my_getXcon_raw(pid, con, "keycreate")); |
| } |
| |
| static char *get_scon(void) |
| { |
| static char dummy_NIL[1] = ""; |
| char *con = NULL, *con_tmp; |
| int ret = -1; |
| |
| switch (opts->from_type) { |
| case OPTS_FROM_ARG: |
| if (!(con_tmp = strdup(opts->f.arg))) |
| err(EXIT_FAILURE, |
| " Couldn't allocate security context"); |
| if (selinux_trans_to_raw_context(con_tmp, &con) < 0) |
| err(EXIT_FAILURE, |
| " Couldn't translate security context"); |
| freecon(con_tmp); |
| break; |
| |
| case OPTS_FROM_STDIN: |
| { |
| char buf[4096] = ""; |
| char *ptr = buf; |
| |
| while (!*ptr) { |
| if (!(ptr = fgets(buf, sizeof(buf), stdin))) |
| err(EXIT_FAILURE, |
| " Couldn't read security context"); |
| |
| ptr += strspn(ptr, " \n\t"); |
| ptr[strcspn(ptr, " \n\t")] = 0; |
| } |
| |
| if (!(con_tmp = strdup(ptr))) |
| err(EXIT_FAILURE, |
| " Couldn't allocate security context"); |
| if (selinux_trans_to_raw_context(con_tmp, &con) < 0) |
| err(EXIT_FAILURE, |
| " Couldn't translate security context"); |
| freecon(con_tmp); |
| break; |
| } |
| |
| case OPTS_FROM_CUR: |
| ret = getcon_raw(&con); |
| |
| if (ret == -1) |
| err(EXIT_FAILURE, |
| " Couldn't get current security context"); |
| break; |
| case OPTS_FROM_CUREXE: |
| ret = getexeccon_raw(&con); |
| |
| if (ret == -1) |
| err(EXIT_FAILURE, |
| " Couldn't get current exec security context"); |
| |
| if (!con) |
| con = strdup(dummy_NIL); |
| break; |
| case OPTS_FROM_CURFS: |
| ret = getfscreatecon_raw(&con); |
| |
| if (ret == -1) |
| err(EXIT_FAILURE, |
| " Couldn't get current fs security context"); |
| |
| if (!con) |
| con = strdup(dummy_NIL); |
| break; |
| case OPTS_FROM_CURKEY: |
| ret = getkeycreatecon_raw(&con); |
| |
| if (ret == -1) |
| err(EXIT_FAILURE, |
| " Couldn't get current key security context"); |
| |
| if (!con) |
| con = strdup(dummy_NIL); |
| break; |
| |
| case OPTS_FROM_PROC: |
| ret = getpidcon_raw(opts->f.pid, &con); |
| |
| if (ret == -1) |
| err(EXIT_FAILURE, |
| " Couldn't get security context for pid %lu", |
| (unsigned long)opts->f.pid); |
| break; |
| case OPTS_FROM_PROCEXE: |
| ret = my_getpidexeccon_raw(opts->f.pid, &con); |
| |
| if (ret == -1) |
| err(EXIT_FAILURE, |
| " Couldn't get security context for pid %lu", |
| (unsigned long)opts->f.pid); |
| |
| if (!con) |
| con = strdup(dummy_NIL); |
| break; |
| case OPTS_FROM_PROCFS: |
| ret = my_getpidfscreatecon_raw(opts->f.pid, &con); |
| |
| if (ret == -1) |
| err(EXIT_FAILURE, |
| " Couldn't get security context for pid %lu", |
| (unsigned long)opts->f.pid); |
| |
| if (!con) |
| con = strdup(dummy_NIL); |
| /* disabled -- override with normal context ... |
| { |
| opts->from_type = OPTS_FROM_PROC; |
| return (get_scon()); |
| } */ |
| break; |
| case OPTS_FROM_PROCKEY: |
| ret = my_getpidkeycreatecon_raw(opts->f.pid, &con); |
| |
| if (ret == -1) |
| err(EXIT_FAILURE, |
| " Couldn't get security context for pid %lu", |
| (unsigned long)opts->f.pid); |
| |
| if (!con) |
| con = strdup(dummy_NIL); |
| break; |
| |
| case OPTS_FROM_FILE: |
| ret = getfilecon_raw(opts->f.file, &con); |
| |
| if (ret == -1) |
| err(EXIT_FAILURE, |
| " Couldn't get security context for file %s", |
| opts->f.file); |
| break; |
| |
| case OPTS_FROM_LINK: |
| ret = lgetfilecon_raw(opts->f.link, &con); |
| |
| if (ret == -1) |
| err(EXIT_FAILURE, |
| " Couldn't get security context for symlink %s", |
| opts->f.link); |
| break; |
| |
| default: |
| assert(FALSE); |
| } |
| |
| return (con); |
| } |
| |
| static unsigned int disp__color_to_ansi(const char *color_str) |
| { |
| int val = 30; |
| |
| /* NOTE: ansi black is 30 for foreground colors */ |
| |
| /* red */ |
| if (strncasecmp(&color_str[1], "7f", 2) >= 0) |
| val += 1; |
| /* green */ |
| if (strncasecmp(&color_str[3], "7f", 2) >= 0) |
| val += 2; |
| /* blue */ |
| if (strncasecmp(&color_str[5], "7f", 2) >= 0) |
| val += 4; |
| |
| return val; |
| } |
| |
| static char *disp__con_color_ansi(const char *name, |
| struct context_color_t *color) |
| { |
| unsigned int fg, bg; |
| char *ansi; |
| int ansi_len = strlen("\e[99;99m") + 1; |
| |
| /* NOTE: ansi background codes are the same as foreground codes +10 */ |
| |
| if (xstreq("user", name)) { |
| fg = disp__color_to_ansi(color->user_fg); |
| bg = disp__color_to_ansi(color->user_bg) + 10; |
| } else if (xstreq("role", name)) { |
| fg = disp__color_to_ansi(color->role_fg); |
| bg = disp__color_to_ansi(color->role_bg) + 10; |
| } else if (xstreq("type", name)) { |
| fg = disp__color_to_ansi(color->type_fg); |
| bg = disp__color_to_ansi(color->type_bg) + 10; |
| } else if (xstreq("sensitivity", name) || |
| xstreq("clearance", name) || |
| xstreq("mls-range", name)) { |
| fg = disp__color_to_ansi(color->range_fg); |
| bg = disp__color_to_ansi(color->range_bg) + 10; |
| } else |
| err(EXIT_FAILURE, " No color information for context field"); |
| |
| if (!(ansi = malloc(ansi_len))) |
| err(EXIT_FAILURE, " Unable to allocate memory"); |
| if (snprintf(ansi, ansi_len, "\e[%d;%dm", fg, bg) > ansi_len) |
| err(EXIT_FAILURE, " Unable to convert colors to ANSI codes"); |
| |
| return ansi; |
| } |
| |
| static void disp__con_val(const char *name, const char *val, |
| struct context_color_t *color) |
| { |
| static int done = FALSE; |
| |
| assert(name); |
| assert(color); |
| |
| if (!val) |
| val = ""; /* targeted has no "level" etc., |
| any errors should happen at context_new() time */ |
| |
| if (opts->disp_prompt) { |
| if (xstreq("mls-range", name) && !*val) |
| return; /* skip, mls-range if it's empty */ |
| |
| if (opts->disp_color && color->valid) { |
| char *ansi = disp__con_color_ansi(name, color); |
| fprintf(stdout, "%s", ansi); |
| free(ansi); |
| } |
| fprintf(stdout, "%s%s", done ? ":" : "", val); |
| if (opts->disp_color && color->valid) |
| fprintf(stdout, "\e[0m"); |
| } else if (disp_multi()) |
| fprintf(stdout, "%s: %s\n", name, val); |
| else |
| fprintf(stdout, "%s\n", val); |
| |
| done = TRUE; |
| } |
| |
| static void disp_con(const char *scon_raw) |
| { |
| char *scon_trans; |
| const char *scon; |
| context_t con = NULL; |
| char *color_str = NULL; |
| struct context_color_t color = { .valid = 0 }; |
| |
| selinux_raw_to_trans_context(scon_raw, &scon_trans); |
| if (opts->disp_raw) |
| scon = scon_raw; |
| else |
| scon = scon_trans; |
| |
| if (!*scon) { /* --self-exec and --self-fs etc. */ |
| if (opts->disp_user) |
| disp__con_val("user", NULL, &color); |
| if (opts->disp_role) |
| disp__con_val("role", NULL, &color); |
| if (opts->disp_type) |
| disp__con_val("type", NULL, &color); |
| if (opts->disp_sen) |
| disp__con_val("sensitivity", NULL, &color); |
| if (opts->disp_clr) |
| disp__con_val("clearance", NULL, &color); |
| if (opts->disp_mlsr) |
| disp__con_val("mls-range", NULL, &color); |
| freecon(scon_trans); |
| return; |
| } |
| |
| if (opts->disp_color) { |
| if (selinux_raw_context_to_color(scon_raw, &color_str) < 0) |
| errx(EXIT_FAILURE, "Couldn't determine colors for: %s", |
| scon); |
| |
| color.user_fg = strtok(color_str, " "); |
| if (!color.user_fg) |
| errx(EXIT_FAILURE, "Invalid color string"); |
| color.user_bg = strtok(NULL, " "); |
| if (!color.user_bg) |
| errx(EXIT_FAILURE, "Invalid color string"); |
| |
| color.role_fg = strtok(NULL, " "); |
| if (!color.role_fg) |
| errx(EXIT_FAILURE, "Invalid color string"); |
| color.role_bg = strtok(NULL, " "); |
| if (!color.role_bg) |
| errx(EXIT_FAILURE, "Invalid color string"); |
| |
| color.type_fg = strtok(NULL, " "); |
| if (!color.type_fg) |
| errx(EXIT_FAILURE, "Invalid color string"); |
| color.type_bg = strtok(NULL, " "); |
| if (!color.type_bg) |
| errx(EXIT_FAILURE, "Invalid color string"); |
| |
| color.range_fg = strtok(NULL, " "); |
| if (!color.range_fg) |
| errx(EXIT_FAILURE, "Invalid color string"); |
| color.range_bg = strtok(NULL, " "); |
| |
| color.valid = 1; |
| } |
| |
| if (!(con = context_new(scon))) |
| errx(EXIT_FAILURE, "Couldn't create context from: %s", scon); |
| |
| if (opts->disp_user) { |
| disp__con_val("user", context_user_get(con), &color); |
| } |
| if (opts->disp_role) { |
| disp__con_val("role", context_role_get(con), &color); |
| } |
| if (opts->disp_type) { |
| disp__con_val("type", context_type_get(con), &color); |
| } |
| if (opts->disp_sen) { |
| const char *val = NULL; |
| char *tmp = NULL; |
| |
| val = context_range_get(con); |
| if (!val) |
| val = ""; /* targeted has no "level" etc., |
| any errors should happen at context_new() time */ |
| |
| tmp = strdup(val); |
| if (!tmp) |
| errx(EXIT_FAILURE, "Couldn't create context from: %s", |
| scon); |
| if (strchr(tmp, '-')) |
| *strchr(tmp, '-') = 0; |
| |
| disp__con_val("sensitivity", tmp, &color); |
| |
| free(tmp); |
| } |
| if (opts->disp_clr) { |
| const char *val = NULL; |
| char *tmp = NULL; |
| |
| val = context_range_get(con); |
| if (!val) |
| val = ""; /* targeted has no "level" etc., |
| any errors should happen at context_new() time */ |
| |
| tmp = strdup(val); |
| if (!tmp) |
| errx(EXIT_FAILURE, "Couldn't create context from: %s", |
| scon); |
| if (strchr(tmp, '-')) |
| disp__con_val("clearance", strchr(tmp, '-') + 1, &color); |
| else |
| disp__con_val("clearance", tmp, &color); |
| |
| free(tmp); |
| } |
| |
| if (opts->disp_mlsr) |
| disp__con_val("mls-range", context_range_get(con), &color); |
| |
| context_free(con); |
| freecon(scon_trans); |
| if (color_str) |
| free(color_str); |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| char *scon_raw = NULL; |
| |
| cmd_line(argc, argv); |
| |
| scon_raw = get_scon(); |
| |
| disp_con(scon_raw); |
| |
| freecon(scon_raw); |
| |
| exit(EXIT_SUCCESS); |
| } |