Home | History | Annotate | Download | only in sestatus
      1 /*
      2  * Copyright 1999-2004 Gentoo Technologies, Inc.
      3  * Distributed under the terms of the GNU General Public License v2
      4  * $Header: /home/cvsroot/gentoo-projects/hardened/policycoreutils-extra/src/sestatus.c,v 1.10 2004/03/26 19:25:52 pebenito Exp $
      5  * Patch provided by Steve Grubb
      6  */
      7 
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 #include <errno.h>
     12 #include <selinux/selinux.h>
     13 #include <selinux/get_default_type.h>
     14 #include <sys/types.h>
     15 #include <sys/stat.h>
     16 #include <dirent.h>
     17 #include <unistd.h>
     18 #include <libgen.h>
     19 #include <ctype.h>
     20 #include <limits.h>
     21 
     22 #define PROC_BASE "/proc"
     23 #define MAX_CHECK 50
     24 #define CONF "/etc/sestatus.conf"
     25 
     26 /* conf file sections */
     27 #define PROCS "[process]"
     28 #define FILES "[files]"
     29 
     30 /* buffer size for cmp_cmdline */
     31 #define BUFSIZE 255
     32 
     33 /* column to put the output (must be a multiple of 8) */
     34 static unsigned int COL = 32;
     35 
     36 extern char *selinux_mnt;
     37 
     38 int cmp_cmdline(const char *command, int pid)
     39 {
     40 
     41 	char buf[BUFSIZE];
     42 	char filename[BUFSIZE];
     43 
     44 	memset(buf, '\0', BUFSIZE);
     45 
     46 	/* first read the proc entry */
     47 	sprintf(filename, "%s/%d/exe", PROC_BASE, pid);
     48 
     49 	if (readlink(filename, buf, BUFSIZE) < 0)
     50 		return 0;
     51 
     52 	if (buf[BUFSIZE - 1] != '\0')
     53 		buf[BUFSIZE - 1] = '\0';
     54 
     55 	/* check if this is the command we're looking for. */
     56 	if (strcmp(command, buf) == 0)
     57 		return 1;
     58 	else
     59 		return 0;
     60 }
     61 
     62 int pidof(const char *command)
     63 {
     64 /* inspired by killall5.c from psmisc */
     65 	char stackpath[PATH_MAX + 1], *p;
     66 	DIR *dir;
     67 	struct dirent *de;
     68 	int pid, ret = -1, self = getpid();
     69 
     70 	if (!(dir = opendir(PROC_BASE))) {
     71 		perror(PROC_BASE);
     72 		return -1;
     73 	}
     74 
     75 	/* Resolve the path if it contains symbolic links */
     76 	p = realpath(command, stackpath);
     77 	if (p)
     78 		command = p;
     79 
     80 	while ((de = readdir(dir)) != NULL) {
     81 		errno = 0;
     82 		pid = (int)strtol(de->d_name, (char **)NULL, 10);
     83 		if (errno || pid == 0 || pid == self)
     84 			continue;
     85 		if (cmp_cmdline(command, pid)) {
     86 			ret = pid;
     87 			break;
     88 		}
     89 	}
     90 
     91 	closedir(dir);
     92 	return ret;
     93 }
     94 
     95 void load_checks(char *pc[], int *npc, char *fc[], int *nfc)
     96 {
     97 
     98 	FILE *fp = fopen(CONF, "r");
     99 	char buf[255], *bufp;
    100 	int buf_len, section = -1;
    101 	int proclen = strlen(PROCS);
    102 	int filelen = strlen(FILES);
    103 
    104 	if (fp == NULL) {
    105 		printf("\nUnable to open %s.\n", CONF);
    106 		return;
    107 	}
    108 
    109 	while (!feof(fp)) {
    110 		if (!fgets(buf, sizeof buf, fp))
    111 			break;
    112 
    113 		buf_len = strlen(buf);
    114 		if (buf[buf_len - 1] == '\n')
    115 			buf[buf_len - 1] = 0;
    116 
    117 		bufp = buf;
    118 		while (*bufp && isspace(*bufp)) {
    119 			bufp++;
    120 			buf_len--;
    121 		}
    122 
    123 		if (*bufp == '#')
    124 			/* skip comments */
    125 			continue;
    126 
    127 		if (*bufp) {
    128 			if (!(*bufp))
    129 				goto out;
    130 
    131 			if (strncmp(bufp, PROCS, proclen) == 0)
    132 				section = 0;
    133 			else if (strncmp(bufp, FILES, filelen) == 0)
    134 				section = 1;
    135 			else {
    136 				switch (section) {
    137 				case 0:
    138 					if (*npc >= MAX_CHECK)
    139 						break;
    140 					pc[*npc] =
    141 					    (char *)malloc((buf_len) *
    142 							   sizeof(char));
    143 					memcpy(pc[*npc], bufp, buf_len);
    144 					(*npc)++;
    145 					bufp = NULL;
    146 					break;
    147 				case 1:
    148 					if (*nfc >= MAX_CHECK)
    149 						break;
    150 					fc[*nfc] =
    151 					    (char *)malloc((buf_len) *
    152 							   sizeof(char));
    153 					memcpy(fc[*nfc], bufp, buf_len);
    154 					(*nfc)++;
    155 					bufp = NULL;
    156 					break;
    157 				default:
    158 					/* ignore lines before a section */
    159 					printf("Line not in a section: %s.\n",
    160 					       buf);
    161 					break;
    162 				}
    163 			}
    164 		}
    165 	}
    166       out:
    167 	fclose(fp);
    168 	return;
    169 }
    170 
    171 void printf_tab(const char *outp)
    172 {
    173 	char buf[20];
    174 	snprintf(buf, sizeof(buf), "%%-%us", COL);
    175 	printf(buf, outp);
    176 
    177 }
    178 
    179 int main(int argc, char **argv)
    180 {
    181 	/* these vars are reused several times */
    182 	int rc, opt, i, c;
    183 	char *context, *root_path;
    184 
    185 	/* files that need context checks */
    186 	char *fc[MAX_CHECK];
    187 	char *cterm = ttyname(0);
    188 	int nfc = 0;
    189 	struct stat m;
    190 
    191 	/* processes that need context checks */
    192 	char *pc[MAX_CHECK];
    193 	int npc = 0;
    194 
    195 	/* booleans */
    196 	char **bools;
    197 	int nbool;
    198 
    199 	int verbose = 0;
    200 	int show_bools = 0;
    201 
    202 	/* policy */
    203 	const char *pol_name, *root_dir;
    204 	char *pol_path;
    205 
    206 
    207 	while (1) {
    208 		opt = getopt(argc, argv, "vb");
    209 		if (opt == -1)
    210 			break;
    211 		switch (opt) {
    212 		case 'v':
    213 			verbose = 1;
    214 			break;
    215 		case 'b':
    216 			show_bools = 1;
    217 			break;
    218 		default:
    219 			/* invalid option */
    220 			printf("\nUsage: %s [OPTION]\n\n", basename(argv[0]));
    221 			printf("  -v  Verbose check of process and file contexts.\n");
    222 			printf("  -b  Display current state of booleans.\n");
    223 			printf("\nWithout options, show SELinux status.\n");
    224 			return -1;
    225 		}
    226 	}
    227 	printf_tab("SELinux status:");
    228 	rc = is_selinux_enabled();
    229 
    230 	switch (rc) {
    231 	case 1:
    232 		printf("enabled\n");
    233 		break;
    234 	case 0:
    235 		printf("disabled\n");
    236 		return 0;
    237 		break;
    238 	default:
    239 		printf("unknown (%s)\n", strerror(errno));
    240 		return 0;
    241 		break;
    242 	}
    243 
    244 	printf_tab("SELinuxfs mount:");
    245 	if (selinux_mnt != NULL) {
    246 		printf("%s\n", selinux_mnt);
    247 	} else {
    248 		printf("not mounted\n\n");
    249 		printf("Please mount selinuxfs for proper results.\n");
    250 		return -1;
    251 	}
    252 
    253 	printf_tab("SELinux root directory:");
    254 	root_dir = selinux_path();
    255 	if (root_dir == NULL) {
    256 		printf("error (%s)\n", strerror(errno));
    257 		return -1;
    258 	}
    259 	/* The path has a trailing '/' so duplicate to edit */
    260 	root_path = strdup(root_dir);
    261 	if (!root_path) {
    262 		printf("malloc error (%s)\n", strerror(errno));
    263 		return -1;
    264 	}
    265 	/* actually blank the '/' */
    266 	root_path[strlen(root_path) - 1] = '\0';
    267 	printf("%s\n", root_path);
    268 	free(root_path);
    269 
    270 	/* Dump all the path information */
    271 	printf_tab("Loaded policy name:");
    272 	pol_path = strdup(selinux_policy_root());
    273 	if (pol_path) {
    274 		pol_name = basename(pol_path);
    275 		puts(pol_name);
    276 		free(pol_path);
    277 	} else {
    278 		printf("error (%s)\n", strerror(errno));
    279 	}
    280 
    281 	printf_tab("Current mode:");
    282 	rc = security_getenforce();
    283 	switch (rc) {
    284 	case 1:
    285 		printf("enforcing\n");
    286 		break;
    287 	case 0:
    288 		printf("permissive\n");
    289 		break;
    290 	default:
    291 		printf("unknown (%s)\n", strerror(errno));
    292 		break;
    293 	}
    294 
    295 	printf_tab("Mode from config file:");
    296 	if (selinux_getenforcemode(&rc) == 0) {
    297 		switch (rc) {
    298 		case 1:
    299 			printf("enforcing\n");
    300 			break;
    301 		case 0:
    302 			printf("permissive\n");
    303 			break;
    304 		case -1:
    305 			printf("disabled\n");
    306 			break;
    307 		}
    308 	} else {
    309 		printf("error (%s)\n", strerror(errno));
    310 	}
    311 
    312 	printf_tab("Policy MLS status:");
    313 	rc = is_selinux_mls_enabled();
    314 	switch (rc) {
    315 		case 0:
    316 			printf("disabled\n");
    317 			break;
    318 		case 1:
    319 			printf("enabled\n");
    320 			break;
    321 		default:
    322 			printf("error (%s)\n", strerror(errno));
    323 			break;
    324 	}
    325 
    326 	printf_tab("Policy deny_unknown status:");
    327 	rc = security_deny_unknown();
    328 	switch (rc) {
    329 		case 0:
    330 			printf("allowed\n");
    331 			break;
    332 		case 1:
    333 			printf("denied\n");
    334 			break;
    335 		default:
    336 			printf("error (%s)\n", strerror(errno));
    337 			break;
    338 	}
    339 
    340 	printf_tab("Memory protection checking:");
    341 	rc = security_get_checkreqprot();
    342 	switch (rc) {
    343 		case 0:
    344 			printf("actual (secure)\n");
    345 			break;
    346 		case 1:
    347 			printf("requested (insecure)\n");
    348 			break;
    349 		default:
    350 			printf("error (%s)\n", strerror(errno));
    351 			break;
    352 	}
    353 
    354 	rc = security_policyvers();
    355 	printf_tab("Max kernel policy version:");
    356 	if (rc < 0)
    357 		printf("unknown (%s)\n", strerror(errno));
    358 	else
    359 		printf("%d\n", rc);
    360 
    361 
    362 	if (show_bools) {
    363 		/* show booleans */
    364 		if (security_get_boolean_names(&bools, &nbool) >= 0) {
    365 			printf("\nPolicy booleans:\n");
    366 
    367 			for (i = 0; i < nbool; i++) {
    368 				if (strlen(bools[i]) + 1 > COL)
    369 					COL = strlen(bools[i]) + 1;
    370 			}
    371 			for (i = 0; i < nbool; i++) {
    372 				printf_tab(bools[i]);
    373 
    374 				rc = security_get_boolean_active(bools[i]);
    375 				switch (rc) {
    376 				case 1:
    377 					printf("on");
    378 					break;
    379 				case 0:
    380 					printf("off");
    381 					break;
    382 				default:
    383 					printf("unknown (%s)", strerror(errno));
    384 					break;
    385 				}
    386 				c = security_get_boolean_pending(bools[i]);
    387 				if (c != rc)
    388 					switch (c) {
    389 					case 1:
    390 						printf(" (activate pending)");
    391 						break;
    392 					case 0:
    393 						printf(" (inactivate pending)");
    394 						break;
    395 					default:
    396 						printf(" (pending error: %s)",
    397 						       strerror(errno));
    398 						break;
    399 					}
    400 				printf("\n");
    401 
    402 				/* free up the booleans */
    403 				free(bools[i]);
    404 			}
    405 			free(bools);
    406 		}
    407 	}
    408 	/* only show contexts if -v is given */
    409 	if (!verbose)
    410 		return 0;
    411 
    412 	load_checks(pc, &npc, fc, &nfc);
    413 
    414 	printf("\nProcess contexts:\n");
    415 
    416 	printf_tab("Current context:");
    417 	if (getcon(&context) >= 0) {
    418 		printf("%s\n", context);
    419 		freecon(context);
    420 	} else
    421 		printf("unknown (%s)\n", strerror(errno));
    422 
    423 	printf_tab("Init context:");
    424 	if (getpidcon(1, &context) >= 0) {
    425 		printf("%s\n", context);
    426 		freecon(context);
    427 	} else
    428 		printf("unknown (%s)\n", strerror(errno));
    429 
    430 	for (i = 0; i < npc; i++) {
    431 		rc = pidof(pc[i]);
    432 		if (rc > 0) {
    433 			if (getpidcon(rc, &context) < 0)
    434 				continue;
    435 
    436 			printf_tab(pc[i]);
    437 			printf("%s\n", context);
    438 			freecon(context);
    439 		}
    440 		free(pc[i]);
    441 	}
    442 
    443 	printf("\nFile contexts:\n");
    444 
    445 	/* controlling term */
    446 	printf_tab("Controlling terminal:");
    447 	if (lgetfilecon(cterm, &context) >= 0) {
    448 		printf("%s\n", context);
    449 		freecon(context);
    450 	} else {
    451 		printf("unknown (%s)\n", strerror(errno));
    452 	}
    453 
    454 	for (i = 0; i < nfc; i++) {
    455 		if (lgetfilecon(fc[i], &context) >= 0) {
    456 			printf_tab(fc[i]);
    457 
    458 			/* check if this is a symlink */
    459 			if (lstat(fc[i], &m)) {
    460 				printf
    461 				    ("%s (could not check link status (%s)!)\n",
    462 				     context, strerror(errno));
    463 				freecon(context);
    464 				continue;
    465 			}
    466 			if (S_ISLNK(m.st_mode)) {
    467 				/* print link target context */
    468 				printf("%s -> ", context);
    469 				freecon(context);
    470 
    471 				if (getfilecon(fc[i], &context) >= 0) {
    472 					printf("%s\n", context);
    473 					freecon(context);
    474 				} else {
    475 					printf("unknown (%s)\n",
    476 					       strerror(errno));
    477 				}
    478 			} else {
    479 				printf("%s\n", context);
    480 				freecon(context);
    481 			}
    482 		}
    483 		free(fc[i]);
    484 	}
    485 
    486 	return 0;
    487 }
    488