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 1999-2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <auth_attr.h> 30 #include <auth_list.h> 31 #include <dirent.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <libintl.h> 35 #include <locale.h> 36 #include <pwd.h> 37 #include <signal.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 43 #include <bsm/devices.h> 44 #include <bsm/audit_uevents.h> 45 46 #include <sys/acl.h> 47 #include <sys/file.h> 48 #include <sys/procfs.h> 49 #include <sys/param.h> 50 #include <sys/resource.h> 51 #include <sys/stat.h> 52 #include <sys/time.h> 53 #include <sys/types.h> 54 #include <sys/wait.h> 55 56 #include "allocate.h" 57 58 #ifdef DEBUG 59 #define dprintf(s, a) (void) fprintf(stderr, s, a) 60 #define dperror(s) perror(s) 61 #else /* !DEBUG */ 62 #define dprintf(s, a) 63 #define dperror(s) 64 #endif /* DEBUG */ 65 66 #define EXIT(number) { \ 67 if (optflg & FORCE) \ 68 error = number; \ 69 else \ 70 return (number); \ 71 } 72 73 #define DEV_ALLOCATED(sbuf) ((sbuf).st_uid != ALLOC_UID || \ 74 ((sbuf).st_mode & ~S_IFMT) == ALLOC_MODE) 75 76 #define DEVICE_AUTH_SEPARATOR "," 77 #define PROCFS "/proc/" 78 79 extern void audit_allocate_list(char *); 80 extern void audit_allocate_device(char *); 81 82 extern char *newenv[]; 83 84 /* 85 * Checks if the specified user has any of the authorizations in the 86 * list of authorizations 87 */ 88 89 static int 90 is_authorized(char *auth_list, uid_t uid) 91 { 92 char *auth; 93 struct passwd *pw; 94 95 pw = getpwuid(uid); 96 if (pw == NULL) { 97 dprintf("Can't get user info for uid=%d\n", (int)uid); 98 return (0); 99 } 100 101 auth = strtok(auth_list, DEVICE_AUTH_SEPARATOR); 102 while (auth != NULL) { 103 if (chkauthattr(auth, pw->pw_name)) 104 return (1); 105 auth = strtok(NULL, DEVICE_AUTH_SEPARATOR); 106 } 107 return (0); 108 } 109 110 static int 111 check_devs(char *list) 112 { 113 char *file; 114 115 file = strtok(list, " "); 116 while (file != NULL) { 117 118 if (access(file, F_OK) == -1) { 119 dprintf("Unable to access file %s\n", file); 120 return (-1); 121 } 122 file = strtok(NULL, " "); 123 } 124 return (0); 125 } 126 127 static void 128 print_dev(devmap_t *dev_list) 129 { 130 char *file; 131 132 (void) printf(gettext("device: %s "), dev_list->dmap_devname); 133 (void) printf(gettext("type: %s "), dev_list->dmap_devtype); 134 (void) printf(gettext("files: ")); 135 136 file = strtok(dev_list->dmap_devlist, " "); 137 while (file != NULL) { 138 (void) printf("%s ", file); 139 file = strtok(NULL, " "); 140 } 141 (void) printf("\n"); 142 } 143 144 static int 145 list_device(int optflg, uid_t uid, char *device) 146 { 147 devalloc_t *dev_ent; 148 devmap_t *dev_list; 149 char file_name[MAXPATHLEN]; 150 struct stat stat_buf; 151 char *list; 152 int bytes_formated; 153 154 if ((dev_ent = getdanam(device)) == NULL) { 155 if ((dev_list = getdmapdev(device)) == NULL) { 156 dprintf("Unable to find %s in the allocate database\n", 157 device); 158 return (NODMAPENT); 159 } else if ((dev_ent = getdanam(dev_list->dmap_devname)) == 160 NULL) { 161 dprintf("Unable to find %s in the allocate database\n", 162 device); 163 return (NODAENT); 164 } 165 } else if ((dev_list = getdmapnam(device)) == NULL) { 166 dprintf("Unable to find %s in the allocate database\n", device); 167 return (NODMAPENT); 168 } 169 170 bytes_formated = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, 171 dev_ent->da_devname); 172 if (bytes_formated <= 0) { 173 return (DEVNAME_ERR); 174 } else if (bytes_formated >= MAXPATHLEN) { 175 dprintf("device name %s is too long.\n", dev_ent->da_devname); 176 return (DEVNAME_TOOLONG); 177 } 178 179 if (stat(file_name, &stat_buf)) { 180 dprintf("Unable to stat %s\n", file_name); 181 dperror("Error:"); 182 return (DACACC); 183 } 184 185 if ((optflg & FREE) && DEV_ALLOCATED(stat_buf)) 186 return (ALLOC); 187 188 if ((optflg & LIST) && DEV_ALLOCATED(stat_buf) && 189 (stat_buf.st_uid != uid)) 190 return (ALLOC_OTHER); 191 192 if ((optflg & CURRENT) && (stat_buf.st_uid != uid)) 193 return (NALLOC); 194 195 if ((stat_buf.st_mode & ~S_IFMT) == ALLOC_ERR_MODE) 196 return (ALLOCERR); 197 198 if ((list = strdup(dev_list->dmap_devlist)) == NULL) 199 return (SYSERROR); 200 201 if (check_devs(list) == -1) { 202 free(list); 203 return (DSPMISS); 204 } 205 206 print_dev(dev_list); 207 208 free(list); 209 return (0); 210 } 211 212 int 213 list_devices(int optflg, uid_t uid, char *device) 214 { 215 DIR * dev_dir; 216 struct dirent *dac_file; 217 int error = 0, ret_code = 1; 218 219 if (optflg & USERID) { 220 if (!is_authorized(DEVICE_REVOKE_AUTH, getuid())) 221 return (NOTAUTH); 222 } 223 setdaent(); 224 225 if (device) { 226 return (list_device(optflg, uid, device)); 227 } 228 229 if ((dev_dir = opendir(DAC_DIR)) == NULL) { 230 231 dperror("Can't open DAC_DIR"); 232 return (DACACC); 233 } 234 235 while ((dac_file = readdir(dev_dir)) != NULL) { 236 if ((strcmp(dac_file->d_name, ".") == 0) || 237 (strcmp(dac_file->d_name, "..") == 0)) { 238 continue; 239 } else { 240 error = list_device(optflg, uid, dac_file->d_name); 241 ret_code = ret_code ? error : ret_code; 242 } 243 } 244 (void) closedir(dev_dir); 245 enddaent(); 246 return (ret_code); 247 } 248 249 /* 250 * Set the DAC characteristics of the file. 251 * This uses a fancy chmod() by setting a minimal ACL which sets the mode 252 * and discards any existing ACL. 253 */ 254 255 static int 256 newdac(char *file, uid_t owner, gid_t group, o_mode_t mode) 257 { 258 int err = 0; 259 aclent_t min_acl[MIN_ACL_ENTRIES]; 260 261 min_acl[0].a_type = USER_OBJ; 262 min_acl[0].a_id = owner; 263 min_acl[0].a_perm = ((mode & 0700) >> 6); 264 265 min_acl[1].a_type = GROUP_OBJ; 266 min_acl[1].a_id = group; 267 min_acl[1].a_perm = ((mode & 0070) >> 3); 268 269 min_acl[2].a_type = CLASS_OBJ; 270 min_acl[2].a_id = (uid_t)-1; 271 min_acl[2].a_perm = ((mode & 0070) >> 3); 272 273 min_acl[3].a_type = OTHER_OBJ; 274 min_acl[3].a_id = (uid_t)-1; 275 min_acl[3].a_perm = (mode & 0007); 276 277 do { 278 if (chown(file, owner, group) == -1) { 279 dperror("newdac, unable to chown"); 280 err = CHOWN_PERR; 281 } 282 } while (fdetach(file) == 0); 283 284 if (acl(file, SETACL, MIN_ACL_ENTRIES, min_acl) < 0) { 285 dperror("newdac, unable to setacl"); 286 err = SETACL_PERR; 287 } 288 289 return (err); 290 } 291 292 static int 293 lock_dev(char *file) 294 { 295 int fd; 296 297 dprintf("locking %s\n", file); 298 if ((fd = open(file, O_RDWR)) == -1) { 299 dperror("lock_dev, cannot open DAC file"); 300 return (DACACC); 301 } 302 303 if (lockf(fd, F_TLOCK, 0) == -1) { 304 dperror("lock_dev, cannot set lock"); 305 return (DACLCK); 306 } 307 308 return (0); 309 } 310 311 static int 312 mk_alloc(char *list, uid_t uid) 313 { 314 char *file; 315 int err; 316 317 file = strtok(list, " "); 318 while (file != NULL) { 319 320 dprintf("Allocating %s\n", file); 321 if ((err = newdac(file, uid, getgid(), ALLOC_MODE)) != 0) { 322 (void) newdac(file, ALLOC_UID, ALLOC_GID, 323 ALLOC_ERR_MODE); 324 return (err); 325 } 326 327 file = strtok(NULL, " "); 328 } 329 return (0); 330 } 331 332 /* 333 * mk_revoke() is used instead of system("/usr/sbin/fuser -k file") 334 * because "/usr/sbin/fuser -k file" kills all processes 335 * working with the file, even "vold" (bug #4095152). 336 */ 337 static int 338 mk_revoke(int optflg, char *file) 339 { 340 char buf[MAXPATHLEN]; 341 int r = 0, p[2], fp, lock; 342 FILE *ptr; 343 prpsinfo_t info; 344 pid_t pid, c_pid; 345 346 (void) strcpy(buf, PROCFS); 347 348 /* 349 * vfork() and execle() just to make the same output 350 * as before fixing of bug #4095152. 351 * The problem is that the "fuser" command prints 352 * one part of output into stderr and another into stdout, 353 * but user sees them mixed. Of course, better to change "fuser" 354 * or to intercept and not to print its output. 355 */ 356 if (!(optflg & SILENT)) { 357 c_pid = vfork(); 358 if (c_pid == -1) 359 return (-1); 360 if (c_pid == 0) { 361 dprintf("first exec fuser %s\n", file); 362 (void) execle("/usr/sbin/fuser", "fuser", file, NULL, 363 newenv); 364 dperror("first exec fuser"); 365 _exit(1); 366 } 367 368 (void) waitpid(c_pid, &lock, 0); 369 dprintf("exit status %x\n", lock); 370 if (WEXITSTATUS(lock) != 0) 371 return (-1); 372 } 373 dprintf("first continuing c_pid=%d\n", c_pid); 374 375 if (pipe(p)) { 376 dperror("pipe"); 377 return (-1); 378 } 379 380 /* vfork() and execle() to catch output and to process it */ 381 c_pid = vfork(); 382 if (c_pid == -1) { 383 dperror("second vfork"); 384 return (-1); 385 } 386 dprintf("second continuing c_pid=%d\n", c_pid); 387 388 if (c_pid == 0) { 389 (void) close(p[0]); 390 (void) close(1); 391 (void) fcntl(p[1], F_DUPFD, 1); 392 (void) close(p[1]); 393 (void) close(2); 394 dprintf("second exec fuser %s\n", file); 395 (void) execle("/usr/sbin/fuser", "fuser", file, NULL, newenv); 396 dperror("second exec fuser"); 397 _exit(1); 398 } 399 400 (void) close(p[1]); 401 if ((ptr = fdopen(p[0], "r")) != NULL) { 402 while (!feof(ptr)) { 403 if (fscanf(ptr, "%d", &pid) > 0) { 404 (void) sprintf(buf + strlen(PROCFS), "%d", pid); 405 if ((fp = open(buf, O_RDONLY)) == -1) { 406 dperror(buf); 407 continue; 408 } 409 if (ioctl(fp, PIOCPSINFO, (char *)&info) 410 == -1) { 411 dprintf("%d psinfo failed", pid); 412 dperror(""); 413 (void) close(fp); 414 continue; 415 } 416 (void) close(fp); 417 if (strcmp(info.pr_fname, "vold") == NULL) { 418 dprintf("%d matched vold name\n", pid); 419 continue; 420 } 421 dprintf("killing %s", info.pr_fname); 422 dprintf("(%d)\n", pid); 423 if ((r = kill(pid, SIGKILL)) == -1) { 424 dprintf("kill %d", pid); 425 dperror(""); 426 break; 427 } 428 } 429 } 430 dprintf("eof reached %x\n", ptr); 431 } else { 432 dperror("fdopen(p[0])"); 433 r = -1; 434 } 435 436 (void) fclose(ptr); 437 return (r); 438 } 439 440 static int 441 mk_unalloc(int optflg, char *list) 442 { 443 char *file; 444 int error = 0; 445 int child, status; 446 447 audit_allocate_list(list); 448 449 child = vfork(); 450 switch (child) { 451 case -1: 452 return (-1); 453 case 0: 454 (void) setuid(0); 455 file = strtok(list, " "); 456 while (file != NULL) { 457 dprintf("Deallocating %s\n", file); 458 if (mk_revoke(optflg, file) < 0) { 459 dprintf("mk_unalloc: unable to revoke %s\n", 460 file); 461 dperror(""); 462 error = CNTFRC; 463 break; 464 } 465 error = newdac(file, ALLOC_UID, ALLOC_GID, 466 DEALLOC_MODE); 467 file = strtok(NULL, " "); 468 } 469 exit(error); 470 default: 471 while (wait(&status) != child); 472 if (WIFEXITED(status)) { 473 return (WEXITSTATUS(status)); 474 } 475 return (-1); 476 } 477 } 478 479 static int 480 exec_clean(int optflg, char *name, char *path) 481 { 482 char *mode, *cmd; 483 int status; 484 int c; 485 486 if ((optflg & (FORCE_ALL | SILENT)) == (FORCE_ALL | SILENT)) 487 mode = "-I"; 488 else if (optflg & FORCE_ALL) 489 mode = "-i"; 490 else if (optflg & FORCE) 491 mode = "-f"; 492 else 493 mode = "-s"; 494 if ((cmd = strrchr(path, '/')) == NULL) 495 cmd = path; 496 else 497 cmd++; /* skip leading '/' */ 498 499 c = vfork(); 500 switch (c) { 501 case -1: 502 return (-1); 503 case 0: 504 (void) setuid(0); 505 dprintf("clean script: %s, ", path); 506 dprintf("cmd=%s, ", cmd); 507 dprintf("mode=%s, ", mode); 508 dprintf("name=%s\n", name); 509 (void) execle(path, cmd, mode, name, NULL, newenv); 510 dprintf("Unable to execute clean up script %s\n", path); 511 dperror(""); 512 exit(CNTDEXEC); 513 default: 514 while (wait(&status) != c); 515 if (WIFEXITED(status)) 516 return (WEXITSTATUS(status)); 517 dprintf("exit status %d\n", status); 518 return (-1); 519 } 520 } 521 522 static int 523 deallocate_dev(int optflg, devalloc_t *dev_ent, uid_t uid) 524 { 525 devmap_t *dev_list; 526 char file_name[MAXPATHLEN]; 527 struct stat stat_buf; 528 char *list; 529 int error = 0, err; 530 int bytes_formated; 531 532 bytes_formated = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, 533 dev_ent->da_devname); 534 if (bytes_formated <= 0) { 535 return (DEVNAME_ERR); 536 } else if (bytes_formated >= MAXPATHLEN) { 537 dprintf("device name %s is too long.\n", dev_ent->da_devname); 538 return (DEVNAME_TOOLONG); 539 } 540 541 audit_allocate_device(file_name); 542 543 if (stat(file_name, &stat_buf)) { 544 dprintf("Unable to stat %s\n", file_name); 545 dperror("Error:"); 546 return (DACACC); 547 } 548 549 if (!(optflg & FORCE) && stat_buf.st_uid != uid && 550 DEV_ALLOCATED(stat_buf)) { 551 return (NALLOCU); 552 } 553 554 if (!(optflg & FORCE_ALL) && !DEV_ALLOCATED(stat_buf)) { 555 if ((stat_buf.st_mode & ~S_IFMT) == ALLOC_ERR_MODE) { 556 if (!(optflg & FORCE)) 557 return (ALLOCERR); 558 } else 559 return (NALLOC); 560 } 561 562 /* All checks passed, time to lock and deallocate */ 563 if ((error = lock_dev(file_name)) != 0) 564 return (error); 565 566 if ((err = newdac(file_name, ALLOC_UID, ALLOC_GID, DEALLOC_MODE)) 567 != 0) { 568 (void) newdac(file_name, ALLOC_UID, ALLOC_GID, ALLOC_ERR_MODE); 569 EXIT(err); 570 } 571 572 if ((dev_list = getdmapnam(dev_ent->da_devname)) == NULL) { 573 dprintf("Unable to find %s in the device map database\n", 574 dev_ent->da_devname); 575 EXIT(NODMAPENT); 576 } else { 577 if ((list = strdup(dev_list->dmap_devlist)) == NULL) { 578 EXIT(SYSERROR) 579 } else { 580 if (mk_unalloc(optflg, list) != 0) { 581 (void) newdac(file_name, ALLOC_UID, ALLOC_GID, 582 ALLOC_ERR_MODE); 583 free(list); 584 list = NULL; 585 EXIT(DEVLST); 586 } 587 } 588 } 589 590 if (list != NULL) 591 free(list); 592 if (exec_clean(optflg, dev_ent->da_devname, dev_ent->da_devexec)) 593 EXIT(CLEAN_ERR); 594 return (error); 595 } 596 597 static int 598 allocate_dev(int optflg, uid_t uid, devalloc_t *dev_ent) 599 { 600 devmap_t *dev_list; 601 char file_name[MAXPATHLEN]; 602 struct stat stat_buf; 603 char *list; 604 int error = 0; 605 int bytes_formated; 606 607 bytes_formated = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, 608 dev_ent->da_devname); 609 if (bytes_formated <= 0) { 610 return (DEVNAME_ERR); 611 } else if (bytes_formated >= MAXPATHLEN) { 612 dprintf("device name %s is too long.\n", dev_ent->da_devname); 613 return (DEVNAME_TOOLONG); 614 } 615 616 audit_allocate_device(file_name); 617 618 if (stat(file_name, &stat_buf)) { 619 dprintf("Unable to stat %s\n", file_name); 620 dperror("Error:"); 621 return (DACACC); 622 } 623 624 if (DEV_ALLOCATED(stat_buf)) { 625 if (optflg & FORCE) { 626 if (deallocate_dev(FORCE, dev_ent, uid)) { 627 dprintf("Couldn't force deallocate device %s\n", 628 dev_ent->da_devname); 629 return (CNTFRC); 630 } 631 } else if (stat_buf.st_uid == uid) { 632 return (ALLOC); 633 } else 634 return (ALLOC_OTHER); 635 } 636 if ((stat_buf.st_mode & ~S_IFMT) == ALLOC_ERR_MODE) 637 return (ALLOCERR); 638 639 if (strcmp(dev_ent->da_devauth, "*") == 0) { 640 dprintf("Device %s is not allocatable\n", dev_ent->da_devname); 641 return (AUTHERR); 642 } 643 644 if (strcmp(dev_ent->da_devauth, "@")) { 645 if (!is_authorized(dev_ent->da_devauth, uid)) { 646 dprintf("User %d is unauthorized to allocate\n", 647 (int)uid); 648 return (IMPORT_ERR); 649 } 650 } 651 652 if ((dev_list = getdmapnam(dev_ent->da_devname)) == NULL) { 653 dprintf("Unable to find %s in device map database\n", 654 dev_ent->da_devname); 655 return (NODMAPENT); 656 } 657 658 if ((list = strdup(dev_list->dmap_devlist)) == NULL) 659 return (SYSERROR); 660 661 if (check_devs(list) == -1) { 662 free(list); 663 return (DSPMISS); 664 } 665 666 /* All checks passed, time to lock and allocate */ 667 if ((error = lock_dev(file_name)) != 0) { 668 free(list); 669 return (error); 670 } 671 672 if ((error = newdac(file_name, uid, getgid(), ALLOC_MODE)) != 0) { 673 (void) newdac(file_name, ALLOC_UID, ALLOC_GID, ALLOC_ERR_MODE); 674 free(list); 675 return (error); 676 } 677 678 /* refresh list from check_devs overwritting it */ 679 (void) strcpy(list, dev_list->dmap_devlist); 680 audit_allocate_list(list); 681 682 if (mk_alloc(list, uid) != 0) { 683 /* refresh list from mk_alloc overwritting it */ 684 (void) strcpy(list, dev_list->dmap_devlist); 685 (void) mk_unalloc(optflg, list); 686 free(list); 687 return (DEVLST); 688 } 689 690 free(list); 691 return (0); 692 } 693 694 int 695 allocate(int optflg, uid_t uid, char *device) 696 { 697 devalloc_t *dev_ent; 698 devmap_t *dev_list; 699 700 if (((optflg & FORCE) || uid != getuid()) && 701 !is_authorized(DEVICE_REVOKE_AUTH, getuid())) 702 return (NOTAUTH); 703 704 setdaent(); 705 setdmapent(); 706 707 if (!(optflg & TYPE)) { 708 if ((dev_ent = getdanam(device)) == NULL) { 709 if ((dev_list = getdmapdev(device)) == NULL) 710 return (NODMAPENT); 711 else if ((dev_ent = getdanam(dev_list->dmap_devname)) 712 == NULL) 713 return (NODAENT); 714 } 715 return (allocate_dev(optflg, uid, dev_ent)); 716 } 717 718 while ((dev_ent = getdatype(device)) != NULL) { 719 dprintf("trying to allocate %s\n", dev_ent->da_devname); 720 if (!allocate_dev(optflg, uid, dev_ent)) { 721 return (0); 722 } 723 } 724 enddaent(); 725 return (NO_DEVICE); 726 } 727 728 int 729 deallocate(int optflg, uid_t uid, char *device) 730 { 731 DIR *dev_dir; 732 struct dirent *dac_file; 733 devalloc_t *dev_ent; 734 devmap_t *dev_list; 735 int error = NODAENT; 736 737 if (optflg & (FORCE | FORCE_ALL) && 738 !is_authorized(DEVICE_REVOKE_AUTH, getuid())) 739 return (NOTAUTH); 740 if (optflg & FORCE_ALL) 741 optflg |= FORCE; 742 743 setdaent(); 744 setdmapent(); 745 746 if (!(optflg & FORCE_ALL)) { 747 if ((dev_ent = getdanam(device)) == NULL) { 748 if ((dev_list = getdmapdev(device)) == NULL) 749 return (NODMAPENT); 750 else if ((dev_ent = getdanam(dev_list->dmap_devname)) 751 == NULL) 752 return (NODAENT); 753 } 754 755 return (deallocate_dev(optflg, dev_ent, uid)); 756 } 757 758 if ((dev_dir = opendir(DAC_DIR)) == NULL) { 759 dperror("Can't open DAC_DIR"); 760 return (DACACC); 761 } 762 763 while ((dac_file = readdir(dev_dir)) != NULL) { 764 if ((strcmp(dac_file->d_name, ".") == 0) || 765 (strcmp(dac_file->d_name, "..") == 0)) { 766 continue; 767 } else { 768 if ((dev_ent = getdanam(dac_file->d_name)) == NULL) { 769 continue; 770 } 771 error = deallocate_dev(optflg, dev_ent, uid); 772 } 773 } 774 (void) closedir(dev_dir); 775 enddaent(); 776 return (error); 777 } 778