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 2014 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 /*
29 * zlogin provides three types of login which allow users in the global
30 * zone to access non-global zones.
31 *
32 * - "interactive login" is similar to rlogin(1); for example, the user could
33 * issue 'zlogin my-zone' or 'zlogin -e ^ -l me my-zone'. The user is
34 * granted a new pty (which is then shoved into the zone), and an I/O
35 * loop between parent and child processes takes care of the interactive
36 * session. In this mode, login(1) (and its -c option, which means
37 * "already authenticated") is employed to take care of the initialization
38 * of the user's session.
39 *
40 * - "non-interactive login" is similar to su(1M); the user could issue
41 * 'zlogin my-zone ls -l' and the command would be run as specified.
42 * In this mode, zlogin sets up pipes as the communication channel, and
43 * 'su' is used to do the login setup work.
44 *
45 * - "console login" is the equivalent to accessing the tip line for a
87 #include <locale.h>
88 #include <libzonecfg.h>
89 #include <libcontract.h>
90 #include <libbrand.h>
91 #include <auth_list.h>
92 #include <auth_attr.h>
93 #include <secdb.h>
94
95 static int masterfd;
96 static struct termios save_termios;
97 static struct termios effective_termios;
98 static int save_fd;
99 static struct winsize winsize;
100 static volatile int dead;
101 static volatile pid_t child_pid = -1;
102 static int interactive = 0;
103 static priv_set_t *dropprivs;
104
105 static int nocmdchar = 0;
106 static int failsafe = 0;
107 static char cmdchar = '~';
108 static int quiet = 0;
109
110 static int pollerr = 0;
111
112 static const char *pname;
113 static char *username;
114
115 /*
116 * When forced_login is true, the user is not prompted
117 * for an authentication password in the target zone.
118 */
119 static boolean_t forced_login = B_FALSE;
120
121 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
122 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
123 #endif
124
125 #define SUPATH "/usr/bin/su"
126 #define FAILSAFESHELL "/sbin/sh"
135 * than ZLOGIN_BUFSIZ (because we share the buffer in doio). This value is
136 * also chosen in conjunction with the HI_WATER setting to make sure we
137 * don't fill up the pipe. We can write FIFOHIWAT (16k) into the pipe before
138 * blocking. By having ZLOGIN_RDBUFSIZ set to 1k and HI_WATER set to 8k, we
139 * know we can always write a ZLOGIN_RDBUFSIZ chunk into the pipe when there
140 * is less than HI_WATER data already in the pipe.
141 */
142 #define ZLOGIN_BUFSIZ 8192
143 #define ZLOGIN_RDBUFSIZ 1024
144 #define HI_WATER 8192
145
146 /*
147 * See canonify() below. CANONIFY_LEN is the maximum length that a
148 * "canonical" sequence will expand to (backslash, three octal digits, NUL).
149 */
150 #define CANONIFY_LEN 5
151
152 static void
153 usage(void)
154 {
155 (void) fprintf(stderr, gettext("usage: %s [ -nQCES ] [ -e cmdchar ] "
156 "[-l user] zonename [command [args ...] ]\n"), pname);
157 exit(2);
158 }
159
160 static const char *
161 getpname(const char *arg0)
162 {
163 const char *p = strrchr(arg0, '/');
164
165 if (p == NULL)
166 p = arg0;
167 else
168 p++;
169
170 pname = p;
171 return (p);
172 }
173
174 static void
175 zerror(const char *fmt, ...)
261 int msglen;
262 int i = 0, err = 0;
263
264 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
265 zperror(gettext("could not create socket"));
266 return (-1);
267 }
268
269 bzero(&servaddr, sizeof (servaddr));
270 servaddr.sun_family = AF_UNIX;
271 (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
272 "%s/%s.console_sock", ZONES_TMPDIR, zname);
273
274 if (connect(sockfd, (struct sockaddr *)&servaddr,
275 sizeof (servaddr)) == -1) {
276 zperror(gettext("Could not connect to zone console"));
277 goto bad;
278 }
279 masterfd = sockfd;
280
281 msglen = snprintf(clientid, sizeof (clientid), "IDENT %lu %s\n",
282 getpid(), setlocale(LC_MESSAGES, NULL));
283
284 if (msglen >= sizeof (clientid) || msglen < 0) {
285 zerror("protocol error");
286 goto bad;
287 }
288
289 if (write(masterfd, clientid, msglen) != msglen) {
290 zerror("protocol error");
291 goto bad;
292 }
293
294 bzero(handshake, sizeof (handshake));
295
296 /*
297 * Take care not to accumulate more than our fill, and leave room for
298 * the NUL at the end.
299 */
300 while ((err = read(masterfd, &c, 1)) == 1) {
301 if (i >= (sizeof (handshake) - 1))
302 break;
1736 char **new_args, **new_env;
1737 sigset_t block_cld;
1738 char devroot[MAXPATHLEN];
1739 char *slavename, slaveshortname[MAXPATHLEN];
1740 priv_set_t *privset;
1741 int tmpl_fd;
1742 char zonebrand[MAXNAMELEN];
1743 char default_brand[MAXNAMELEN];
1744 struct stat sb;
1745 char kernzone[ZONENAME_MAX];
1746 brand_handle_t bh;
1747 char user_cmd[MAXPATHLEN];
1748 char authname[MAXAUTHS];
1749
1750 (void) setlocale(LC_ALL, "");
1751 (void) textdomain(TEXT_DOMAIN);
1752
1753 (void) getpname(argv[0]);
1754 username = get_username();
1755
1756 while ((arg = getopt(argc, argv, "nECR:Se:l:Q")) != EOF) {
1757 switch (arg) {
1758 case 'C':
1759 console = 1;
1760 break;
1761 case 'E':
1762 nocmdchar = 1;
1763 break;
1764 case 'R': /* undocumented */
1765 if (*optarg != '/') {
1766 zerror(gettext("root path must be absolute."));
1767 exit(2);
1768 }
1769 if (stat(optarg, &sb) == -1 || !S_ISDIR(sb.st_mode)) {
1770 zerror(
1771 gettext("root path must be a directory."));
1772 exit(2);
1773 }
1774 zonecfg_set_root(optarg);
1775 break;
1776 case 'Q':
1777 quiet = 1;
1778 break;
1779 case 'S':
1780 failsafe = 1;
1781 break;
1782 case 'e':
1783 set_cmdchar(optarg);
1784 break;
1785 case 'l':
1786 login = optarg;
1787 lflag = 1;
1788 break;
1789 case 'n':
1790 nflag = 1;
1791 break;
1792 default:
1793 usage();
1794 }
1795 }
1796
1797 if (console != 0) {
1798
1799 if (lflag != 0) {
1800 zerror(gettext(
1801 "-l may not be specified for console login"));
1809 }
1810
1811 if (failsafe != 0) {
1812 zerror(gettext(
1813 "-S may not be specified for console login"));
1814 usage();
1815 }
1816
1817 if (zonecfg_in_alt_root()) {
1818 zerror(gettext(
1819 "-R may not be specified for console login"));
1820 exit(2);
1821 }
1822
1823 }
1824
1825 if (failsafe != 0 && lflag != 0) {
1826 zerror(gettext("-l may not be specified for failsafe login"));
1827 usage();
1828 }
1829
1830 if (optind == (argc - 1)) {
1831 /*
1832 * zone name, no process name; this should be an interactive
1833 * as long as STDIN is really a tty.
1834 */
1835 if (nflag != 0) {
1836 zerror(gettext(
1837 "-n may not be specified for interactive login"));
1838 usage();
1839 }
1840 if (isatty(STDIN_FILENO))
1841 interactive = 1;
1842 zonename = argv[optind];
1843 } else if (optind < (argc - 1)) {
1844 if (console) {
1845 zerror(gettext("Commands may not be specified for "
1846 "console login."));
1847 usage();
1848 }
|
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 */
27
28 /*
29 * zlogin provides three types of login which allow users in the global
30 * zone to access non-global zones.
31 *
32 * - "interactive login" is similar to rlogin(1); for example, the user could
33 * issue 'zlogin my-zone' or 'zlogin -e ^ -l me my-zone'. The user is
34 * granted a new pty (which is then shoved into the zone), and an I/O
35 * loop between parent and child processes takes care of the interactive
36 * session. In this mode, login(1) (and its -c option, which means
37 * "already authenticated") is employed to take care of the initialization
38 * of the user's session.
39 *
40 * - "non-interactive login" is similar to su(1M); the user could issue
41 * 'zlogin my-zone ls -l' and the command would be run as specified.
42 * In this mode, zlogin sets up pipes as the communication channel, and
43 * 'su' is used to do the login setup work.
44 *
45 * - "console login" is the equivalent to accessing the tip line for a
87 #include <locale.h>
88 #include <libzonecfg.h>
89 #include <libcontract.h>
90 #include <libbrand.h>
91 #include <auth_list.h>
92 #include <auth_attr.h>
93 #include <secdb.h>
94
95 static int masterfd;
96 static struct termios save_termios;
97 static struct termios effective_termios;
98 static int save_fd;
99 static struct winsize winsize;
100 static volatile int dead;
101 static volatile pid_t child_pid = -1;
102 static int interactive = 0;
103 static priv_set_t *dropprivs;
104
105 static int nocmdchar = 0;
106 static int failsafe = 0;
107 static int disconnect = 0;
108 static char cmdchar = '~';
109 static int quiet = 0;
110
111 static int pollerr = 0;
112
113 static const char *pname;
114 static char *username;
115
116 /*
117 * When forced_login is true, the user is not prompted
118 * for an authentication password in the target zone.
119 */
120 static boolean_t forced_login = B_FALSE;
121
122 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
123 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
124 #endif
125
126 #define SUPATH "/usr/bin/su"
127 #define FAILSAFESHELL "/sbin/sh"
136 * than ZLOGIN_BUFSIZ (because we share the buffer in doio). This value is
137 * also chosen in conjunction with the HI_WATER setting to make sure we
138 * don't fill up the pipe. We can write FIFOHIWAT (16k) into the pipe before
139 * blocking. By having ZLOGIN_RDBUFSIZ set to 1k and HI_WATER set to 8k, we
140 * know we can always write a ZLOGIN_RDBUFSIZ chunk into the pipe when there
141 * is less than HI_WATER data already in the pipe.
142 */
143 #define ZLOGIN_BUFSIZ 8192
144 #define ZLOGIN_RDBUFSIZ 1024
145 #define HI_WATER 8192
146
147 /*
148 * See canonify() below. CANONIFY_LEN is the maximum length that a
149 * "canonical" sequence will expand to (backslash, three octal digits, NUL).
150 */
151 #define CANONIFY_LEN 5
152
153 static void
154 usage(void)
155 {
156 (void) fprintf(stderr, gettext("usage: %s [ -dnQCES ] [ -e cmdchar ] "
157 "[-l user] zonename [command [args ...] ]\n"), pname);
158 exit(2);
159 }
160
161 static const char *
162 getpname(const char *arg0)
163 {
164 const char *p = strrchr(arg0, '/');
165
166 if (p == NULL)
167 p = arg0;
168 else
169 p++;
170
171 pname = p;
172 return (p);
173 }
174
175 static void
176 zerror(const char *fmt, ...)
262 int msglen;
263 int i = 0, err = 0;
264
265 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
266 zperror(gettext("could not create socket"));
267 return (-1);
268 }
269
270 bzero(&servaddr, sizeof (servaddr));
271 servaddr.sun_family = AF_UNIX;
272 (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
273 "%s/%s.console_sock", ZONES_TMPDIR, zname);
274
275 if (connect(sockfd, (struct sockaddr *)&servaddr,
276 sizeof (servaddr)) == -1) {
277 zperror(gettext("Could not connect to zone console"));
278 goto bad;
279 }
280 masterfd = sockfd;
281
282 msglen = snprintf(clientid, sizeof (clientid), "IDENT %lu %s %d\n",
283 getpid(), setlocale(LC_MESSAGES, NULL), disconnect);
284
285 if (msglen >= sizeof (clientid) || msglen < 0) {
286 zerror("protocol error");
287 goto bad;
288 }
289
290 if (write(masterfd, clientid, msglen) != msglen) {
291 zerror("protocol error");
292 goto bad;
293 }
294
295 bzero(handshake, sizeof (handshake));
296
297 /*
298 * Take care not to accumulate more than our fill, and leave room for
299 * the NUL at the end.
300 */
301 while ((err = read(masterfd, &c, 1)) == 1) {
302 if (i >= (sizeof (handshake) - 1))
303 break;
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, "dnECR: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 'd':
1784 disconnect = 1;
1785 break;
1786 case 'e':
1787 set_cmdchar(optarg);
1788 break;
1789 case 'l':
1790 login = optarg;
1791 lflag = 1;
1792 break;
1793 case 'n':
1794 nflag = 1;
1795 break;
1796 default:
1797 usage();
1798 }
1799 }
1800
1801 if (console != 0) {
1802
1803 if (lflag != 0) {
1804 zerror(gettext(
1805 "-l may not be specified for console login"));
1813 }
1814
1815 if (failsafe != 0) {
1816 zerror(gettext(
1817 "-S may not be specified for console login"));
1818 usage();
1819 }
1820
1821 if (zonecfg_in_alt_root()) {
1822 zerror(gettext(
1823 "-R may not be specified for console login"));
1824 exit(2);
1825 }
1826
1827 }
1828
1829 if (failsafe != 0 && lflag != 0) {
1830 zerror(gettext("-l may not be specified for failsafe login"));
1831 usage();
1832 }
1833
1834 if (!console && disconnect != 0) {
1835 zerror(gettext(
1836 "-d may only be specified with console login"));
1837 usage();
1838 }
1839
1840 if (optind == (argc - 1)) {
1841 /*
1842 * zone name, no process name; this should be an interactive
1843 * as long as STDIN is really a tty.
1844 */
1845 if (nflag != 0) {
1846 zerror(gettext(
1847 "-n may not be specified for interactive login"));
1848 usage();
1849 }
1850 if (isatty(STDIN_FILENO))
1851 interactive = 1;
1852 zonename = argv[optind];
1853 } else if (optind < (argc - 1)) {
1854 if (console) {
1855 zerror(gettext("Commands may not be specified for "
1856 "console login."));
1857 usage();
1858 }
|