Print this page
3091 add -n to zlogin so its more compatible with rsh command line


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2013 DEY Storage Systems, Inc.

  24  */
  25 
  26 /*
  27  * zlogin provides three types of login which allow users in the global
  28  * zone to access non-global zones.
  29  *
  30  * - "interactive login" is similar to rlogin(1); for example, the user could
  31  *   issue 'zlogin my-zone' or 'zlogin -e ^ -l me my-zone'.   The user is
  32  *   granted a new pty (which is then shoved into the zone), and an I/O
  33  *   loop between parent and child processes takes care of the interactive
  34  *   session.  In this mode, login(1) (and its -c option, which means
  35  *   "already authenticated") is employed to take care of the initialization
  36  *   of the user's session.
  37  *
  38  * - "non-interactive login" is similar to su(1M); the user could issue
  39  *   'zlogin my-zone ls -l' and the command would be run as specified.
  40  *   In this mode, zlogin sets up pipes as the communication channel, and
  41  *   'su' is used to do the login setup work.
  42  *
  43  * - "console login" is the equivalent to accessing the tip line for a
  44  *   zone.  For example, the user can issue 'zlogin -C my-zone'.
  45  *   In this mode, zlogin contacts the zoneadmd process via unix domain
  46  *   socket.  If zoneadmd is not running, it starts it.  This allows the
  47  *   console to be available anytime the zone is installed, regardless of
  48  *   whether it is running.
  49  */
  50 
  51 #include <sys/socket.h>
  52 #include <sys/termios.h>
  53 #include <sys/utsname.h>
  54 #include <sys/stat.h>
  55 #include <sys/types.h>
  56 #include <sys/contract/process.h>
  57 #include <sys/ctfs.h>
  58 #include <sys/brand.h>
  59 #include <sys/wait.h>
  60 #include <alloca.h>
  61 #include <assert.h>
  62 #include <ctype.h>

  63 #include <door.h>
  64 #include <errno.h>
  65 #include <nss_dbdefs.h>
  66 #include <poll.h>
  67 #include <priv.h>
  68 #include <pwd.h>
  69 #include <unistd.h>
  70 #include <utmpx.h>
  71 #include <sac.h>
  72 #include <signal.h>
  73 #include <stdarg.h>
  74 #include <stdio.h>
  75 #include <stdlib.h>
  76 #include <string.h>
  77 #include <strings.h>
  78 #include <stropts.h>
  79 #include <wait.h>
  80 #include <zone.h>
  81 #include <fcntl.h>
  82 #include <libdevinfo.h>


 132  * than ZLOGIN_BUFSIZ (because we share the buffer in doio).  This value is
 133  * also chosen in conjunction with the HI_WATER setting to make sure we
 134  * don't fill up the pipe.  We can write FIFOHIWAT (16k) into the pipe before
 135  * blocking.  By having ZLOGIN_RDBUFSIZ set to 1k and HI_WATER set to 8k, we
 136  * know we can always write a ZLOGIN_RDBUFSIZ chunk into the pipe when there
 137  * is less than HI_WATER data already in the pipe.
 138  */
 139 #define ZLOGIN_BUFSIZ   8192
 140 #define ZLOGIN_RDBUFSIZ 1024
 141 #define HI_WATER        8192
 142 
 143 /*
 144  * See canonify() below.  CANONIFY_LEN is the maximum length that a
 145  * "canonical" sequence will expand to (backslash, three octal digits, NUL).
 146  */
 147 #define CANONIFY_LEN 5
 148 
 149 static void
 150 usage(void)
 151 {
 152         (void) fprintf(stderr, gettext("usage: %s [ -QCES ] [ -e cmdchar ] "
 153             "[-l user] zonename [command [args ...] ]\n"), pname);
 154         exit(2);
 155 }
 156 
 157 static const char *
 158 getpname(const char *arg0)
 159 {
 160         const char *p = strrchr(arg0, '/');
 161 
 162         if (p == NULL)
 163                 p = arg0;
 164         else
 165                 p++;
 166 
 167         pname = p;
 168         return (p);
 169 }
 170 
 171 static void
 172 zerror(const char *fmt, ...)


1712          * operating. So we start by getting the username that will be
1713          * used for subsequent authorization checks.
1714          */
1715 
1716         uid = getuid();
1717         if ((nptr = getpwuid(uid)) == NULL) {
1718                 zerror(gettext("could not get user name."));
1719                 _exit(1);
1720         }
1721         return (nptr->pw_name);
1722 }
1723 
1724 int
1725 main(int argc, char **argv)
1726 {
1727         int arg, console = 0;
1728         zoneid_t zoneid;
1729         zone_state_t st;
1730         char *login = "root";
1731         int lflag = 0;

1732         char *zonename = NULL;
1733         char **proc_args = NULL;
1734         char **new_args, **new_env;
1735         sigset_t block_cld;
1736         char devroot[MAXPATHLEN];
1737         char *slavename, slaveshortname[MAXPATHLEN];
1738         priv_set_t *privset;
1739         int tmpl_fd;
1740         char zonebrand[MAXNAMELEN];
1741         char default_brand[MAXNAMELEN];
1742         struct stat sb;
1743         char kernzone[ZONENAME_MAX];
1744         brand_handle_t bh;
1745         char user_cmd[MAXPATHLEN];
1746         char authname[MAXAUTHS];
1747 
1748         (void) setlocale(LC_ALL, "");
1749         (void) textdomain(TEXT_DOMAIN);
1750 
1751         (void) getpname(argv[0]);
1752         username = get_username();
1753 
1754         while ((arg = getopt(argc, argv, "ECR:Se:l:Q")) != EOF) {
1755                 switch (arg) {
1756                 case 'C':
1757                         console = 1;
1758                         break;
1759                 case 'E':
1760                         nocmdchar = 1;
1761                         break;
1762                 case 'R':       /* undocumented */
1763                         if (*optarg != '/') {
1764                                 zerror(gettext("root path must be absolute."));
1765                                 exit(2);
1766                         }
1767                         if (stat(optarg, &sb) == -1 || !S_ISDIR(sb.st_mode)) {
1768                                 zerror(
1769                                     gettext("root path must be a directory."));
1770                                 exit(2);
1771                         }
1772                         zonecfg_set_root(optarg);
1773                         break;
1774                 case 'Q':
1775                         quiet = 1;
1776                         break;
1777                 case 'S':
1778                         failsafe = 1;
1779                         break;
1780                 case 'e':
1781                         set_cmdchar(optarg);
1782                         break;
1783                 case 'l':
1784                         login = optarg;
1785                         lflag = 1;
1786                         break;



1787                 default:
1788                         usage();
1789                 }
1790         }
1791 
1792         if (console != 0 && lflag != 0) {
1793                 zerror(gettext("-l may not be specified for console login"));



1794                 usage();
1795         }
1796 
1797         if (console != 0 && failsafe != 0) {
1798                 zerror(gettext("-S may not be specified for console login"));

1799                 usage();
1800         }
1801 
1802         if (console != 0 && zonecfg_in_alt_root()) {
1803                 zerror(gettext("-R may not be specified for console login"));







1804                 exit(2);
1805         }
1806 


1807         if (failsafe != 0 && lflag != 0) {
1808                 zerror(gettext("-l may not be specified for failsafe login"));
1809                 usage();
1810         }
1811 
1812         if (optind == (argc - 1)) {
1813                 /*
1814                  * zone name, no process name; this should be an interactive
1815                  * as long as STDIN is really a tty.
1816                  */





1817                 if (isatty(STDIN_FILENO))
1818                         interactive = 1;
1819                 zonename = argv[optind];
1820         } else if (optind < (argc - 1)) {
1821                 if (console) {
1822                         zerror(gettext("Commands may not be specified for "
1823                             "console login."));
1824                         usage();
1825                 }
1826                 /* zone name and process name, and possibly some args */
1827                 zonename = argv[optind];
1828                 proc_args = &argv[optind + 1];
1829                 interactive = 0;
1830         } else {
1831                 usage();
1832         }
1833 
1834         if (getzoneid() != GLOBAL_ZONEID) {
1835                 zerror(gettext("'%s' may only be used from the global zone"),
1836                     pname);


2026         /*
2027          * Get the brand specific user_cmd.  This command is used to get
2028          * a passwd(4) entry for login.
2029          */
2030         if (!interactive && !failsafe) {
2031                 if (zone_get_user_cmd(bh, login, user_cmd,
2032                     sizeof (user_cmd)) == NULL) {
2033                         zerror(gettext("could not get user_cmd for zone %s"),
2034                             zonename);
2035                         brand_close(bh);
2036                         return (1);
2037                 }
2038         }
2039         brand_close(bh);
2040 
2041         if ((new_env = prep_env()) == NULL) {
2042                 zperror(gettext("could not assemble new environment"));
2043                 return (1);
2044         }
2045 
2046         if (!interactive)

















2047                 return (noninteractive_login(zonename, user_cmd, zoneid,
2048                     new_args, new_env));

2049 
2050         if (zonecfg_in_alt_root()) {
2051                 zerror(gettext("cannot use interactive login with scratch "
2052                     "zone"));
2053                 return (1);
2054         }
2055 
2056         /*
2057          * Things are more complex in interactive mode; we get the
2058          * master side of the pty, then place the user's terminal into
2059          * raw mode.
2060          */
2061         if (get_master_pty() == -1) {
2062                 zerror(gettext("could not setup master pty device"));
2063                 return (1);
2064         }
2065 
2066         /*
2067          * Compute the "short name" of the pts.  /dev/pts/2 --> pts/2
2068          */




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (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  */
  26 
  27 /*
  28  * zlogin provides three types of login which allow users in the global
  29  * zone to access non-global zones.
  30  *
  31  * - "interactive login" is similar to rlogin(1); for example, the user could
  32  *   issue 'zlogin my-zone' or 'zlogin -e ^ -l me my-zone'.   The user is
  33  *   granted a new pty (which is then shoved into the zone), and an I/O
  34  *   loop between parent and child processes takes care of the interactive
  35  *   session.  In this mode, login(1) (and its -c option, which means
  36  *   "already authenticated") is employed to take care of the initialization
  37  *   of the user's session.
  38  *
  39  * - "non-interactive login" is similar to su(1M); the user could issue
  40  *   'zlogin my-zone ls -l' and the command would be run as specified.
  41  *   In this mode, zlogin sets up pipes as the communication channel, and
  42  *   'su' is used to do the login setup work.
  43  *
  44  * - "console login" is the equivalent to accessing the tip line for a
  45  *   zone.  For example, the user can issue 'zlogin -C my-zone'.
  46  *   In this mode, zlogin contacts the zoneadmd process via unix domain
  47  *   socket.  If zoneadmd is not running, it starts it.  This allows the
  48  *   console to be available anytime the zone is installed, regardless of
  49  *   whether it is running.
  50  */
  51 
  52 #include <sys/socket.h>
  53 #include <sys/termios.h>
  54 #include <sys/utsname.h>
  55 #include <sys/stat.h>
  56 #include <sys/types.h>
  57 #include <sys/contract/process.h>
  58 #include <sys/ctfs.h>
  59 #include <sys/brand.h>
  60 #include <sys/wait.h>
  61 #include <alloca.h>
  62 #include <assert.h>
  63 #include <ctype.h>
  64 #include <paths.h>
  65 #include <door.h>
  66 #include <errno.h>
  67 #include <nss_dbdefs.h>
  68 #include <poll.h>
  69 #include <priv.h>
  70 #include <pwd.h>
  71 #include <unistd.h>
  72 #include <utmpx.h>
  73 #include <sac.h>
  74 #include <signal.h>
  75 #include <stdarg.h>
  76 #include <stdio.h>
  77 #include <stdlib.h>
  78 #include <string.h>
  79 #include <strings.h>
  80 #include <stropts.h>
  81 #include <wait.h>
  82 #include <zone.h>
  83 #include <fcntl.h>
  84 #include <libdevinfo.h>


 134  * than ZLOGIN_BUFSIZ (because we share the buffer in doio).  This value is
 135  * also chosen in conjunction with the HI_WATER setting to make sure we
 136  * don't fill up the pipe.  We can write FIFOHIWAT (16k) into the pipe before
 137  * blocking.  By having ZLOGIN_RDBUFSIZ set to 1k and HI_WATER set to 8k, we
 138  * know we can always write a ZLOGIN_RDBUFSIZ chunk into the pipe when there
 139  * is less than HI_WATER data already in the pipe.
 140  */
 141 #define ZLOGIN_BUFSIZ   8192
 142 #define ZLOGIN_RDBUFSIZ 1024
 143 #define HI_WATER        8192
 144 
 145 /*
 146  * See canonify() below.  CANONIFY_LEN is the maximum length that a
 147  * "canonical" sequence will expand to (backslash, three octal digits, NUL).
 148  */
 149 #define CANONIFY_LEN 5
 150 
 151 static void
 152 usage(void)
 153 {
 154         (void) fprintf(stderr, gettext("usage: %s [ -nQCES ] [ -e cmdchar ] "
 155             "[-l user] zonename [command [args ...] ]\n"), pname);
 156         exit(2);
 157 }
 158 
 159 static const char *
 160 getpname(const char *arg0)
 161 {
 162         const char *p = strrchr(arg0, '/');
 163 
 164         if (p == NULL)
 165                 p = arg0;
 166         else
 167                 p++;
 168 
 169         pname = p;
 170         return (p);
 171 }
 172 
 173 static void
 174 zerror(const char *fmt, ...)


1714          * operating. So we start by getting the username that will be
1715          * used for subsequent authorization checks.
1716          */
1717 
1718         uid = getuid();
1719         if ((nptr = getpwuid(uid)) == NULL) {
1720                 zerror(gettext("could not get user name."));
1721                 _exit(1);
1722         }
1723         return (nptr->pw_name);
1724 }
1725 
1726 int
1727 main(int argc, char **argv)
1728 {
1729         int arg, console = 0;
1730         zoneid_t zoneid;
1731         zone_state_t st;
1732         char *login = "root";
1733         int lflag = 0;
1734         int nflag = 0;
1735         char *zonename = NULL;
1736         char **proc_args = NULL;
1737         char **new_args, **new_env;
1738         sigset_t block_cld;
1739         char devroot[MAXPATHLEN];
1740         char *slavename, slaveshortname[MAXPATHLEN];
1741         priv_set_t *privset;
1742         int tmpl_fd;
1743         char zonebrand[MAXNAMELEN];
1744         char default_brand[MAXNAMELEN];
1745         struct stat sb;
1746         char kernzone[ZONENAME_MAX];
1747         brand_handle_t bh;
1748         char user_cmd[MAXPATHLEN];
1749         char authname[MAXAUTHS];
1750 
1751         (void) setlocale(LC_ALL, "");
1752         (void) textdomain(TEXT_DOMAIN);
1753 
1754         (void) getpname(argv[0]);
1755         username = get_username();
1756 
1757         while ((arg = getopt(argc, argv, "nECR:Se:l:Q")) != EOF) {
1758                 switch (arg) {
1759                 case 'C':
1760                         console = 1;
1761                         break;
1762                 case 'E':
1763                         nocmdchar = 1;
1764                         break;
1765                 case 'R':       /* undocumented */
1766                         if (*optarg != '/') {
1767                                 zerror(gettext("root path must be absolute."));
1768                                 exit(2);
1769                         }
1770                         if (stat(optarg, &sb) == -1 || !S_ISDIR(sb.st_mode)) {
1771                                 zerror(
1772                                     gettext("root path must be a directory."));
1773                                 exit(2);
1774                         }
1775                         zonecfg_set_root(optarg);
1776                         break;
1777                 case 'Q':
1778                         quiet = 1;
1779                         break;
1780                 case 'S':
1781                         failsafe = 1;
1782                         break;
1783                 case 'e':
1784                         set_cmdchar(optarg);
1785                         break;
1786                 case 'l':
1787                         login = optarg;
1788                         lflag = 1;
1789                         break;
1790                 case 'n':
1791                         nflag = 1;
1792                         break;
1793                 default:
1794                         usage();
1795                 }
1796         }
1797 
1798         if (console != 0) {
1799 
1800                 if (lflag != 0) {
1801                         zerror(gettext(
1802                             "-l may not be specified for console login"));
1803                         usage();
1804                 }
1805 
1806                 if (nflag != 0) {
1807                         zerror(gettext(
1808                             "-n may not be specified for console login"));
1809                         usage();
1810                 }
1811 
1812                 if (failsafe != 0) {
1813                         zerror(gettext(
1814                             "-S may not be specified for console login"));
1815                         usage();
1816                 }
1817 
1818                 if (zonecfg_in_alt_root()) {
1819                         zerror(gettext(
1820                             "-R may not be specified for console login"));
1821                         exit(2);
1822                 }
1823 
1824         }
1825 
1826         if (failsafe != 0 && lflag != 0) {
1827                 zerror(gettext("-l may not be specified for failsafe login"));
1828                 usage();
1829         }
1830 
1831         if (optind == (argc - 1)) {
1832                 /*
1833                  * zone name, no process name; this should be an interactive
1834                  * as long as STDIN is really a tty.
1835                  */
1836                 if (nflag != 0) {
1837                         zerror(gettext(
1838                             "-n may not be specified for interactive login"));
1839                         usage();
1840                 }
1841                 if (isatty(STDIN_FILENO))
1842                         interactive = 1;
1843                 zonename = argv[optind];
1844         } else if (optind < (argc - 1)) {
1845                 if (console) {
1846                         zerror(gettext("Commands may not be specified for "
1847                             "console login."));
1848                         usage();
1849                 }
1850                 /* zone name and process name, and possibly some args */
1851                 zonename = argv[optind];
1852                 proc_args = &argv[optind + 1];
1853                 interactive = 0;
1854         } else {
1855                 usage();
1856         }
1857 
1858         if (getzoneid() != GLOBAL_ZONEID) {
1859                 zerror(gettext("'%s' may only be used from the global zone"),
1860                     pname);


2050         /*
2051          * Get the brand specific user_cmd.  This command is used to get
2052          * a passwd(4) entry for login.
2053          */
2054         if (!interactive && !failsafe) {
2055                 if (zone_get_user_cmd(bh, login, user_cmd,
2056                     sizeof (user_cmd)) == NULL) {
2057                         zerror(gettext("could not get user_cmd for zone %s"),
2058                             zonename);
2059                         brand_close(bh);
2060                         return (1);
2061                 }
2062         }
2063         brand_close(bh);
2064 
2065         if ((new_env = prep_env()) == NULL) {
2066                 zperror(gettext("could not assemble new environment"));
2067                 return (1);
2068         }
2069 
2070         if (!interactive) {
2071                 if (nflag) {
2072                         int nfd;
2073 
2074                         if ((nfd = open(_PATH_DEVNULL, O_RDONLY)) < 0) {
2075                                 zperror(gettext("failed to open null device"));
2076                                 return (1);
2077                         }
2078                         if (nfd != STDIN_FILENO) {
2079                                 if (dup2(nfd, STDIN_FILENO) < 0) {
2080                                         zperror(gettext(
2081                                             "failed to dup2 null device"));
2082                                         return (1);
2083                                 }
2084                                 (void) close(nfd);
2085                         }
2086                         /* /dev/null is now standard input */
2087                 }
2088                 return (noninteractive_login(zonename, user_cmd, zoneid,
2089                     new_args, new_env));
2090         }
2091 
2092         if (zonecfg_in_alt_root()) {
2093                 zerror(gettext("cannot use interactive login with scratch "
2094                     "zone"));
2095                 return (1);
2096         }
2097 
2098         /*
2099          * Things are more complex in interactive mode; we get the
2100          * master side of the pty, then place the user's terminal into
2101          * raw mode.
2102          */
2103         if (get_master_pty() == -1) {
2104                 zerror(gettext("could not setup master pty device"));
2105                 return (1);
2106         }
2107 
2108         /*
2109          * Compute the "short name" of the pts.  /dev/pts/2 --> pts/2
2110          */