• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
cmp_cmdline(const char * command,int pid)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 
pidof(const char * command)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 
load_checks(char * pc[],int * npc,char * fc[],int * nfc)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 
printf_tab(const char * outp)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 
main(int argc,char ** argv)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