1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * Program to examine or set process privileges. 27 */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <fcntl.h> 35 #include <string.h> 36 #include <limits.h> 37 #include <sys/types.h> 38 #include <libproc.h> 39 #include <priv.h> 40 #include <errno.h> 41 #include <ctype.h> 42 43 #include <locale.h> 44 #include <langinfo.h> 45 46 static int look(char *); 47 static void perr(char *); 48 static void usage(void); 49 static void loadprivinfo(void); 50 static int parsespec(const char *); 51 static void privupdate(prpriv_t *, const char *); 52 static void privupdate_self(void); 53 static int dumppriv(char **); 54 static void flags2str(uint_t); 55 56 static char *command; 57 static char *procname; 58 static boolean_t verb = B_FALSE; 59 static boolean_t set = B_FALSE; 60 static boolean_t exec = B_FALSE; 61 static boolean_t Don = B_FALSE; 62 static boolean_t Doff = B_FALSE; 63 static boolean_t list = B_FALSE; 64 static int mode = PRIV_STR_PORT; 65 66 int 67 main(int argc, char **argv) 68 { 69 int rc = 0; 70 int opt; 71 struct rlimit rlim; 72 73 (void) setlocale(LC_ALL, ""); 74 (void) textdomain(TEXT_DOMAIN); 75 76 if ((command = strrchr(argv[0], '/')) != NULL) 77 command++; 78 else 79 command = argv[0]; 80 81 while ((opt = getopt(argc, argv, "lDNevs:S")) != EOF) { 82 switch (opt) { 83 case 'l': 84 list = B_TRUE; 85 break; 86 case 'D': 87 set = B_TRUE; 88 Don = B_TRUE; 89 break; 90 case 'N': 91 set = B_TRUE; 92 Doff = B_TRUE; 93 break; 94 case 'e': 95 exec = B_TRUE; 96 break; 97 case 'S': 98 mode = PRIV_STR_SHORT; 99 break; 100 case 'v': 101 verb = B_TRUE; 102 mode = PRIV_STR_LIT; 103 break; 104 case 's': 105 set = B_TRUE; 106 if ((rc = parsespec(optarg)) != 0) 107 return (rc); 108 break; 109 default: 110 usage(); 111 /*NOTREACHED*/ 112 } 113 } 114 115 argc -= optind; 116 argv += optind; 117 118 if ((argc < 1 && !list) || Doff && Don || list && (set || exec)) 119 usage(); 120 121 /* 122 * Make sure we'll have enough file descriptors to handle a target 123 * that has many many mappings. 124 */ 125 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 126 rlim.rlim_cur = rlim.rlim_max; 127 (void) setrlimit(RLIMIT_NOFILE, &rlim); 128 } 129 130 if (exec) { 131 privupdate_self(); 132 rc = execvp(argv[0], &argv[0]); 133 (void) fprintf(stderr, "%s: %s: %s\n", command, argv[0], 134 strerror(errno)); 135 } else if (list) { 136 rc = dumppriv(argv); 137 } else { 138 while (argc-- > 0) 139 rc += look(*argv++); 140 } 141 142 return (rc); 143 } 144 145 static int 146 look(char *arg) 147 { 148 static size_t pprivsz = sizeof (prpriv_t); 149 static prpriv_t *ppriv; 150 151 struct ps_prochandle *Pr; 152 int gcode; 153 size_t sz; 154 void *pdata; 155 char *x; 156 int i; 157 boolean_t nodata; 158 159 procname = arg; /* for perr() */ 160 161 if ((Pr = proc_arg_grab(arg, set ? PR_ARG_PIDS : PR_ARG_ANY, 162 PGRAB_RETAIN | PGRAB_FORCE | (set ? 0 : PGRAB_RDONLY) | 163 PGRAB_NOSTOP, &gcode)) == NULL) { 164 (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 165 command, arg, Pgrab_error(gcode)); 166 return (1); 167 } 168 169 if (ppriv == NULL) 170 ppriv = malloc(pprivsz); 171 172 if (Ppriv(Pr, ppriv, pprivsz) == -1) { 173 perr(command); 174 Prelease(Pr, 0); 175 return (1); 176 } 177 178 sz = PRIV_PRPRIV_SIZE(ppriv); 179 180 /* 181 * The ppriv fields are unsigned and may overflow, so check them 182 * separately. Size must be word aligned, so check that too. 183 * Make sure size is "smallish" too. 184 */ 185 if ((sz & 3) || ppriv->pr_nsets == 0 || 186 sz / ppriv->pr_nsets < ppriv->pr_setsize || 187 ppriv->pr_infosize > sz || sz > 1024 * 1024) { 188 (void) fprintf(stderr, 189 "%s: %s: bad PRNOTES section, size = %lx\n", 190 command, arg, (long)sz); 191 Prelease(Pr, 0); 192 return (1); 193 } 194 195 if (sz > pprivsz) { 196 ppriv = realloc(ppriv, sz); 197 198 if (ppriv == NULL || Ppriv(Pr, ppriv, sz) != sz) { 199 perr(command); 200 Prelease(Pr, 0); 201 return (1); 202 } 203 pprivsz = sz; 204 } 205 206 if (set) { 207 privupdate(ppriv, arg); 208 if (Psetpriv(Pr, ppriv) != 0) { 209 perr(command); 210 Prelease(Pr, 0); 211 return (1); 212 } 213 Prelease(Pr, 0); 214 return (0); 215 } 216 217 if (Pstate(Pr) == PS_DEAD) { 218 (void) printf("core '%s' of %d:\t%.70s\n", 219 arg, (int)Ppsinfo(Pr)->pr_pid, Ppsinfo(Pr)->pr_psargs); 220 pdata = Pprivinfo(Pr); 221 nodata = Pstate(Pr) == PS_DEAD && pdata == NULL; 222 } else { 223 (void) printf("%d:\t%.70s\n", 224 (int)Ppsinfo(Pr)->pr_pid, Ppsinfo(Pr)->pr_psargs); 225 pdata = NULL; 226 nodata = B_FALSE; 227 } 228 229 x = (char *)ppriv + sz - ppriv->pr_infosize; 230 while (x < (char *)ppriv + sz) { 231 /* LINTED: alignment */ 232 priv_info_t *pi = (priv_info_t *)x; 233 priv_info_uint_t *pii; 234 235 switch (pi->priv_info_type) { 236 case PRIV_INFO_FLAGS: 237 /* LINTED: alignment */ 238 pii = (priv_info_uint_t *)x; 239 (void) printf("flags ="); 240 flags2str(pii->val); 241 (void) putchar('\n'); 242 break; 243 default: 244 (void) fprintf(stderr, "%s: unknown priv_info: %d\n", 245 arg, pi->priv_info_type); 246 break; 247 } 248 if (pi->priv_info_size > ppriv->pr_infosize || 249 pi->priv_info_size <= sizeof (priv_info_t) || 250 (pi->priv_info_size & 3) != 0) { 251 (void) fprintf(stderr, "%s: bad priv_info_size: %u\n", 252 arg, pi->priv_info_size); 253 break; 254 } 255 x += pi->priv_info_size; 256 } 257 258 for (i = 0; i < ppriv->pr_nsets; i++) { 259 extern const char *__priv_getsetbynum(const void *, int); 260 const char *setnm = pdata ? __priv_getsetbynum(pdata, i) 261 : priv_getsetbynum(i); 262 priv_chunk_t *pc = (priv_chunk_t *) 263 &ppriv->pr_sets[ppriv->pr_setsize * i]; 264 265 266 (void) printf("\t%c: ", setnm && !nodata ? *setnm : '?'); 267 if (!nodata) { 268 extern char *__priv_set_to_str(void *, 269 const priv_set_t *, char, int); 270 priv_set_t *pset = (priv_set_t *)pc; 271 272 char *s; 273 274 if (pdata) 275 s = __priv_set_to_str(pdata, pset, ',', mode); 276 else 277 s = priv_set_to_str(pset, ',', mode); 278 (void) puts(s); 279 free(s); 280 } else { 281 int j; 282 for (j = 0; j < ppriv->pr_setsize; j++) 283 (void) printf("%08x", pc[j]); 284 (void) putchar('\n'); 285 } 286 } 287 Prelease(Pr, 0); 288 return (0); 289 } 290 291 static void 292 fatal(const char *s) 293 { 294 (void) fprintf(stderr, "%s: %s: %s\n", command, s, strerror(errno)); 295 exit(3); 296 } 297 298 static void 299 perr(char *s) 300 { 301 int err = errno; 302 303 if (s != NULL) 304 (void) fprintf(stderr, "%s: ", procname); 305 else 306 s = procname; 307 308 errno = err; 309 perror(s); 310 } 311 312 static void 313 usage(void) 314 { 315 (void) fprintf(stderr, 316 "usage:\t%s [-v] [-S] [-D|-N] [-s spec] { pid | core } ...\n" 317 "\t%s -e [-D|-N] [-s spec] cmd [args ...]\n" 318 "\t%s -l [-v] [privilege ...]\n" 319 " (report, set or list process privileges)\n", command, 320 command, command); 321 exit(2); 322 /*NOTREACHED*/ 323 } 324 325 /* 326 * Parse the privilege bits to add and/or remove from 327 * a privilege set. 328 * 329 * [EPIL][+-=]priv,priv,priv 330 */ 331 332 static int 333 strindex(char c, const char *str) 334 { 335 const char *s; 336 337 if (islower(c)) 338 c = toupper(c); 339 340 s = strchr(str, c); 341 342 if (s == NULL) 343 return (-1); 344 else 345 return (s - str); 346 } 347 348 static void 349 badspec(const char *spec) 350 { 351 (void) fprintf(stderr, "%s: bad privilege specification: \"%s\"\n", 352 command, spec); 353 exit(3); 354 /*NOTREACHED*/ 355 } 356 357 /* 358 * For each set, you can set either add and/or 359 * remove or you can set assign. 360 */ 361 static priv_set_t **rem, **add, **assign; 362 static const priv_impl_info_t *pri = NULL; 363 static char *sets; 364 365 static void 366 loadprivinfo(void) 367 { 368 int i; 369 370 if (pri != NULL) 371 return; 372 373 pri = getprivimplinfo(); 374 375 if (pri == NULL) 376 fatal("getprivimplinfo"); 377 378 sets = malloc(pri->priv_nsets + 1); 379 if (sets == NULL) 380 fatal("malloc"); 381 382 for (i = 0; i < pri->priv_nsets; i++) { 383 sets[i] = *priv_getsetbynum(i); 384 if (islower(sets[i])) 385 sets[i] = toupper(sets[i]); 386 } 387 388 sets[pri->priv_nsets] = '\0'; 389 390 rem = calloc(pri->priv_nsets, sizeof (priv_set_t *)); 391 add = calloc(pri->priv_nsets, sizeof (priv_set_t *)); 392 assign = calloc(pri->priv_nsets, sizeof (priv_set_t *)); 393 if (rem == NULL || add == NULL || assign == NULL) 394 fatal("calloc"); 395 } 396 397 static int 398 parsespec(const char *spec) 399 { 400 char *p; 401 const char *q; 402 int count; 403 priv_set_t ***toupd; 404 priv_set_t *upd; 405 int i; 406 boolean_t freeupd = B_TRUE; 407 408 if (pri == NULL) 409 loadprivinfo(); 410 411 p = strpbrk(spec, "+-="); 412 413 if (p == NULL || p - spec > pri->priv_nsets) 414 badspec(spec); 415 416 if (p[1] == '\0' || (upd = priv_str_to_set(p + 1, ",", NULL)) == NULL) 417 badspec(p + 1); 418 419 count = p - spec; 420 switch (*p) { 421 case '+': 422 toupd = &add; 423 break; 424 case '-': 425 toupd = &rem; 426 priv_inverse(upd); 427 break; 428 case '=': 429 toupd = &assign; 430 break; 431 } 432 433 /* Update all sets? */ 434 if (count == 0 || *spec == 'a' || *spec == 'A') { 435 count = pri->priv_nsets; 436 q = sets; 437 } else 438 q = spec; 439 440 for (i = 0; i < count; i++) { 441 int ind = strindex(q[i], sets); 442 443 if (ind == -1) 444 badspec(spec); 445 446 /* Assign is mutually exclusive with add/remove and itself */ 447 if (((toupd == &rem || toupd == &add) && assign[ind] != NULL) || 448 (toupd == &assign && (assign[ind] != NULL || 449 rem[ind] != NULL || add[ind] != NULL))) { 450 (void) fprintf(stderr, "%s: conflicting spec: %s\n", 451 command, spec); 452 exit(1); 453 } 454 if ((*toupd)[ind] != NULL) { 455 if (*p == '-') 456 priv_intersect(upd, (*toupd)[ind]); 457 else 458 priv_union(upd, (*toupd)[ind]); 459 } else { 460 (*toupd)[ind] = upd; 461 freeupd = B_FALSE; 462 } 463 } 464 if (freeupd) 465 priv_freeset(upd); 466 return (0); 467 } 468 469 static void 470 privupdate(prpriv_t *pr, const char *arg) 471 { 472 int i; 473 474 if (sets != NULL) { 475 for (i = 0; i < pri->priv_nsets; i++) { 476 priv_set_t *target = 477 (priv_set_t *)&pr->pr_sets[pr->pr_setsize * i]; 478 if (rem[i] != NULL) 479 priv_intersect(rem[i], target); 480 if (add[i] != NULL) 481 priv_union(add[i], target); 482 if (assign[i] != NULL) 483 priv_copyset(assign[i], target); 484 } 485 } 486 487 if (Doff || Don) { 488 priv_info_uint_t *pii; 489 int sz = PRIV_PRPRIV_SIZE(pr); 490 char *x = (char *)pr + PRIV_PRPRIV_INFO_OFFSET(pr); 491 uint32_t fl = 0; 492 493 while (x < (char *)pr + sz) { 494 /* LINTED: alignment */ 495 priv_info_t *pi = (priv_info_t *)x; 496 497 if (pi->priv_info_type == PRIV_INFO_FLAGS) { 498 /* LINTED: alignment */ 499 pii = (priv_info_uint_t *)x; 500 fl = pii->val; 501 goto done; 502 } 503 if (pi->priv_info_size > pr->pr_infosize || 504 pi->priv_info_size <= sizeof (priv_info_t) || 505 (pi->priv_info_size & 3) != 0) 506 break; 507 x += pi->priv_info_size; 508 } 509 (void) fprintf(stderr, 510 "%s: cannot find privilege flags to set\n", arg); 511 pr->pr_infosize = 0; 512 return; 513 done: 514 515 pr->pr_infosize = sizeof (priv_info_uint_t); 516 /* LINTED: alignment */ 517 pii = (priv_info_uint_t *) 518 ((char *)pr + PRIV_PRPRIV_INFO_OFFSET(pr)); 519 520 if (Don) 521 fl |= PRIV_DEBUG; 522 else 523 fl &= ~PRIV_DEBUG; 524 525 pii->info.priv_info_size = sizeof (*pii); 526 pii->info.priv_info_type = PRIV_INFO_FLAGS; 527 pii->val = fl; 528 } else { 529 pr->pr_infosize = 0; 530 } 531 } 532 533 static void 534 privupdate_self(void) 535 { 536 int set; 537 538 if (sets != NULL) { 539 priv_set_t *target = priv_allocset(); 540 541 if (target == NULL) 542 fatal("priv_allocet"); 543 544 set = priv_getsetbyname(PRIV_INHERITABLE); 545 if (rem[set] != NULL || add[set] != NULL || 546 assign[set] != NULL) { 547 (void) getppriv(PRIV_INHERITABLE, target); 548 if (rem[set] != NULL) 549 priv_intersect(rem[set], target); 550 if (add[set] != NULL) 551 priv_union(add[set], target); 552 if (assign[set] != NULL) 553 priv_copyset(assign[set], target); 554 if (setppriv(PRIV_SET, PRIV_INHERITABLE, target) != 0) 555 fatal("setppriv(Inheritable)"); 556 } 557 set = priv_getsetbyname(PRIV_LIMIT); 558 if (rem[set] != NULL || add[set] != NULL || 559 assign[set] != NULL) { 560 (void) getppriv(PRIV_LIMIT, target); 561 if (rem[set] != NULL) 562 priv_intersect(rem[set], target); 563 if (add[set] != NULL) 564 priv_union(add[set], target); 565 if (assign[set] != NULL) 566 priv_copyset(assign[set], target); 567 if (setppriv(PRIV_SET, PRIV_LIMIT, target) != 0) 568 fatal("setppriv(Limit)"); 569 } 570 priv_freeset(target); 571 } 572 573 if (Doff || Don) 574 (void) setpflags(PRIV_DEBUG, Don ? 1 : 0); 575 } 576 577 static int 578 dopriv(const char *p) 579 { 580 (void) puts(p); 581 if (verb) { 582 char *text = priv_gettext(p); 583 char *p, *q; 584 if (text == NULL) 585 return (1); 586 for (p = text; q = strchr(p, '\n'); p = q + 1) 587 (void) printf("\t%.*s", (int)(q - p + 1), p); 588 free(text); 589 } 590 return (0); 591 } 592 593 static int 594 dumppriv(char **argv) 595 { 596 int rc = 0; 597 const char *pname; 598 int i; 599 600 if (argv[0] == NULL) { 601 for (i = 0; ((pname = priv_getbynum(i++)) != NULL); ) 602 rc += dopriv(pname); 603 } else { 604 for (; *argv; argv++) { 605 priv_set_t *pset = priv_str_to_set(*argv, ",", NULL); 606 607 if (pset == NULL) { 608 (void) fprintf(stderr, "%s: %s: bad privilege" 609 " list\n", command, *argv); 610 rc++; 611 continue; 612 } 613 for (i = 0; ((pname = priv_getbynum(i++)) != NULL); ) 614 if (priv_ismember(pset, pname)) 615 rc += dopriv(pname); 616 } 617 } 618 return (rc); 619 } 620 621 static struct { 622 int flag; 623 char *name; 624 } flags[] = { 625 { PRIV_DEBUG, "PRIV_DEBUG" }, 626 { PRIV_AWARE, "PRIV_AWARE" }, 627 { PRIV_AWARE_INHERIT, "PRIV_AWARE_INHERIT" }, 628 }; 629 630 /* 631 * Print flags preceeded by a space. 632 */ 633 static void 634 flags2str(uint_t pflags) 635 { 636 char c = ' '; 637 int i; 638 639 if (pflags == 0) { 640 (void) fputs(" <none>", stdout); 641 return; 642 } 643 for (i = 0; i < sizeof (flags)/sizeof (flags[0]) && pflags != 0; i++) { 644 if ((pflags & flags[i].flag) != 0) { 645 (void) printf("%c%s", c, flags[i].name); 646 pflags &= ~flags[i].flag; 647 c = '|'; 648 } 649 } 650 if (pflags != 0) 651 (void) printf("%c<0x%x>", c, pflags); 652 } 653