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