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 static 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 static 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 static 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 if (!pc[*npc])
144 break;
145 memcpy(pc[*npc], bufp, buf_len);
146 (*npc)++;
147 bufp = NULL;
148 break;
149 case 1:
150 if (*nfc >= MAX_CHECK)
151 break;
152 fc[*nfc] =
153 (char *)malloc((buf_len) *
154 sizeof(char));
155 if (!fc[*nfc])
156 break;
157 memcpy(fc[*nfc], bufp, buf_len);
158 (*nfc)++;
159 bufp = NULL;
160 break;
161 default:
162 /* ignore lines before a section */
163 printf("Line not in a section: %s.\n",
164 buf);
165 break;
166 }
167 }
168 }
169 }
170 out:
171 fclose(fp);
172 return;
173 }
174
printf_tab(const char * outp)175 static void printf_tab(const char *outp)
176 {
177 printf("%-*s", COL, outp);
178
179 }
180
main(int argc,char ** argv)181 int main(int argc, char **argv)
182 {
183 /* these vars are reused several times */
184 int rc, opt, i, c;
185 char *context, *root_path;
186
187 /* files that need context checks */
188 char *fc[MAX_CHECK];
189 char *cterm = ttyname(0);
190 int nfc = 0;
191 struct stat m;
192
193 /* processes that need context checks */
194 char *pc[MAX_CHECK];
195 int npc = 0;
196
197 /* booleans */
198 char **bools;
199 int nbool;
200
201 int verbose = 0;
202 int show_bools = 0;
203
204 /* policy */
205 const char *pol_name, *root_dir;
206 char *pol_path;
207
208
209 while (1) {
210 opt = getopt(argc, argv, "vb");
211 if (opt == -1)
212 break;
213 switch (opt) {
214 case 'v':
215 verbose = 1;
216 break;
217 case 'b':
218 show_bools = 1;
219 break;
220 default:
221 /* invalid option */
222 printf("\nUsage: %s [OPTION]\n\n", basename(argv[0]));
223 printf(" -v Verbose check of process and file contexts.\n");
224 printf(" -b Display current state of booleans.\n");
225 printf("\nWithout options, show SELinux status.\n");
226 return -1;
227 }
228 }
229 printf_tab("SELinux status:");
230 rc = is_selinux_enabled();
231
232 switch (rc) {
233 case 1:
234 printf("enabled\n");
235 break;
236 case 0:
237 printf("disabled\n");
238 return 0;
239 break;
240 default:
241 printf("unknown (%s)\n", strerror(errno));
242 return 0;
243 break;
244 }
245
246 printf_tab("SELinuxfs mount:");
247 if (selinux_mnt != NULL) {
248 printf("%s\n", selinux_mnt);
249 } else {
250 printf("not mounted\n\n");
251 printf("Please mount selinuxfs for proper results.\n");
252 return -1;
253 }
254
255 printf_tab("SELinux root directory:");
256 root_dir = selinux_path();
257 if (root_dir == NULL) {
258 printf("error (%s)\n", strerror(errno));
259 return -1;
260 }
261 /* The path has a trailing '/' so duplicate to edit */
262 root_path = strdup(root_dir);
263 if (!root_path) {
264 printf("malloc error (%s)\n", strerror(errno));
265 return -1;
266 }
267 /* actually blank the '/' */
268 root_path[strlen(root_path) - 1] = '\0';
269 printf("%s\n", root_path);
270 free(root_path);
271
272 /* Dump all the path information */
273 printf_tab("Loaded policy name:");
274 pol_path = strdup(selinux_policy_root());
275 if (pol_path) {
276 pol_name = basename(pol_path);
277 puts(pol_name);
278 free(pol_path);
279 } else {
280 printf("error (%s)\n", strerror(errno));
281 }
282
283 printf_tab("Current mode:");
284 rc = security_getenforce();
285 switch (rc) {
286 case 1:
287 printf("enforcing\n");
288 break;
289 case 0:
290 printf("permissive\n");
291 break;
292 default:
293 printf("unknown (%s)\n", strerror(errno));
294 break;
295 }
296
297 printf_tab("Mode from config file:");
298 if (selinux_getenforcemode(&rc) == 0) {
299 switch (rc) {
300 case 1:
301 printf("enforcing\n");
302 break;
303 case 0:
304 printf("permissive\n");
305 break;
306 case -1:
307 printf("disabled\n");
308 break;
309 }
310 } else {
311 printf("error (%s)\n", strerror(errno));
312 }
313
314 printf_tab("Policy MLS status:");
315 rc = is_selinux_mls_enabled();
316 switch (rc) {
317 case 0:
318 printf("disabled\n");
319 break;
320 case 1:
321 printf("enabled\n");
322 break;
323 default:
324 printf("error (%s)\n", strerror(errno));
325 break;
326 }
327
328 printf_tab("Policy deny_unknown status:");
329 rc = security_deny_unknown();
330 switch (rc) {
331 case 0:
332 printf("allowed\n");
333 break;
334 case 1:
335 printf("denied\n");
336 break;
337 default:
338 printf("error (%s)\n", strerror(errno));
339 break;
340 }
341
342 printf_tab("Memory protection checking:");
343 rc = security_get_checkreqprot();
344 switch (rc) {
345 case 0:
346 printf("actual (secure)\n");
347 break;
348 case 1:
349 printf("requested (insecure)\n");
350 break;
351 default:
352 printf("error (%s)\n", strerror(errno));
353 break;
354 }
355
356 rc = security_policyvers();
357 printf_tab("Max kernel policy version:");
358 if (rc < 0)
359 printf("unknown (%s)\n", strerror(errno));
360 else
361 printf("%d\n", rc);
362
363
364 if (show_bools) {
365 /* show booleans */
366 if (security_get_boolean_names(&bools, &nbool) >= 0) {
367 printf("\nPolicy booleans:\n");
368
369 for (i = 0; i < nbool; i++) {
370 if (strlen(bools[i]) + 1 > COL)
371 COL = strlen(bools[i]) + 1;
372 }
373 for (i = 0; i < nbool; i++) {
374 printf_tab(bools[i]);
375
376 rc = security_get_boolean_active(bools[i]);
377 switch (rc) {
378 case 1:
379 printf("on");
380 break;
381 case 0:
382 printf("off");
383 break;
384 default:
385 printf("unknown (%s)", strerror(errno));
386 break;
387 }
388 c = security_get_boolean_pending(bools[i]);
389 if (c != rc)
390 switch (c) {
391 case 1:
392 printf(" (activate pending)");
393 break;
394 case 0:
395 printf(" (inactivate pending)");
396 break;
397 default:
398 printf(" (pending error: %s)",
399 strerror(errno));
400 break;
401 }
402 printf("\n");
403
404 /* free up the booleans */
405 free(bools[i]);
406 }
407 free(bools);
408 }
409 }
410 /* only show contexts if -v is given */
411 if (!verbose)
412 return 0;
413
414 load_checks(pc, &npc, fc, &nfc);
415
416 printf("\nProcess contexts:\n");
417
418 printf_tab("Current context:");
419 if (getcon(&context) >= 0) {
420 printf("%s\n", context);
421 freecon(context);
422 } else
423 printf("unknown (%s)\n", strerror(errno));
424
425 printf_tab("Init context:");
426 if (getpidcon(1, &context) >= 0) {
427 printf("%s\n", context);
428 freecon(context);
429 } else
430 printf("unknown (%s)\n", strerror(errno));
431
432 for (i = 0; i < npc; i++) {
433 rc = pidof(pc[i]);
434 if (rc > 0) {
435 if (getpidcon(rc, &context) < 0)
436 continue;
437
438 printf_tab(pc[i]);
439 printf("%s\n", context);
440 freecon(context);
441 }
442 free(pc[i]);
443 }
444
445 printf("\nFile contexts:\n");
446
447 /* controlling term */
448 printf_tab("Controlling terminal:");
449 if (lgetfilecon(cterm, &context) >= 0) {
450 printf("%s\n", context);
451 freecon(context);
452 } else {
453 printf("unknown (%s)\n", strerror(errno));
454 }
455
456 for (i = 0; i < nfc; i++) {
457 if (lgetfilecon(fc[i], &context) >= 0) {
458 printf_tab(fc[i]);
459
460 /* check if this is a symlink */
461 if (lstat(fc[i], &m)) {
462 printf
463 ("%s (could not check link status (%s)!)\n",
464 context, strerror(errno));
465 freecon(context);
466 free(fc[i]);
467 continue;
468 }
469 if (S_ISLNK(m.st_mode)) {
470 /* print link target context */
471 printf("%s -> ", context);
472 freecon(context);
473
474 if (getfilecon(fc[i], &context) >= 0) {
475 printf("%s\n", context);
476 freecon(context);
477 } else {
478 printf("unknown (%s)\n",
479 strerror(errno));
480 }
481 } else {
482 printf("%s\n", context);
483 freecon(context);
484 }
485 }
486 free(fc[i]);
487 }
488
489 return 0;
490 }
491