#include #include #include #include #define xstreq(x, y) !strcmp(x, y) #include #include #include #include #include #include #define TRUE 1 #define FALSE 0 #define SECON_CONF_PROG_NAME "secon" /* default program name */ #define SECON_OPTS_SM "hVurtscmPRfLp" /* small options available, print */ #define SECON_OPTS_GO "hVurtlscmPRf: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 { 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_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, OPTS_FROM_ARG, { 0}}}; static 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" " --current Get the context for the current process.\n" " --self Get the context for the current process.\n" " --self-exec Get the exec context for the current process.\n" " --self-fs Get the fs context for the current process.\n" " --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 Use the context from the specified pid.\n" " --pid-exec Use the exec context from the specified pid.\n" " --pid-fs Use the fs context from the specified pid.\n" " --pid-key Use the key context from the specified pid.\n" " --file -f Use the context from the specified file.\n" " --link -L 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'}, {"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 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) { /* defualt, 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) { 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, security_context_t * 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, security_context_t * con) { return (my_getXcon_raw(pid, con, "exec")); } static int my_getpidfscreatecon_raw(pid_t pid, security_context_t * con) { return (my_getXcon_raw(pid, con, "fscreate")); } static int my_getpidkeycreatecon_raw(pid_t pid, security_context_t * con) { return (my_getXcon_raw(pid, con, "keycreate")); } static security_context_t get_scon(void) { static char dummy_NIL[1] = ""; security_context_t con = NULL; int ret = -1; int raw = TRUE; switch (opts->from_type) { case OPTS_FROM_ARG: if (!(con = strdup(opts->f.arg))) err(EXIT_FAILURE, " Couldn't allocate security context"); raw = !opts->disp_raw; /* always do conversion */ 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 = strdup(ptr))) err(EXIT_FAILURE, " Couldn't allocate security context"); raw = !opts->disp_raw; /* always do conversion */ 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); } if (opts->disp_raw != raw) { security_context_t ncon = NULL; if (opts->disp_raw) selinux_trans_to_raw_context(con, &ncon); else selinux_raw_to_trans_context(con, &ncon); freecon(con); con = ncon; } return (con); } static void disp__con_val(const char *name, const char *val) { static int done = FALSE; assert(name); 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 */ fprintf(stdout, "%s%s", done ? ":" : "", val); } else if (disp_multi()) fprintf(stdout, "%s: %s\n", name, val); else fprintf(stdout, "%s\n", val); done = TRUE; } static void disp_con(security_context_t scon) { context_t con = NULL; if (!*scon) { /* --self-exec and --self-fs etc. */ if (opts->disp_user) disp__con_val("user", NULL); if (opts->disp_role) disp__con_val("role", NULL); if (opts->disp_type) disp__con_val("type", NULL); if (opts->disp_sen) disp__con_val("sensitivity", NULL); if (opts->disp_clr) disp__con_val("clearance", NULL); if (opts->disp_mlsr) disp__con_val("mls-range", NULL); return; } 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)); if (opts->disp_role) disp__con_val("role", context_role_get(con)); if (opts->disp_type) disp__con_val("type", context_type_get(con)); 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); 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); else disp__con_val("clearance", tmp); free(tmp); } if (opts->disp_mlsr) disp__con_val("mls-range", context_range_get(con)); context_free(con); } int main(int argc, char *argv[]) { security_context_t scon = NULL; cmd_line(argc, argv); scon = get_scon(); disp_con(scon); freecon(scon); exit(EXIT_SUCCESS); }