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
cmp_cmdline(const char * command,int pid)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
pidof(const char * command)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
load_checks(char * pc[],int * npc,char * fc[],int * nfc)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
printf_tab(const char * outp)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
main(int argc,char ** argv)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 rc = security_policyvers();
334 printf_tab("Max kernel policy version:");
335 if (rc < 0)
336 printf("unknown (%s)\n", strerror(errno));
337 else
338 printf("%d\n", rc);
339
340
341 if (show_bools) {
342 /* show booleans */
343 if (security_get_boolean_names(&bools, &nbool) >= 0) {
344 printf("\nPolicy booleans:\n");
345
346 for (i = 0; i < nbool; i++) {
347 if (strlen(bools[i]) + 1 > COL)
348 COL = strlen(bools[i]) + 1;
349 }
350 for (i = 0; i < nbool; i++) {
351 printf_tab(bools[i]);
352
353 rc = security_get_boolean_active(bools[i]);
354 switch (rc) {
355 case 1:
356 printf("on");
357 break;
358 case 0:
359 printf("off");
360 break;
361 default:
362 printf("unknown (%s)", strerror(errno));
363 break;
364 }
365 c = security_get_boolean_pending(bools[i]);
366 if (c != rc)
367 switch (c) {
368 case 1:
369 printf(" (activate pending)");
370 break;
371 case 0:
372 printf(" (inactivate pending)");
373 break;
374 default:
375 printf(" (pending error: %s)",
376 strerror(errno));
377 break;
378 }
379 printf("\n");
380
381 /* free up the booleans */
382 free(bools[i]);
383 }
384 free(bools);
385 }
386 }
387 /* only show contexts if -v is given */
388 if (!verbose)
389 return 0;
390
391 load_checks(pc, &npc, fc, &nfc);
392
393 printf("\nProcess contexts:\n");
394
395 printf_tab("Current context:");
396 if (getcon(&context) >= 0) {
397 printf("%s\n", context);
398 freecon(context);
399 } else
400 printf("unknown (%s)\n", strerror(errno));
401
402 printf_tab("Init context:");
403 if (getpidcon(1, &context) >= 0) {
404 printf("%s\n", context);
405 freecon(context);
406 } else
407 printf("unknown (%s)\n", strerror(errno));
408
409 for (i = 0; i < npc; i++) {
410 rc = pidof(pc[i]);
411 if (rc > 0) {
412 if (getpidcon(rc, &context) < 0)
413 continue;
414
415 printf_tab(pc[i]);
416 printf("%s\n", context);
417 freecon(context);
418 }
419 }
420
421 printf("\nFile contexts:\n");
422
423 /* controlling term */
424 printf_tab("Controlling terminal:");
425 if (lgetfilecon(cterm, &context) >= 0) {
426 printf("%s\n", context);
427 freecon(context);
428 } else {
429 printf("unknown (%s)\n", strerror(errno));
430 }
431
432 for (i = 0; i < nfc; i++) {
433 if (lgetfilecon(fc[i], &context) >= 0) {
434 printf_tab(fc[i]);
435
436 /* check if this is a symlink */
437 if (lstat(fc[i], &m)) {
438 printf
439 ("%s (could not check link status (%s)!)\n",
440 context, strerror(errno));
441 freecon(context);
442 continue;
443 }
444 if (S_ISLNK(m.st_mode)) {
445 /* print link target context */
446 printf("%s -> ", context);
447 freecon(context);
448
449 if (getfilecon(fc[i], &context) >= 0) {
450 printf("%s\n", context);
451 freecon(context);
452 } else {
453 printf("unknown (%s)\n",
454 strerror(errno));
455 }
456 } else {
457 printf("%s\n", context);
458 freecon(context);
459 }
460 }
461 }
462
463 return 0;
464 }
465