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 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 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 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 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 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