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