5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2013 DEY Storage Systems, Inc.
  24  * Copyright (c) 2014 Gary Mills
  25  * Copyright 2016 Joyent, Inc.
  26  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  27  */
  28 
  29 /*
  30  * zlogin provides five types of login which allow users in the global
  31  * zone to access non-global zones.
  32  *
  33  * - "interactive login" is similar to rlogin(1); for example, the user could
  34  *   issue 'zlogin my-zone' or 'zlogin -e ^ -l me my-zone'.   The user is
  35  *   granted a new pty (which is then shoved into the zone), and an I/O
  36  *   loop between parent and child processes takes care of the interactive
  37  *   session.  In this mode, login(1) (and its -c option, which means
  38  *   "already authenticated") is employed to take care of the initialization
  39  *   of the user's session.
  40  *
  41  * - "non-interactive login" is similar to su(1M); the user could issue
  42  *   'zlogin my-zone ls -l' and the command would be run as specified.
  43  *   In this mode, zlogin sets up pipes as the communication channel, and
  44  *   'su' is used to do the login setup work.
  45  *
  46  * - "interactive command" is a combination of the above two modes where
 
 
 268 static int
 269 connect_zone_sock(const char *zname, const char *suffix, boolean_t verbose)
 270 {
 271         int sockfd = -1;
 272         struct sockaddr_un servaddr;
 273 
 274         if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
 275                 if (verbose)
 276                         zperror(gettext("could not create socket"));
 277                 return (-1);
 278         }
 279 
 280         bzero(&servaddr, sizeof (servaddr));
 281         servaddr.sun_family = AF_UNIX;
 282         (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
 283             "%s/%s.%s", ZONES_TMPDIR, zname, suffix);
 284         if (connect(sockfd, (struct sockaddr *)&servaddr,
 285             sizeof (servaddr)) == -1) {
 286                 if (verbose)
 287                         zperror(gettext("Could not connect to zone"));
 288                 close(sockfd);
 289                 return (-1);
 290         }
 291         return (sockfd);
 292 }
 293 
 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 
 306         if (msglen >= sizeof (clientid) || msglen < 0) {
 307                 zerror("protocol error");
 308                 return (-1);
 
 544                 return (-1);
 545         }
 546         effective_termios.c_cc[VEOF] = save_termios.c_cc[VEOF];
 547         effective_termios.c_cc[VEOL] = save_termios.c_cc[VEOL];
 548 
 549         return (0);
 550 }
 551 
 552 /*
 553  * Copy terminal window size from our terminal to the pts.
 554  */
 555 /*ARGSUSED*/
 556 static void
 557 sigwinch(int s)
 558 {
 559         struct winsize ws;
 560 
 561         if (ioctl(0, TIOCGWINSZ, &ws) == 0) {
 562                 if (ctlfd != -1) {
 563                         char buf[BUFSIZ];
 564                         snprintf(buf, sizeof (buf), "TIOCSWINSZ %hu %hu\n",
 565                             ws.ws_row, ws.ws_col);
 566                         (void) send_ctl_sock(buf, strlen(buf));
 567                 } else {
 568                         (void) ioctl(masterfd, TIOCSWINSZ, &ws);
 569                 }
 570         }
 571 }
 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                 snprintf(buf, sizeof (buf), "SETFLAGS %u\n",
 584                     connect_flags);
 585                 (void) send_ctl_sock(buf, strlen(buf));
 586         }
 587 }
 588 
 589 static volatile int close_on_sig = -1;
 590 
 591 static void
 592 /*ARGSUSED*/
 593 sigcld(int s)
 594 {
 595         int status;
 596         pid_t pid;
 597 
 598         /*
 599          * Peek at the exit status.  If this isn't the process we cared
 600          * about, then just reap it.
 601          */
 602         if ((pid = waitpid(child_pid, &status, WNOHANG|WNOWAIT)) != -1) {
 603                 if (pid == child_pid &&
 
2200                 }
2201 
2202                 /*
2203                  * Ensure that zoneadmd for this zone is running.
2204                  */
2205                 if (start_zoneadmd(zonename) == -1)
2206                         return (1);
2207 
2208                 /*
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.
2214                  */
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                         sleep(1);
2221                 }
2222 
2223                 if (retry == MAX_RETRY) {
2224                         zerror(gettext("unable to connect for %d seconds"),
2225                             MAX_RETRY);
2226                         return (1);
2227                 }
2228 
2229                 if (handshake_zone_sock(masterfd, connect_flags) != 0) {
2230                         (void) close(masterfd);
2231                         return (1);
2232                 }
2233 
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,
 
 | 
 
 
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2013 DEY Storage Systems, Inc.
  24  * Copyright (c) 2014 Gary Mills
  25  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  26  * Copyright 2016 Joyent, Inc.
  27  */
  28 
  29 /*
  30  * zlogin provides five types of login which allow users in the global
  31  * zone to access non-global zones.
  32  *
  33  * - "interactive login" is similar to rlogin(1); for example, the user could
  34  *   issue 'zlogin my-zone' or 'zlogin -e ^ -l me my-zone'.   The user is
  35  *   granted a new pty (which is then shoved into the zone), and an I/O
  36  *   loop between parent and child processes takes care of the interactive
  37  *   session.  In this mode, login(1) (and its -c option, which means
  38  *   "already authenticated") is employed to take care of the initialization
  39  *   of the user's session.
  40  *
  41  * - "non-interactive login" is similar to su(1M); the user could issue
  42  *   'zlogin my-zone ls -l' and the command would be run as specified.
  43  *   In this mode, zlogin sets up pipes as the communication channel, and
  44  *   'su' is used to do the login setup work.
  45  *
  46  * - "interactive command" is a combination of the above two modes where
 
 
 268 static int
 269 connect_zone_sock(const char *zname, const char *suffix, boolean_t verbose)
 270 {
 271         int sockfd = -1;
 272         struct sockaddr_un servaddr;
 273 
 274         if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
 275                 if (verbose)
 276                         zperror(gettext("could not create socket"));
 277                 return (-1);
 278         }
 279 
 280         bzero(&servaddr, sizeof (servaddr));
 281         servaddr.sun_family = AF_UNIX;
 282         (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
 283             "%s/%s.%s", ZONES_TMPDIR, zname, suffix);
 284         if (connect(sockfd, (struct sockaddr *)&servaddr,
 285             sizeof (servaddr)) == -1) {
 286                 if (verbose)
 287                         zperror(gettext("Could not connect to zone"));
 288                 (void) close(sockfd);
 289                 return (-1);
 290         }
 291         return (sockfd);
 292 }
 293 
 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 
 306         if (msglen >= sizeof (clientid) || msglen < 0) {
 307                 zerror("protocol error");
 308                 return (-1);
 
 544                 return (-1);
 545         }
 546         effective_termios.c_cc[VEOF] = save_termios.c_cc[VEOF];
 547         effective_termios.c_cc[VEOL] = save_termios.c_cc[VEOL];
 548 
 549         return (0);
 550 }
 551 
 552 /*
 553  * Copy terminal window size from our terminal to the pts.
 554  */
 555 /*ARGSUSED*/
 556 static void
 557 sigwinch(int s)
 558 {
 559         struct winsize ws;
 560 
 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         }
 571 }
 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 
 589 static volatile int close_on_sig = -1;
 590 
 591 static void
 592 /*ARGSUSED*/
 593 sigcld(int s)
 594 {
 595         int status;
 596         pid_t pid;
 597 
 598         /*
 599          * Peek at the exit status.  If this isn't the process we cared
 600          * about, then just reap it.
 601          */
 602         if ((pid = waitpid(child_pid, &status, WNOHANG|WNOWAIT)) != -1) {
 603                 if (pid == child_pid &&
 
2200                 }
2201 
2202                 /*
2203                  * Ensure that zoneadmd for this zone is running.
2204                  */
2205                 if (start_zoneadmd(zonename) == -1)
2206                         return (1);
2207 
2208                 /*
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.
2214                  */
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);
2226                         return (1);
2227                 }
2228 
2229                 if (handshake_zone_sock(masterfd, connect_flags) != 0) {
2230                         (void) close(masterfd);
2231                         return (1);
2232                 }
2233 
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,
 
 |