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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <errno.h> 28 #include <locale.h> 29 #include <pwd.h> 30 #include <unistd.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <ctype.h> 35 #include <fcntl.h> 36 #include <nss_dbdefs.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <sys/wait.h> 40 #include <tsol/label.h> 41 #include <zone.h> 42 #include <bsm/devalloc.h> 43 #include "allocate.h" 44 45 #if !defined(TEXT_DOMAIN) 46 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 47 #endif 48 49 #define ALLOC "allocate" 50 #define DEALLOC "deallocate" 51 #define LIST "list_devices" 52 53 extern void audit_allocate_argv(int, int, char *[]); 54 extern int audit_allocate_record(int); 55 56 int system_labeled = 0; 57 static int windowing = 0; 58 static int wdwmsg(char *name, char *msg); 59 60 static void 61 usage(int func) 62 { 63 if (system_labeled) { 64 char *use[6]; 65 66 use[0] = gettext("allocate [-s] [-w] [-U uname] [-z zonename] " 67 "[-F] device|-g dev-type"); 68 use[1] = gettext("deallocate [-s] [-w] [-z zonename] " 69 "[-F] device|-c dev-class|-g dev-type"); 70 use[2] = gettext("deallocate [-s] [-w] [-z zonename] -I"); 71 use[3] = gettext("list_devices [-s] [-U uid] [-z zonename] " 72 "[-a [-w]] -l|-n|-u [device]"); 73 use[4] = gettext("list_devices [-s] [-U uid] [-z zonename] " 74 "[-a [-w]] [-l|-n|-u] -c dev-class"); 75 use[5] = gettext("list_devices [-s] -d [dev-type]"); 76 77 switch (func) { 78 case 0: 79 (void) fprintf(stderr, "%s\n", use[0]); 80 break; 81 case 1: 82 (void) fprintf(stderr, "%s\n%s\n", 83 use[1], use[2]); 84 break; 85 case 2: 86 (void) fprintf(stderr, "%s\n%s\n%s\n", 87 use[3], use[4], use[5]); 88 break; 89 default: 90 (void) fprintf(stderr, 91 "%s\n%s\n%s\n%s\n%s\n%s\n", 92 use[0], use[1], use[2], use[3], use[4], 93 use[5]); 94 } 95 } else { 96 char *use[5]; 97 98 use[0] = gettext("allocate " 99 "[-s] [-U uname] [-F] device|-g dev-type"); 100 use[1] = gettext("deallocate [-s] [-F] device|-c dev-class"); 101 use[2] = gettext("deallocate [-s] -I"); 102 use[3] = gettext("list_devices " 103 "[-s] [-U uid] -l|-n|-u [device]"); 104 use[4] = gettext("list_devices " 105 "[-s] [-U uid] [-l|-n|-u] -c dev-class"); 106 107 switch (func) { 108 case 0: 109 (void) fprintf(stderr, "%s\n", use[0]); 110 break; 111 case 1: 112 (void) fprintf(stderr, "%s\n%s\n", 113 use[1], use[2]); 114 break; 115 case 2: 116 (void) fprintf(stderr, "%s\n%s\n", 117 use[3], use[4]); 118 break; 119 default: 120 (void) fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", 121 use[0], use[1], use[2], use[3], use[4]); 122 } 123 } 124 exit(1); 125 } 126 127 void 128 print_error(int error, char *name) 129 { 130 char *msg; 131 char msgbuf[200]; 132 133 switch (error) { 134 case ALLOCUERR: 135 msg = gettext("Specified device is allocated to another user."); 136 break; 137 case CHOWNERR: 138 msg = gettext("Failed to chown."); 139 break; 140 case CLEANERR: 141 msg = gettext("Unable to clean up device."); 142 break; 143 case CNTDEXECERR: 144 msg = gettext( 145 "Can't exec device-clean program for specified device."); 146 break; 147 case CNTFRCERR: 148 msg = gettext("Can't force deallocate specified device."); 149 break; 150 case DACACCERR: 151 msg = gettext( 152 "Can't access DAC file for the device specified."); 153 break; 154 case DAOFFERR: 155 msg = gettext( 156 "Device allocation feature is not activated " 157 "on this system."); 158 break; 159 case DAUTHERR: 160 msg = gettext("Device not allocatable."); 161 break; 162 case DEFATTRSERR: 163 msg = gettext("No default attributes for specified " 164 "device type."); 165 break; 166 case DEVLKERR: 167 msg = gettext("Concurrent operations for specified device, " 168 "try later."); 169 break; 170 case DEVLONGERR: 171 msg = gettext("Device name is too long."); 172 break; 173 case DEVNALLOCERR: 174 msg = gettext("Device not allocated."); 175 break; 176 case DEVNAMEERR: 177 msg = gettext("Device name error."); 178 break; 179 case DEVSTATEERR: 180 msg = gettext("Device specified is in allocate error state."); 181 break; 182 case DEVZONEERR: 183 msg = gettext("Can't find name of the zone to which " 184 "device is allocated."); 185 break; 186 case DSPMISSERR: 187 msg = gettext( 188 "Device special file(s) missing for specified device."); 189 break; 190 case LABELRNGERR: 191 msg = gettext( 192 "Operation inconsistent with device's label range."); 193 break; 194 case LOGINDEVPERMERR: 195 msg = gettext("Device controlled by logindevperm(5)"); 196 break; 197 case NODAERR: 198 msg = gettext("No entry for specified device."); 199 break; 200 case NODMAPERR: 201 msg = gettext("No entry for specified device."); 202 break; 203 case PREALLOCERR: 204 msg = gettext("Device already allocated."); 205 break; 206 case SETACLERR: 207 msg = gettext("Failed to set ACL."); 208 break; 209 case UAUTHERR: 210 msg = gettext( 211 "User lacks authorization required for this operation."); 212 break; 213 case ZONEERR: 214 msg = gettext("Failed to configure device in zone."); 215 break; 216 default: 217 msg = gettext("Unknown error code."); 218 break; 219 } 220 221 if (windowing) { 222 (void) snprintf(msgbuf, sizeof (msgbuf), "%s: %s\n", name, msg); 223 (void) wdwmsg(name, msgbuf); 224 } else { 225 (void) fprintf(stderr, "%s: %s\n", name, msg); 226 (void) fflush(stderr); 227 } 228 } 229 230 char *newenv[] = {"PATH=/usr/bin:/usr/sbin", 231 NULL, /* for LC_ALL */ 232 NULL, /* for LC_COLLATE */ 233 NULL, /* for LC_CTYPE */ 234 NULL, /* for LC_MESSAGES */ 235 NULL, /* for LC_NUMERIC */ 236 NULL, /* for LC_TIME */ 237 NULL, /* for LANG */ 238 NULL 239 }; 240 241 static char * 242 getenvent(char *name, char *env[]) 243 { 244 for (; *env != NULL; env++) { 245 if (strncmp(*env, name, strlen(name)) == 0) 246 return (*env); 247 } 248 return (NULL); 249 } 250 251 int 252 main(int argc, char *argv[], char *envp[]) 253 { 254 char *name, *env; 255 int func = -1, optflg = 0, error = 0, c; 256 zoneid_t zoneid; 257 uid_t uid; 258 char *uname = NULL, *device = NULL, *zonename = NULL; 259 char *zname; 260 char pw_buf[NSS_BUFLEN_PASSWD]; 261 struct passwd pw_ent; 262 int env_num = 1; /* PATH= is 0 entry */ 263 #ifdef DEBUG 264 struct stat statbuf; 265 #endif 266 267 (void) setlocale(LC_ALL, ""); 268 (void) textdomain(TEXT_DOMAIN); 269 270 system_labeled = is_system_labeled(); 271 272 /* test hook: see also mkdevalloc.c and devfsadm.c */ 273 if (!system_labeled) { 274 system_labeled = is_system_labeled_debug(&statbuf); 275 if (system_labeled) { 276 fprintf(stderr, "/ALLOCATE_FORCE_LABEL is set,\n" 277 "forcing system label on for testing...\n"); 278 } 279 } 280 281 /* 282 * get all enviroment variables 283 * which affect on internationalization. 284 */ 285 env = getenvent("LC_ALL=", envp); 286 if (env != NULL) 287 newenv[env_num++] = env; 288 env = getenvent("LC_COLLATE=", envp); 289 if (env != NULL) 290 newenv[env_num++] = env; 291 env = getenvent("LC_CTYPE=", envp); 292 if (env != NULL) 293 newenv[env_num++] = env; 294 env = getenvent("LC_MESSAGES=", envp); 295 if (env != NULL) 296 newenv[env_num++] = env; 297 env = getenvent("LC_NUMERIC=", envp); 298 if (env != NULL) 299 newenv[env_num++] = env; 300 env = getenvent("LC_TIME=", envp); 301 if (env != NULL) 302 newenv[env_num++] = env; 303 env = getenvent("LANG=", envp); 304 if (env != NULL) 305 newenv[env_num] = env; 306 307 if ((name = strrchr(argv[0], '/')) == NULL) 308 name = argv[0]; 309 else 310 name++; 311 312 if (strcmp(name, ALLOC) == 0) 313 func = 0; 314 else if (strcmp(name, DEALLOC) == 0) 315 func = 1; 316 else if (strcmp(name, LIST) == 0) 317 func = 2; 318 else 319 usage(-1); 320 321 audit_allocate_argv(func, argc, argv); 322 323 if (system_labeled) { 324 /* 325 * allocate, deallocate, list_devices run in 326 * global zone only. 327 */ 328 zoneid = getzoneid(); 329 if (zoneid != GLOBAL_ZONEID) 330 exit(GLOBALERR); 331 zname = GLOBAL_ZONENAME; 332 /* 333 * check if device allocation is activated. 334 */ 335 if (da_is_on() == 0) { 336 (void) fprintf(stderr, "%s%s", 337 gettext("Turn device allocation on"), 338 gettext(" to use this feature.\n")); 339 exit(DAOFFERR); 340 } 341 } 342 343 if (func == 0) { /* allocate */ 344 while ((c = getopt(argc, argv, "g:swz:FU:")) != -1) { 345 switch (c) { 346 case 'g': 347 optflg |= TYPE; 348 device = optarg; 349 break; 350 case 's': 351 optflg |= SILENT; 352 break; 353 case 'w': 354 if (system_labeled) { 355 optflg |= WINDOWING; 356 windowing = 1; 357 } else { 358 usage(func); 359 } 360 break; 361 case 'z': 362 if (system_labeled) { 363 optflg |= ZONENAME; 364 zonename = optarg; 365 } else { 366 usage(func); 367 } 368 break; 369 case 'F': 370 optflg |= FORCE; 371 break; 372 case 'U': 373 optflg |= USERNAME; 374 uname = optarg; 375 break; 376 case '?': 377 default : 378 usage(func); 379 } 380 } 381 382 /* 383 * allocate(1) must be supplied with one device argument 384 */ 385 if (device && ((argc - optind) >= 1)) 386 usage(func); 387 if (device == NULL) { 388 if ((argc - optind) != 1) 389 usage(func); 390 device = argv[optind]; 391 } 392 } 393 394 else if (func == 1) { /* deallocate */ 395 while ((c = getopt(argc, argv, "c:g:swz:FI")) != -1) { 396 switch (c) { 397 case 'c': 398 if (optflg & (TYPE | FORCE_ALL)) 399 usage(func); 400 optflg |= CLASS; 401 device = optarg; 402 break; 403 case 'g': 404 if (system_labeled) { 405 if (optflg & (CLASS | FORCE_ALL)) 406 usage(func); 407 optflg |= TYPE; 408 device = optarg; 409 } else { 410 usage(func); 411 } 412 break; 413 case 's': 414 optflg |= SILENT; 415 break; 416 case 'w': 417 if (system_labeled) { 418 optflg |= WINDOWING; 419 windowing = 1; 420 } else { 421 usage(func); 422 } 423 break; 424 case 'z': 425 if (system_labeled) { 426 optflg |= ZONENAME; 427 zonename = optarg; 428 } else { 429 usage(func); 430 } 431 break; 432 case 'F': 433 if (optflg & FORCE_ALL) 434 usage(func); 435 optflg |= FORCE; 436 break; 437 case 'I': 438 if (optflg & (CLASS | TYPE | FORCE)) 439 usage(func); 440 optflg |= FORCE_ALL; 441 break; 442 case '?': 443 default : 444 usage(func); 445 } 446 } 447 448 /* 449 * deallocate(1) must be supplied with one device 450 * argument unless the '-I' argument is supplied 451 */ 452 if (device || (optflg & FORCE_ALL)) { 453 if ((argc - optind) >= 1) 454 usage(func); 455 } else if (device == NULL) { 456 if ((argc - optind) != 1) 457 usage(func); 458 device = argv[optind]; 459 } 460 } 461 462 else if (func == 2) { /* list_devices */ 463 while ((c = getopt(argc, argv, "ac:dlnsuwz:U:")) != -1) { 464 switch (c) { 465 case 'a': 466 if (system_labeled) { 467 /* 468 * list auths, cleaning programs, 469 * labels. 470 */ 471 if (optflg & LISTDEFS) 472 usage(func); 473 optflg |= LISTATTRS; 474 } else { 475 usage(func); 476 } 477 break; 478 case 'c': 479 optflg |= CLASS; 480 device = optarg; 481 break; 482 case 'd': 483 if (system_labeled) { 484 /* 485 * List devalloc_defaults 486 * This cannot used with anything other 487 * than -s. 488 */ 489 if (optflg & (LISTATTRS | CLASS | 490 LISTALL | LISTFREE | LISTALLOC | 491 WINDOWING | ZONENAME | USERID)) 492 usage(func); 493 optflg |= LISTDEFS; 494 } else { 495 usage(func); 496 } 497 break; 498 case 'l': 499 if (optflg & (LISTFREE | LISTALLOC | LISTDEFS)) 500 usage(func); 501 optflg |= LISTALL; 502 break; 503 case 'n': 504 if (optflg & (LISTALL | LISTALLOC | LISTDEFS)) 505 usage(func); 506 optflg |= LISTFREE; 507 break; 508 case 's': 509 optflg |= SILENT; 510 break; 511 case 'u': 512 if (optflg & (LISTALL | LISTFREE | LISTDEFS)) 513 usage(func); 514 optflg |= LISTALLOC; 515 break; 516 case 'w': 517 if (system_labeled) { 518 if (optflg & LISTDEFS) 519 usage(func); 520 optflg |= WINDOWING; 521 } else { 522 usage(func); 523 } 524 break; 525 case 'z': 526 if (system_labeled) { 527 if (optflg & LISTDEFS) 528 usage(func); 529 optflg |= ZONENAME; 530 zonename = optarg; 531 } else { 532 usage(func); 533 } 534 break; 535 case 'U': 536 if (optflg & LISTDEFS) 537 usage(func); 538 optflg |= USERID; 539 uid = atoi(optarg); 540 break; 541 case '?': 542 default : 543 usage(func); 544 } 545 } 546 547 if (system_labeled) { 548 if (!(optflg & (LISTALL | LISTFREE | LISTALLOC | 549 LISTDEFS | WINDOWING))) { 550 if (!(optflg & CLASS)) 551 usage(func); 552 } 553 } else if (!(optflg & (LISTALL | LISTFREE | LISTALLOC))) { 554 if (!(optflg & CLASS)) 555 usage(func); 556 } 557 558 /* 559 * list_devices(1) takes an optional device argument. 560 */ 561 if (device && ((argc - optind) >= 1)) 562 usage(func); 563 if (device == NULL) { 564 if ((argc - optind) == 1) 565 device = argv[optind]; 566 else if ((argc - optind) > 1) 567 usage(func); 568 } 569 } 570 571 if (optflg & USERNAME) { 572 if (getpwnam_r(uname, &pw_ent, pw_buf, sizeof (pw_buf)) == 573 NULL) { 574 (void) fprintf(stderr, 575 gettext("Invalid user name -- %s -- \n"), uname); 576 exit(1); 577 } 578 uid = pw_ent.pw_uid; 579 } else if (optflg & USERID) { 580 if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) { 581 (void) fprintf(stderr, 582 gettext("Invalid user ID -- %d -- \n"), uid); 583 exit(1); 584 } 585 uid = pw_ent.pw_uid; 586 } else { 587 /* 588 * caller's uid is the default if no user specified. 589 */ 590 uid = getuid(); 591 } 592 593 /* 594 * global zone is the default if no zonename specified. 595 */ 596 if (zonename == NULL) { 597 zonename = zname; 598 } else { 599 if (zone_get_id(zonename, &zoneid) != 0) { 600 (void) fprintf(stderr, 601 gettext("Invalid zone name -- %s -- \n"), zonename); 602 exit(1); 603 } 604 } 605 606 if (func == 0) 607 error = allocate(optflg, uid, device, zonename); 608 else if (func == 1) 609 error = deallocate(optflg, uid, device, zonename); 610 else if (func == 2) 611 error = list_devices(optflg, uid, device, zonename); 612 613 (void) audit_allocate_record(error); 614 615 if (error) { 616 if (!(optflg & SILENT)) 617 print_error(error, name); 618 exit(error); 619 } 620 621 return (0); 622 } 623 624 /* 625 * Display error message via /etc/security/lib/wdwmsg script 626 */ 627 static int 628 wdwmsg(char *name, char *msg) 629 { 630 pid_t child_pid; 631 pid_t wait_pid; 632 int child_status; 633 634 /* Fork a child */ 635 switch (child_pid = fork()) { 636 case -1: /* FAILURE */ 637 return (-1); 638 break; 639 640 case 0: /* CHILD */ 641 (void) execl("/etc/security/lib/wdwmsg", "wdwmsg", msg, 642 name, "OK", NULL); 643 /* If exec failed, send message to stderr */ 644 (void) fprintf(stderr, "%s", msg); 645 return (-1); 646 647 default: /* PARENT */ 648 /* Wait for child to exit */ 649 wait_pid = waitpid(child_pid, &child_status, 0); 650 if ((wait_pid < 0) && (errno == ECHILD)) 651 return (0); 652 if ((wait_pid < 0) || (wait_pid != child_pid)) 653 return (-1); 654 if (WIFEXITED(child_status)) 655 return (WEXITSTATUS(child_status)); 656 if (WIFSIGNALED(child_status)) 657 return (WTERMSIG(child_status)); 658 return (0); 659 } 660 } 661