Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/zlogin/zlogin.c
          +++ new/usr/src/cmd/zlogin/zlogin.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  
    | 
      ↓ open down ↓ | 
    14 lines elided | 
    
      ↑ open up ↑ | 
  
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright 2013 DEY Storage Systems, Inc.
  24   24   * Copyright (c) 2014 Gary Mills
  25      - * Copyright 2016 Joyent, Inc.
  26   25   * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
       26 + * Copyright 2016 Joyent, Inc.
  27   27   */
  28   28  
  29   29  /*
  30   30   * zlogin provides five types of login which allow users in the global
  31   31   * zone to access non-global zones.
  32   32   *
  33   33   * - "interactive login" is similar to rlogin(1); for example, the user could
  34   34   *   issue 'zlogin my-zone' or 'zlogin -e ^ -l me my-zone'.   The user is
  35   35   *   granted a new pty (which is then shoved into the zone), and an I/O
  36   36   *   loop between parent and child processes takes care of the interactive
  37   37   *   session.  In this mode, login(1) (and its -c option, which means
  38   38   *   "already authenticated") is employed to take care of the initialization
  39   39   *   of the user's session.
  40   40   *
  41   41   * - "non-interactive login" is similar to su(1M); the user could issue
  42   42   *   'zlogin my-zone ls -l' and the command would be run as specified.
  43   43   *   In this mode, zlogin sets up pipes as the communication channel, and
  44   44   *   'su' is used to do the login setup work.
  45   45   *
  46   46   * - "interactive command" is a combination of the above two modes where
  47   47   *   a command is provide like the non-interactive case, but the -i option is
  48   48   *   also provided to make things interactive. For example, the user could
  49   49   *   issue 'zlogin -i my-zone /bin/sh'. In this mode neither 'login -c' nor
  50   50   *   'su root -c' is prepended to the command invocation. Because of this
  51   51   *   there will be no wtmpx login record within the zone.
  52   52   *
  53   53   * - "console login" is the equivalent to accessing the tip line for a
  54   54   *   zone.  For example, the user can issue 'zlogin -C my-zone'.
  55   55   *   In this mode, zlogin contacts the zoneadmd process via unix domain
  56   56   *   socket.  If zoneadmd is not running, it starts it.  This allows the
  57   57   *   console to be available anytime the zone is installed, regardless of
  58   58   *   whether it is running.
  59   59   *
  60   60   * - "standalone-processs interactive" is specified with -I and connects to
  61   61   *   the zone's stdin, stdout and stderr zfd(7D) devices.
  62   62   */
  63   63  
  64   64  #include <sys/socket.h>
  65   65  #include <sys/termios.h>
  66   66  #include <sys/utsname.h>
  67   67  #include <sys/stat.h>
  68   68  #include <sys/types.h>
  69   69  #include <sys/contract/process.h>
  70   70  #include <sys/ctfs.h>
  71   71  #include <sys/brand.h>
  72   72  #include <sys/wait.h>
  73   73  #include <alloca.h>
  74   74  #include <assert.h>
  75   75  #include <ctype.h>
  76   76  #include <paths.h>
  77   77  #include <door.h>
  78   78  #include <errno.h>
  79   79  #include <nss_dbdefs.h>
  80   80  #include <poll.h>
  81   81  #include <priv.h>
  82   82  #include <pwd.h>
  83   83  #include <unistd.h>
  84   84  #include <utmpx.h>
  85   85  #include <sac.h>
  86   86  #include <signal.h>
  87   87  #include <stdarg.h>
  88   88  #include <stdio.h>
  89   89  #include <stdlib.h>
  90   90  #include <string.h>
  91   91  #include <strings.h>
  92   92  #include <stropts.h>
  93   93  #include <wait.h>
  94   94  #include <zone.h>
  95   95  #include <fcntl.h>
  96   96  #include <libdevinfo.h>
  97   97  #include <libintl.h>
  98   98  #include <locale.h>
  99   99  #include <libzonecfg.h>
 100  100  #include <libcontract.h>
 101  101  #include <libbrand.h>
 102  102  #include <auth_list.h>
 103  103  #include <auth_attr.h>
 104  104  #include <secdb.h>
 105  105  
 106  106  static int masterfd = -1;
 107  107  static int ctlfd = -1;
 108  108  static struct termios save_termios;
 109  109  static struct termios effective_termios;
 110  110  static int save_fd;
 111  111  static struct winsize winsize;
 112  112  static volatile int dead;
 113  113  static volatile pid_t child_pid = -1;
 114  114  static int interactive = 0;
 115  115  static priv_set_t *dropprivs;
 116  116  static unsigned int connect_flags = 0;
 117  117  
 118  118  static int nocmdchar = 0;
 119  119  static int failsafe = 0;
 120  120  static char cmdchar = '~';
 121  121  static int quiet = 0;
 122  122  static char zonebrand[MAXNAMELEN];
 123  123  
 124  124  static int pollerr = 0;
 125  125  
 126  126  static const char *pname;
 127  127  static char *username;
 128  128  
 129  129  /*
 130  130   * When forced_login is true, the user is not prompted
 131  131   * for an authentication password in the target zone.
 132  132   */
 133  133  static boolean_t forced_login = B_FALSE;
 134  134  
 135  135  #if !defined(TEXT_DOMAIN)               /* should be defined by cc -D */
 136  136  #define TEXT_DOMAIN     "SYS_TEST"      /* Use this only if it wasn't */
 137  137  #endif
 138  138  
 139  139  #define SUPATH1 "/usr/bin/su"
 140  140  #define SUPATH2 "/bin/su"
 141  141  #define FAILSAFESHELL   "/sbin/sh"
 142  142  #define DEFAULTSHELL    "/sbin/sh"
 143  143  #define DEF_PATH        "/usr/sbin:/usr/bin"
 144  144  #define LX_DEF_PATH     "/bin:/usr/sbin:/usr/bin"
 145  145  
 146  146  #define MAX_RETRY       30
 147  147  
 148  148  #define CLUSTER_BRAND_NAME      "cluster"
 149  149  
 150  150  /*
 151  151   * The ZLOGIN_BUFSIZ is larger than PIPE_BUF so we can be sure we're clearing
 152  152   * out the pipe when the child is exiting.  The ZLOGIN_RDBUFSIZ must be less
 153  153   * than ZLOGIN_BUFSIZ (because we share the buffer in doio).  This value is
 154  154   * also chosen in conjunction with the HI_WATER setting to make sure we
 155  155   * don't fill up the pipe.  We can write FIFOHIWAT (16k) into the pipe before
 156  156   * blocking.  By having ZLOGIN_RDBUFSIZ set to 1k and HI_WATER set to 8k, we
 157  157   * know we can always write a ZLOGIN_RDBUFSIZ chunk into the pipe when there
 158  158   * is less than HI_WATER data already in the pipe.
 159  159   */
 160  160  #define ZLOGIN_BUFSIZ   8192
 161  161  #define ZLOGIN_RDBUFSIZ 1024
 162  162  #define HI_WATER        8192
 163  163  
 164  164  /*
 165  165   * See canonify() below.  CANONIFY_LEN is the maximum length that a
 166  166   * "canonical" sequence will expand to (backslash, three octal digits, NUL).
 167  167   */
 168  168  #define CANONIFY_LEN 5
 169  169  
 170  170  static void
 171  171  usage(void)
 172  172  {
 173  173          (void) fprintf(stderr, gettext("usage: %s [-dinCEINQS] [-e cmdchar] "
 174  174              "[-l user] zonename [command [args ...] ]\n"), pname);
 175  175          exit(2);
 176  176  }
 177  177  
 178  178  static const char *
 179  179  getpname(const char *arg0)
 180  180  {
 181  181          const char *p = strrchr(arg0, '/');
 182  182  
 183  183          if (p == NULL)
 184  184                  p = arg0;
 185  185          else
 186  186                  p++;
 187  187  
 188  188          pname = p;
 189  189          return (p);
 190  190  }
 191  191  
 192  192  static void
 193  193  zerror(const char *fmt, ...)
 194  194  {
 195  195          va_list alist;
 196  196  
 197  197          (void) fprintf(stderr, "%s: ", pname);
 198  198          va_start(alist, fmt);
 199  199          (void) vfprintf(stderr, fmt, alist);
 200  200          va_end(alist);
 201  201          (void) fprintf(stderr, "\n");
 202  202  }
 203  203  
 204  204  static void
 205  205  zperror(const char *str)
 206  206  {
 207  207          const char *estr;
 208  208  
 209  209          if ((estr = strerror(errno)) != NULL)
 210  210                  (void) fprintf(stderr, "%s: %s: %s\n", pname, str, estr);
 211  211          else
 212  212                  (void) fprintf(stderr, "%s: %s: errno %d\n", pname, str, errno);
 213  213  }
 214  214  
 215  215  /*
 216  216   * The first part of our privilege dropping scheme needs to be called before
 217  217   * fork(), since we must have it for security; we don't want to be surprised
 218  218   * later that we couldn't allocate the privset.
 219  219   */
 220  220  static int
 221  221  prefork_dropprivs()
 222  222  {
 223  223          if ((dropprivs = priv_allocset()) == NULL)
 224  224                  return (1);
 225  225  
 226  226          priv_basicset(dropprivs);
 227  227          (void) priv_delset(dropprivs, PRIV_PROC_INFO);
 228  228          (void) priv_delset(dropprivs, PRIV_PROC_FORK);
 229  229          (void) priv_delset(dropprivs, PRIV_PROC_EXEC);
 230  230          (void) priv_delset(dropprivs, PRIV_FILE_LINK_ANY);
 231  231  
 232  232          /*
 233  233           * We need to keep the basic privilege PROC_SESSION and all unknown
 234  234           * basic privileges as well as the privileges PROC_ZONE and
 235  235           * PROC_OWNER in order to query session information and
 236  236           * send signals.
 237  237           */
 238  238          if (interactive == 0) {
 239  239                  (void) priv_addset(dropprivs, PRIV_PROC_ZONE);
 240  240                  (void) priv_addset(dropprivs, PRIV_PROC_OWNER);
 241  241          } else {
 242  242                  (void) priv_delset(dropprivs, PRIV_PROC_SESSION);
 243  243          }
 244  244  
 245  245          return (0);
 246  246  }
 247  247  
 248  248  /*
 249  249   * The second part of the privilege drop.  We are paranoid about being attacked
 250  250   * by the zone, so we drop all privileges.  This should prevent a compromise
 251  251   * which gets us to fork(), exec(), symlink(), etc.
 252  252   */
 253  253  static void
 254  254  postfork_dropprivs()
 255  255  {
 256  256          if ((setppriv(PRIV_SET, PRIV_PERMITTED, dropprivs)) == -1) {
 257  257                  zperror(gettext("Warning: could not set permitted privileges"));
 258  258          }
 259  259          if ((setppriv(PRIV_SET, PRIV_LIMIT, dropprivs)) == -1) {
 260  260                  zperror(gettext("Warning: could not set limit privileges"));
 261  261          }
 262  262          if ((setppriv(PRIV_SET, PRIV_INHERITABLE, dropprivs)) == -1) {
 263  263                  zperror(gettext("Warning: could not set inheritable "
 264  264                      "privileges"));
 265  265          }
 266  266  }
 267  267  
 268  268  static int
 269  269  connect_zone_sock(const char *zname, const char *suffix, boolean_t verbose)
 270  270  {
 271  271          int sockfd = -1;
 272  272          struct sockaddr_un servaddr;
 273  273  
 274  274          if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
 275  275                  if (verbose)
 276  276                          zperror(gettext("could not create socket"));
 277  277                  return (-1);
  
    | 
      ↓ open down ↓ | 
    241 lines elided | 
    
      ↑ open up ↑ | 
  
 278  278          }
 279  279  
 280  280          bzero(&servaddr, sizeof (servaddr));
 281  281          servaddr.sun_family = AF_UNIX;
 282  282          (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
 283  283              "%s/%s.%s", ZONES_TMPDIR, zname, suffix);
 284  284          if (connect(sockfd, (struct sockaddr *)&servaddr,
 285  285              sizeof (servaddr)) == -1) {
 286  286                  if (verbose)
 287  287                          zperror(gettext("Could not connect to zone"));
 288      -                close(sockfd);
      288 +                (void) close(sockfd);
 289  289                  return (-1);
 290  290          }
 291  291          return (sockfd);
 292  292  }
 293  293  
 294  294  
 295  295  static int
 296  296  handshake_zone_sock(int sockfd, unsigned int flags)
 297  297  {
 298  298          char clientid[MAXPATHLEN];
 299  299          char handshake[MAXPATHLEN], c;
 300  300          int msglen;
 301  301          int i = 0, err = 0;
 302  302  
 303  303          msglen = snprintf(clientid, sizeof (clientid), "IDENT %s %u\n",
 304  304              setlocale(LC_MESSAGES, NULL), flags);
 305  305  
 306  306          if (msglen >= sizeof (clientid) || msglen < 0) {
 307  307                  zerror("protocol error");
 308  308                  return (-1);
 309  309          }
 310  310  
 311  311          if (write(sockfd, clientid, msglen) != msglen) {
 312  312                  zerror("protocol error");
 313  313                  return (-1);
 314  314          }
 315  315  
 316  316          /*
 317  317           * Take care not to accumulate more than our fill, and leave room for
 318  318           * the NUL at the end.
 319  319           */
 320  320          bzero(handshake, sizeof (handshake));
 321  321          while ((err = read(sockfd, &c, 1)) == 1) {
 322  322                  if (i >= (sizeof (handshake) - 1))
 323  323                          break;
 324  324                  if (c == '\n')
 325  325                          break;
 326  326                  handshake[i] = c;
 327  327                  i++;
 328  328          }
 329  329  
 330  330          /*
 331  331           * If something went wrong during the handshake we bail.
 332  332           * Perhaps the server died off.
 333  333           */
 334  334          if (err == -1) {
 335  335                  zperror(gettext("Could not connect to zone"));
 336  336                  return (-1);
 337  337          }
 338  338  
 339  339          if (strncmp(handshake, "OK", sizeof (handshake)) != 0) {
 340  340                  zerror(gettext("Zone is already in use by process ID %s."),
 341  341                      handshake);
 342  342                  return (-1);
 343  343          }
 344  344  
 345  345          return (0);
 346  346  }
 347  347  
 348  348  static int
 349  349  send_ctl_sock(const char *buf, size_t len)
 350  350  {
 351  351          char rbuf[BUFSIZ];
 352  352          int i;
 353  353          if (ctlfd == -1) {
 354  354                  return (-1);
 355  355          }
 356  356          if (write(ctlfd, buf, len) != len) {
 357  357                  return (-1);
 358  358          }
 359  359          /* read the response */
 360  360          for (i = 0; i < (BUFSIZ - 1); i++) {
 361  361                  char c;
 362  362                  if (read(ctlfd, &c, 1) != 1 || c == '\n' || c == '\0') {
 363  363                          break;
 364  364                  }
 365  365                  rbuf[i] = c;
 366  366          }
 367  367          rbuf[i+1] = '\0';
 368  368          if (strncmp("OK", rbuf, BUFSIZ) != 0) {
 369  369                  return (-1);
 370  370          }
 371  371          return (0);
 372  372  }
 373  373  /*
 374  374   * Routines to handle pty creation upon zone entry and to shuttle I/O back
 375  375   * and forth between the two terminals.  We also compute and store the
 376  376   * name of the slave terminal associated with the master side.
 377  377   */
 378  378  static int
 379  379  get_master_pty()
 380  380  {
 381  381          if ((masterfd = open("/dev/ptmx", O_RDWR|O_NONBLOCK)) < 0) {
 382  382                  zperror(gettext("failed to obtain a pseudo-tty"));
 383  383                  return (-1);
 384  384          }
 385  385          if (tcgetattr(STDIN_FILENO, &save_termios) == -1) {
 386  386                  zperror(gettext("failed to get terminal settings from stdin"));
 387  387                  return (-1);
 388  388          }
 389  389          (void) ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&winsize);
 390  390  
 391  391          return (0);
 392  392  }
 393  393  
 394  394  /*
 395  395   * This is a bit tricky; normally a pts device will belong to the zone it
 396  396   * is granted to.  But in the case of "entering" a zone, we need to establish
 397  397   * the pty before entering the zone so that we can vector I/O to and from it
 398  398   * from the global zone.
 399  399   *
 400  400   * We use the zonept() call to let the ptm driver know what we are up to;
 401  401   * the only other hairy bit is the setting of zoneslavename (which happens
 402  402   * above, in get_master_pty()).
 403  403   */
 404  404  static int
 405  405  init_slave_pty(zoneid_t zoneid, char *devroot)
 406  406  {
 407  407          int slavefd = -1;
 408  408          char *slavename, zoneslavename[MAXPATHLEN];
 409  409  
 410  410          /*
 411  411           * Set slave permissions, zone the pts, then unlock it.
 412  412           */
 413  413          if (grantpt(masterfd) != 0) {
 414  414                  zperror(gettext("grantpt failed"));
 415  415                  return (-1);
 416  416          }
 417  417  
 418  418          if (unlockpt(masterfd) != 0) {
 419  419                  zperror(gettext("unlockpt failed"));
 420  420                  return (-1);
 421  421          }
 422  422  
 423  423          /*
 424  424           * We must open the slave side before zoning this pty; otherwise
 425  425           * the kernel would refuse us the open-- zoning a pty makes it
 426  426           * inaccessible to the global zone.  Note we are trying to open
 427  427           * the device node via the $ZONEROOT/dev path for this pty.
 428  428           *
 429  429           * Later we'll close the slave out when once we've opened it again
 430  430           * from within the target zone.  Blarg.
 431  431           */
 432  432          if ((slavename = ptsname(masterfd)) == NULL) {
 433  433                  zperror(gettext("failed to get name for pseudo-tty"));
 434  434                  return (-1);
 435  435          }
 436  436  
 437  437          (void) snprintf(zoneslavename, sizeof (zoneslavename), "%s%s",
 438  438              devroot, slavename);
 439  439  
 440  440          if ((slavefd = open(zoneslavename, O_RDWR)) < 0) {
 441  441                  zerror(gettext("failed to open %s: %s"), zoneslavename,
 442  442                      strerror(errno));
 443  443                  return (-1);
 444  444          }
 445  445  
 446  446          /*
 447  447           * Push hardware emulation (ptem), line discipline (ldterm),
 448  448           * and V7/4BSD/Xenix compatibility (ttcompat) modules.
 449  449           */
 450  450          if (ioctl(slavefd, I_PUSH, "ptem") == -1) {
 451  451                  zperror(gettext("failed to push ptem module"));
 452  452                  if (!failsafe)
 453  453                          goto bad;
 454  454          }
 455  455  
 456  456          /*
 457  457           * Anchor the stream to prevent malicious I_POPs; we prefer to do
 458  458           * this prior to entering the zone so that we can detect any errors
 459  459           * early, and so that we can set the anchor from the global zone.
 460  460           */
 461  461          if (ioctl(slavefd, I_ANCHOR) == -1) {
 462  462                  zperror(gettext("failed to set stream anchor"));
 463  463                  if (!failsafe)
 464  464                          goto bad;
 465  465          }
 466  466  
 467  467          if (ioctl(slavefd, I_PUSH, "ldterm") == -1) {
 468  468                  zperror(gettext("failed to push ldterm module"));
 469  469                  if (!failsafe)
 470  470                          goto bad;
 471  471          }
 472  472          if (ioctl(slavefd, I_PUSH, "ttcompat") == -1) {
 473  473                  zperror(gettext("failed to push ttcompat module"));
 474  474                  if (!failsafe)
 475  475                          goto bad;
 476  476          }
 477  477  
 478  478          /*
 479  479           * Propagate terminal settings from the external term to the new one.
 480  480           */
 481  481          if (tcsetattr(slavefd, TCSAFLUSH, &save_termios) == -1) {
 482  482                  zperror(gettext("failed to set terminal settings"));
 483  483                  if (!failsafe)
 484  484                          goto bad;
 485  485          }
 486  486          (void) ioctl(slavefd, TIOCSWINSZ, (char *)&winsize);
 487  487  
 488  488          if (zonept(masterfd, zoneid) != 0) {
 489  489                  zperror(gettext("could not set zoneid of pty"));
 490  490                  goto bad;
 491  491          }
 492  492  
 493  493          return (slavefd);
 494  494  
 495  495  bad:
 496  496          (void) close(slavefd);
 497  497          return (-1);
 498  498  }
 499  499  
 500  500  /*
 501  501   * Place terminal into raw mode.
 502  502   */
 503  503  static int
 504  504  set_tty_rawmode(int fd)
 505  505  {
 506  506          struct termios term;
 507  507          if (tcgetattr(fd, &term) < 0) {
 508  508                  zperror(gettext("failed to get user terminal settings"));
 509  509                  return (-1);
 510  510          }
 511  511  
 512  512          /* Stash for later, so we can revert back to previous mode */
 513  513          save_termios = term;
 514  514          save_fd = fd;
 515  515  
 516  516          /* disable 8->7 bit strip, start/stop, enable any char to restart */
 517  517          term.c_iflag &= ~(ISTRIP|IXON|IXANY);
 518  518          /* disable NL->CR, CR->NL, ignore CR, UPPER->lower */
 519  519          term.c_iflag &= ~(INLCR|ICRNL|IGNCR|IUCLC);
 520  520          /* disable output post-processing */
 521  521          term.c_oflag &= ~OPOST;
 522  522          /* disable canonical mode, signal chars, echo & extended functions */
 523  523          term.c_lflag &= ~(ICANON|ISIG|ECHO|IEXTEN);
 524  524  
 525  525          term.c_cc[VMIN] = 1;    /* byte-at-a-time */
 526  526          term.c_cc[VTIME] = 0;
 527  527  
 528  528          if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)) {
 529  529                  zperror(gettext("failed to set user terminal to raw mode"));
 530  530                  return (-1);
 531  531          }
 532  532  
 533  533          /*
 534  534           * We need to know the value of VEOF so that we can properly process for
 535  535           * client-side ~<EOF>.  But we have obliterated VEOF in term,
 536  536           * because VMIN overloads the same array slot in non-canonical mode.
 537  537           * Stupid @&^%!
 538  538           *
 539  539           * So here we construct the "effective" termios from the current
 540  540           * terminal settings, and the corrected VEOF and VEOL settings.
 541  541           */
 542  542          if (tcgetattr(STDIN_FILENO, &effective_termios) < 0) {
 543  543                  zperror(gettext("failed to get user terminal settings"));
 544  544                  return (-1);
 545  545          }
 546  546          effective_termios.c_cc[VEOF] = save_termios.c_cc[VEOF];
 547  547          effective_termios.c_cc[VEOL] = save_termios.c_cc[VEOL];
 548  548  
 549  549          return (0);
 550  550  }
 551  551  
 552  552  /*
 553  553   * Copy terminal window size from our terminal to the pts.
  
    | 
      ↓ open down ↓ | 
    255 lines elided | 
    
      ↑ open up ↑ | 
  
 554  554   */
 555  555  /*ARGSUSED*/
 556  556  static void
 557  557  sigwinch(int s)
 558  558  {
 559  559          struct winsize ws;
 560  560  
 561  561          if (ioctl(0, TIOCGWINSZ, &ws) == 0) {
 562  562                  if (ctlfd != -1) {
 563  563                          char buf[BUFSIZ];
 564      -                        snprintf(buf, sizeof (buf), "TIOCSWINSZ %hu %hu\n",
 565      -                            ws.ws_row, ws.ws_col);
      564 +                        (void) snprintf(buf, sizeof (buf),
      565 +                            "TIOCSWINSZ %hu %hu\n", ws.ws_row, ws.ws_col);
 566  566                          (void) send_ctl_sock(buf, strlen(buf));
 567  567                  } else {
 568  568                          (void) ioctl(masterfd, TIOCSWINSZ, &ws);
 569  569                  }
 570  570          }
 571  571  }
 572  572  
 573  573  /*
 574  574   * Toggle zfd EOF mode and notify zoneadmd
 575  575   */
 576  576  /*ARGSUSED*/
 577  577  static void
 578  578  sigusr1(int s)
 579  579  {
 580  580          connect_flags ^= ZLOGIN_ZFD_EOF;
 581  581          if (ctlfd != -1) {
 582  582                  char buf[BUFSIZ];
 583      -                snprintf(buf, sizeof (buf), "SETFLAGS %u\n",
      583 +                (void) snprintf(buf, sizeof (buf), "SETFLAGS %u\n",
 584  584                      connect_flags);
 585  585                  (void) send_ctl_sock(buf, strlen(buf));
 586  586          }
 587  587  }
 588  588  
 589  589  static volatile int close_on_sig = -1;
 590  590  
 591  591  static void
 592  592  /*ARGSUSED*/
 593  593  sigcld(int s)
 594  594  {
 595  595          int status;
 596  596          pid_t pid;
 597  597  
 598  598          /*
 599  599           * Peek at the exit status.  If this isn't the process we cared
 600  600           * about, then just reap it.
 601  601           */
 602  602          if ((pid = waitpid(child_pid, &status, WNOHANG|WNOWAIT)) != -1) {
 603  603                  if (pid == child_pid &&
 604  604                      (WIFEXITED(status) || WIFSIGNALED(status))) {
 605  605                          dead = 1;
 606  606                          if (close_on_sig != -1) {
 607  607                                  (void) write(close_on_sig, "a", 1);
 608  608                                  (void) close(close_on_sig);
 609  609                                  close_on_sig = -1;
 610  610                          }
 611  611                  } else {
 612  612                          (void) waitpid(pid, &status, WNOHANG);
 613  613                  }
 614  614          }
 615  615  }
 616  616  
 617  617  /*
 618  618   * Some signals (currently, SIGINT) must be forwarded on to the process
 619  619   * group of the child process.
 620  620   */
 621  621  static void
 622  622  sig_forward(int s)
 623  623  {
 624  624          if (child_pid != -1) {
 625  625                  (void) sigsend(P_PGID, child_pid, s);
 626  626          }
 627  627  }
 628  628  
 629  629  /*
 630  630   * reset terminal settings for global environment
 631  631   */
 632  632  static void
 633  633  reset_tty()
 634  634  {
 635  635          (void) tcsetattr(save_fd, TCSADRAIN, &save_termios);
 636  636  }
 637  637  
 638  638  /*
 639  639   * Convert character to printable representation, for display with locally
 640  640   * echoed command characters (like when we need to display ~^D)
 641  641   */
 642  642  static void
 643  643  canonify(char c, char *cc)
 644  644  {
 645  645          if (isprint(c)) {
 646  646                  cc[0] = c;
 647  647                  cc[1] = '\0';
 648  648          } else if (c >= 0 && c <= 31) { /* ^@ through ^_ */
 649  649                  cc[0] = '^';
 650  650                  cc[1] = c + '@';
 651  651                  cc[2] = '\0';
 652  652          } else {
 653  653                  cc[0] = '\\';
 654  654                  cc[1] = ((c >> 6) & 7) + '0';
 655  655                  cc[2] = ((c >> 3) & 7) + '0';
 656  656                  cc[3] = (c & 7) + '0';
 657  657                  cc[4] = '\0';
 658  658          }
 659  659  }
 660  660  
 661  661  /*
 662  662   * process_user_input watches the input stream for the escape sequence for
 663  663   * 'quit' (by default, tilde-period).  Because we might be fed just one
 664  664   * keystroke at a time, state associated with the user input (are we at the
 665  665   * beginning of the line?  are we locally echoing the next character?) is
 666  666   * maintained by beginning_of_line and local_echo across calls to the routine.
 667  667   * If the write to outfd fails, we'll try to read from infd in an attempt
 668  668   * to prevent deadlock between the two processes.
 669  669   *
 670  670   * This routine returns -1 when the 'quit' escape sequence has been issued,
 671  671   * or an error is encountered, 1 if stdin is EOF, and 0 otherwise.
 672  672   */
 673  673  static int
 674  674  process_user_input(int outfd, int infd)
 675  675  {
 676  676          static boolean_t beginning_of_line = B_TRUE;
 677  677          static boolean_t local_echo = B_FALSE;
 678  678          char ibuf[ZLOGIN_BUFSIZ];
 679  679          int nbytes;
 680  680          char *buf = ibuf;
 681  681          char c = *buf;
 682  682  
 683  683          nbytes = read(STDIN_FILENO, ibuf, ZLOGIN_RDBUFSIZ);
 684  684          if (nbytes == -1 && (errno != EINTR || dead))
 685  685                  return (-1);
 686  686  
 687  687          if (nbytes == -1)       /* The read was interrupted. */
 688  688                  return (0);
 689  689  
 690  690          /* 0 read means EOF, close the pipe to the child */
 691  691          if (nbytes == 0)
 692  692                  return (1);
 693  693  
 694  694          for (c = *buf; nbytes > 0; c = *buf, --nbytes) {
 695  695                  buf++;
 696  696                  if (beginning_of_line && !nocmdchar) {
 697  697                          beginning_of_line = B_FALSE;
 698  698                          if (c == cmdchar) {
 699  699                                  local_echo = B_TRUE;
 700  700                                  continue;
 701  701                          }
 702  702                  } else if (local_echo) {
 703  703                          local_echo = B_FALSE;
 704  704                          if (c == '.' || c == effective_termios.c_cc[VEOF]) {
 705  705                                  char cc[CANONIFY_LEN];
 706  706  
 707  707                                  canonify(c, cc);
 708  708                                  (void) write(STDOUT_FILENO, &cmdchar, 1);
 709  709                                  (void) write(STDOUT_FILENO, cc, strlen(cc));
 710  710                                  return (-1);
 711  711                          }
 712  712                  }
 713  713  retry:
 714  714                  if (write(outfd, &c, 1) <= 0) {
 715  715                          /*
 716  716                           * Since the fd we are writing to is opened with
 717  717                           * O_NONBLOCK it is possible to get EAGAIN if the
 718  718                           * pipe is full.  One way this could happen is if we
 719  719                           * are writing a lot of data into the pipe in this loop
 720  720                           * and the application on the other end is echoing that
 721  721                           * data back out to its stdout.  The output pipe can
 722  722                           * fill up since we are stuck here in this loop and not
 723  723                           * draining the other pipe.  We can try to read some of
 724  724                           * the data to see if we can drain the pipe so that the
 725  725                           * application can continue to make progress.  The read
 726  726                           * is non-blocking so we won't hang here.  We also wait
 727  727                           * a bit before retrying since there could be other
 728  728                           * reasons why the pipe is full and we don't want to
 729  729                           * continuously retry.
 730  730                           */
 731  731                          if (errno == EAGAIN) {
 732  732                                  struct timespec rqtp;
 733  733                                  int ln;
 734  734                                  char obuf[ZLOGIN_BUFSIZ];
 735  735  
 736  736                                  if ((ln = read(infd, obuf, ZLOGIN_BUFSIZ)) > 0)
 737  737                                          (void) write(STDOUT_FILENO, obuf, ln);
 738  738  
 739  739                                  /* sleep for 10 milliseconds */
 740  740                                  rqtp.tv_sec = 0;
 741  741                                  rqtp.tv_nsec = MSEC2NSEC(10);
 742  742                                  (void) nanosleep(&rqtp, NULL);
 743  743                                  if (!dead)
 744  744                                          goto retry;
 745  745                          }
 746  746  
 747  747                          return (-1);
 748  748                  }
 749  749                  beginning_of_line = (c == '\r' || c == '\n' ||
 750  750                      c == effective_termios.c_cc[VKILL] ||
 751  751                      c == effective_termios.c_cc[VEOL] ||
 752  752                      c == effective_termios.c_cc[VSUSP] ||
 753  753                      c == effective_termios.c_cc[VINTR]);
 754  754          }
 755  755          return (0);
 756  756  }
 757  757  
 758  758  /*
 759  759   * This function prevents deadlock between zlogin and the application in the
 760  760   * zone that it is talking to.  This can happen when we read from zlogin's
 761  761   * stdin and write the data down the pipe to the application.  If the pipe
 762  762   * is full, we'll block in the write.  Because zlogin could be blocked in
 763  763   * the write, it would never read the application's stdout/stderr so the
 764  764   * application can then block on those writes (when the pipe fills up).  If the
 765  765   * the application gets blocked this way, it can never get around to reading
 766  766   * its stdin so that zlogin can unblock from its write.  Once in this state,
 767  767   * the two processes are deadlocked.
 768  768   *
 769  769   * To prevent this, we want to verify that we can write into the pipe before we
 770  770   * read from our stdin.  If the pipe already is pretty full, we bypass the read
 771  771   * for now.  We'll circle back here again after the poll() so that we can
 772  772   * try again.  When this function is called, we already know there is data
 773  773   * ready to read on STDIN_FILENO.  We return -1 if there is a problem, 1 if
 774  774   * stdin is EOF, and 0 if everything is ok (even though we might not have
 775  775   * read/written any data into the pipe on this iteration).
 776  776   */
 777  777  static int
 778  778  process_raw_input(int stdin_fd, int appin_fd)
 779  779  {
 780  780          int cc;
 781  781          struct stat64 sb;
 782  782          char ibuf[ZLOGIN_RDBUFSIZ];
 783  783  
 784  784          /* Check how much data is already in the pipe */
 785  785          if (fstat64(appin_fd, &sb) == -1) {
 786  786                  perror("stat failed");
 787  787                  return (-1);
 788  788          }
 789  789  
 790  790          if (dead)
 791  791                  return (-1);
 792  792  
 793  793          /*
 794  794           * The pipe already has a lot of data in it,  don't write any more
 795  795           * right now.
 796  796           */
 797  797          if (sb.st_size >= HI_WATER)
 798  798                  return (0);
 799  799  
 800  800          cc = read(STDIN_FILENO, ibuf, ZLOGIN_RDBUFSIZ);
 801  801          if (cc == -1 && (errno != EINTR || dead))
 802  802                  return (-1);
 803  803  
 804  804          if (cc == -1)   /* The read was interrupted. */
 805  805                  return (0);
 806  806  
 807  807          /* 0 read means EOF, close the pipe to the child */
 808  808          if (cc == 0)
 809  809                  return (1);
 810  810  
 811  811          /*
 812  812           * stdin_fd is stdin of the target; so, the thing we'll write the user
 813  813           * data *to*.
 814  814           */
 815  815          if (write(stdin_fd, ibuf, cc) == -1)
 816  816                  return (-1);
 817  817  
 818  818          return (0);
 819  819  }
 820  820  
 821  821  /*
 822  822   * Write the output from the application running in the zone.  We can get
 823  823   * a signal during the write (usually it would be SIGCHLD when the application
 824  824   * has exited) so we loop to make sure we have written all of the data we read.
 825  825   */
 826  826  static int
 827  827  process_output(int in_fd, int out_fd)
 828  828  {
 829  829          int wrote = 0;
 830  830          int cc;
 831  831          char ibuf[ZLOGIN_BUFSIZ];
 832  832  
 833  833          cc = read(in_fd, ibuf, ZLOGIN_BUFSIZ);
 834  834          if (cc == -1 && (errno != EINTR || dead))
 835  835                  return (-1);
 836  836          if (cc == 0)    /* EOF */
 837  837                  return (-1);
 838  838          if (cc == -1)   /* The read was interrupted. */
 839  839                  return (0);
 840  840  
 841  841          do {
 842  842                  int len;
 843  843  
 844  844                  len = write(out_fd, ibuf + wrote, cc - wrote);
 845  845                  if (len == -1 && errno != EINTR)
 846  846                          return (-1);
 847  847                  if (len != -1)
 848  848                          wrote += len;
 849  849          } while (wrote < cc);
 850  850  
 851  851          return (0);
 852  852  }
 853  853  
 854  854  /*
 855  855   * This is the main I/O loop, and is shared across all zlogin modes.
 856  856   * Parameters:
 857  857   *      stdin_fd:  The fd representing 'stdin' for the slave side; input to
 858  858   *                 the zone will be written here.
 859  859   *
 860  860   *      appin_fd:  The fd representing the other end of the 'stdin' pipe (when
 861  861   *                 we're running non-interactive); used in process_raw_input
 862  862   *                 to ensure we don't fill up the application's stdin pipe.
 863  863   *
 864  864   *      stdout_fd: The fd representing 'stdout' for the slave side; output
 865  865   *                 from the zone will arrive here.
 866  866   *
 867  867   *      stderr_fd: The fd representing 'stderr' for the slave side; output
 868  868   *                 from the zone will arrive here.
 869  869   *
 870  870   *      raw_mode:  If TRUE, then no processing (for example, for '~.') will
 871  871   *                 be performed on the input coming from STDIN.
 872  872   *
 873  873   * stderr_fd may be specified as -1 if there is no stderr (only non-interactive
 874  874   * mode supplies a stderr).
 875  875   *
 876  876   */
 877  877  static void
 878  878  doio(int stdin_fd, int appin_fd, int stdout_fd, int stderr_fd, int sig_fd,
 879  879      boolean_t raw_mode)
 880  880  {
 881  881          struct pollfd pollfds[4];
 882  882          char ibuf[ZLOGIN_BUFSIZ];
 883  883          int cc, ret;
 884  884  
 885  885          /* read from stdout of zone and write to stdout of global zone */
 886  886          pollfds[0].fd = stdout_fd;
 887  887          pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
 888  888  
 889  889          /* read from stderr of zone and write to stderr of global zone */
 890  890          pollfds[1].fd = stderr_fd;
 891  891          pollfds[1].events = pollfds[0].events;
 892  892  
 893  893          /* read from stdin of global zone and write to stdin of zone */
 894  894          pollfds[2].fd = STDIN_FILENO;
 895  895          pollfds[2].events = pollfds[0].events;
 896  896  
 897  897          /* read from signalling pipe so we know when child dies */
 898  898          pollfds[3].fd = sig_fd;
 899  899          pollfds[3].events = pollfds[0].events;
 900  900  
 901  901          for (;;) {
 902  902                  pollfds[0].revents = pollfds[1].revents =
 903  903                      pollfds[2].revents = pollfds[3].revents = 0;
 904  904  
 905  905                  if (dead)
 906  906                          break;
 907  907  
 908  908                  /*
 909  909                   * There is a race condition here where we can receive the
 910  910                   * child death signal, set the dead flag, but since we have
 911  911                   * passed the test above, we would go into poll and hang.
 912  912                   * To avoid this we use the sig_fd as an additional poll fd.
 913  913                   * The signal handler writes into the other end of this pipe
 914  914                   * when the child dies so that the poll will always see that
 915  915                   * input and proceed.  We just loop around at that point and
 916  916                   * then notice the dead flag.
 917  917                   */
 918  918  
 919  919                  ret = poll(pollfds,
 920  920                      sizeof (pollfds) / sizeof (struct pollfd), -1);
 921  921  
 922  922                  if (ret == -1 && errno != EINTR) {
 923  923                          perror("poll failed");
 924  924                          break;
 925  925                  }
 926  926  
 927  927                  if (errno == EINTR && dead) {
 928  928                          break;
 929  929                  }
 930  930  
 931  931                  /* event from master side stderr */
 932  932                  if (pollfds[1].revents) {
 933  933                          if (pollfds[1].revents &
 934  934                              (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
 935  935                                  if (process_output(stderr_fd, STDERR_FILENO)
 936  936                                      != 0)
 937  937                                          break;
 938  938                          } else {
 939  939                                  pollerr = pollfds[1].revents;
 940  940                                  break;
 941  941                          }
 942  942                  }
 943  943  
 944  944                  /* event from master side stdout */
 945  945                  if (pollfds[0].revents) {
 946  946                          if (pollfds[0].revents &
 947  947                              (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
 948  948                                  if (process_output(stdout_fd, STDOUT_FILENO)
 949  949                                      != 0)
 950  950                                          break;
 951  951                          } else {
 952  952                                  pollerr = pollfds[0].revents;
 953  953                                  break;
 954  954                          }
 955  955                  }
 956  956  
 957  957                  /* event from user STDIN side */
 958  958                  if (pollfds[2].revents) {
 959  959                          if (pollfds[2].revents &
 960  960                              (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
 961  961                                  /*
 962  962                                   * stdin fd is stdin of the target; so,
 963  963                                   * the thing we'll write the user data *to*.
 964  964                                   *
 965  965                                   * Also, unlike on the output side, we
 966  966                                   * close the pipe on a zero-length message.
 967  967                                   */
 968  968                                  int res;
 969  969  
 970  970                                  if (raw_mode)
 971  971                                          res = process_raw_input(stdin_fd,
 972  972                                              appin_fd);
 973  973                                  else
 974  974                                          res = process_user_input(stdin_fd,
 975  975                                              stdout_fd);
 976  976  
 977  977                                  if (res < 0)
 978  978                                          break;
 979  979                                  if (res > 0) {
 980  980                                          /* EOF (close) child's stdin_fd */
 981  981                                          pollfds[2].fd = -1;
 982  982                                          while ((res = close(stdin_fd)) != 0 &&
 983  983                                              errno == EINTR)
 984  984                                                  ;
 985  985                                          if (res != 0)
 986  986                                                  break;
 987  987                                  }
 988  988  
 989  989                          } else if (raw_mode && pollfds[2].revents & POLLHUP) {
 990  990                                  /*
 991  991                                   * It's OK to get a POLLHUP on STDIN-- it
 992  992                                   * always happens if you do:
 993  993                                   *
 994  994                                   * echo foo | zlogin <zone> <command>
 995  995                                   *
 996  996                                   * We reset fd to -1 in this case to clear
 997  997                                   * the condition and close the pipe (EOF) to
 998  998                                   * the other side in order to wrap things up.
 999  999                                   */
1000 1000                                  int res;
1001 1001  
1002 1002                                  pollfds[2].fd = -1;
1003 1003                                  while ((res = close(stdin_fd)) != 0 &&
1004 1004                                      errno == EINTR)
1005 1005                                          ;
1006 1006                                  if (res != 0)
1007 1007                                          break;
1008 1008                          } else {
1009 1009                                  pollerr = pollfds[2].revents;
1010 1010                                  break;
1011 1011                          }
1012 1012                  }
1013 1013          }
1014 1014  
1015 1015          /*
1016 1016           * We are in the midst of dying, but try to poll with a short
1017 1017           * timeout to see if we can catch the last bit of I/O from the
1018 1018           * children.
1019 1019           */
1020 1020  retry:
1021 1021          pollfds[0].revents = pollfds[1].revents = 0;
1022 1022          (void) poll(pollfds, 2, 100);
1023 1023          if (pollfds[0].revents &
1024 1024              (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
1025 1025                  if ((cc = read(stdout_fd, ibuf, ZLOGIN_BUFSIZ)) > 0) {
1026 1026                          (void) write(STDOUT_FILENO, ibuf, cc);
1027 1027                          goto retry;
1028 1028                  }
1029 1029          }
1030 1030          if (pollfds[1].revents &
1031 1031              (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
1032 1032                  if ((cc = read(stderr_fd, ibuf, ZLOGIN_BUFSIZ)) > 0) {
1033 1033                          (void) write(STDERR_FILENO, ibuf, cc);
1034 1034                          goto retry;
1035 1035                  }
1036 1036          }
1037 1037  }
1038 1038  
1039 1039  /*
1040 1040   * Fetch the user_cmd brand hook for getting a user's passwd(4) entry.
1041 1041   */
1042 1042  static const char *
1043 1043  zone_get_user_cmd(brand_handle_t bh, const char *login, char *user_cmd,
1044 1044      size_t len)
1045 1045  {
1046 1046          bzero(user_cmd, sizeof (user_cmd));
1047 1047          if (brand_get_user_cmd(bh, login, user_cmd, len) != 0)
1048 1048                  return (NULL);
1049 1049  
1050 1050          return (user_cmd);
1051 1051  }
1052 1052  
1053 1053  /* From libc */
1054 1054  extern int str2passwd(const char *, int, void *, char *, int);
1055 1055  
1056 1056  /*
1057 1057   * exec() the user_cmd brand hook, and convert the output string to a
1058 1058   * struct passwd.  This is to be called after zone_enter().
1059 1059   *
1060 1060   */
1061 1061  static struct passwd *
1062 1062  zone_get_user_pw(const char *user_cmd, struct passwd *pwent, char *pwbuf,
1063 1063      int pwbuflen)
1064 1064  {
1065 1065          char pwline[NSS_BUFLEN_PASSWD];
1066 1066          char *cin = NULL;
1067 1067          FILE *fin;
1068 1068          int status;
1069 1069  
1070 1070          assert(getzoneid() != GLOBAL_ZONEID);
1071 1071  
1072 1072          if ((fin = popen(user_cmd, "r")) == NULL)
1073 1073                  return (NULL);
1074 1074  
1075 1075          while (cin == NULL && !feof(fin))
1076 1076                  cin = fgets(pwline, sizeof (pwline), fin);
1077 1077  
1078 1078          if (cin == NULL) {
1079 1079                  (void) pclose(fin);
1080 1080                  return (NULL);
1081 1081          }
1082 1082  
1083 1083          status = pclose(fin);
1084 1084          if (!WIFEXITED(status))
1085 1085                  return (NULL);
1086 1086          if (WEXITSTATUS(status) != 0)
1087 1087                  return (NULL);
1088 1088  
1089 1089          if (str2passwd(pwline, sizeof (pwline), pwent, pwbuf, pwbuflen) == 0)
1090 1090                  return (pwent);
1091 1091          else
1092 1092                  return (NULL);
1093 1093  }
1094 1094  
1095 1095  static char **
1096 1096  zone_login_cmd(brand_handle_t bh, const char *login)
1097 1097  {
1098 1098          static char result_buf[ARG_MAX];
1099 1099          char **new_argv, *ptr, *lasts;
1100 1100          int n, a;
1101 1101  
1102 1102          /* Get the login command for the target zone. */
1103 1103          bzero(result_buf, sizeof (result_buf));
1104 1104  
1105 1105          if (forced_login) {
1106 1106                  if (brand_get_forcedlogin_cmd(bh, login,
1107 1107                      result_buf, sizeof (result_buf)) != 0)
1108 1108                          return (NULL);
1109 1109          } else {
1110 1110                  if (brand_get_login_cmd(bh, login,
1111 1111                      result_buf, sizeof (result_buf)) != 0)
1112 1112                          return (NULL);
1113 1113          }
1114 1114  
1115 1115          /*
1116 1116           * We got back a string that we'd like to execute.  But since
1117 1117           * we're not doing the execution via a shell we'll need to convert
1118 1118           * the exec string to an array of strings.  We'll do that here
1119 1119           * but we're going to be very simplistic about it and break stuff
1120 1120           * up based on spaces.  We're not even going to support any kind
1121 1121           * of quoting or escape characters.  It's truly amazing that
1122 1122           * there is no library function in Illumos to do this for us.
1123 1123           */
1124 1124  
1125 1125          /*
1126 1126           * Be paranoid.  Since we're deliniating based on spaces make
1127 1127           * sure there are no adjacent spaces.
1128 1128           */
1129 1129          if (strstr(result_buf, "  ") != NULL)
1130 1130                  return (NULL);
1131 1131  
1132 1132          /* Remove any trailing whitespace.  */
1133 1133          n = strlen(result_buf);
1134 1134          if (result_buf[n - 1] == ' ')
1135 1135                  result_buf[n - 1] = '\0';
1136 1136  
1137 1137          /* Count how many elements there are in the exec string. */
1138 1138          ptr = result_buf;
1139 1139          for (n = 2; ((ptr = strchr(ptr + 1, (int)' ')) != NULL); n++)
1140 1140                  ;
1141 1141  
1142 1142          /* Allocate the argv array that we're going to return. */
1143 1143          if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
1144 1144                  return (NULL);
1145 1145  
1146 1146          /* Tokenize the exec string and return. */
1147 1147          a = 0;
1148 1148          new_argv[a++] = result_buf;
1149 1149          if (n > 2) {
1150 1150                  (void) strtok_r(result_buf, " ", &lasts);
1151 1151                  while ((new_argv[a++] = strtok_r(NULL, " ", &lasts)) != NULL)
1152 1152                          ;
1153 1153          } else {
1154 1154                  new_argv[a++] = NULL;
1155 1155          }
1156 1156          assert(n == a);
1157 1157          return (new_argv);
1158 1158  }
1159 1159  
1160 1160  /*
1161 1161   * Prepare argv array for exec'd process.  If commands are passed to the new
1162 1162   * process and su(1M) is avalable, use it for the invocation.  Otherwise, use
1163 1163   * 'login -z <from_zonename> -f' (-z is an undocumented option which tells
1164 1164   * login that we're coming from another zone, and to disregard its CONSOLE
1165 1165   * checks).
1166 1166   */
1167 1167  static char **
1168 1168  prep_args(brand_handle_t bh, char *zonename, const char *login, char **argv)
1169 1169  {
1170 1170          int argc = 0, i;
1171 1171          size_t subshell_len = 1;
1172 1172          char *subshell = NULL, *supath = NULL;
1173 1173          char **new_argv = NULL;
1174 1174  
1175 1175          if (argv == NULL) {
1176 1176                  if (failsafe) {
1177 1177                          if ((new_argv = malloc(sizeof (char *) * 2)) == NULL)
1178 1178                                  return (NULL);
1179 1179                          new_argv[0] = FAILSAFESHELL;
1180 1180                          new_argv[1] = NULL;
1181 1181                  } else {
1182 1182                          new_argv = zone_login_cmd(bh, login);
1183 1183                  }
1184 1184                  return (new_argv);
1185 1185          }
1186 1186  
1187 1187          /*
1188 1188           * Attempt to locate a 'su' binary if not using the failsafe shell.
1189 1189           */
1190 1190          if (!failsafe) {
1191 1191                  struct stat sb;
1192 1192                  char zonepath[MAXPATHLEN];
1193 1193                  char supath_check[MAXPATHLEN];
1194 1194  
1195 1195                  if (zone_get_zonepath(zonename, zonepath,
1196 1196                      sizeof (zonepath)) != Z_OK) {
1197 1197                          zerror(gettext("unable to determine zone "
1198 1198                              "path"));
1199 1199                          return (NULL);
1200 1200                  }
1201 1201  
1202 1202                  (void) snprintf(supath_check, sizeof (supath), "%s/root/%s",
1203 1203                      zonepath, SUPATH1);
1204 1204                  if (stat(supath_check, &sb) == 0) {
1205 1205                          supath = SUPATH1;
1206 1206                  } else {
1207 1207                          (void) snprintf(supath_check, sizeof (supath_check),
1208 1208                              "%s/root/%s", zonepath, SUPATH2);
1209 1209                          if (stat(supath_check, &sb) == 0) {
1210 1210                                  supath = SUPATH2;
1211 1211                          }
1212 1212                  }
1213 1213          }
1214 1214  
1215 1215          /*
1216 1216           * With no failsafe shell or supath to wrap the incoming command, the
1217 1217           * arguments are passed straight through.
1218 1218           */
1219 1219          if (!failsafe && supath == NULL) {
1220 1220                  /*
1221 1221                   * Such an outcome is not acceptable, however, if the caller
1222 1222                   * expressed a desire to switch users.
1223 1223                   */
1224 1224                  if (strcmp(login, "root") != 0) {
1225 1225                          zerror(gettext("unable to find 'su' command"));
1226 1226                          return (NULL);
1227 1227                  }
1228 1228                  return (argv);
1229 1229          }
1230 1230  
1231 1231          /*
1232 1232           * Inventory arguments and allocate a buffer to escape them for the
1233 1233           * subshell.
1234 1234           */
1235 1235          while (argv[argc] != NULL) {
1236 1236                  /*
1237 1237                   * Allocate enough space for the delimiter and 2
1238 1238                   * quotes which might be needed.
1239 1239                   */
1240 1240                  subshell_len += strlen(argv[argc]) + 3;
1241 1241                  argc++;
1242 1242          }
1243 1243          if ((subshell = calloc(1, subshell_len)) == NULL) {
1244 1244                  return (NULL);
1245 1245          }
1246 1246  
1247 1247          /*
1248 1248           * The handling of quotes in the following block may seem unusual, but
1249 1249           * it is done this way for backward compatibility.
1250 1250           * When running a command, zlogin is documented as:
1251 1251           *    zlogin zonename command args
1252 1252           * However, some code has come to depend on the following usage:
1253 1253           *    zlogin zonename 'command args'
1254 1254           * This relied on the fact that the single argument would be re-parsed
1255 1255           * within the zone and excuted as a command with an argument. To remain
1256 1256           * compatible with this (incorrect) usage, if there is only a single
1257 1257           * argument, it is not quoted, even if it has embedded spaces.
1258 1258           *
1259 1259           * Here are two examples which both need to work:
1260 1260           * 1) zlogin foo 'echo hello'
1261 1261           *    This has a single argv member with a space in it but will not be
1262 1262           *    quoted on the command passed into the zone.
1263 1263           * 2) zlogin foo bash -c 'echo hello'
1264 1264           *    This has 3 argv members. The 3rd arg has a space and must be
1265 1265           *    quoted on the command passed into the zone.
1266 1266           */
1267 1267          for (i = 0; i < argc; i++) {
1268 1268                  if (i > 0)
1269 1269                          (void) strcat(subshell, " ");
1270 1270  
1271 1271                  if (argc > 1 && (strchr(argv[i], ' ') != NULL ||
1272 1272                      strchr(argv[i], '\t') != NULL)) {
1273 1273                          (void) strcat(subshell, "'");
1274 1274                          (void) strcat(subshell, argv[i]);
1275 1275                          (void) strcat(subshell, "'");
1276 1276                  } else {
1277 1277                          (void) strcat(subshell, argv[i]);
1278 1278                  }
1279 1279          }
1280 1280  
1281 1281          if (failsafe) {
1282 1282                  int a = 0, n = 4;
1283 1283  
1284 1284                  if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
1285 1285                          return (NULL);
1286 1286  
1287 1287                  new_argv[a++] = FAILSAFESHELL;
1288 1288                  new_argv[a++] = "-c";
1289 1289                  new_argv[a++] = subshell;
1290 1290                  new_argv[a++] = NULL;
1291 1291                  assert(a == n);
1292 1292          } else {
1293 1293                  int a = 0, n = 6;
1294 1294  
1295 1295                  assert(supath != NULL);
1296 1296                  if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
1297 1297                          return (NULL);
1298 1298  
1299 1299                  new_argv[a++] = supath;
1300 1300                  if (strcmp(login, "root") != 0) {
1301 1301                          new_argv[a++] = "-";
1302 1302                  } else {
1303 1303                          n--;
1304 1304                  }
1305 1305                  new_argv[a++] = (char *)login;
1306 1306                  new_argv[a++] = "-c";
1307 1307                  new_argv[a++] = subshell;
1308 1308                  new_argv[a++] = NULL;
1309 1309                  assert(a == n);
1310 1310          }
1311 1311  
1312 1312          return (new_argv);
1313 1313  }
1314 1314  
1315 1315  /*
1316 1316   * Helper routine for prep_env below.
1317 1317   */
1318 1318  static char *
1319 1319  add_env(char *name, char *value)
1320 1320  {
1321 1321          size_t sz = strlen(name) + strlen(value) + 2; /* name, =, value, NUL */
1322 1322          char *str;
1323 1323  
1324 1324          if ((str = malloc(sz)) == NULL)
1325 1325                  return (NULL);
1326 1326  
1327 1327          (void) snprintf(str, sz, "%s=%s", name, value);
1328 1328          return (str);
1329 1329  }
1330 1330  
1331 1331  /*
1332 1332   * Prepare envp array for exec'd process.
1333 1333   */
1334 1334  static char **
1335 1335  prep_env()
1336 1336  {
1337 1337          int e = 0, size = 1;
1338 1338          char **new_env, *estr;
1339 1339          char *term = getenv("TERM");
1340 1340          char *path;
1341 1341  
1342 1342          size++; /* for $PATH */
1343 1343          if (term != NULL)
1344 1344                  size++;
1345 1345  
1346 1346          /*
1347 1347           * In failsafe mode we set $HOME, since '-l' isn't valid in this mode.
1348 1348           * We also set $SHELL, since neither login nor su will be around to do
1349 1349           * it.
1350 1350           */
1351 1351          if (failsafe)
1352 1352                  size += 2;
1353 1353  
1354 1354          if ((new_env = malloc(sizeof (char *) * size)) == NULL)
1355 1355                  return (NULL);
1356 1356  
1357 1357          if (strcmp(zonebrand, "lx") == 0)
1358 1358                  path = LX_DEF_PATH;
1359 1359          else
1360 1360                  path = DEF_PATH;
1361 1361  
1362 1362          if ((estr = add_env("PATH", path)) == NULL)
1363 1363                  return (NULL);
1364 1364          new_env[e++] = estr;
1365 1365  
1366 1366          if (term != NULL) {
1367 1367                  if ((estr = add_env("TERM", term)) == NULL)
1368 1368                          return (NULL);
1369 1369                  new_env[e++] = estr;
1370 1370          }
1371 1371  
1372 1372          if (failsafe) {
1373 1373                  if ((estr = add_env("HOME", "/")) == NULL)
1374 1374                          return (NULL);
1375 1375                  new_env[e++] = estr;
1376 1376  
1377 1377                  if ((estr = add_env("SHELL", FAILSAFESHELL)) == NULL)
1378 1378                          return (NULL);
1379 1379                  new_env[e++] = estr;
1380 1380          }
1381 1381  
1382 1382          new_env[e++] = NULL;
1383 1383  
1384 1384          assert(e == size);
1385 1385  
1386 1386          return (new_env);
1387 1387  }
1388 1388  
1389 1389  /*
1390 1390   * Finish the preparation of the envp array for exec'd non-interactive
1391 1391   * zlogins.  This is called in the child process *after* we zone_enter(), since
1392 1392   * it derives things we can only know within the zone, such as $HOME, $SHELL,
1393 1393   * etc.  We need only do this in the non-interactive, mode, since otherwise
1394 1394   * login(1) will do it.  We don't do this in failsafe mode, since it presents
1395 1395   * additional ways in which the command could fail, and we'd prefer to avoid
1396 1396   * that.
1397 1397   */
1398 1398  static char **
1399 1399  prep_env_noninteractive(const char *user_cmd, char **env)
1400 1400  {
1401 1401          size_t size;
1402 1402          char **new_env;
1403 1403          int e, i;
1404 1404          char *estr;
1405 1405          char varmail[LOGNAME_MAX + 11]; /* strlen(/var/mail/) = 10, NUL */
1406 1406          char pwbuf[NSS_BUFLEN_PASSWD + 1];
1407 1407          struct passwd pwent;
1408 1408          struct passwd *pw = NULL;
1409 1409  
1410 1410          assert(env != NULL);
1411 1411          assert(failsafe == 0);
1412 1412  
1413 1413          /*
1414 1414           * Exec the "user_cmd" brand hook to get a pwent for the
1415 1415           * login user.  If this fails, HOME will be set to "/", SHELL
1416 1416           * will be set to $DEFAULTSHELL, and we will continue to exec
1417 1417           * SUPATH <login> -c <cmd>.
1418 1418           */
1419 1419          pw = zone_get_user_pw(user_cmd, &pwent, pwbuf, sizeof (pwbuf));
1420 1420  
1421 1421          /*
1422 1422           * Get existing envp size.
1423 1423           */
1424 1424          for (size = 0; env[size] != NULL; size++)
1425 1425                  ;
1426 1426  
1427 1427          e = size;
1428 1428  
1429 1429          /*
1430 1430           * Finish filling out the environment; we duplicate the environment
1431 1431           * setup described in login(1), for lack of a better precedent.
1432 1432           */
1433 1433          if (pw != NULL)
1434 1434                  size += 3;      /* LOGNAME, HOME, MAIL */
1435 1435          else
1436 1436                  size += 1;      /* HOME */
1437 1437  
1438 1438          size++; /* always fill in SHELL */
1439 1439          size++; /* terminating NULL */
1440 1440  
1441 1441          if ((new_env = malloc(sizeof (char *) * size)) == NULL)
1442 1442                  goto malloc_fail;
1443 1443  
1444 1444          /*
1445 1445           * Copy existing elements of env into new_env.
1446 1446           */
1447 1447          for (i = 0; env[i] != NULL; i++) {
1448 1448                  if ((new_env[i] = strdup(env[i])) == NULL)
1449 1449                          goto malloc_fail;
1450 1450          }
1451 1451          assert(e == i);
1452 1452  
1453 1453          if (pw != NULL) {
1454 1454                  if ((estr = add_env("LOGNAME", pw->pw_name)) == NULL)
1455 1455                          goto malloc_fail;
1456 1456                  new_env[e++] = estr;
1457 1457  
1458 1458                  if ((estr = add_env("HOME", pw->pw_dir)) == NULL)
1459 1459                          goto malloc_fail;
1460 1460                  new_env[e++] = estr;
1461 1461  
1462 1462                  if (chdir(pw->pw_dir) != 0)
1463 1463                          zerror(gettext("Could not chdir to home directory "
1464 1464                              "%s: %s"), pw->pw_dir, strerror(errno));
1465 1465  
1466 1466                  (void) snprintf(varmail, sizeof (varmail), "/var/mail/%s",
1467 1467                      pw->pw_name);
1468 1468                  if ((estr = add_env("MAIL", varmail)) == NULL)
1469 1469                          goto malloc_fail;
1470 1470                  new_env[e++] = estr;
1471 1471          } else {
1472 1472                  if ((estr = add_env("HOME", "/")) == NULL)
1473 1473                          goto malloc_fail;
1474 1474                  new_env[e++] = estr;
1475 1475          }
1476 1476  
1477 1477          if (pw != NULL && strlen(pw->pw_shell) > 0) {
1478 1478                  if ((estr = add_env("SHELL", pw->pw_shell)) == NULL)
1479 1479                          goto malloc_fail;
1480 1480                  new_env[e++] = estr;
1481 1481          } else {
1482 1482                  if ((estr = add_env("SHELL", DEFAULTSHELL)) == NULL)
1483 1483                          goto malloc_fail;
1484 1484                  new_env[e++] = estr;
1485 1485          }
1486 1486  
1487 1487          new_env[e++] = NULL;    /* add terminating NULL */
1488 1488  
1489 1489          assert(e == size);
1490 1490          return (new_env);
1491 1491  
1492 1492  malloc_fail:
1493 1493          zperror(gettext("failed to allocate memory for process environment"));
1494 1494          return (NULL);
1495 1495  }
1496 1496  
1497 1497  static int
1498 1498  close_func(void *slavefd, int fd)
1499 1499  {
1500 1500          if (fd != *(int *)slavefd)
1501 1501                  (void) close(fd);
1502 1502          return (0);
1503 1503  }
1504 1504  
1505 1505  static void
1506 1506  set_cmdchar(char *cmdcharstr)
1507 1507  {
1508 1508          char c;
1509 1509          long lc;
1510 1510  
1511 1511          if ((c = *cmdcharstr) != '\\') {
1512 1512                  cmdchar = c;
1513 1513                  return;
1514 1514          }
1515 1515  
1516 1516          c = cmdcharstr[1];
1517 1517          if (c == '\0' || c == '\\') {
1518 1518                  cmdchar = '\\';
1519 1519                  return;
1520 1520          }
1521 1521  
1522 1522          if (c < '0' || c > '7') {
1523 1523                  zerror(gettext("Unrecognized escape character option %s"),
1524 1524                      cmdcharstr);
1525 1525                  usage();
1526 1526          }
1527 1527  
1528 1528          lc = strtol(cmdcharstr + 1, NULL, 8);
1529 1529          if (lc < 0 || lc > 255) {
1530 1530                  zerror(gettext("Octal escape character '%s' too large"),
1531 1531                      cmdcharstr);
1532 1532                  usage();
1533 1533          }
1534 1534          cmdchar = (char)lc;
1535 1535  }
1536 1536  
1537 1537  static int
1538 1538  setup_utmpx(char *slavename)
1539 1539  {
1540 1540          struct utmpx ut;
1541 1541  
1542 1542          bzero(&ut, sizeof (ut));
1543 1543          (void) strncpy(ut.ut_user, ".zlogin", sizeof (ut.ut_user));
1544 1544          (void) strncpy(ut.ut_line, slavename, sizeof (ut.ut_line));
1545 1545          ut.ut_pid = getpid();
1546 1546          ut.ut_id[0] = 'z';
1547 1547          ut.ut_id[1] = ut.ut_id[2] = ut.ut_id[3] = (char)SC_WILDC;
1548 1548          ut.ut_type = LOGIN_PROCESS;
1549 1549          (void) time(&ut.ut_tv.tv_sec);
1550 1550  
1551 1551          if (makeutx(&ut) == NULL) {
1552 1552                  zerror(gettext("makeutx failed"));
1553 1553                  return (-1);
1554 1554          }
1555 1555          return (0);
1556 1556  }
1557 1557  
1558 1558  static void
1559 1559  release_lock_file(int lockfd)
1560 1560  {
1561 1561          (void) close(lockfd);
1562 1562  }
1563 1563  
1564 1564  static int
1565 1565  grab_lock_file(const char *zone_name, int *lockfd)
1566 1566  {
1567 1567          char pathbuf[PATH_MAX];
1568 1568          struct flock flock;
1569 1569  
1570 1570          if (mkdir(ZONES_TMPDIR, S_IRWXU) < 0 && errno != EEXIST) {
1571 1571                  zerror(gettext("could not mkdir %s: %s"), ZONES_TMPDIR,
1572 1572                      strerror(errno));
1573 1573                  return (-1);
1574 1574          }
1575 1575          (void) chmod(ZONES_TMPDIR, S_IRWXU);
1576 1576          (void) snprintf(pathbuf, sizeof (pathbuf), "%s/%s.zoneadm.lock",
1577 1577              ZONES_TMPDIR, zone_name);
1578 1578  
1579 1579          if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
1580 1580                  zerror(gettext("could not open %s: %s"), pathbuf,
1581 1581                      strerror(errno));
1582 1582                  return (-1);
1583 1583          }
1584 1584          /*
1585 1585           * Lock the file to synchronize with other zoneadmds
1586 1586           */
1587 1587          flock.l_type = F_WRLCK;
1588 1588          flock.l_whence = SEEK_SET;
1589 1589          flock.l_start = (off_t)0;
1590 1590          flock.l_len = (off_t)0;
1591 1591          if (fcntl(*lockfd, F_SETLKW, &flock) < 0) {
1592 1592                  zerror(gettext("unable to lock %s: %s"), pathbuf,
1593 1593                      strerror(errno));
1594 1594                  release_lock_file(*lockfd);
1595 1595                  return (-1);
1596 1596          }
1597 1597          return (Z_OK);
1598 1598  }
1599 1599  
1600 1600  static int
1601 1601  start_zoneadmd(const char *zone_name)
1602 1602  {
1603 1603          pid_t retval;
1604 1604          int pstatus = 0, error = -1, lockfd, doorfd;
1605 1605          struct door_info info;
1606 1606          char doorpath[MAXPATHLEN];
1607 1607  
1608 1608          (void) snprintf(doorpath, sizeof (doorpath), ZONE_DOOR_PATH, zone_name);
1609 1609  
1610 1610          if (grab_lock_file(zone_name, &lockfd) != Z_OK)
1611 1611                  return (-1);
1612 1612          /*
1613 1613           * We must do the door check with the lock held.  Otherwise, we
1614 1614           * might race against another zoneadm/zlogin process and wind
1615 1615           * up with two processes trying to start zoneadmd at the same
1616 1616           * time.  zoneadmd will detect this, and fail, but we prefer this
1617 1617           * to be as seamless as is practical, from a user perspective.
1618 1618           */
1619 1619          if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
1620 1620                  if (errno != ENOENT) {
1621 1621                          zerror("failed to open %s: %s", doorpath,
1622 1622                              strerror(errno));
1623 1623                          goto out;
1624 1624                  }
1625 1625          } else {
1626 1626                  /*
1627 1627                   * Seems to be working ok.
1628 1628                   */
1629 1629                  if (door_info(doorfd, &info) == 0 &&
1630 1630                      ((info.di_attributes & DOOR_REVOKED) == 0)) {
1631 1631                          error = 0;
1632 1632                          goto out;
1633 1633                  }
1634 1634          }
1635 1635  
1636 1636          if ((child_pid = fork()) == -1) {
1637 1637                  zperror(gettext("could not fork"));
1638 1638                  goto out;
1639 1639          } else if (child_pid == 0) {
1640 1640                  /* child process */
1641 1641                  (void) execl("/usr/lib/zones/zoneadmd", "zoneadmd", "-z",
1642 1642                      zone_name, NULL);
1643 1643                  zperror(gettext("could not exec zoneadmd"));
1644 1644                  _exit(1);
1645 1645          }
1646 1646  
1647 1647          /* parent process */
1648 1648          do {
1649 1649                  retval = waitpid(child_pid, &pstatus, 0);
1650 1650          } while (retval != child_pid);
1651 1651          if (WIFSIGNALED(pstatus) ||
1652 1652              (WIFEXITED(pstatus) && WEXITSTATUS(pstatus) != 0)) {
1653 1653                  zerror(gettext("could not start %s"), "zoneadmd");
1654 1654                  goto out;
1655 1655          }
1656 1656          error = 0;
1657 1657  out:
1658 1658          release_lock_file(lockfd);
1659 1659          (void) close(doorfd);
1660 1660          return (error);
1661 1661  }
1662 1662  
1663 1663  static int
1664 1664  init_template(void)
1665 1665  {
1666 1666          int fd;
1667 1667          int err = 0;
1668 1668  
1669 1669          fd = open64(CTFS_ROOT "/process/template", O_RDWR);
1670 1670          if (fd == -1)
1671 1671                  return (-1);
1672 1672  
1673 1673          /*
1674 1674           * zlogin doesn't do anything with the contract.
1675 1675           * Deliver no events, don't inherit, and allow it to be orphaned.
1676 1676           */
1677 1677          err |= ct_tmpl_set_critical(fd, 0);
1678 1678          err |= ct_tmpl_set_informative(fd, 0);
1679 1679          err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
1680 1680          err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
1681 1681          if (err || ct_tmpl_activate(fd)) {
1682 1682                  (void) close(fd);
1683 1683                  return (-1);
1684 1684          }
1685 1685  
1686 1686          return (fd);
1687 1687  }
1688 1688  
1689 1689  static int
1690 1690  noninteractive_login(char *zonename, const char *user_cmd, zoneid_t zoneid,
1691 1691      char **new_args, char **new_env)
1692 1692  {
1693 1693          pid_t retval;
1694 1694          int stdin_pipe[2], stdout_pipe[2], stderr_pipe[2], dead_child_pipe[2];
1695 1695          int child_status;
1696 1696          int tmpl_fd;
1697 1697          sigset_t block_cld;
1698 1698  
1699 1699          if ((tmpl_fd = init_template()) == -1) {
1700 1700                  reset_tty();
1701 1701                  zperror(gettext("could not create contract"));
1702 1702                  return (1);
1703 1703          }
1704 1704  
1705 1705          if (pipe(stdin_pipe) != 0) {
1706 1706                  zperror(gettext("could not create STDIN pipe"));
1707 1707                  return (1);
1708 1708          }
1709 1709          /*
1710 1710           * When the user types ^D, we get a zero length message on STDIN.
1711 1711           * We need to echo that down the pipe to send it to the other side;
1712 1712           * but by default, pipes don't propagate zero-length messages.  We
1713 1713           * toggle that behavior off using I_SWROPT.  See streamio(7i).
1714 1714           */
1715 1715          if (ioctl(stdin_pipe[0], I_SWROPT, SNDZERO) != 0) {
1716 1716                  zperror(gettext("could not configure STDIN pipe"));
1717 1717                  return (1);
1718 1718  
1719 1719          }
1720 1720          if (pipe(stdout_pipe) != 0) {
1721 1721                  zperror(gettext("could not create STDOUT pipe"));
1722 1722                  return (1);
1723 1723          }
1724 1724          if (pipe(stderr_pipe) != 0) {
1725 1725                  zperror(gettext("could not create STDERR pipe"));
1726 1726                  return (1);
1727 1727          }
1728 1728  
1729 1729          if (pipe(dead_child_pipe) != 0) {
1730 1730                  zperror(gettext("could not create signalling pipe"));
1731 1731                  return (1);
1732 1732          }
1733 1733          close_on_sig = dead_child_pipe[0];
1734 1734  
1735 1735          /*
1736 1736           * If any of the pipe FD's winds up being less than STDERR, then we
1737 1737           * have a mess on our hands-- and we are lacking some of the I/O
1738 1738           * streams we would expect anyway.  So we bail.
1739 1739           */
1740 1740          if (stdin_pipe[0] <= STDERR_FILENO ||
1741 1741              stdin_pipe[1] <= STDERR_FILENO ||
1742 1742              stdout_pipe[0] <= STDERR_FILENO ||
1743 1743              stdout_pipe[1] <= STDERR_FILENO ||
1744 1744              stderr_pipe[0] <= STDERR_FILENO ||
1745 1745              stderr_pipe[1] <= STDERR_FILENO ||
1746 1746              dead_child_pipe[0] <= STDERR_FILENO ||
1747 1747              dead_child_pipe[1] <= STDERR_FILENO) {
1748 1748                  zperror(gettext("process lacks valid STDIN, STDOUT, STDERR"));
1749 1749                  return (1);
1750 1750          }
1751 1751  
1752 1752          if (prefork_dropprivs() != 0) {
1753 1753                  zperror(gettext("could not allocate privilege set"));
1754 1754                  return (1);
1755 1755          }
1756 1756  
1757 1757          (void) sigset(SIGCLD, sigcld);
1758 1758          (void) sigemptyset(&block_cld);
1759 1759          (void) sigaddset(&block_cld, SIGCLD);
1760 1760          (void) sigprocmask(SIG_BLOCK, &block_cld, NULL);
1761 1761  
1762 1762          if ((child_pid = fork()) == -1) {
1763 1763                  (void) ct_tmpl_clear(tmpl_fd);
1764 1764                  (void) close(tmpl_fd);
1765 1765                  zperror(gettext("could not fork"));
1766 1766                  return (1);
1767 1767          } else if (child_pid == 0) { /* child process */
1768 1768                  (void) ct_tmpl_clear(tmpl_fd);
1769 1769  
1770 1770                  /*
1771 1771                   * Do a dance to get the pipes hooked up as FD's 0, 1 and 2.
1772 1772                   */
1773 1773                  (void) close(STDIN_FILENO);
1774 1774                  (void) close(STDOUT_FILENO);
1775 1775                  (void) close(STDERR_FILENO);
1776 1776                  (void) dup2(stdin_pipe[1], STDIN_FILENO);
1777 1777                  (void) dup2(stdout_pipe[1], STDOUT_FILENO);
1778 1778                  (void) dup2(stderr_pipe[1], STDERR_FILENO);
1779 1779                  (void) closefrom(STDERR_FILENO + 1);
1780 1780  
1781 1781                  (void) sigset(SIGCLD, SIG_DFL);
1782 1782                  (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL);
1783 1783                  /*
1784 1784                   * In case any of stdin, stdout or stderr are streams,
1785 1785                   * anchor them to prevent malicious I_POPs.
1786 1786                   */
1787 1787                  (void) ioctl(STDIN_FILENO, I_ANCHOR);
1788 1788                  (void) ioctl(STDOUT_FILENO, I_ANCHOR);
1789 1789                  (void) ioctl(STDERR_FILENO, I_ANCHOR);
1790 1790  
1791 1791                  if (zone_enter(zoneid) == -1) {
1792 1792                          zerror(gettext("could not enter zone %s: %s"),
1793 1793                              zonename, strerror(errno));
1794 1794                          _exit(1);
1795 1795                  }
1796 1796  
1797 1797                  /*
1798 1798                   * For non-native zones, tell libc where it can find locale
1799 1799                   * specific getttext() messages.
1800 1800                   */
1801 1801                  if (access("/.SUNWnative/usr/lib/locale", R_OK) == 0)
1802 1802                          (void) bindtextdomain(TEXT_DOMAIN,
1803 1803                              "/.SUNWnative/usr/lib/locale");
1804 1804                  else if (access("/native/usr/lib/locale", R_OK) == 0)
1805 1805                          (void) bindtextdomain(TEXT_DOMAIN,
1806 1806                              "/native/usr/lib/locale");
1807 1807  
1808 1808                  if (!failsafe)
1809 1809                          new_env = prep_env_noninteractive(user_cmd, new_env);
1810 1810  
1811 1811                  if (new_env == NULL) {
1812 1812                          _exit(1);
1813 1813                  }
1814 1814  
1815 1815                  /*
1816 1816                   * Move into a new process group; the zone_enter will have
1817 1817                   * placed us into zsched's session, and we want to be in
1818 1818                   * a unique process group.
1819 1819                   */
1820 1820                  (void) setpgid(getpid(), getpid());
1821 1821  
1822 1822                  /*
1823 1823                   * The child needs to run as root to
1824 1824                   * execute the su program.
1825 1825                   */
1826 1826                  if (setuid(0) == -1) {
1827 1827                          zperror(gettext("insufficient privilege"));
1828 1828                          return (1);
1829 1829                  }
1830 1830  
1831 1831                  (void) execve(new_args[0], new_args, new_env);
1832 1832                  zperror(gettext("exec failure"));
1833 1833                  _exit(1);
1834 1834          }
1835 1835          /* parent */
1836 1836  
1837 1837          /* close pipe sides written by child */
1838 1838          (void) close(stdout_pipe[1]);
1839 1839          (void) close(stderr_pipe[1]);
1840 1840  
1841 1841          (void) sigset(SIGINT, sig_forward);
1842 1842  
1843 1843          postfork_dropprivs();
1844 1844  
1845 1845          (void) ct_tmpl_clear(tmpl_fd);
1846 1846          (void) close(tmpl_fd);
1847 1847  
1848 1848          (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL);
1849 1849          doio(stdin_pipe[0], stdin_pipe[1], stdout_pipe[0], stderr_pipe[0],
1850 1850              dead_child_pipe[1], B_TRUE);
1851 1851          do {
1852 1852                  retval = waitpid(child_pid, &child_status, 0);
1853 1853                  if (retval == -1) {
1854 1854                          child_status = 0;
1855 1855                  }
1856 1856          } while (retval != child_pid && errno != ECHILD);
1857 1857  
1858 1858          return (WEXITSTATUS(child_status));
1859 1859  }
1860 1860  
1861 1861  static char *
1862 1862  get_username()
1863 1863  {
1864 1864          uid_t   uid;
1865 1865          struct passwd *nptr;
1866 1866  
1867 1867          /*
1868 1868           * Authorizations are checked to restrict access based on the
1869 1869           * requested operation and zone name, It is assumed that the
1870 1870           * program is running with all privileges, but that the real
1871 1871           * user ID is that of the user or role on whose behalf we are
1872 1872           * operating. So we start by getting the username that will be
1873 1873           * used for subsequent authorization checks.
1874 1874           */
1875 1875  
1876 1876          uid = getuid();
1877 1877          if ((nptr = getpwuid(uid)) == NULL) {
1878 1878                  zerror(gettext("could not get user name."));
1879 1879                  _exit(1);
1880 1880          }
1881 1881          return (nptr->pw_name);
1882 1882  }
1883 1883  
1884 1884  static boolean_t
1885 1885  zlog_mode_logging(char *zonename, boolean_t *found)
1886 1886  {
1887 1887          boolean_t lm = B_FALSE;
1888 1888          zone_dochandle_t handle;
1889 1889          struct zone_attrtab attr;
1890 1890  
1891 1891          *found = B_FALSE;
1892 1892          if ((handle = zonecfg_init_handle()) == NULL)
1893 1893                  return (lm);
1894 1894  
1895 1895          if (zonecfg_get_handle(zonename, handle) != Z_OK)
1896 1896                  goto done;
1897 1897  
1898 1898          if (zonecfg_setattrent(handle) != Z_OK)
1899 1899                  goto done;
1900 1900          while (zonecfg_getattrent(handle, &attr) == Z_OK) {
1901 1901                  if (strcmp("zlog-mode", attr.zone_attr_name) == 0) {
1902 1902                          int len = strlen(attr.zone_attr_value);
1903 1903  
1904 1904                          *found = B_TRUE;
1905 1905                          if (strncmp("log", attr.zone_attr_value, 3) == 0 ||
1906 1906                              strncmp("nolog", attr.zone_attr_value, 5) == 0 ||
1907 1907                              (len >= 3 && attr.zone_attr_value[len - 2] == '-'))
1908 1908                                  lm = B_TRUE;
1909 1909                          break;
1910 1910                  }
1911 1911          }
1912 1912          (void) zonecfg_endattrent(handle);
1913 1913  
1914 1914  done:
1915 1915          zonecfg_fini_handle(handle);
1916 1916          return (lm);
1917 1917  }
1918 1918  
1919 1919  int
1920 1920  main(int argc, char **argv)
1921 1921  {
1922 1922          int arg, console = 0, imode = 0;
1923 1923          int estatus = 0;
1924 1924          zoneid_t zoneid;
1925 1925          zone_state_t st;
1926 1926          char *login = "root";
1927 1927          int iflag = 0;
1928 1928          int lflag = 0;
1929 1929          int nflag = 0;
1930 1930          char *zonename = NULL;
1931 1931          char **proc_args = NULL;
1932 1932          char **new_args, **new_env;
1933 1933          sigset_t block_cld;
1934 1934          siginfo_t si;
1935 1935          char devroot[MAXPATHLEN];
1936 1936          char *slavename, slaveshortname[MAXPATHLEN];
1937 1937          priv_set_t *privset;
1938 1938          int tmpl_fd;
1939 1939          char default_brand[MAXNAMELEN];
1940 1940          struct stat sb;
1941 1941          char kernzone[ZONENAME_MAX];
1942 1942          brand_handle_t bh;
1943 1943          char user_cmd[MAXPATHLEN];
1944 1944          char authname[MAXAUTHS];
1945 1945  
1946 1946          (void) setlocale(LC_ALL, "");
1947 1947          (void) textdomain(TEXT_DOMAIN);
1948 1948  
1949 1949          (void) getpname(argv[0]);
1950 1950          username = get_username();
1951 1951  
1952 1952          while ((arg = getopt(argc, argv, "diNnECIR:Se:l:Q")) != EOF) {
1953 1953                  switch (arg) {
1954 1954                  case 'C':
1955 1955                          console = 1;
1956 1956                          break;
1957 1957                  case 'E':
1958 1958                          nocmdchar = 1;
1959 1959                          break;
1960 1960                  case 'I':
1961 1961                          /*
1962 1962                           * interactive mode is just a slight variation on the
1963 1963                           * console mode.
1964 1964                           */
1965 1965                          console = 1;
1966 1966                          imode = 1;
1967 1967                          /* The default is HUP, disconnect on EOF */
1968 1968                          connect_flags ^= ZLOGIN_ZFD_EOF;
1969 1969                          break;
1970 1970                  case 'R':       /* undocumented */
1971 1971                          if (*optarg != '/') {
1972 1972                                  zerror(gettext("root path must be absolute."));
1973 1973                                  exit(2);
1974 1974                          }
1975 1975                          if (stat(optarg, &sb) == -1 || !S_ISDIR(sb.st_mode)) {
1976 1976                                  zerror(
1977 1977                                      gettext("root path must be a directory."));
1978 1978                                  exit(2);
1979 1979                          }
1980 1980                          zonecfg_set_root(optarg);
1981 1981                          break;
1982 1982                  case 'Q':
1983 1983                          quiet = 1;
1984 1984                          break;
1985 1985                  case 'S':
1986 1986                          failsafe = 1;
1987 1987                          break;
1988 1988                  case 'd':
1989 1989                          connect_flags |= ZLOGIN_DISCONNECT;
1990 1990                          break;
1991 1991                  case 'e':
1992 1992                          set_cmdchar(optarg);
1993 1993                          break;
1994 1994                  case 'i':
1995 1995                          iflag = 1;
1996 1996                          break;
1997 1997                  case 'l':
1998 1998                          login = optarg;
1999 1999                          lflag = 1;
2000 2000                          break;
2001 2001                  case 'N':
2002 2002                          /* NOHUP - do not send EOF */
2003 2003                          connect_flags ^= ZLOGIN_ZFD_EOF;
2004 2004                          break;
2005 2005                  case 'n':
2006 2006                          nflag = 1;
2007 2007                          break;
2008 2008                  default:
2009 2009                          usage();
2010 2010                  }
2011 2011          }
2012 2012  
2013 2013          if (console != 0) {
2014 2014  
2015 2015                  /*
2016 2016                   * The only connect option in console mode is ZLOGIN_DISCONNECT
2017 2017                   */
2018 2018                  if (imode == 0)
2019 2019                          connect_flags &= ZLOGIN_DISCONNECT;
2020 2020  
2021 2021                  if (lflag != 0) {
2022 2022                          zerror(gettext(
2023 2023                              "-l may not be specified for console login"));
2024 2024                          usage();
2025 2025                  }
2026 2026  
2027 2027                  if (nflag != 0) {
2028 2028                          zerror(gettext(
2029 2029                              "-n may not be specified for console login"));
2030 2030                          usage();
2031 2031                  }
2032 2032  
2033 2033                  if (failsafe != 0) {
2034 2034                          zerror(gettext(
2035 2035                              "-S may not be specified for console login"));
2036 2036                          usage();
2037 2037                  }
2038 2038  
2039 2039                  if (zonecfg_in_alt_root()) {
2040 2040                          zerror(gettext(
2041 2041                              "-R may not be specified for console login"));
2042 2042                          exit(2);
2043 2043                  }
2044 2044  
2045 2045          }
2046 2046  
2047 2047          if (iflag != 0 && nflag != 0) {
2048 2048                  zerror(gettext("-i and -n flags are incompatible"));
2049 2049                  usage();
2050 2050          }
2051 2051  
2052 2052          if (failsafe != 0 && lflag != 0) {
2053 2053                  zerror(gettext("-l may not be specified for failsafe login"));
2054 2054                  usage();
2055 2055          }
2056 2056  
2057 2057          if (!console && (connect_flags & ZLOGIN_DISCONNECT) != 0) {
2058 2058                  zerror(gettext(
2059 2059                      "-d may only be specified with console login"));
2060 2060                  usage();
2061 2061          }
2062 2062  
2063 2063          if (imode == 0 && (connect_flags & ZLOGIN_ZFD_EOF) != 0) {
2064 2064                  zerror(gettext("-N may only be specified with -I"));
2065 2065                  usage();
2066 2066          }
2067 2067  
2068 2068          if (optind == (argc - 1)) {
2069 2069                  /*
2070 2070                   * zone name, no process name; this should be an interactive
2071 2071                   * as long as STDIN is really a tty.
2072 2072                   */
2073 2073                  if (nflag != 0) {
2074 2074                          zerror(gettext(
2075 2075                              "-n may not be specified for interactive login"));
2076 2076                          usage();
2077 2077                  }
2078 2078                  if (isatty(STDIN_FILENO))
2079 2079                          interactive = 1;
2080 2080                  zonename = argv[optind];
2081 2081          } else if (optind < (argc - 1)) {
2082 2082                  if (console) {
2083 2083                          zerror(gettext("Commands may not be specified for "
2084 2084                              "console login."));
2085 2085                          usage();
2086 2086                  }
2087 2087                  /* zone name and process name, and possibly some args */
2088 2088                  zonename = argv[optind];
2089 2089                  proc_args = &argv[optind + 1];
2090 2090                  if (iflag && isatty(STDIN_FILENO))
2091 2091                          interactive = 1;
2092 2092          } else {
2093 2093                  usage();
2094 2094          }
2095 2095  
2096 2096          if (getzoneid() != GLOBAL_ZONEID) {
2097 2097                  zerror(gettext("'%s' may only be used from the global zone"),
2098 2098                      pname);
2099 2099                  return (1);
2100 2100          }
2101 2101  
2102 2102          if (strcmp(zonename, GLOBAL_ZONENAME) == 0) {
2103 2103                  zerror(gettext("'%s' not applicable to the global zone"),
2104 2104                      pname);
2105 2105                  return (1);
2106 2106          }
2107 2107  
2108 2108          if (zone_get_state(zonename, &st) != Z_OK) {
2109 2109                  zerror(gettext("zone '%s' unknown"), zonename);
2110 2110                  return (1);
2111 2111          }
2112 2112  
2113 2113          if (st < ZONE_STATE_INSTALLED) {
2114 2114                  zerror(gettext("cannot login to a zone which is '%s'"),
2115 2115                      zone_state_str(st));
2116 2116                  return (1);
2117 2117          }
2118 2118  
2119 2119          /*
2120 2120           * In both console and non-console cases, we require all privs.
2121 2121           * In the console case, because we may need to startup zoneadmd.
2122 2122           * In the non-console case in order to do zone_enter(2), zonept()
2123 2123           * and other tasks.
2124 2124           */
2125 2125  
2126 2126          if ((privset = priv_allocset()) == NULL) {
2127 2127                  zperror(gettext("priv_allocset failed"));
2128 2128                  return (1);
2129 2129          }
2130 2130  
2131 2131          if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
2132 2132                  zperror(gettext("getppriv failed"));
2133 2133                  priv_freeset(privset);
2134 2134                  return (1);
2135 2135          }
2136 2136  
2137 2137          if (priv_isfullset(privset) == B_FALSE) {
2138 2138                  zerror(gettext("You lack sufficient privilege to run "
2139 2139                      "this command (all privs required)"));
2140 2140                  priv_freeset(privset);
2141 2141                  return (1);
2142 2142          }
2143 2143          priv_freeset(privset);
2144 2144  
2145 2145          /*
2146 2146           * Check if user is authorized for requested usage of the zone
2147 2147           */
2148 2148  
2149 2149          (void) snprintf(authname, MAXAUTHS, "%s%s%s",
2150 2150              ZONE_MANAGE_AUTH, KV_OBJECT, zonename);
2151 2151          if (chkauthattr(authname, username) == 0) {
2152 2152                  if (console) {
2153 2153                          zerror(gettext("%s is not authorized for console "
2154 2154                              "access to  %s zone."),
2155 2155                              username, zonename);
2156 2156                          return (1);
2157 2157                  } else {
2158 2158                          (void) snprintf(authname, MAXAUTHS, "%s%s%s",
2159 2159                              ZONE_LOGIN_AUTH, KV_OBJECT, zonename);
2160 2160                          if (failsafe || !interactive) {
2161 2161                                  zerror(gettext("%s is not authorized for  "
2162 2162                                      "failsafe or non-interactive login "
2163 2163                                      "to  %s zone."), username, zonename);
2164 2164                                  return (1);
2165 2165                          } else if (chkauthattr(authname, username) == 0) {
2166 2166                                  zerror(gettext("%s is not authorized "
2167 2167                                      " to login to %s zone."),
2168 2168                                      username, zonename);
2169 2169                                  return (1);
2170 2170                          }
2171 2171                  }
2172 2172          } else {
2173 2173                  forced_login = B_TRUE;
2174 2174          }
2175 2175  
2176 2176          /*
2177 2177           * The console (or standalong interactive mode) is a separate case from
2178 2178           * the rest of the code; handle it first.
2179 2179           */
2180 2180          if (console) {
2181 2181                  int gz_stderr_fd = -1;
2182 2182                  int retry;
2183 2183                  boolean_t set_raw = B_TRUE;
2184 2184  
2185 2185                  if (imode) {
2186 2186                          boolean_t has_zfd_config;
2187 2187  
2188 2188                          if (zlog_mode_logging(zonename, &has_zfd_config))
2189 2189                                  set_raw = B_FALSE;
2190 2190  
2191 2191                          /*
2192 2192                           * Asked for standalone interactive mode but the
2193 2193                           * zlog-mode attribute is not configured on the zone.
2194 2194                           */
2195 2195                          if (!has_zfd_config) {
2196 2196                                  zerror(gettext("'%s' is not configured on "
2197 2197                                      "the zone"), "zlog-mode");
2198 2198                                  return (1);
2199 2199                          }
2200 2200                  }
2201 2201  
2202 2202                  /*
2203 2203                   * Ensure that zoneadmd for this zone is running.
2204 2204                   */
2205 2205                  if (start_zoneadmd(zonename) == -1)
2206 2206                          return (1);
2207 2207  
2208 2208                  /*
2209 2209                   * Make contact with zoneadmd.
  
    | 
      ↓ open down ↓ | 
    1616 lines elided | 
    
      ↑ open up ↑ | 
  
2210 2210                   *
2211 2211                   * Handshake with the control socket first. We handle retries
2212 2212                   * here since the relevant thread in zoneadmd might not have
2213 2213                   * finished setting up yet.
2214 2214                   */
2215 2215                  for (retry = 0; retry < MAX_RETRY; retry++) {
2216 2216                          masterfd = connect_zone_sock(zonename,
2217 2217                              (imode ? "server_ctl" : "console_sock"), B_FALSE);
2218 2218                          if (masterfd != -1)
2219 2219                                  break;
2220      -                        sleep(1);
     2220 +                        (void) sleep(1);
2221 2221                  }
2222 2222  
2223 2223                  if (retry == MAX_RETRY) {
2224 2224                          zerror(gettext("unable to connect for %d seconds"),
2225 2225                              MAX_RETRY);
2226 2226                          return (1);
2227 2227                  }
2228 2228  
2229 2229                  if (handshake_zone_sock(masterfd, connect_flags) != 0) {
2230 2230                          (void) close(masterfd);
2231 2231                          return (1);
2232 2232                  }
2233 2233  
2234 2234                  if (imode) {
2235 2235                          ctlfd = masterfd;
2236 2236  
2237 2237                          /* Now open the io-related sockets */
2238 2238                          masterfd = connect_zone_sock(zonename, "server_out",
2239 2239                              B_TRUE);
2240 2240                          gz_stderr_fd = connect_zone_sock(zonename,
2241 2241                              "server_err", B_TRUE);
2242 2242                          if (masterfd == -1 || gz_stderr_fd == -1) {
2243 2243                                  (void) close(ctlfd);
2244 2244                                  (void) close(masterfd);
2245 2245                                  (void) close(gz_stderr_fd);
2246 2246                                  return (1);
2247 2247                          }
2248 2248                  }
2249 2249  
2250 2250                  if (!quiet) {
2251 2251                          if (imode)
2252 2252                                  (void) printf(gettext("[Connected to zone '%s' "
2253 2253                                      "interactively]\n"), zonename);
2254 2254                          else
2255 2255                                  (void) printf(gettext("[Connected to zone '%s' "
2256 2256                                      "console]\n"), zonename);
2257 2257                  }
2258 2258  
2259 2259                  if (set_raw && set_tty_rawmode(STDIN_FILENO) == -1) {
2260 2260                          reset_tty();
2261 2261                          zperror(gettext("failed to set stdin pty to raw mode"));
2262 2262                          return (1);
2263 2263                  }
2264 2264  
2265 2265                  (void) sigset(SIGWINCH, sigwinch);
2266 2266                  (void) sigwinch(0);
2267 2267  
2268 2268                  if (imode) {
2269 2269                          /* Allow EOF mode toggling via SIGUSR1 */
2270 2270                          (void) sigset(SIGUSR1, sigusr1);
2271 2271                  }
2272 2272  
2273 2273                  /*
2274 2274                   * Run the I/O loop until we get disconnected.
2275 2275                   */
2276 2276                  doio(masterfd, -1, masterfd, gz_stderr_fd, -1, B_FALSE);
2277 2277                  reset_tty();
2278 2278                  if (!quiet) {
2279 2279                          if (imode)
2280 2280                                  (void) printf(gettext("\n[Interactive "
2281 2281                                      "connection to zone '%s' closed]\n"),
2282 2282                                      zonename);
2283 2283                          else
2284 2284                                  (void) printf(gettext("\n[Connection to zone "
2285 2285                                      "'%s' console closed]\n"), zonename);
2286 2286                  }
2287 2287  
2288 2288                  return (0);
2289 2289          }
2290 2290  
2291 2291          if (st != ZONE_STATE_RUNNING && st != ZONE_STATE_MOUNTED) {
2292 2292                  zerror(gettext("login allowed only to running zones "
2293 2293                      "(%s is '%s')."), zonename, zone_state_str(st));
2294 2294                  return (1);
2295 2295          }
2296 2296  
2297 2297          (void) strlcpy(kernzone, zonename, sizeof (kernzone));
2298 2298          if (zonecfg_in_alt_root()) {
2299 2299                  FILE *fp = zonecfg_open_scratch("", B_FALSE);
2300 2300  
2301 2301                  if (fp == NULL || zonecfg_find_scratch(fp, zonename,
2302 2302                      zonecfg_get_root(), kernzone, sizeof (kernzone)) == -1) {
2303 2303                          zerror(gettext("cannot find scratch zone %s"),
2304 2304                              zonename);
2305 2305                          if (fp != NULL)
2306 2306                                  zonecfg_close_scratch(fp);
2307 2307                          return (1);
2308 2308                  }
2309 2309                  zonecfg_close_scratch(fp);
2310 2310          }
2311 2311  
2312 2312          if ((zoneid = getzoneidbyname(kernzone)) == -1) {
2313 2313                  zerror(gettext("failed to get zoneid for zone '%s'"),
2314 2314                      zonename);
2315 2315                  return (1);
2316 2316          }
2317 2317  
2318 2318          /*
2319 2319           * We need the zone root path only if we are setting up a pty.
2320 2320           */
2321 2321          if (zone_get_devroot(zonename, devroot, sizeof (devroot)) == -1) {
2322 2322                  zerror(gettext("could not get dev path for zone %s"),
2323 2323                      zonename);
2324 2324                  return (1);
2325 2325          }
2326 2326  
2327 2327          if (zone_get_brand(zonename, zonebrand, sizeof (zonebrand)) != Z_OK) {
2328 2328                  zerror(gettext("could not get brand for zone %s"), zonename);
2329 2329                  return (1);
2330 2330          }
2331 2331          /*
2332 2332           * In the alternate root environment, the only supported
2333 2333           * operations are mount and unmount.  In this case, just treat
2334 2334           * the zone as native if it is cluster.  Cluster zones can be
2335 2335           * native for the purpose of LU or upgrade, and the cluster
2336 2336           * brand may not exist in the miniroot (such as in net install
2337 2337           * upgrade).
2338 2338           */
2339 2339          if (zonecfg_default_brand(default_brand,
2340 2340              sizeof (default_brand)) != Z_OK) {
2341 2341                  zerror(gettext("unable to determine default brand"));
2342 2342                  return (1);
2343 2343          }
2344 2344          if (zonecfg_in_alt_root() &&
2345 2345              strcmp(zonebrand, CLUSTER_BRAND_NAME) == 0) {
2346 2346                  (void) strlcpy(zonebrand, default_brand, sizeof (zonebrand));
2347 2347          }
2348 2348  
2349 2349          if ((bh = brand_open(zonebrand)) == NULL) {
2350 2350                  zerror(gettext("could not open brand for zone %s"), zonename);
2351 2351                  return (1);
2352 2352          }
2353 2353  
2354 2354          /*
2355 2355           * The 'interactive' parameter (-i option) indicates that we're running
2356 2356           * a command interactively. In this case we skip prep_args so that we
2357 2357           * don't prepend the 'su root -c' preamble to the command invocation
2358 2358           * since the 'su' command typically will execute a setpgrp which will
2359 2359           * disassociate the actual command from the controlling terminal that
2360 2360           * we (zlogin) setup.
2361 2361           */
2362 2362          if (!iflag) {
2363 2363                  if ((new_args = prep_args(bh, zonename, login, proc_args))
2364 2364                      == NULL) {
2365 2365                          zperror(gettext("could not assemble new arguments"));
2366 2366                          brand_close(bh);
2367 2367                          return (1);
2368 2368                  }
2369 2369          }
2370 2370  
2371 2371          /*
2372 2372           * Get the brand specific user_cmd.  This command is used to get
2373 2373           * a passwd(4) entry for login.
2374 2374           */
2375 2375          if (!interactive && !failsafe) {
2376 2376                  if (zone_get_user_cmd(bh, login, user_cmd,
2377 2377                      sizeof (user_cmd)) == NULL) {
2378 2378                          zerror(gettext("could not get user_cmd for zone %s"),
2379 2379                              zonename);
2380 2380                          brand_close(bh);
2381 2381                          return (1);
2382 2382                  }
2383 2383          }
2384 2384          brand_close(bh);
2385 2385  
2386 2386          if ((new_env = prep_env()) == NULL) {
2387 2387                  zperror(gettext("could not assemble new environment"));
2388 2388                  return (1);
2389 2389          }
2390 2390  
2391 2391          if (!interactive) {
2392 2392                  if (nflag) {
2393 2393                          int nfd;
2394 2394  
2395 2395                          if ((nfd = open(_PATH_DEVNULL, O_RDONLY)) < 0) {
2396 2396                                  zperror(gettext("failed to open null device"));
2397 2397                                  return (1);
2398 2398                          }
2399 2399                          if (nfd != STDIN_FILENO) {
2400 2400                                  if (dup2(nfd, STDIN_FILENO) < 0) {
2401 2401                                          zperror(gettext(
2402 2402                                              "failed to dup2 null device"));
2403 2403                                          return (1);
2404 2404                                  }
2405 2405                                  (void) close(nfd);
2406 2406                          }
2407 2407                          /* /dev/null is now standard input */
2408 2408                  }
2409 2409                  return (noninteractive_login(zonename, user_cmd, zoneid,
2410 2410                      new_args, new_env));
2411 2411          }
2412 2412  
2413 2413          if (zonecfg_in_alt_root()) {
2414 2414                  zerror(gettext("cannot use interactive login with scratch "
2415 2415                      "zone"));
2416 2416                  return (1);
2417 2417          }
2418 2418  
2419 2419          /*
2420 2420           * Things are more complex in interactive mode; we get the
2421 2421           * master side of the pty, then place the user's terminal into
2422 2422           * raw mode.
2423 2423           */
2424 2424          if (get_master_pty() == -1) {
2425 2425                  zerror(gettext("could not setup master pty device"));
2426 2426                  return (1);
2427 2427          }
2428 2428  
2429 2429          /*
2430 2430           * Compute the "short name" of the pts.  /dev/pts/2 --> pts/2
2431 2431           */
2432 2432          if ((slavename = ptsname(masterfd)) == NULL) {
2433 2433                  zperror(gettext("failed to get name for pseudo-tty"));
2434 2434                  return (1);
2435 2435          }
2436 2436          if (strncmp(slavename, "/dev/", strlen("/dev/")) == 0)
2437 2437                  (void) strlcpy(slaveshortname, slavename + strlen("/dev/"),
2438 2438                      sizeof (slaveshortname));
2439 2439          else
2440 2440                  (void) strlcpy(slaveshortname, slavename,
2441 2441                      sizeof (slaveshortname));
2442 2442  
2443 2443          if (!quiet)
2444 2444                  (void) printf(gettext("[Connected to zone '%s' %s]\n"),
2445 2445                      zonename, slaveshortname);
2446 2446  
2447 2447          if (set_tty_rawmode(STDIN_FILENO) == -1) {
2448 2448                  reset_tty();
2449 2449                  zperror(gettext("failed to set stdin pty to raw mode"));
2450 2450                  return (1);
2451 2451          }
2452 2452  
2453 2453          if (prefork_dropprivs() != 0) {
2454 2454                  reset_tty();
2455 2455                  zperror(gettext("could not allocate privilege set"));
2456 2456                  return (1);
2457 2457          }
2458 2458  
2459 2459          /*
2460 2460           * We must mask SIGCLD until after we have coped with the fork
2461 2461           * sufficiently to deal with it; otherwise we can race and receive the
2462 2462           * signal before child_pid has been initialized (yes, this really
2463 2463           * happens).
2464 2464           */
2465 2465          (void) sigset(SIGCLD, sigcld);
2466 2466          (void) sigemptyset(&block_cld);
2467 2467          (void) sigaddset(&block_cld, SIGCLD);
2468 2468          (void) sigprocmask(SIG_BLOCK, &block_cld, NULL);
2469 2469  
2470 2470          /*
2471 2471           * We activate the contract template at the last minute to
2472 2472           * avoid intermediate functions that could be using fork(2)
2473 2473           * internally.
2474 2474           */
2475 2475          if ((tmpl_fd = init_template()) == -1) {
2476 2476                  reset_tty();
2477 2477                  zperror(gettext("could not create contract"));
2478 2478                  return (1);
2479 2479          }
2480 2480  
2481 2481          if ((child_pid = fork()) == -1) {
2482 2482                  (void) ct_tmpl_clear(tmpl_fd);
2483 2483                  reset_tty();
2484 2484                  zperror(gettext("could not fork"));
2485 2485                  return (1);
2486 2486          } else if (child_pid == 0) { /* child process */
2487 2487                  int slavefd, newslave;
2488 2488  
2489 2489                  (void) ct_tmpl_clear(tmpl_fd);
2490 2490                  (void) close(tmpl_fd);
2491 2491  
2492 2492                  (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL);
2493 2493  
2494 2494                  if ((slavefd = init_slave_pty(zoneid, devroot)) == -1)
2495 2495                          return (1);
2496 2496  
2497 2497                  /*
2498 2498                   * Close all fds except for the slave pty.
2499 2499                   */
2500 2500                  (void) fdwalk(close_func, &slavefd);
2501 2501  
2502 2502                  /*
2503 2503                   * Temporarily dup slavefd to stderr; that way if we have
2504 2504                   * to print out that zone_enter failed, the output will
2505 2505                   * have somewhere to go.
2506 2506                   */
2507 2507                  if (slavefd != STDERR_FILENO)
2508 2508                          (void) dup2(slavefd, STDERR_FILENO);
2509 2509  
2510 2510                  if (zone_enter(zoneid) == -1) {
2511 2511                          zerror(gettext("could not enter zone %s: %s"),
2512 2512                              zonename, strerror(errno));
2513 2513                          return (1);
2514 2514                  }
2515 2515  
2516 2516                  /* Note: we're now inside the zone, can't use gettext anymore */
2517 2517  
2518 2518                  if (slavefd != STDERR_FILENO)
2519 2519                          (void) close(STDERR_FILENO);
2520 2520  
2521 2521                  /*
2522 2522                   * We take pains to get this process into a new process
2523 2523                   * group, and subsequently a new session.  In this way,
2524 2524                   * we'll have a session which doesn't yet have a controlling
2525 2525                   * terminal.  When we open the slave, it will become the
2526 2526                   * controlling terminal; no PIDs concerning pgrps or sids
2527 2527                   * will leak inappropriately into the zone.
2528 2528                   */
2529 2529                  (void) setpgrp();
2530 2530  
2531 2531                  /*
2532 2532                   * We need the slave pty to be referenced from the zone's
2533 2533                   * /dev in order to ensure that the devt's, etc are all
2534 2534                   * correct.  Otherwise we break ttyname and the like.
2535 2535                   */
2536 2536                  if ((newslave = open(slavename, O_RDWR)) == -1) {
2537 2537                          (void) close(slavefd);
2538 2538                          return (1);
2539 2539                  }
2540 2540                  (void) close(slavefd);
2541 2541                  slavefd = newslave;
2542 2542  
2543 2543                  /*
2544 2544                   * dup the slave to the various FDs, so that when the
2545 2545                   * spawned process does a write/read it maps to the slave
2546 2546                   * pty.
2547 2547                   */
2548 2548                  (void) dup2(slavefd, STDIN_FILENO);
2549 2549                  (void) dup2(slavefd, STDOUT_FILENO);
2550 2550                  (void) dup2(slavefd, STDERR_FILENO);
2551 2551                  if (slavefd != STDIN_FILENO && slavefd != STDOUT_FILENO &&
2552 2552                      slavefd != STDERR_FILENO) {
2553 2553                          (void) close(slavefd);
2554 2554                  }
2555 2555  
2556 2556                  /*
2557 2557                   * In failsafe mode, we don't use login(1), so don't try
2558 2558                   * setting up a utmpx entry.
2559 2559                   *
2560 2560                   * A branded zone may have very different utmpx semantics.
2561 2561                   * At the moment, we only have two brand types:
2562 2562                   * Illumos-like (native, sn1) and Linux.  In the Illumos
2563 2563                   * case, we know exactly how to do the necessary utmpx
2564 2564                   * setup.  Fortunately for us, the Linux /bin/login is
2565 2565                   * prepared to deal with a non-initialized utmpx entry, so
2566 2566                   * we can simply skip it.  If future brands don't fall into
2567 2567                   * either category, we'll have to add a per-brand utmpx
2568 2568                   * setup hook.
2569 2569                   */
2570 2570                  if (!failsafe && (strcmp(zonebrand, "lx") != 0))
2571 2571                          if (setup_utmpx(slaveshortname) == -1)
2572 2572                                  return (1);
2573 2573  
2574 2574                  /*
2575 2575                   * The child needs to run as root to
2576 2576                   * execute the brand's login program.
2577 2577                   */
2578 2578                  if (setuid(0) == -1) {
2579 2579                          zperror("insufficient privilege");
2580 2580                          return (1);
2581 2581                  }
2582 2582  
2583 2583                  if (iflag) {
2584 2584                          (void) execve(proc_args[0], proc_args, new_env);
2585 2585                  } else {
2586 2586                          (void) execve(new_args[0], new_args, new_env);
2587 2587                  }
2588 2588                  zperror("exec failure");
2589 2589                  return (ENOEXEC);
2590 2590          }
2591 2591  
2592 2592          (void) ct_tmpl_clear(tmpl_fd);
2593 2593          (void) close(tmpl_fd);
2594 2594  
2595 2595          /*
2596 2596           * The rest is only for the parent process.
2597 2597           */
2598 2598          (void) sigset(SIGWINCH, sigwinch);
2599 2599  
2600 2600          postfork_dropprivs();
2601 2601  
2602 2602          (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL);
2603 2603          doio(masterfd, -1, masterfd, -1, -1, B_FALSE);
2604 2604  
2605 2605          reset_tty();
2606 2606          if (!quiet)
2607 2607                  (void) fprintf(stderr,
2608 2608                      gettext("\n[Connection to zone '%s' %s closed]\n"),
2609 2609                      zonename, slaveshortname);
2610 2610  
2611 2611          if (pollerr != 0) {
2612 2612                  (void) fprintf(stderr, gettext("Error: connection closed due "
2613 2613                      "to unexpected pollevents=0x%x.\n"), pollerr);
2614 2614                  return (EPIPE);
2615 2615          }
2616 2616  
2617 2617          /* reap child and get its status */
2618 2618          if (waitid(P_PID, child_pid, &si, WEXITED | WNOHANG) == -1) {
2619 2619                  estatus = errno;
2620 2620          } else if (si.si_pid == 0) {
2621 2621                  estatus = ECHILD;
2622 2622          } else if (si.si_code == CLD_EXITED) {
2623 2623                  estatus = si.si_status;
2624 2624          } else {
2625 2625                  estatus = ECONNABORTED;
2626 2626          }
2627 2627  
2628 2628          return (estatus);
2629 2629  }
  
    | 
      ↓ open down ↓ | 
    399 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX