| /* |
| * Copyright 1999-2004 Gentoo Technologies, Inc. |
| * Distributed under the terms of the GNU General Public License v2 |
| * $Header: /home/cvsroot/gentoo-projects/hardened/policycoreutils-extra/src/sestatus.c,v 1.10 2004/03/26 19:25:52 pebenito Exp $ |
| * Patch provided by Steve Grubb |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <selinux/selinux.h> |
| #include <selinux/get_default_type.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <dirent.h> |
| #include <unistd.h> |
| #include <libgen.h> |
| #include <ctype.h> |
| #include <limits.h> |
| |
| #define PROC_BASE "/proc" |
| #define MAX_CHECK 50 |
| #define CONF "/etc/sestatus.conf" |
| |
| /* conf file sections */ |
| #define PROCS "[process]" |
| #define FILES "[files]" |
| |
| /* buffer size for cmp_cmdline */ |
| #define BUFSIZE 255 |
| |
| /* column to put the output (must be a multiple of 8) */ |
| static unsigned int COL = 32; |
| |
| extern char *selinux_mnt; |
| |
| static int cmp_cmdline(const char *command, int pid) |
| { |
| |
| char buf[BUFSIZE]; |
| char filename[BUFSIZE]; |
| |
| memset(buf, '\0', BUFSIZE); |
| |
| /* first read the proc entry */ |
| sprintf(filename, "%s/%d/exe", PROC_BASE, pid); |
| |
| if (readlink(filename, buf, BUFSIZE) < 0) |
| return 0; |
| |
| if (buf[BUFSIZE - 1] != '\0') |
| buf[BUFSIZE - 1] = '\0'; |
| |
| /* check if this is the command we're looking for. */ |
| if (strcmp(command, buf) == 0) |
| return 1; |
| else |
| return 0; |
| } |
| |
| static int pidof(const char *command) |
| { |
| /* inspired by killall5.c from psmisc */ |
| char stackpath[PATH_MAX + 1], *p; |
| DIR *dir; |
| struct dirent *de; |
| int pid, ret = -1, self = getpid(); |
| |
| if (!(dir = opendir(PROC_BASE))) { |
| perror(PROC_BASE); |
| return -1; |
| } |
| |
| /* Resolve the path if it contains symbolic links */ |
| p = realpath(command, stackpath); |
| if (p) |
| command = p; |
| |
| while ((de = readdir(dir)) != NULL) { |
| errno = 0; |
| pid = (int)strtol(de->d_name, (char **)NULL, 10); |
| if (errno || pid == 0 || pid == self) |
| continue; |
| if (cmp_cmdline(command, pid)) { |
| ret = pid; |
| break; |
| } |
| } |
| |
| closedir(dir); |
| return ret; |
| } |
| |
| static void load_checks(char *pc[], int *npc, char *fc[], int *nfc) |
| { |
| |
| FILE *fp = fopen(CONF, "r"); |
| char buf[255], *bufp; |
| int buf_len, section = -1; |
| int proclen = strlen(PROCS); |
| int filelen = strlen(FILES); |
| |
| if (fp == NULL) { |
| printf("\nUnable to open %s.\n", CONF); |
| return; |
| } |
| |
| while (!feof(fp)) { |
| if (!fgets(buf, sizeof buf, fp)) |
| break; |
| |
| buf_len = strlen(buf); |
| if (buf[buf_len - 1] == '\n') |
| buf[buf_len - 1] = 0; |
| |
| bufp = buf; |
| while (*bufp && isspace(*bufp)) { |
| bufp++; |
| buf_len--; |
| } |
| |
| if (*bufp == '#') |
| /* skip comments */ |
| continue; |
| |
| if (*bufp) { |
| if (!(*bufp)) |
| goto out; |
| |
| if (strncmp(bufp, PROCS, proclen) == 0) |
| section = 0; |
| else if (strncmp(bufp, FILES, filelen) == 0) |
| section = 1; |
| else { |
| switch (section) { |
| case 0: |
| if (*npc >= MAX_CHECK) |
| break; |
| pc[*npc] = |
| (char *)malloc((buf_len) * |
| sizeof(char)); |
| if (!pc[*npc]) |
| break; |
| memcpy(pc[*npc], bufp, buf_len); |
| (*npc)++; |
| bufp = NULL; |
| break; |
| case 1: |
| if (*nfc >= MAX_CHECK) |
| break; |
| fc[*nfc] = |
| (char *)malloc((buf_len) * |
| sizeof(char)); |
| if (!fc[*nfc]) |
| break; |
| memcpy(fc[*nfc], bufp, buf_len); |
| (*nfc)++; |
| bufp = NULL; |
| break; |
| default: |
| /* ignore lines before a section */ |
| printf("Line not in a section: %s.\n", |
| buf); |
| break; |
| } |
| } |
| } |
| } |
| out: |
| fclose(fp); |
| return; |
| } |
| |
| static void printf_tab(const char *outp) |
| { |
| printf("%-*s", COL, outp); |
| |
| } |
| |
| int main(int argc, char **argv) |
| { |
| /* these vars are reused several times */ |
| int rc, opt, i, c; |
| char *context, *root_path; |
| |
| /* files that need context checks */ |
| char *fc[MAX_CHECK]; |
| char *cterm = ttyname(0); |
| int nfc = 0; |
| struct stat m; |
| |
| /* processes that need context checks */ |
| char *pc[MAX_CHECK]; |
| int npc = 0; |
| |
| /* booleans */ |
| char **bools; |
| int nbool; |
| |
| int verbose = 0; |
| int show_bools = 0; |
| |
| /* policy */ |
| const char *pol_name, *root_dir; |
| char *pol_path; |
| |
| |
| while (1) { |
| opt = getopt(argc, argv, "vb"); |
| if (opt == -1) |
| break; |
| switch (opt) { |
| case 'v': |
| verbose = 1; |
| break; |
| case 'b': |
| show_bools = 1; |
| break; |
| default: |
| /* invalid option */ |
| printf("\nUsage: %s [OPTION]\n\n", basename(argv[0])); |
| printf(" -v Verbose check of process and file contexts.\n"); |
| printf(" -b Display current state of booleans.\n"); |
| printf("\nWithout options, show SELinux status.\n"); |
| return -1; |
| } |
| } |
| printf_tab("SELinux status:"); |
| rc = is_selinux_enabled(); |
| |
| switch (rc) { |
| case 1: |
| printf("enabled\n"); |
| break; |
| case 0: |
| printf("disabled\n"); |
| return 0; |
| break; |
| default: |
| printf("unknown (%s)\n", strerror(errno)); |
| return 0; |
| break; |
| } |
| |
| printf_tab("SELinuxfs mount:"); |
| if (selinux_mnt != NULL) { |
| printf("%s\n", selinux_mnt); |
| } else { |
| printf("not mounted\n\n"); |
| printf("Please mount selinuxfs for proper results.\n"); |
| return -1; |
| } |
| |
| printf_tab("SELinux root directory:"); |
| root_dir = selinux_path(); |
| if (root_dir == NULL) { |
| printf("error (%s)\n", strerror(errno)); |
| return -1; |
| } |
| /* The path has a trailing '/' so duplicate to edit */ |
| root_path = strdup(root_dir); |
| if (!root_path) { |
| printf("malloc error (%s)\n", strerror(errno)); |
| return -1; |
| } |
| /* actually blank the '/' */ |
| root_path[strlen(root_path) - 1] = '\0'; |
| printf("%s\n", root_path); |
| free(root_path); |
| |
| /* Dump all the path information */ |
| printf_tab("Loaded policy name:"); |
| pol_path = strdup(selinux_policy_root()); |
| if (pol_path) { |
| pol_name = basename(pol_path); |
| puts(pol_name); |
| free(pol_path); |
| } else { |
| printf("error (%s)\n", strerror(errno)); |
| } |
| |
| printf_tab("Current mode:"); |
| rc = security_getenforce(); |
| switch (rc) { |
| case 1: |
| printf("enforcing\n"); |
| break; |
| case 0: |
| printf("permissive\n"); |
| break; |
| default: |
| printf("unknown (%s)\n", strerror(errno)); |
| break; |
| } |
| |
| printf_tab("Mode from config file:"); |
| if (selinux_getenforcemode(&rc) == 0) { |
| switch (rc) { |
| case 1: |
| printf("enforcing\n"); |
| break; |
| case 0: |
| printf("permissive\n"); |
| break; |
| case -1: |
| printf("disabled\n"); |
| break; |
| } |
| } else { |
| printf("error (%s)\n", strerror(errno)); |
| } |
| |
| printf_tab("Policy MLS status:"); |
| rc = is_selinux_mls_enabled(); |
| switch (rc) { |
| case 0: |
| printf("disabled\n"); |
| break; |
| case 1: |
| printf("enabled\n"); |
| break; |
| default: |
| printf("error (%s)\n", strerror(errno)); |
| break; |
| } |
| |
| printf_tab("Policy deny_unknown status:"); |
| rc = security_deny_unknown(); |
| switch (rc) { |
| case 0: |
| printf("allowed\n"); |
| break; |
| case 1: |
| printf("denied\n"); |
| break; |
| default: |
| printf("error (%s)\n", strerror(errno)); |
| break; |
| } |
| |
| printf_tab("Memory protection checking:"); |
| rc = security_get_checkreqprot(); |
| switch (rc) { |
| case 0: |
| printf("actual (secure)\n"); |
| break; |
| case 1: |
| printf("requested (insecure)\n"); |
| break; |
| default: |
| printf("error (%s)\n", strerror(errno)); |
| break; |
| } |
| |
| rc = security_policyvers(); |
| printf_tab("Max kernel policy version:"); |
| if (rc < 0) |
| printf("unknown (%s)\n", strerror(errno)); |
| else |
| printf("%d\n", rc); |
| |
| |
| if (show_bools) { |
| /* show booleans */ |
| if (security_get_boolean_names(&bools, &nbool) >= 0) { |
| printf("\nPolicy booleans:\n"); |
| |
| for (i = 0; i < nbool; i++) { |
| if (strlen(bools[i]) + 1 > COL) |
| COL = strlen(bools[i]) + 1; |
| } |
| for (i = 0; i < nbool; i++) { |
| printf_tab(bools[i]); |
| |
| rc = security_get_boolean_active(bools[i]); |
| switch (rc) { |
| case 1: |
| printf("on"); |
| break; |
| case 0: |
| printf("off"); |
| break; |
| default: |
| printf("unknown (%s)", strerror(errno)); |
| break; |
| } |
| c = security_get_boolean_pending(bools[i]); |
| if (c != rc) |
| switch (c) { |
| case 1: |
| printf(" (activate pending)"); |
| break; |
| case 0: |
| printf(" (inactivate pending)"); |
| break; |
| default: |
| printf(" (pending error: %s)", |
| strerror(errno)); |
| break; |
| } |
| printf("\n"); |
| |
| /* free up the booleans */ |
| free(bools[i]); |
| } |
| free(bools); |
| } |
| } |
| /* only show contexts if -v is given */ |
| if (!verbose) |
| return 0; |
| |
| load_checks(pc, &npc, fc, &nfc); |
| |
| printf("\nProcess contexts:\n"); |
| |
| printf_tab("Current context:"); |
| if (getcon(&context) >= 0) { |
| printf("%s\n", context); |
| freecon(context); |
| } else |
| printf("unknown (%s)\n", strerror(errno)); |
| |
| printf_tab("Init context:"); |
| if (getpidcon(1, &context) >= 0) { |
| printf("%s\n", context); |
| freecon(context); |
| } else |
| printf("unknown (%s)\n", strerror(errno)); |
| |
| for (i = 0; i < npc; i++) { |
| rc = pidof(pc[i]); |
| if (rc > 0) { |
| if (getpidcon(rc, &context) < 0) |
| continue; |
| |
| printf_tab(pc[i]); |
| printf("%s\n", context); |
| freecon(context); |
| } |
| free(pc[i]); |
| } |
| |
| printf("\nFile contexts:\n"); |
| |
| /* controlling term */ |
| printf_tab("Controlling terminal:"); |
| if (lgetfilecon(cterm, &context) >= 0) { |
| printf("%s\n", context); |
| freecon(context); |
| } else { |
| printf("unknown (%s)\n", strerror(errno)); |
| } |
| |
| for (i = 0; i < nfc; i++) { |
| if (lgetfilecon(fc[i], &context) >= 0) { |
| printf_tab(fc[i]); |
| |
| /* check if this is a symlink */ |
| if (lstat(fc[i], &m)) { |
| printf |
| ("%s (could not check link status (%s)!)\n", |
| context, strerror(errno)); |
| freecon(context); |
| free(fc[i]); |
| continue; |
| } |
| if (S_ISLNK(m.st_mode)) { |
| /* print link target context */ |
| printf("%s -> ", context); |
| freecon(context); |
| |
| if (getfilecon(fc[i], &context) >= 0) { |
| printf("%s\n", context); |
| freecon(context); |
| } else { |
| printf("unknown (%s)\n", |
| strerror(errno)); |
| } |
| } else { |
| printf("%s\n", context); |
| freecon(context); |
| } |
| } |
| free(fc[i]); |
| } |
| |
| return 0; |
| } |