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