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 2005 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 /* 30 * zlogin provides three types of login which allow users in the global 31 * zone to access non-global zones. 32 * 33 * - "interactive login" is similar to rlogin(1); for example, the user could 34 * issue 'zlogin my-zone' or 'zlogin -e ^ -l me my-zone'. The user is 35 * granted a new pty (which is then shoved into the zone), and an I/O 36 * loop between parent and child processes takes care of the interactive 37 * session. In this mode, login(1) (and its -c option, which means 38 * "already authenticated") is employed to take care of the initialization 39 * of the user's session. 40 * 41 * - "non-interactive login" is similar to su(1M); the user could issue 42 * 'zlogin my-zone ls -l' and the command would be run as specified. 43 * In this mode, zlogin sets up pipes as the communication channel, and 44 * 'su' is used to do the login setup work. 45 * 46 * - "console login" is the equivalent to accessing the tip line for a 47 * zone. For example, the user can issue 'zlogin -C my-zone'. 48 * In this mode, zlogin contacts the zoneadmd process via unix domain 49 * socket. If zoneadmd is not running, it starts it. This allows the 50 * console to be available anytime the zone is installed, regardless of 51 * whether it is running. 52 */ 53 54 #include <sys/socket.h> 55 #include <sys/termios.h> 56 #include <sys/utsname.h> 57 #include <sys/stat.h> 58 #include <sys/types.h> 59 #include <sys/contract/process.h> 60 #include <sys/ctfs.h> 61 62 #include <alloca.h> 63 #include <assert.h> 64 #include <ctype.h> 65 #include <door.h> 66 #include <errno.h> 67 #include <poll.h> 68 #include <priv.h> 69 #include <pwd.h> 70 #include <unistd.h> 71 #include <utmpx.h> 72 #include <sac.h> 73 #include <signal.h> 74 #include <stdarg.h> 75 #include <stdio.h> 76 #include <stdlib.h> 77 #include <string.h> 78 #include <strings.h> 79 #include <stropts.h> 80 #include <wait.h> 81 #include <zone.h> 82 #include <fcntl.h> 83 #include <libdevinfo.h> 84 #include <libintl.h> 85 #include <locale.h> 86 #include <libzonecfg.h> 87 #include <libcontract.h> 88 89 static int masterfd; 90 static struct termios save_termios; 91 static struct termios effective_termios; 92 static int save_fd; 93 static struct winsize winsize; 94 static volatile int dead; 95 static volatile pid_t child_pid = -1; 96 static int interactive = 0; 97 static priv_set_t *dropprivs; 98 99 static int nocmdchar = 0; 100 static int failsafe = 0; 101 static char cmdchar = '~'; 102 103 static int pollerr = 0; 104 105 static const char *pname; 106 107 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */ 108 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 109 #endif 110 111 #define SUPATH "/usr/bin/su" 112 #define FAILSAFESHELL "/sbin/sh" 113 #define DEFAULTSHELL "/sbin/sh" 114 #define LOGINPATH "/usr/bin/login" 115 #define DEF_PATH "/usr/sbin:/usr/bin" 116 117 /* 118 * See canonify() below. CANONIFY_LEN is the maximum length that a 119 * "canonical" sequence will expand to (backslash, three octal digits, NUL). 120 */ 121 #define CANONIFY_LEN 5 122 123 static void 124 usage(void) 125 { 126 (void) fprintf(stderr, gettext("usage: %s [ -CES ] [ -e cmdchar ] " 127 "[-l user] zonename [command [args ...] ]\n"), pname); 128 exit(2); 129 } 130 131 static const char * 132 getpname(const char *arg0) 133 { 134 const char *p = strrchr(arg0, '/'); 135 136 if (p == NULL) 137 p = arg0; 138 else 139 p++; 140 141 pname = p; 142 return (p); 143 } 144 145 static void 146 zerror(const char *fmt, ...) 147 { 148 va_list alist; 149 150 (void) fprintf(stderr, "%s: ", pname); 151 va_start(alist, fmt); 152 (void) vfprintf(stderr, fmt, alist); 153 va_end(alist); 154 (void) fprintf(stderr, "\n"); 155 } 156 157 static void 158 zperror(const char *str) 159 { 160 const char *estr; 161 162 if ((estr = strerror(errno)) != NULL) 163 (void) fprintf(stderr, "%s: %s: %s\n", pname, str, estr); 164 else 165 (void) fprintf(stderr, "%s: %s: errno %d\n", pname, str, errno); 166 } 167 168 /* 169 * The first part of our privilege dropping scheme needs to be called before 170 * fork(), since we must have it for security; we don't want to be surprised 171 * later that we couldn't allocate the privset. 172 */ 173 static int 174 prefork_dropprivs() 175 { 176 if ((dropprivs = priv_allocset()) == NULL) 177 return (1); 178 priv_emptyset(dropprivs); 179 180 /* 181 * We need these privileges in order to query session information and 182 * send signals. 183 */ 184 if (interactive == 0) { 185 if (priv_addset(dropprivs, "proc_session") == -1) 186 return (1); 187 if (priv_addset(dropprivs, "proc_zone") == -1) 188 return (1); 189 if (priv_addset(dropprivs, "proc_owner") == -1) 190 return (1); 191 } 192 193 return (0); 194 } 195 196 /* 197 * The second part of the privilege drop. We are paranoid about being attacked 198 * by the zone, so we drop all privileges. This should prevent a compromise 199 * which gets us to fork(), exec(), symlink(), etc. 200 */ 201 static void 202 postfork_dropprivs() 203 { 204 if ((setppriv(PRIV_SET, PRIV_PERMITTED, dropprivs)) == -1) { 205 zperror(gettext("Warning: could not set permitted privileges")); 206 } 207 if ((setppriv(PRIV_SET, PRIV_LIMIT, dropprivs)) == -1) { 208 zperror(gettext("Warning: could not set limit privileges")); 209 } 210 if ((setppriv(PRIV_SET, PRIV_INHERITABLE, dropprivs)) == -1) { 211 zperror(gettext("Warning: could not set inheritable " 212 "privileges")); 213 } 214 } 215 216 /* 217 * Create the unix domain socket and call the zoneadmd server; handshake 218 * with it to determine whether it will allow us to connect. 219 */ 220 static int 221 get_console_master(const char *zname) 222 { 223 int sockfd = -1; 224 struct sockaddr_un servaddr; 225 char clientid[MAXPATHLEN]; 226 char handshake[MAXPATHLEN], c; 227 int msglen; 228 int i = 0, err = 0; 229 230 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 231 zperror(gettext("could not create socket")); 232 return (-1); 233 } 234 235 bzero(&servaddr, sizeof (servaddr)); 236 servaddr.sun_family = AF_UNIX; 237 (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path), 238 "%s/%s.console_sock", ZONES_TMPDIR, zname); 239 240 if (connect(sockfd, (struct sockaddr *)&servaddr, 241 sizeof (servaddr)) == -1) { 242 zperror(gettext("Could not connect to zone console")); 243 goto bad; 244 } 245 masterfd = sockfd; 246 247 msglen = snprintf(clientid, sizeof (clientid), "IDENT %lu %s\n", 248 getpid(), setlocale(LC_MESSAGES, NULL)); 249 250 if (msglen >= sizeof (clientid) || msglen < 0) { 251 zerror("protocol error"); 252 goto bad; 253 } 254 255 if (write(masterfd, clientid, msglen) != msglen) { 256 zerror("protocol error"); 257 goto bad; 258 } 259 260 bzero(handshake, sizeof (handshake)); 261 262 /* 263 * Take care not to accumulate more than our fill, and leave room for 264 * the NUL at the end. 265 */ 266 while ((err = read(masterfd, &c, 1)) == 1) { 267 if (i >= (sizeof (handshake) - 1)) 268 break; 269 if (c == '\n') 270 break; 271 handshake[i] = c; 272 i++; 273 } 274 275 /* 276 * If something went wrong during the handshake we bail; perhaps 277 * the server died off. 278 */ 279 if (err == -1) { 280 zperror(gettext("Could not connect to zone console")); 281 goto bad; 282 } 283 284 if (strncmp(handshake, "OK", sizeof (handshake)) == 0) 285 return (0); 286 287 zerror(gettext("Console is already in use by process ID %s."), 288 handshake); 289 bad: 290 (void) close(sockfd); 291 masterfd = -1; 292 return (-1); 293 } 294 295 296 /* 297 * Routines to handle pty creation upon zone entry and to shuttle I/O back 298 * and forth between the two terminals. We also compute and store the 299 * name of the slave terminal associated with the master side. 300 */ 301 static int 302 get_master_pty() 303 { 304 if ((masterfd = open("/dev/ptmx", O_RDWR|O_NONBLOCK)) < 0) { 305 zperror(gettext("failed to obtain a pseudo-tty")); 306 return (-1); 307 } 308 if (tcgetattr(STDIN_FILENO, &save_termios) == -1) { 309 zperror(gettext("failed to get terminal settings from stdin")); 310 return (-1); 311 } 312 (void) ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&winsize); 313 314 return (0); 315 } 316 317 /* 318 * This is a bit tricky; normally a pts device will belong to the zone it 319 * is granted to. But in the case of "entering" a zone, we need to establish 320 * the pty before entering the zone so that we can vector I/O to and from it 321 * from the global zone. 322 * 323 * We use the zonept() call to let the ptm driver know what we are up to; 324 * the only other hairy bit is the setting of zoneslavename (which happens 325 * above, in get_master_pty()). 326 */ 327 static int 328 init_slave_pty(zoneid_t zoneid, char *zonepath) 329 { 330 int slavefd = -1; 331 char *slavename, zoneslavename[MAXPATHLEN]; 332 333 /* 334 * Set slave permissions, zone the pts, then unlock it. 335 */ 336 if (grantpt(masterfd) != 0) { 337 zperror(gettext("grantpt failed")); 338 return (-1); 339 } 340 341 if (unlockpt(masterfd) != 0) { 342 zperror(gettext("unlockpt failed")); 343 return (-1); 344 } 345 346 /* 347 * We must open the slave side before zoning this pty; otherwise 348 * the kernel would refuse us the open-- zoning a pty makes it 349 * inaccessible to the global zone. Since we are trying to 350 * open the device node via the $ZONEPATH/dev path, we may have to 351 * give devfsadm a kick to get it to create the device node for 352 * us. Normally this would "just work" because pt_chmod inside 353 * the zone would take care of it for us. 354 * 355 * Later we'll close the slave out when once we've opened it again 356 * from within the target zone. Blarg. 357 */ 358 if ((slavename = ptsname(masterfd)) == NULL) { 359 zperror(gettext("failed to get name for pseudo-tty")); 360 return (-1); 361 } 362 363 (void) snprintf(zoneslavename, sizeof (zoneslavename), "%s%s", 364 zonepath, slavename); 365 366 if ((slavefd = open(zoneslavename, O_RDWR)) < 0) { 367 di_devlink_handle_t h = di_devlink_init("pts", DI_MAKE_LINK); 368 if (h != NULL) { 369 (void) di_devlink_fini(&h); 370 } 371 if ((slavefd = open(zoneslavename, O_RDWR)) < 0) { 372 zerror(gettext("failed to open %s: %s"), zoneslavename, 373 strerror(errno)); 374 return (-1); 375 } 376 } 377 378 /* 379 * Push hardware emulation (ptem), line discipline (ldterm), 380 * and V7/4BSD/Xenix compatibility (ttcompat) modules. 381 */ 382 if (ioctl(slavefd, I_PUSH, "ptem") == -1) { 383 zperror(gettext("failed to push ptem module")); 384 if (!failsafe) 385 goto bad; 386 } 387 388 /* 389 * Anchor the stream to prevent malicious I_POPs; we prefer to do 390 * this prior to entering the zone so that we can detect any errors 391 * early, and so that we can set the anchor from the global zone. 392 */ 393 if (ioctl(slavefd, I_ANCHOR) == -1) { 394 zperror(gettext("failed to set stream anchor")); 395 if (!failsafe) 396 goto bad; 397 } 398 399 if (ioctl(slavefd, I_PUSH, "ldterm") == -1) { 400 zperror(gettext("failed to push ldterm module")); 401 if (!failsafe) 402 goto bad; 403 } 404 if (ioctl(slavefd, I_PUSH, "ttcompat") == -1) { 405 zperror(gettext("failed to push ttcompat module")); 406 if (!failsafe) 407 goto bad; 408 } 409 410 /* 411 * Propagate terminal settings from the external term to the new one. 412 */ 413 if (tcsetattr(slavefd, TCSAFLUSH, &save_termios) == -1) { 414 zperror(gettext("failed to set terminal settings")); 415 if (!failsafe) 416 goto bad; 417 } 418 (void) ioctl(slavefd, TIOCSWINSZ, (char *)&winsize); 419 420 if (zonept(masterfd, zoneid) != 0) { 421 zperror(gettext("could not set zoneid of pty")); 422 goto bad; 423 } 424 425 return (slavefd); 426 427 bad: 428 (void) close(slavefd); 429 return (-1); 430 } 431 432 /* 433 * Place terminal into raw mode. 434 */ 435 static int 436 set_tty_rawmode(int fd) 437 { 438 struct termios term; 439 if (tcgetattr(fd, &term) < 0) { 440 zperror(gettext("failed to get user terminal settings")); 441 return (-1); 442 } 443 444 /* Stash for later, so we can revert back to previous mode */ 445 save_termios = term; 446 save_fd = fd; 447 448 /* disable 8->7 bit strip, start/stop, enable any char to restart */ 449 term.c_iflag &= ~(ISTRIP|IXON|IXANY); 450 /* disable NL->CR, CR->NL, ignore CR, UPPER->lower */ 451 term.c_iflag &= ~(INLCR|ICRNL|IGNCR|IUCLC); 452 /* disable output post-processing */ 453 term.c_oflag &= ~OPOST; 454 /* disable canonical mode, signal chars, echo & extended functions */ 455 term.c_lflag &= ~(ICANON|ISIG|ECHO|IEXTEN); 456 457 term.c_cc[VMIN] = 1; /* byte-at-a-time */ 458 term.c_cc[VTIME] = 0; 459 460 if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)) { 461 zperror(gettext("failed to set user terminal to raw mode")); 462 return (-1); 463 } 464 465 /* 466 * We need to know the value of VEOF so that we can properly process for 467 * client-side ~<EOF>. But we have obliterated VEOF in term, 468 * because VMIN overloads the same array slot in non-canonical mode. 469 * Stupid @&^%! 470 * 471 * So here we construct the "effective" termios from the current 472 * terminal settings, and the corrected VEOF and VEOL settings. 473 */ 474 if (tcgetattr(STDIN_FILENO, &effective_termios) < 0) { 475 zperror(gettext("failed to get user terminal settings")); 476 return (-1); 477 } 478 effective_termios.c_cc[VEOF] = save_termios.c_cc[VEOF]; 479 effective_termios.c_cc[VEOL] = save_termios.c_cc[VEOL]; 480 481 return (0); 482 } 483 484 /* 485 * Copy terminal window size from our terminal to the pts. 486 */ 487 /*ARGSUSED*/ 488 static void 489 sigwinch(int s) 490 { 491 struct winsize ws; 492 493 if (ioctl(0, TIOCGWINSZ, &ws) == 0) 494 (void) ioctl(masterfd, TIOCSWINSZ, &ws); 495 } 496 497 static void 498 /*ARGSUSED*/ 499 sigcld(int s) 500 { 501 int status; 502 pid_t pid; 503 504 /* 505 * Peek at the exit status. If this isn't the process we cared 506 * about, then just reap it. 507 */ 508 if ((pid = waitpid(child_pid, &status, WNOHANG|WNOWAIT)) != -1) { 509 if (pid == child_pid && 510 (WIFEXITED(status) || WIFSIGNALED(status))) 511 dead = 1; 512 else 513 (void) waitpid(pid, &status, WNOHANG); 514 } 515 } 516 517 /* 518 * Some signals (currently, SIGINT) must be forwarded on to the process 519 * group of the child process. 520 */ 521 static void 522 sig_forward(int s) 523 { 524 if (child_pid != -1) { 525 pid_t pgid = getpgid(child_pid); 526 if (pgid != -1) 527 (void) sigsend(P_PGID, pgid, s); 528 } 529 } 530 531 /* 532 * reset terminal settings for global environment 533 */ 534 static void 535 reset_tty() 536 { 537 (void) tcsetattr(save_fd, TCSADRAIN, &save_termios); 538 } 539 540 /* 541 * Convert character to printable representation, for display with locally 542 * echoed command characters (like when we need to display ~^D) 543 */ 544 static void 545 canonify(char c, char *cc) 546 { 547 if (isprint(c)) { 548 cc[0] = c; 549 cc[1] = '\0'; 550 } else if (c >= 0 && c <= 31) { /* ^@ through ^_ */ 551 cc[0] = '^'; 552 cc[1] = c + '@'; 553 cc[2] = '\0'; 554 } else { 555 cc[0] = '\\'; 556 cc[1] = ((c >> 6) & 7) + '0'; 557 cc[2] = ((c >> 3) & 7) + '0'; 558 cc[3] = (c & 7) + '0'; 559 cc[4] = '\0'; 560 } 561 } 562 563 /* 564 * process_user_input watches the input stream for the escape sequence for 565 * 'quit' (by default, tilde-period). Because we might be fed just one 566 * keystroke at a time, state associated with the user input (are we at the 567 * beginning of the line? are we locally echoing the next character?) is 568 * maintained by beginning_of_line and local_echo across calls to the routine. 569 * 570 * This routine returns -1 when the 'quit' escape sequence has been issued, 571 * and 0 otherwise. 572 */ 573 static int 574 process_user_input(int outfd, char *buf, size_t nbytes) 575 { 576 static boolean_t beginning_of_line = B_TRUE; 577 static boolean_t local_echo = B_FALSE; 578 579 char c = *buf; 580 for (c = *buf; nbytes > 0; c = *buf, --nbytes) { 581 buf++; 582 if (beginning_of_line && !nocmdchar) { 583 beginning_of_line = B_FALSE; 584 if (c == cmdchar) { 585 local_echo = B_TRUE; 586 continue; 587 } 588 } else if (local_echo) { 589 local_echo = B_FALSE; 590 if (c == '.' || c == effective_termios.c_cc[VEOF]) { 591 char cc[CANONIFY_LEN]; 592 canonify(c, cc); 593 (void) write(STDOUT_FILENO, &cmdchar, 1); 594 (void) write(STDOUT_FILENO, cc, strlen(cc)); 595 return (-1); 596 } 597 } 598 if (write(outfd, &c, 1) <= 0) 599 return (-1); 600 beginning_of_line = (c == '\r' || c == '\n' || 601 c == effective_termios.c_cc[VKILL] || 602 c == effective_termios.c_cc[VEOL] || 603 c == effective_termios.c_cc[VSUSP] || 604 c == effective_termios.c_cc[VINTR]); 605 } 606 return (0); 607 } 608 609 /* 610 * This is the main I/O loop, and is shared across all zlogin modes. 611 * Parameters: 612 * stdin_fd: The fd representing 'stdin' for the slave side; input to 613 * the zone will be written here. 614 * 615 * stdout_fd: The fd representing 'stdout' for the slave side; output 616 * from the zone will arrive here. 617 * 618 * stderr_fd: The fd representing 'stderr' for the slave side; output 619 * from the zone will arrive here. 620 * 621 * raw_mode: If TRUE, then no processing (for example, for '~.') will 622 * be performed on the input coming from STDIN. 623 * 624 * stderr_fd may be specified as -1 if there is no stderr (only non-interactive 625 * mode supplies a stderr). 626 * 627 */ 628 static void 629 doio(int stdin_fd, int stdout_fd, int stderr_fd, boolean_t raw_mode) 630 { 631 struct pollfd pollfds[3]; 632 char ibuf[BUFSIZ]; 633 int cc, ret; 634 635 /* read from stdout of zone and write to stdout of global zone */ 636 pollfds[0].fd = stdout_fd; 637 pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI; 638 639 /* read from stderr of zone and write to stderr of global zone */ 640 pollfds[1].fd = stderr_fd; 641 pollfds[1].events = pollfds[0].events; 642 643 /* read from stdin of global zone and write to stdin of zone */ 644 pollfds[2].fd = STDIN_FILENO; 645 pollfds[2].events = pollfds[0].events; 646 647 for (;;) { 648 pollfds[0].revents = pollfds[1].revents = 649 pollfds[2].revents = 0; 650 651 if (dead) 652 break; 653 654 ret = poll(pollfds, 655 sizeof (pollfds) / sizeof (struct pollfd), -1); 656 if (ret == -1 && errno != EINTR) { 657 perror("poll failed"); 658 break; 659 } 660 661 if (errno == EINTR && dead) { 662 break; 663 } 664 665 /* event from master side stdout */ 666 if (pollfds[0].revents) { 667 if (pollfds[0].revents & 668 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) { 669 cc = read(stdout_fd, ibuf, BUFSIZ); 670 if (cc == -1 && (errno != EINTR || dead)) 671 break; 672 if (cc == 0) /* EOF */ 673 break; 674 (void) write(STDOUT_FILENO, ibuf, cc); 675 } else { 676 pollerr = pollfds[0].revents; 677 break; 678 } 679 } 680 681 /* event from master side stderr */ 682 if (pollfds[1].revents) { 683 if (pollfds[1].revents & 684 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) { 685 cc = read(stderr_fd, ibuf, BUFSIZ); 686 if (cc == -1 && (errno != EINTR || dead)) 687 break; 688 if (cc == 0) /* EOF */ 689 break; 690 (void) write(STDERR_FILENO, ibuf, cc); 691 } else { 692 pollerr = pollfds[1].revents; 693 break; 694 } 695 } 696 697 /* event from user STDIN side */ 698 if (pollfds[2].revents) { 699 if (pollfds[2].revents & 700 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) { 701 cc = read(STDIN_FILENO, ibuf, BUFSIZ); 702 if (cc == -1 && (errno != EINTR || dead)) 703 break; 704 705 /* 706 * stdin fd is stdin of the target; so, 707 * the thing we'll write the user data *to*. 708 * 709 * Also, unlike on the output side, we 710 * propagate zero-length messages to the 711 * other side. 712 */ 713 if (raw_mode == B_TRUE) { 714 if (write(stdin_fd, ibuf, cc) == -1) 715 break; 716 } else { 717 if (process_user_input(stdin_fd, ibuf, 718 cc) == -1) 719 break; 720 } 721 } else if (raw_mode == B_TRUE && 722 pollfds[2].revents & POLLHUP) { 723 /* 724 * It's OK to get a POLLHUP on STDIN-- it 725 * always happens if you do: 726 * 727 * echo foo | zlogin <zone> <command> 728 * 729 * We reset fd to -1 in this case to clear 730 * the condition and write an EOF to the 731 * other side in order to wrap things up. 732 */ 733 pollfds[2].fd = -1; 734 (void) write(stdin_fd, ibuf, 0); 735 } else { 736 pollerr = pollfds[2].revents; 737 break; 738 } 739 } 740 } 741 742 /* 743 * We are in the midst of dying, but try to poll with a short 744 * timeout to see if we can catch the last bit of I/O from the 745 * children. 746 */ 747 pollfds[0].revents = pollfds[1].revents = pollfds[2].revents = 0; 748 (void) poll(pollfds, 749 sizeof (pollfds) / sizeof (struct pollfd), 100); 750 if (pollfds[0].revents & 751 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) { 752 if ((cc = read(stdout_fd, ibuf, BUFSIZ)) > 0) 753 (void) write(STDOUT_FILENO, ibuf, cc); 754 } 755 if (pollfds[1].revents & 756 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) { 757 if ((cc = read(stderr_fd, ibuf, BUFSIZ)) > 0) 758 (void) write(STDERR_FILENO, ibuf, cc); 759 } 760 } 761 762 /* 763 * Prepare argv array for exec'd process; if we're passing commands to the 764 * new process, then use su(1M) to do the invocation. Otherwise, use 765 * 'login -z <from_zonename> -f' (-z is an undocumented option which tells 766 * login that we're coming from another zone, and to disregard its CONSOLE 767 * checks). 768 */ 769 static char ** 770 prep_args(char *login, char **argv) 771 { 772 int argc = 0, a = 0, i, n = -1; 773 char **new_argv; 774 775 if (argv != NULL) { 776 size_t subshell_len = 1; 777 char *subshell; 778 779 while (argv[argc] != NULL) 780 argc++; 781 782 for (i = 0; i < argc; i++) { 783 subshell_len += strlen(argv[i]) + 1; 784 } 785 if ((subshell = calloc(1, subshell_len)) == NULL) 786 return (NULL); 787 788 for (i = 0; i < argc; i++) { 789 (void) strcat(subshell, argv[i]); 790 (void) strcat(subshell, " "); 791 } 792 793 if (failsafe) { 794 n = 4; 795 if ((new_argv = malloc(sizeof (char *) * n)) == NULL) 796 return (NULL); 797 798 new_argv[a++] = FAILSAFESHELL; 799 } else { 800 n = 5; 801 if ((new_argv = malloc(sizeof (char *) * n)) == NULL) 802 return (NULL); 803 804 new_argv[a++] = SUPATH; 805 new_argv[a++] = login; 806 } 807 new_argv[a++] = "-c"; 808 new_argv[a++] = subshell; 809 new_argv[a++] = NULL; 810 assert(a == n); 811 } else { 812 if (failsafe) { 813 n = 2; 814 if ((new_argv = malloc(sizeof (char *) * n)) == NULL) 815 return (NULL); 816 new_argv[a++] = FAILSAFESHELL; 817 new_argv[a++] = NULL; 818 } else { 819 n = 6; 820 821 if ((new_argv = malloc(sizeof (char *) * n)) == NULL) 822 return (NULL); 823 824 new_argv[a++] = LOGINPATH; 825 new_argv[a++] = "-z"; 826 new_argv[a++] = "global"; /* hardcode, for now */ 827 new_argv[a++] = "-f"; 828 new_argv[a++] = login; 829 new_argv[a++] = NULL; 830 } 831 } 832 /* 833 * If this assert ever trips, it's because we've botched the setup 834 * of ARGV above-- it's too large or too small. 835 */ 836 assert(n == a); 837 return (new_argv); 838 } 839 840 /* 841 * Helper routine for prep_env below. 842 */ 843 static char * 844 add_env(char *name, char *value) 845 { 846 size_t sz = strlen(name) + strlen(value) + 2; /* name, =, value, NUL */ 847 char *str; 848 849 if ((str = malloc(sz)) == NULL) 850 return (NULL); 851 852 (void) snprintf(str, sz, "%s=%s", name, value); 853 return (str); 854 } 855 856 /* 857 * Prepare envp array for exec'd process. 858 */ 859 static char ** 860 prep_env() 861 { 862 int e = 0, size = 1; 863 char **new_env, *estr; 864 char *term = getenv("TERM"); 865 866 size++; /* for $PATH */ 867 if (term != NULL) 868 size++; 869 870 /* 871 * In failsafe mode we set $HOME, since '-l' isn't valid in this mode. 872 * We also set $SHELL, since neither login nor su will be around to do 873 * it. 874 */ 875 if (failsafe) 876 size += 2; 877 878 if ((new_env = malloc(sizeof (char *) * size)) == NULL) 879 return (NULL); 880 881 if ((estr = add_env("PATH", DEF_PATH)) == NULL) 882 return (NULL); 883 new_env[e++] = estr; 884 885 if (term != NULL) { 886 if ((estr = add_env("TERM", term)) == NULL) 887 return (NULL); 888 new_env[e++] = estr; 889 } 890 891 if (failsafe) { 892 if ((estr = add_env("HOME", "/")) == NULL) 893 return (NULL); 894 new_env[e++] = estr; 895 896 if ((estr = add_env("SHELL", FAILSAFESHELL)) == NULL) 897 return (NULL); 898 new_env[e++] = estr; 899 } 900 901 new_env[e++] = NULL; 902 903 assert(e == size); 904 905 return (new_env); 906 } 907 908 /* 909 * Finish the preparation of the envp array for exec'd non-interactive 910 * zlogins. This is called in the child process *after* we zone_enter(), since 911 * it derives things we can only know within the zone, such as $HOME, $SHELL, 912 * etc. We need only do this in the non-interactive, mode, since otherwise 913 * login(1) will do it. We don't do this in failsafe mode, since it presents 914 * additional ways in which the command could fail, and we'd prefer to avoid 915 * that. 916 */ 917 static char ** 918 prep_env_noninteractive(char *login, char **env) 919 { 920 size_t size; 921 struct passwd *pw; 922 char **new_env; 923 int e, i; 924 char *estr; 925 char varmail[LOGNAME_MAX + 11]; /* strlen(/var/mail/) = 10, NUL */ 926 927 assert(env != NULL); 928 assert(failsafe == 0); 929 930 /* 931 * Get existing envp size. 932 */ 933 for (size = 0; env[size] != NULL; size++) 934 ; 935 e = size; 936 937 /* 938 * Finish filling out the environment; we duplicate the environment 939 * setup described in login(1), for lack of a better precedent. 940 */ 941 if ((pw = getpwnam(login)) != NULL) { 942 size += 3; /* LOGNAME, HOME, MAIL */ 943 } 944 size++; /* always fill in SHELL */ 945 size++; /* terminating NULL */ 946 947 if ((new_env = malloc(sizeof (char *) * size)) == NULL) 948 goto malloc_fail; 949 950 /* 951 * Copy existing elements of env into new_env. 952 */ 953 for (i = 0; env[i] != NULL; i++) { 954 if ((new_env[i] = strdup(env[i])) == NULL) 955 goto malloc_fail; 956 } 957 assert(e == i); 958 959 if (pw != NULL) { 960 if ((estr = add_env("LOGNAME", pw->pw_name)) == NULL) 961 goto malloc_fail; 962 new_env[e++] = estr; 963 964 if ((estr = add_env("HOME", pw->pw_dir)) == NULL) 965 goto malloc_fail; 966 new_env[e++] = estr; 967 968 if (chdir(pw->pw_dir) != 0) 969 zerror(gettext("Could not chdir to home directory " 970 "%s: %s"), pw->pw_dir, strerror(errno)); 971 972 (void) snprintf(varmail, sizeof (varmail), "/var/mail/%s", 973 pw->pw_name); 974 if ((estr = add_env("MAIL", varmail)) == NULL) 975 goto malloc_fail; 976 new_env[e++] = estr; 977 } 978 979 if (pw != NULL && strlen(pw->pw_shell) > 0) { 980 if ((estr = add_env("SHELL", pw->pw_shell)) == NULL) 981 goto malloc_fail; 982 new_env[e++] = estr; 983 } else { 984 if ((estr = add_env("SHELL", DEFAULTSHELL)) == NULL) 985 goto malloc_fail; 986 new_env[e++] = estr; 987 } 988 989 new_env[e++] = NULL; /* add terminating NULL */ 990 991 assert(e == size); 992 return (new_env); 993 994 malloc_fail: 995 zperror(gettext("failed to allocate memory for process environment")); 996 return (NULL); 997 } 998 999 static int 1000 close_func(void *slavefd, int fd) 1001 { 1002 if (fd != *(int *)slavefd) 1003 (void) close(fd); 1004 return (0); 1005 } 1006 1007 static void 1008 set_cmdchar(char *cmdcharstr) 1009 { 1010 char c; 1011 long lc; 1012 1013 if ((c = *cmdcharstr) != '\\') { 1014 cmdchar = c; 1015 return; 1016 } 1017 1018 c = cmdcharstr[1]; 1019 if (c == '\0' || c == '\\') { 1020 cmdchar = '\\'; 1021 return; 1022 } 1023 1024 if (c < '0' || c > '7') { 1025 zerror(gettext("Unrecognized escape character option %s"), 1026 cmdcharstr); 1027 usage(); 1028 } 1029 1030 lc = strtol(cmdcharstr + 1, NULL, 8); 1031 if (lc < 0 || lc > 255) { 1032 zerror(gettext("Octal escape character '%s' too large"), 1033 cmdcharstr); 1034 usage(); 1035 } 1036 cmdchar = (char)lc; 1037 } 1038 1039 static int 1040 setup_utmpx(char *slavename) 1041 { 1042 struct utmpx ut; 1043 1044 bzero(&ut, sizeof (ut)); 1045 (void) strncpy(ut.ut_user, ".zlogin", sizeof (ut.ut_user)); 1046 (void) strncpy(ut.ut_line, slavename, sizeof (ut.ut_line)); 1047 ut.ut_pid = getpid(); 1048 ut.ut_id[0] = 'z'; 1049 ut.ut_id[1] = ut.ut_id[2] = ut.ut_id[3] = (char)SC_WILDC; 1050 ut.ut_type = LOGIN_PROCESS; 1051 (void) time(&ut.ut_tv.tv_sec); 1052 1053 if (makeutx(&ut) == NULL) { 1054 zerror(gettext("makeutx failed")); 1055 return (-1); 1056 } 1057 return (0); 1058 } 1059 1060 static void 1061 release_lock_file(int lockfd) 1062 { 1063 (void) close(lockfd); 1064 } 1065 1066 static int 1067 grab_lock_file(const char *zone_name, int *lockfd) 1068 { 1069 char pathbuf[PATH_MAX]; 1070 struct flock flock; 1071 1072 if (mkdir(ZONES_TMPDIR, S_IRWXU) < 0 && errno != EEXIST) { 1073 zerror(gettext("could not mkdir %s: %s"), ZONES_TMPDIR, 1074 strerror(errno)); 1075 return (-1); 1076 } 1077 (void) chmod(ZONES_TMPDIR, S_IRWXU); 1078 (void) snprintf(pathbuf, sizeof (pathbuf), "%s/%s.zoneadm.lock", 1079 ZONES_TMPDIR, zone_name); 1080 1081 if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { 1082 zerror(gettext("could not open %s: %s"), pathbuf, 1083 strerror(errno)); 1084 return (-1); 1085 } 1086 /* 1087 * Lock the file to synchronize with other zoneadmds 1088 */ 1089 flock.l_type = F_WRLCK; 1090 flock.l_whence = SEEK_SET; 1091 flock.l_start = (off_t)0; 1092 flock.l_len = (off_t)0; 1093 if (fcntl(*lockfd, F_SETLKW, &flock) < 0) { 1094 zerror(gettext("unable to lock %s: %s"), pathbuf, 1095 strerror(errno)); 1096 release_lock_file(*lockfd); 1097 return (-1); 1098 } 1099 return (Z_OK); 1100 } 1101 1102 static int 1103 start_zoneadmd(const char *zone_name) 1104 { 1105 pid_t retval; 1106 int pstatus = 0, error = -1, lockfd, doorfd; 1107 struct door_info info; 1108 char doorpath[MAXPATHLEN]; 1109 1110 (void) snprintf(doorpath, sizeof (doorpath), ZONE_DOOR_PATH, zone_name); 1111 1112 if (grab_lock_file(zone_name, &lockfd) != Z_OK) 1113 return (-1); 1114 /* 1115 * We must do the door check with the lock held. Otherwise, we 1116 * might race against another zoneadm/zlogin process and wind 1117 * up with two processes trying to start zoneadmd at the same 1118 * time. zoneadmd will detect this, and fail, but we prefer this 1119 * to be as seamless as is practical, from a user perspective. 1120 */ 1121 if ((doorfd = open(doorpath, O_RDONLY)) < 0) { 1122 if (errno != ENOENT) { 1123 zerror("failed to open %s: %s", doorpath, 1124 strerror(errno)); 1125 goto out; 1126 } 1127 } else { 1128 /* 1129 * Seems to be working ok. 1130 */ 1131 if (door_info(doorfd, &info) == 0 && 1132 ((info.di_attributes & DOOR_REVOKED) == 0)) { 1133 error = 0; 1134 goto out; 1135 } 1136 } 1137 1138 if ((child_pid = fork()) == -1) { 1139 zperror(gettext("could not fork")); 1140 goto out; 1141 } else if (child_pid == 0) { 1142 /* child process */ 1143 (void) execl("/usr/lib/zones/zoneadmd", "zoneadmd", "-z", 1144 zone_name, NULL); 1145 zperror(gettext("could not exec zoneadmd")); 1146 _exit(1); 1147 } 1148 1149 /* parent process */ 1150 do { 1151 retval = waitpid(child_pid, &pstatus, 0); 1152 } while (retval != child_pid); 1153 if (WIFSIGNALED(pstatus) || 1154 (WIFEXITED(pstatus) && WEXITSTATUS(pstatus) != 0)) { 1155 zerror(gettext("could not start %s"), "zoneadmd"); 1156 goto out; 1157 } 1158 error = 0; 1159 out: 1160 release_lock_file(lockfd); 1161 (void) close(doorfd); 1162 return (error); 1163 } 1164 1165 static int 1166 init_template(void) 1167 { 1168 int fd; 1169 int err = 0; 1170 1171 fd = open64(CTFS_ROOT "/process/template", O_RDWR); 1172 if (fd == -1) 1173 return (-1); 1174 1175 /* 1176 * zlogin doesn't do anything with the contract. 1177 * Deliver no events, don't inherit, and allow it to be orphaned. 1178 */ 1179 err |= ct_tmpl_set_critical(fd, 0); 1180 err |= ct_tmpl_set_informative(fd, 0); 1181 err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR); 1182 err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT); 1183 if (err || ct_tmpl_activate(fd)) { 1184 (void) close(fd); 1185 return (-1); 1186 } 1187 1188 return (fd); 1189 } 1190 1191 static int 1192 noninteractive_login(char *zonename, zoneid_t zoneid, char *login, 1193 char **new_args, char **new_env) 1194 { 1195 pid_t retval; 1196 int stdin_pipe[2], stdout_pipe[2], stderr_pipe[2]; 1197 int child_status; 1198 int tmpl_fd; 1199 sigset_t block_cld; 1200 1201 if ((tmpl_fd = init_template()) == -1) { 1202 reset_tty(); 1203 zperror(gettext("could not create contract")); 1204 return (1); 1205 } 1206 1207 if (pipe(stdin_pipe) != 0) { 1208 zperror(gettext("could not create STDIN pipe")); 1209 return (1); 1210 } 1211 /* 1212 * When the user types ^D, we get a zero length message on STDIN. 1213 * We need to echo that down the pipe to send it to the other side; 1214 * but by default, pipes don't propagate zero-length messages. We 1215 * toggle that behavior off using I_SWROPT. See streamio(7i). 1216 */ 1217 if (ioctl(stdin_pipe[0], I_SWROPT, SNDZERO) != 0) { 1218 zperror(gettext("could not configure STDIN pipe")); 1219 return (1); 1220 1221 } 1222 if (pipe(stdout_pipe) != 0) { 1223 zperror(gettext("could not create STDOUT pipe")); 1224 return (1); 1225 } 1226 if (pipe(stderr_pipe) != 0) { 1227 zperror(gettext("could not create STDERR pipe")); 1228 return (1); 1229 } 1230 1231 /* 1232 * If any of the pipe FD's winds up being less than STDERR, then we 1233 * have a mess on our hands-- and we are lacking some of the I/O 1234 * streams we would expect anyway. So we bail. 1235 */ 1236 if (stdin_pipe[0] <= STDERR_FILENO || 1237 stdin_pipe[1] <= STDERR_FILENO || 1238 stdout_pipe[0] <= STDERR_FILENO || 1239 stdout_pipe[1] <= STDERR_FILENO || 1240 stderr_pipe[0] <= STDERR_FILENO || 1241 stderr_pipe[1] <= STDERR_FILENO) { 1242 zperror(gettext("process lacks valid STDIN, STDOUT, STDERR")); 1243 return (1); 1244 } 1245 1246 if (prefork_dropprivs() != 0) { 1247 zperror(gettext("could not allocate privilege set")); 1248 return (1); 1249 } 1250 1251 (void) sigset(SIGCLD, sigcld); 1252 (void) sigemptyset(&block_cld); 1253 (void) sigaddset(&block_cld, SIGCLD); 1254 (void) sigprocmask(SIG_BLOCK, &block_cld, NULL); 1255 1256 if ((child_pid = fork()) == -1) { 1257 (void) ct_tmpl_clear(tmpl_fd); 1258 (void) close(tmpl_fd); 1259 zperror(gettext("could not fork")); 1260 return (1); 1261 } else if (child_pid == 0) { /* child process */ 1262 (void) ct_tmpl_clear(tmpl_fd); 1263 1264 /* 1265 * Do a dance to get the pipes hooked up as FD's 0, 1 and 2. 1266 */ 1267 (void) close(STDIN_FILENO); 1268 (void) close(STDOUT_FILENO); 1269 (void) close(STDERR_FILENO); 1270 (void) dup2(stdin_pipe[1], STDIN_FILENO); 1271 (void) dup2(stdout_pipe[1], STDOUT_FILENO); 1272 (void) dup2(stderr_pipe[1], STDERR_FILENO); 1273 (void) closefrom(STDERR_FILENO + 1); 1274 1275 (void) sigset(SIGCLD, SIG_DFL); 1276 (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL); 1277 /* 1278 * In case any of stdin, stdout or stderr are streams, 1279 * anchor them to prevent malicious I_POPs. 1280 */ 1281 (void) ioctl(STDIN_FILENO, I_ANCHOR); 1282 (void) ioctl(STDOUT_FILENO, I_ANCHOR); 1283 (void) ioctl(STDERR_FILENO, I_ANCHOR); 1284 1285 if (zone_enter(zoneid) == -1) { 1286 zerror(gettext("could not enter zone %s: %s"), 1287 zonename, strerror(errno)); 1288 _exit(1); 1289 } 1290 1291 if (!failsafe) 1292 new_env = prep_env_noninteractive(login, new_env); 1293 1294 if (new_env == NULL) { 1295 _exit(1); 1296 } 1297 1298 /* 1299 * Move into a new process group; the zone_enter will have 1300 * placed us into zsched's session, and we want to be in 1301 * a unique process group. 1302 */ 1303 (void) setpgid(getpid(), getpid()); 1304 1305 (void) execve(new_args[0], new_args, new_env); 1306 zperror(gettext("exec failure")); 1307 _exit(1); 1308 } 1309 /* parent */ 1310 (void) sigset(SIGINT, sig_forward); 1311 1312 postfork_dropprivs(); 1313 1314 (void) ct_tmpl_clear(tmpl_fd); 1315 (void) close(tmpl_fd); 1316 1317 (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL); 1318 doio(stdin_pipe[0], stdout_pipe[0], stderr_pipe[0], B_TRUE); 1319 do { 1320 retval = waitpid(child_pid, &child_status, 0); 1321 if (retval == -1) { 1322 child_status = 0; 1323 } 1324 } while (retval != child_pid && errno != ECHILD); 1325 1326 return (WEXITSTATUS(child_status)); 1327 } 1328 1329 int 1330 main(int argc, char **argv) 1331 { 1332 int arg, console = 0; 1333 zoneid_t zoneid; 1334 zone_state_t st; 1335 char *login = "root"; 1336 int lflag = 0; 1337 char *zonename = NULL; 1338 char **proc_args = NULL; 1339 char **new_args, **new_env; 1340 sigset_t block_cld; 1341 char zonepath[MAXPATHLEN]; 1342 char *slavename, slaveshortname[MAXPATHLEN]; 1343 priv_set_t *privset; 1344 int tmpl_fd; 1345 struct stat sb; 1346 char kernzone[ZONENAME_MAX]; 1347 1348 (void) setlocale(LC_ALL, ""); 1349 (void) textdomain(TEXT_DOMAIN); 1350 1351 (void) getpname(argv[0]); 1352 1353 while ((arg = getopt(argc, argv, "ECR:Se:l:")) != EOF) { 1354 switch (arg) { 1355 case 'C': 1356 console = 1; 1357 break; 1358 case 'E': 1359 nocmdchar = 1; 1360 break; 1361 case 'R': /* undocumented */ 1362 if (*optarg != '/') { 1363 zerror(gettext("root path must be absolute.")); 1364 exit(2); 1365 } 1366 if (stat(optarg, &sb) == -1 || !S_ISDIR(sb.st_mode)) { 1367 zerror( 1368 gettext("root path must be a directory.")); 1369 exit(2); 1370 } 1371 zonecfg_set_root(optarg); 1372 break; 1373 case 'S': 1374 failsafe = 1; 1375 break; 1376 case 'e': 1377 set_cmdchar(optarg); 1378 break; 1379 case 'l': 1380 login = optarg; 1381 lflag = 1; 1382 break; 1383 default: 1384 usage(); 1385 } 1386 } 1387 1388 if (console != 0 && lflag != 0) { 1389 zerror(gettext("-l may not be specified for console login")); 1390 usage(); 1391 } 1392 1393 if (console != 0 && failsafe != 0) { 1394 zerror(gettext("-S may not be specified for console login")); 1395 usage(); 1396 } 1397 1398 if (console != 0 && zonecfg_in_alt_root()) { 1399 zerror(gettext("-R may not be specified for console login")); 1400 exit(2); 1401 } 1402 1403 if (failsafe != 0 && lflag != 0) { 1404 zerror(gettext("-l may not be specified for failsafe login")); 1405 usage(); 1406 } 1407 1408 if (optind == (argc - 1)) { 1409 /* 1410 * zone name, no process name; this should be an interactive 1411 * as long as STDIN is really a tty. 1412 */ 1413 if (isatty(STDIN_FILENO)) 1414 interactive = 1; 1415 zonename = argv[optind]; 1416 } else if (optind < (argc - 1)) { 1417 if (console) { 1418 zerror(gettext("Commands may not be specified for " 1419 "console login.")); 1420 usage(); 1421 } 1422 /* zone name and process name, and possibly some args */ 1423 zonename = argv[optind]; 1424 proc_args = &argv[optind + 1]; 1425 interactive = 0; 1426 } else { 1427 usage(); 1428 } 1429 1430 if (getzoneid() != GLOBAL_ZONEID) { 1431 zerror(gettext("'%s' may only be used from the global zone"), 1432 pname); 1433 return (1); 1434 } 1435 1436 if (strcmp(zonename, GLOBAL_ZONENAME) == 0) { 1437 zerror(gettext("'%s' not applicable to the global zone"), 1438 pname); 1439 return (1); 1440 } 1441 1442 if (zone_get_state(zonename, &st) != Z_OK) { 1443 zerror(gettext("zone '%s' unknown"), zonename); 1444 return (1); 1445 } 1446 1447 if (st < ZONE_STATE_INSTALLED) { 1448 zerror(gettext("cannot login to a zone which is '%s'"), 1449 zone_state_str(st)); 1450 return (1); 1451 } 1452 1453 /* 1454 * In both console and non-console cases, we require all privs. 1455 * In the console case, because we may need to startup zoneadmd. 1456 * In the non-console case in order to do zone_enter(2), zonept() 1457 * and other tasks. 1458 * 1459 * Future work: this solution is temporary. Ultimately, we need to 1460 * move to a flexible system which allows the global admin to 1461 * designate that a particular user can zlogin (and probably zlogin 1462 * -C) to a particular zone. This all-root business we have now is 1463 * quite sketchy. 1464 */ 1465 if ((privset = priv_allocset()) == NULL) { 1466 zperror(gettext("priv_allocset failed")); 1467 return (1); 1468 } 1469 1470 if (getppriv(PRIV_EFFECTIVE, privset) != 0) { 1471 zperror(gettext("getppriv failed")); 1472 priv_freeset(privset); 1473 return (1); 1474 } 1475 1476 if (priv_isfullset(privset) == B_FALSE) { 1477 zerror(gettext("You lack sufficient privilege to run " 1478 "this command (all privs required)")); 1479 priv_freeset(privset); 1480 return (1); 1481 } 1482 priv_freeset(privset); 1483 1484 /* 1485 * The console is a separate case from the rest of the code; handle 1486 * it first. 1487 */ 1488 if (console) { 1489 1490 /* 1491 * Ensure that zoneadmd for this zone is running. 1492 */ 1493 if (start_zoneadmd(zonename) == -1) 1494 return (1); 1495 1496 /* 1497 * Make contact with zoneadmd. 1498 */ 1499 if (get_console_master(zonename) == -1) 1500 return (1); 1501 1502 (void) printf(gettext("[Connected to zone '%s' console]\n"), 1503 zonename); 1504 1505 if (set_tty_rawmode(STDIN_FILENO) == -1) { 1506 reset_tty(); 1507 zperror(gettext("failed to set stdin pty to raw mode")); 1508 return (1); 1509 } 1510 1511 (void) sigset(SIGWINCH, sigwinch); 1512 (void) sigwinch(0); 1513 1514 /* 1515 * Run the I/O loop until we get disconnected. 1516 */ 1517 doio(masterfd, masterfd, -1, B_FALSE); 1518 reset_tty(); 1519 (void) printf(gettext("\n[Connection to zone '%s' console " 1520 "closed]\n"), zonename); 1521 1522 return (0); 1523 } 1524 1525 if (st != ZONE_STATE_RUNNING && st != ZONE_STATE_MOUNTED) { 1526 zerror(gettext("login allowed only to running zones " 1527 "(%s is '%s')."), zonename, zone_state_str(st)); 1528 return (1); 1529 } 1530 1531 (void) strlcpy(kernzone, zonename, sizeof (kernzone)); 1532 if (zonecfg_in_alt_root()) { 1533 FILE *fp = zonecfg_open_scratch("", B_FALSE); 1534 1535 if (fp == NULL || zonecfg_find_scratch(fp, zonename, 1536 zonecfg_get_root(), kernzone, sizeof (kernzone)) == -1) { 1537 zerror(gettext("cannot find scratch zone %s"), 1538 zonename); 1539 if (fp != NULL) 1540 zonecfg_close_scratch(fp); 1541 return (1); 1542 } 1543 zonecfg_close_scratch(fp); 1544 } 1545 1546 if ((zoneid = getzoneidbyname(kernzone)) == -1) { 1547 zerror(gettext("failed to get zoneid for zone '%s'"), 1548 zonename); 1549 return (1); 1550 } 1551 1552 /* 1553 * We need the zone path only if we are setting up a pty. 1554 */ 1555 if (zone_get_zonepath(zonename, zonepath, sizeof (zonepath)) == -1) { 1556 zerror(gettext("could not get root path for zone %s"), 1557 zonename); 1558 return (1); 1559 } 1560 1561 if ((new_args = prep_args(login, proc_args)) == NULL) { 1562 zperror(gettext("could not assemble new arguments")); 1563 return (1); 1564 } 1565 1566 if ((new_env = prep_env()) == NULL) { 1567 zperror(gettext("could not assemble new environment")); 1568 return (1); 1569 } 1570 1571 if (!interactive) 1572 return (noninteractive_login(zonename, zoneid, login, new_args, 1573 new_env)); 1574 1575 if (zonecfg_in_alt_root()) { 1576 zerror(gettext("cannot use interactive login with scratch " 1577 "zone")); 1578 return (1); 1579 } 1580 1581 /* 1582 * Things are more complex in interactive mode; we get the 1583 * master side of the pty, then place the user's terminal into 1584 * raw mode. 1585 */ 1586 if (get_master_pty() == -1) { 1587 zerror(gettext("could not setup master pty device")); 1588 return (1); 1589 } 1590 1591 /* 1592 * Compute the "short name" of the pts. /dev/pts/2 --> pts/2 1593 */ 1594 if ((slavename = ptsname(masterfd)) == NULL) { 1595 zperror(gettext("failed to get name for pseudo-tty")); 1596 return (1); 1597 } 1598 if (strncmp(slavename, "/dev/", strlen("/dev/")) == 0) 1599 (void) strlcpy(slaveshortname, slavename + strlen("/dev/"), 1600 sizeof (slaveshortname)); 1601 else 1602 (void) strlcpy(slaveshortname, slavename, 1603 sizeof (slaveshortname)); 1604 1605 (void) printf(gettext("[Connected to zone '%s' %s]\n"), zonename, 1606 slaveshortname); 1607 1608 if (set_tty_rawmode(STDIN_FILENO) == -1) { 1609 reset_tty(); 1610 zperror(gettext("failed to set stdin pty to raw mode")); 1611 return (1); 1612 } 1613 1614 if (prefork_dropprivs() != 0) { 1615 reset_tty(); 1616 zperror(gettext("could not allocate privilege set")); 1617 return (1); 1618 } 1619 1620 /* 1621 * We must mask SIGCLD until after we have coped with the fork 1622 * sufficiently to deal with it; otherwise we can race and receive the 1623 * signal before child_pid has been initialized (yes, this really 1624 * happens). 1625 */ 1626 (void) sigset(SIGCLD, sigcld); 1627 (void) sigemptyset(&block_cld); 1628 (void) sigaddset(&block_cld, SIGCLD); 1629 (void) sigprocmask(SIG_BLOCK, &block_cld, NULL); 1630 1631 /* 1632 * We activate the contract template at the last minute to 1633 * avoid intermediate functions that could be using fork(2) 1634 * internally. 1635 */ 1636 if ((tmpl_fd = init_template()) == -1) { 1637 reset_tty(); 1638 zperror(gettext("could not create contract")); 1639 return (1); 1640 } 1641 1642 if ((child_pid = fork()) == -1) { 1643 (void) ct_tmpl_clear(tmpl_fd); 1644 reset_tty(); 1645 zperror(gettext("could not fork")); 1646 return (1); 1647 } else if (child_pid == 0) { /* child process */ 1648 int slavefd, newslave; 1649 1650 (void) ct_tmpl_clear(tmpl_fd); 1651 (void) close(tmpl_fd); 1652 1653 (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL); 1654 1655 if ((slavefd = init_slave_pty(zoneid, zonepath)) == -1) 1656 return (1); 1657 1658 /* 1659 * Close all fds except for the slave pty. 1660 */ 1661 (void) fdwalk(close_func, &slavefd); 1662 1663 /* 1664 * Temporarily dup slavefd to stderr; that way if we have 1665 * to print out that zone_enter failed, the output will 1666 * have somewhere to go. 1667 */ 1668 if (slavefd != STDERR_FILENO) 1669 (void) dup2(slavefd, STDERR_FILENO); 1670 1671 if (zone_enter(zoneid) == -1) { 1672 zerror(gettext("could not enter zone %s: %s"), 1673 zonename, strerror(errno)); 1674 return (1); 1675 } 1676 1677 if (slavefd != STDERR_FILENO) 1678 (void) close(STDERR_FILENO); 1679 1680 /* 1681 * We take pains to get this process into a new process 1682 * group, and subsequently a new session. In this way, 1683 * we'll have a session which doesn't yet have a controlling 1684 * terminal. When we open the slave, it will become the 1685 * controlling terminal; no PIDs concerning pgrps or sids 1686 * will leak inappropriately into the zone. 1687 */ 1688 (void) setpgrp(); 1689 1690 /* 1691 * We need the slave pty to be referenced from the zone's 1692 * /dev in order to ensure that the devt's, etc are all 1693 * correct. Otherwise we break ttyname and the like. 1694 */ 1695 if ((newslave = open(slavename, O_RDWR)) == -1) { 1696 (void) close(slavefd); 1697 return (1); 1698 } 1699 (void) close(slavefd); 1700 slavefd = newslave; 1701 1702 /* 1703 * dup the slave to the various FDs, so that when the 1704 * spawned process does a write/read it maps to the slave 1705 * pty. 1706 */ 1707 (void) dup2(slavefd, STDIN_FILENO); 1708 (void) dup2(slavefd, STDOUT_FILENO); 1709 (void) dup2(slavefd, STDERR_FILENO); 1710 if (slavefd != STDIN_FILENO && slavefd != STDOUT_FILENO && 1711 slavefd != STDERR_FILENO) { 1712 (void) close(slavefd); 1713 } 1714 1715 /* 1716 * In failsafe mode, we don't use login(1), so don't try 1717 * setting up a utmpx entry. 1718 */ 1719 if (!failsafe) { 1720 if (setup_utmpx(slaveshortname) == -1) 1721 return (1); 1722 } 1723 1724 (void) execve(new_args[0], new_args, new_env); 1725 zperror(gettext("exec failure")); 1726 return (1); 1727 } 1728 (void) ct_tmpl_clear(tmpl_fd); 1729 (void) close(tmpl_fd); 1730 1731 /* 1732 * The rest is only for the parent process. 1733 */ 1734 (void) sigset(SIGWINCH, sigwinch); 1735 1736 postfork_dropprivs(); 1737 1738 (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL); 1739 doio(masterfd, masterfd, -1, B_FALSE); 1740 1741 reset_tty(); 1742 (void) fprintf(stderr, 1743 gettext("\n[Connection to zone '%s' %s closed]\n"), zonename, 1744 slaveshortname); 1745 1746 if (pollerr != 0) { 1747 (void) fprintf(stderr, gettext("Error: connection closed due " 1748 "to unexpected pollevents=0x%x.\n"), pollerr); 1749 return (1); 1750 } 1751 1752 return (0); 1753 } 1754