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