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 */
|