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