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