/*
* 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;
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;
}
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;
}
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));
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));
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;
}
void printf_tab(const char *outp)
{
char buf[20];
snprintf(buf, sizeof(buf), "%%-%us", COL);
printf(buf, 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);
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;
}