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
46 * zone. For example, the user can issue 'zlogin -C my-zone'.
47 * In this mode, zlogin contacts the zoneadmd process via unix domain
48 * socket. If zoneadmd is not running, it starts it. This allows the
49 * console to be available anytime the zone is installed, regardless of
50 * whether it is running.
51 */
52
53 #include <sys/socket.h>
54 #include <sys/termios.h>
55 #include <sys/utsname.h>
56 #include <sys/stat.h>
57 #include <sys/types.h>
58 #include <sys/contract/process.h>
59 #include <sys/ctfs.h>
60 #include <sys/brand.h>
61 #include <sys/wait.h>
62 #include <alloca.h>
63 #include <assert.h>
64 #include <ctype.h>
65 #include <paths.h>
66 #include <door.h>
67 #include <errno.h>
68 #include <nss_dbdefs.h>
69 #include <poll.h>
70 #include <priv.h>
75 #include <signal.h>
76 #include <stdarg.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <strings.h>
81 #include <stropts.h>
82 #include <wait.h>
83 #include <zone.h>
84 #include <fcntl.h>
85 #include <libdevinfo.h>
86 #include <libintl.h>
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"
128 #define DEFAULTSHELL "/sbin/sh"
129 #define DEF_PATH "/usr/sbin:/usr/bin"
130
131 #define CLUSTER_BRAND_NAME "cluster"
132
133 /*
134 * The ZLOGIN_BUFSIZ is larger than PIPE_BUF so we can be sure we're clearing
135 * out the pipe when the child is exiting. The ZLOGIN_RDBUFSIZ must be less
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, ...)
231 /*
232 * The second part of the privilege drop. We are paranoid about being attacked
233 * by the zone, so we drop all privileges. This should prevent a compromise
234 * which gets us to fork(), exec(), symlink(), etc.
235 */
236 static void
237 postfork_dropprivs()
238 {
239 if ((setppriv(PRIV_SET, PRIV_PERMITTED, dropprivs)) == -1) {
240 zperror(gettext("Warning: could not set permitted privileges"));
241 }
242 if ((setppriv(PRIV_SET, PRIV_LIMIT, dropprivs)) == -1) {
243 zperror(gettext("Warning: could not set limit privileges"));
244 }
245 if ((setppriv(PRIV_SET, PRIV_INHERITABLE, dropprivs)) == -1) {
246 zperror(gettext("Warning: could not set inheritable "
247 "privileges"));
248 }
249 }
250
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 static int
256 get_console_master(const char *zname)
257 {
258 int sockfd = -1;
259 struct sockaddr_un servaddr;
260 char clientid[MAXPATHLEN];
261 char handshake[MAXPATHLEN], c;
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;
304 if (c == '\n')
305 break;
306 handshake[i] = c;
307 i++;
308 }
309
310 /*
311 * If something went wrong during the handshake we bail; perhaps
312 * the server died off.
313 */
314 if (err == -1) {
315 zperror(gettext("Could not connect to zone console"));
316 goto bad;
317 }
318
319 if (strncmp(handshake, "OK", sizeof (handshake)) == 0)
320 return (0);
321
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);
328 }
329
330
331 /*
332 * Routines to handle pty creation upon zone entry and to shuttle I/O back
333 * and forth between the two terminals. We also compute and store the
334 * name of the slave terminal associated with the master side.
335 */
336 static int
337 get_master_pty()
338 {
339 if ((masterfd = open("/dev/ptmx", O_RDWR|O_NONBLOCK)) < 0) {
340 zperror(gettext("failed to obtain a pseudo-tty"));
341 return (-1);
342 }
343 if (tcgetattr(STDIN_FILENO, &save_termios) == -1) {
344 zperror(gettext("failed to get terminal settings from stdin"));
345 return (-1);
346 }
347 (void) ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&winsize);
348
349 return (0);
350 }
499 */
500 if (tcgetattr(STDIN_FILENO, &effective_termios) < 0) {
501 zperror(gettext("failed to get user terminal settings"));
502 return (-1);
503 }
504 effective_termios.c_cc[VEOF] = save_termios.c_cc[VEOF];
505 effective_termios.c_cc[VEOL] = save_termios.c_cc[VEOL];
506
507 return (0);
508 }
509
510 /*
511 * Copy terminal window size from our terminal to the pts.
512 */
513 /*ARGSUSED*/
514 static void
515 sigwinch(int s)
516 {
517 struct winsize ws;
518
519 if (ioctl(0, TIOCGWINSZ, &ws) == 0)
520 (void) ioctl(masterfd, TIOCSWINSZ, &ws);
521 }
522
523 static volatile int close_on_sig = -1;
524
525 static void
526 /*ARGSUSED*/
527 sigcld(int s)
528 {
529 int status;
530 pid_t pid;
531
532 /*
533 * Peek at the exit status. If this isn't the process we cared
534 * about, then just reap it.
535 */
536 if ((pid = waitpid(child_pid, &status, WNOHANG|WNOWAIT)) != -1) {
537 if (pid == child_pid &&
538 (WIFEXITED(status) || WIFSIGNALED(status))) {
539 dead = 1;
540 if (close_on_sig != -1) {
541 (void) write(close_on_sig, "a", 1);
542 (void) close(close_on_sig);
845 * passed the test above, we would go into poll and hang.
846 * To avoid this we use the sig_fd as an additional poll fd.
847 * The signal handler writes into the other end of this pipe
848 * when the child dies so that the poll will always see that
849 * input and proceed. We just loop around at that point and
850 * then notice the dead flag.
851 */
852
853 ret = poll(pollfds,
854 sizeof (pollfds) / sizeof (struct pollfd), -1);
855
856 if (ret == -1 && errno != EINTR) {
857 perror("poll failed");
858 break;
859 }
860
861 if (errno == EINTR && dead) {
862 break;
863 }
864
865 /* event from master side stdout */
866 if (pollfds[0].revents) {
867 if (pollfds[0].revents &
868 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
869 if (process_output(stdout_fd, STDOUT_FILENO)
870 != 0)
871 break;
872 } else {
873 pollerr = pollfds[0].revents;
874 break;
875 }
876 }
877
878 /* event from master side stderr */
879 if (pollfds[1].revents) {
880 if (pollfds[1].revents &
881 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
882 if (process_output(stderr_fd, STDERR_FILENO)
883 != 0)
884 break;
885 } else {
886 pollerr = pollfds[1].revents;
887 break;
888 }
889 }
890
891 /* event from user STDIN side */
892 if (pollfds[2].revents) {
893 if (pollfds[2].revents &
894 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
895 /*
896 * stdin fd is stdin of the target; so,
897 * the thing we'll write the user data *to*.
898 *
899 * Also, unlike on the output side, we
900 * close the pipe on a zero-length message.
901 */
902 int res;
903
904 if (raw_mode)
905 res = process_raw_input(stdin_fd,
906 appin_fd);
1036 /* Get the login command for the target zone. */
1037 bzero(result_buf, sizeof (result_buf));
1038
1039 if (forced_login) {
1040 if (brand_get_forcedlogin_cmd(bh, login,
1041 result_buf, sizeof (result_buf)) != 0)
1042 return (NULL);
1043 } else {
1044 if (brand_get_login_cmd(bh, login,
1045 result_buf, sizeof (result_buf)) != 0)
1046 return (NULL);
1047 }
1048
1049 /*
1050 * We got back a string that we'd like to execute. But since
1051 * we're not doing the execution via a shell we'll need to convert
1052 * the exec string to an array of strings. We'll do that here
1053 * but we're going to be very simplistic about it and break stuff
1054 * up based on spaces. We're not even going to support any kind
1055 * of quoting or escape characters. It's truly amazing that
1056 * there is no library function in OpenSolaris to do this for us.
1057 */
1058
1059 /*
1060 * Be paranoid. Since we're deliniating based on spaces make
1061 * sure there are no adjacent spaces.
1062 */
1063 if (strstr(result_buf, " ") != NULL)
1064 return (NULL);
1065
1066 /* Remove any trailing whitespace. */
1067 n = strlen(result_buf);
1068 if (result_buf[n - 1] == ' ')
1069 result_buf[n - 1] = '\0';
1070
1071 /* Count how many elements there are in the exec string. */
1072 ptr = result_buf;
1073 for (n = 2; ((ptr = strchr(ptr + 1, (int)' ')) != NULL); n++)
1074 ;
1075
1076 /* Allocate the argv array that we're going to return. */
1077 if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
1078 return (NULL);
1079
1080 /* Tokenize the exec string and return. */
1081 a = 0;
1082 new_argv[a++] = result_buf;
1083 if (n > 2) {
1084 (void) strtok_r(result_buf, " ", &lasts);
1085 while ((new_argv[a++] = strtok_r(NULL, " ", &lasts)) != NULL)
1086 ;
1087 } else {
1088 new_argv[a++] = NULL;
1089 }
1090 assert(n == a);
1091 return (new_argv);
1092 }
1093
1094 /*
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
1097 * 'login -z <from_zonename> -f' (-z is an undocumented option which tells
1098 * login that we're coming from another zone, and to disregard its CONSOLE
1099 * checks).
1100 */
1101 static char **
1102 prep_args(brand_handle_t bh, const char *login, char **argv)
1103 {
1104 int argc = 0, a = 0, i, n = -1;
1105 char **new_argv;
1106
1107 if (argv != NULL) {
1108 size_t subshell_len = 1;
1109 char *subshell;
1110
1111 while (argv[argc] != NULL)
1112 argc++;
1113
1114 for (i = 0; i < argc; i++) {
1115 subshell_len += strlen(argv[i]) + 1;
1116 }
1117 if ((subshell = calloc(1, subshell_len)) == NULL)
1118 return (NULL);
1119
1120 for (i = 0; i < argc; i++) {
1121 (void) strcat(subshell, argv[i]);
1122 (void) strcat(subshell, " ");
1123 }
1124
1125 if (failsafe) {
1126 n = 4;
1127 if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
1128 return (NULL);
1129
1130 new_argv[a++] = FAILSAFESHELL;
1131 } else {
1132 n = 5;
1133 if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
1134 return (NULL);
1135
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 }
1143 new_argv[a++] = "-c";
1144 new_argv[a++] = subshell;
1145 new_argv[a++] = NULL;
1146 assert(a == n);
1147 } 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);
1155 } else {
1156 new_argv = zone_login_cmd(bh, login);
1157 }
1158 }
1159
1160 return (new_argv);
1161 }
1162
1163 /*
1164 * Helper routine for prep_env below.
1165 */
1166 static char *
1167 add_env(char *name, char *value)
1168 {
1169 size_t sz = strlen(name) + strlen(value) + 2; /* name, =, value, NUL */
1170 char *str;
1171
1172 if ((str = malloc(sz)) == NULL)
1173 return (NULL);
1174
1175 (void) snprintf(str, sz, "%s=%s", name, value);
1176 return (str);
1177 }
1178
1179 /*
1180 * Prepare envp array for exec'd process.
1181 */
1182 static char **
1183 prep_env()
1184 {
1185 int e = 0, size = 1;
1186 char **new_env, *estr;
1187 char *term = getenv("TERM");
1188
1189 size++; /* for $PATH */
1190 if (term != NULL)
1191 size++;
1192
1193 /*
1194 * In failsafe mode we set $HOME, since '-l' isn't valid in this mode.
1195 * We also set $SHELL, since neither login nor su will be around to do
1196 * it.
1197 */
1198 if (failsafe)
1199 size += 2;
1200
1201 if ((new_env = malloc(sizeof (char *) * size)) == NULL)
1202 return (NULL);
1203
1204 if ((estr = add_env("PATH", DEF_PATH)) == NULL)
1205 return (NULL);
1206 new_env[e++] = estr;
1207
1208 if (term != NULL) {
1209 if ((estr = add_env("TERM", term)) == NULL)
1210 return (NULL);
1211 new_env[e++] = estr;
1212 }
1213
1214 if (failsafe) {
1215 if ((estr = add_env("HOME", "/")) == NULL)
1216 return (NULL);
1217 new_env[e++] = estr;
1218
1219 if ((estr = add_env("SHELL", FAILSAFESHELL)) == NULL)
1220 return (NULL);
1221 new_env[e++] = estr;
1222 }
1223
1224 new_env[e++] = NULL;
1706 uid_t uid;
1707 struct passwd *nptr;
1708
1709 /*
1710 * Authorizations are checked to restrict access based on the
1711 * requested operation and zone name, It is assumed that the
1712 * program is running with all privileges, but that the real
1713 * user ID is that of the user or role on whose behalf we are
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, "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"));
1806 usage();
1807 }
1808
1809 if (nflag != 0) {
1810 zerror(gettext(
1811 "-n may not be specified for console login"));
1812 usage();
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 }
1859 /* zone name and process name, and possibly some args */
1860 zonename = argv[optind];
1861 proc_args = &argv[optind + 1];
1862 interactive = 0;
1863 } else {
1864 usage();
1865 }
1866
1867 if (getzoneid() != GLOBAL_ZONEID) {
1868 zerror(gettext("'%s' may only be used from the global zone"),
1869 pname);
1870 return (1);
1871 }
1872
1873 if (strcmp(zonename, GLOBAL_ZONENAME) == 0) {
1874 zerror(gettext("'%s' not applicable to the global zone"),
1875 pname);
1876 return (1);
1877 }
1878
1879 if (zone_get_state(zonename, &st) != Z_OK) {
1880 zerror(gettext("zone '%s' unknown"), zonename);
1881 return (1);
1882 }
1928 } else {
1929 (void) snprintf(authname, MAXAUTHS, "%s%s%s",
1930 ZONE_LOGIN_AUTH, KV_OBJECT, zonename);
1931 if (failsafe || !interactive) {
1932 zerror(gettext("%s is not authorized for "
1933 "failsafe or non-interactive login "
1934 "to %s zone."), username, zonename);
1935 return (1);
1936 } else if (chkauthattr(authname, username) == 0) {
1937 zerror(gettext("%s is not authorized "
1938 " to login to %s zone."),
1939 username, zonename);
1940 return (1);
1941 }
1942 }
1943 } else {
1944 forced_login = B_TRUE;
1945 }
1946
1947 /*
1948 * The console is a separate case from the rest of the code; handle
1949 * it first.
1950 */
1951 if (console) {
1952 /*
1953 * Ensure that zoneadmd for this zone is running.
1954 */
1955 if (start_zoneadmd(zonename) == -1)
1956 return (1);
1957
1958 /*
1959 * Make contact with zoneadmd.
1960 */
1961 if (get_console_master(zonename) == -1)
1962 return (1);
1963
1964 if (!quiet)
1965 (void) printf(
1966 gettext("[Connected to zone '%s' console]\n"),
1967 zonename);
1968
1969 if (set_tty_rawmode(STDIN_FILENO) == -1) {
1970 reset_tty();
1971 zperror(gettext("failed to set stdin pty to raw mode"));
1972 return (1);
1973 }
1974
1975 (void) sigset(SIGWINCH, sigwinch);
1976 (void) sigwinch(0);
1977
1978 /*
1979 * Run the I/O loop until we get disconnected.
1980 */
1981 doio(masterfd, -1, masterfd, -1, -1, B_FALSE);
1982 reset_tty();
1983 if (!quiet)
1984 (void) printf(
1985 gettext("\n[Connection to zone '%s' console "
1986 "closed]\n"), zonename);
1987
1988 return (0);
1989 }
1990
1991 if (st != ZONE_STATE_RUNNING && st != ZONE_STATE_MOUNTED) {
1992 zerror(gettext("login allowed only to running zones "
1993 "(%s is '%s')."), zonename, zone_state_str(st));
1994 return (1);
1995 }
1996
1997 (void) strlcpy(kernzone, zonename, sizeof (kernzone));
1998 if (zonecfg_in_alt_root()) {
1999 FILE *fp = zonecfg_open_scratch("", B_FALSE);
2000
2001 if (fp == NULL || zonecfg_find_scratch(fp, zonename,
2002 zonecfg_get_root(), kernzone, sizeof (kernzone)) == -1) {
2003 zerror(gettext("cannot find scratch zone %s"),
2004 zonename);
2005 if (fp != NULL)
2006 zonecfg_close_scratch(fp);
2034 * the zone as native if it is cluster. Cluster zones can be
2035 * native for the purpose of LU or upgrade, and the cluster
2036 * brand may not exist in the miniroot (such as in net install
2037 * upgrade).
2038 */
2039 if (zonecfg_default_brand(default_brand,
2040 sizeof (default_brand)) != Z_OK) {
2041 zerror(gettext("unable to determine default brand"));
2042 return (1);
2043 }
2044 if (zonecfg_in_alt_root() &&
2045 strcmp(zonebrand, CLUSTER_BRAND_NAME) == 0) {
2046 (void) strlcpy(zonebrand, default_brand, sizeof (zonebrand));
2047 }
2048
2049 if ((bh = brand_open(zonebrand)) == NULL) {
2050 zerror(gettext("could not open brand for zone %s"), zonename);
2051 return (1);
2052 }
2053
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);
2058 }
2059 /*
2060 * Get the brand specific user_cmd. This command is used to get
2061 * a passwd(4) entry for login.
2062 */
2063 if (!interactive && !failsafe) {
2064 if (zone_get_user_cmd(bh, login, user_cmd,
2065 sizeof (user_cmd)) == NULL) {
2066 zerror(gettext("could not get user_cmd for zone %s"),
2067 zonename);
2068 brand_close(bh);
2069 return (1);
2070 }
2071 }
2072 brand_close(bh);
2073
2074 if ((new_env = prep_env()) == NULL) {
2075 zperror(gettext("could not assemble new environment"));
2076 return (1);
2077 }
2078
2184
2185 /*
2186 * Close all fds except for the slave pty.
2187 */
2188 (void) fdwalk(close_func, &slavefd);
2189
2190 /*
2191 * Temporarily dup slavefd to stderr; that way if we have
2192 * to print out that zone_enter failed, the output will
2193 * have somewhere to go.
2194 */
2195 if (slavefd != STDERR_FILENO)
2196 (void) dup2(slavefd, STDERR_FILENO);
2197
2198 if (zone_enter(zoneid) == -1) {
2199 zerror(gettext("could not enter zone %s: %s"),
2200 zonename, strerror(errno));
2201 return (1);
2202 }
2203
2204 if (slavefd != STDERR_FILENO)
2205 (void) close(STDERR_FILENO);
2206
2207 /*
2208 * We take pains to get this process into a new process
2209 * group, and subsequently a new session. In this way,
2210 * we'll have a session which doesn't yet have a controlling
2211 * terminal. When we open the slave, it will become the
2212 * controlling terminal; no PIDs concerning pgrps or sids
2213 * will leak inappropriately into the zone.
2214 */
2215 (void) setpgrp();
2216
2217 /*
2218 * We need the slave pty to be referenced from the zone's
2219 * /dev in order to ensure that the devt's, etc are all
2220 * correct. Otherwise we break ttyname and the like.
2221 */
2222 if ((newslave = open(slavename, O_RDWR)) == -1) {
2223 (void) close(slavefd);
2225 }
2226 (void) close(slavefd);
2227 slavefd = newslave;
2228
2229 /*
2230 * dup the slave to the various FDs, so that when the
2231 * spawned process does a write/read it maps to the slave
2232 * pty.
2233 */
2234 (void) dup2(slavefd, STDIN_FILENO);
2235 (void) dup2(slavefd, STDOUT_FILENO);
2236 (void) dup2(slavefd, STDERR_FILENO);
2237 if (slavefd != STDIN_FILENO && slavefd != STDOUT_FILENO &&
2238 slavefd != STDERR_FILENO) {
2239 (void) close(slavefd);
2240 }
2241
2242 /*
2243 * In failsafe mode, we don't use login(1), so don't try
2244 * setting up a utmpx entry.
2245 */
2246 if (!failsafe)
2247 if (setup_utmpx(slaveshortname) == -1)
2248 return (1);
2249
2250 /*
2251 * The child needs to run as root to
2252 * execute the brand's login program.
2253 */
2254 if (setuid(0) == -1) {
2255 zperror(gettext("insufficient privilege"));
2256 return (1);
2257 }
2258
2259 (void) execve(new_args[0], new_args, new_env);
2260 zperror(gettext("exec failure"));
2261 return (1);
2262 }
2263
2264 (void) ct_tmpl_clear(tmpl_fd);
2265 (void) close(tmpl_fd);
2266
2267 /*
2268 * The rest is only for the parent process.
2269 */
2270 (void) sigset(SIGWINCH, sigwinch);
2271
2272 postfork_dropprivs();
2273
2274 (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL);
2275 doio(masterfd, -1, masterfd, -1, -1, B_FALSE);
2276
2277 reset_tty();
2278 if (!quiet)
2279 (void) fprintf(stderr,
2280 gettext("\n[Connection to zone '%s' %s closed]\n"),
2281 zonename, slaveshortname);
2282
2283 if (pollerr != 0) {
2284 (void) fprintf(stderr, gettext("Error: connection closed due "
2285 "to unexpected pollevents=0x%x.\n"), pollerr);
2286 return (1);
2287 }
2288
2289 return (0);
2290 }
|
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
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 *
53 * - "console login" is the equivalent to accessing the tip line for a
54 * zone. For example, the user can issue 'zlogin -C my-zone'.
55 * In this mode, zlogin contacts the zoneadmd process via unix domain
56 * socket. If zoneadmd is not running, it starts it. This allows the
57 * console to be available anytime the zone is installed, regardless of
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.
62 */
63
64 #include <sys/socket.h>
65 #include <sys/termios.h>
66 #include <sys/utsname.h>
67 #include <sys/stat.h>
68 #include <sys/types.h>
69 #include <sys/contract/process.h>
70 #include <sys/ctfs.h>
71 #include <sys/brand.h>
72 #include <sys/wait.h>
73 #include <alloca.h>
74 #include <assert.h>
75 #include <ctype.h>
76 #include <paths.h>
77 #include <door.h>
78 #include <errno.h>
79 #include <nss_dbdefs.h>
80 #include <poll.h>
81 #include <priv.h>
86 #include <signal.h>
87 #include <stdarg.h>
88 #include <stdio.h>
89 #include <stdlib.h>
90 #include <string.h>
91 #include <strings.h>
92 #include <stropts.h>
93 #include <wait.h>
94 #include <zone.h>
95 #include <fcntl.h>
96 #include <libdevinfo.h>
97 #include <libintl.h>
98 #include <locale.h>
99 #include <libzonecfg.h>
100 #include <libcontract.h>
101 #include <libbrand.h>
102 #include <auth_list.h>
103 #include <auth_attr.h>
104 #include <secdb.h>
105
106 static int masterfd = -1;
107 static int ctlfd = -1;
108 static struct termios save_termios;
109 static struct termios effective_termios;
110 static int save_fd;
111 static struct winsize winsize;
112 static volatile int dead;
113 static volatile pid_t child_pid = -1;
114 static int interactive = 0;
115 static priv_set_t *dropprivs;
116 static unsigned int connect_flags = 0;
117
118 static int nocmdchar = 0;
119 static int failsafe = 0;
120 static char cmdchar = '~';
121 static int quiet = 0;
122 static char zonebrand[MAXNAMELEN];
123
124 static int pollerr = 0;
125
126 static const char *pname;
127 static char *username;
128
129 /*
130 * When forced_login is true, the user is not prompted
131 * for an authentication password in the target zone.
132 */
133 static boolean_t forced_login = B_FALSE;
134
135 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
136 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
137 #endif
138
139 #define SUPATH1 "/usr/bin/su"
140 #define SUPATH2 "/bin/su"
141 #define FAILSAFESHELL "/sbin/sh"
142 #define DEFAULTSHELL "/sbin/sh"
143 #define DEF_PATH "/usr/sbin:/usr/bin"
144 #define LX_DEF_PATH "/bin:/usr/sbin:/usr/bin"
145
146 #define MAX_RETRY 30
147
148 #define CLUSTER_BRAND_NAME "cluster"
149
150 /*
151 * The ZLOGIN_BUFSIZ is larger than PIPE_BUF so we can be sure we're clearing
152 * out the pipe when the child is exiting. The ZLOGIN_RDBUFSIZ must be less
153 * than ZLOGIN_BUFSIZ (because we share the buffer in doio). This value is
154 * also chosen in conjunction with the HI_WATER setting to make sure we
155 * don't fill up the pipe. We can write FIFOHIWAT (16k) into the pipe before
156 * blocking. By having ZLOGIN_RDBUFSIZ set to 1k and HI_WATER set to 8k, we
157 * know we can always write a ZLOGIN_RDBUFSIZ chunk into the pipe when there
158 * is less than HI_WATER data already in the pipe.
159 */
160 #define ZLOGIN_BUFSIZ 8192
161 #define ZLOGIN_RDBUFSIZ 1024
162 #define HI_WATER 8192
163
164 /*
165 * See canonify() below. CANONIFY_LEN is the maximum length that a
166 * "canonical" sequence will expand to (backslash, three octal digits, NUL).
167 */
168 #define CANONIFY_LEN 5
169
170 static void
171 usage(void)
172 {
173 (void) fprintf(stderr, gettext("usage: %s [-dinCEINQS] [-e cmdchar] "
174 "[-l user] zonename [command [args ...] ]\n"), pname);
175 exit(2);
176 }
177
178 static const char *
179 getpname(const char *arg0)
180 {
181 const char *p = strrchr(arg0, '/');
182
183 if (p == NULL)
184 p = arg0;
185 else
186 p++;
187
188 pname = p;
189 return (p);
190 }
191
192 static void
193 zerror(const char *fmt, ...)
248 /*
249 * The second part of the privilege drop. We are paranoid about being attacked
250 * by the zone, so we drop all privileges. This should prevent a compromise
251 * which gets us to fork(), exec(), symlink(), etc.
252 */
253 static void
254 postfork_dropprivs()
255 {
256 if ((setppriv(PRIV_SET, PRIV_PERMITTED, dropprivs)) == -1) {
257 zperror(gettext("Warning: could not set permitted privileges"));
258 }
259 if ((setppriv(PRIV_SET, PRIV_LIMIT, dropprivs)) == -1) {
260 zperror(gettext("Warning: could not set limit privileges"));
261 }
262 if ((setppriv(PRIV_SET, PRIV_INHERITABLE, dropprivs)) == -1) {
263 zperror(gettext("Warning: could not set inheritable "
264 "privileges"));
265 }
266 }
267
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);
309 }
310
311 if (write(sockfd, clientid, msglen) != msglen) {
312 zerror("protocol error");
313 return (-1);
314 }
315
316 /*
317 * Take care not to accumulate more than our fill, and leave room for
318 * the NUL at the end.
319 */
320 bzero(handshake, sizeof (handshake));
321 while ((err = read(sockfd, &c, 1)) == 1) {
322 if (i >= (sizeof (handshake) - 1))
323 break;
324 if (c == '\n')
325 break;
326 handshake[i] = c;
327 i++;
328 }
329
330 /*
331 * If something went wrong during the handshake we bail.
332 * Perhaps the server died off.
333 */
334 if (err == -1) {
335 zperror(gettext("Could not connect to zone"));
336 return (-1);
337 }
338
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 }
344
345 return (0);
346 }
347
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 }
373 /*
374 * Routines to handle pty creation upon zone entry and to shuttle I/O back
375 * and forth between the two terminals. We also compute and store the
376 * name of the slave terminal associated with the master side.
377 */
378 static int
379 get_master_pty()
380 {
381 if ((masterfd = open("/dev/ptmx", O_RDWR|O_NONBLOCK)) < 0) {
382 zperror(gettext("failed to obtain a pseudo-tty"));
383 return (-1);
384 }
385 if (tcgetattr(STDIN_FILENO, &save_termios) == -1) {
386 zperror(gettext("failed to get terminal settings from stdin"));
387 return (-1);
388 }
389 (void) ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&winsize);
390
391 return (0);
392 }
541 */
542 if (tcgetattr(STDIN_FILENO, &effective_termios) < 0) {
543 zperror(gettext("failed to get user terminal settings"));
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 &&
604 (WIFEXITED(status) || WIFSIGNALED(status))) {
605 dead = 1;
606 if (close_on_sig != -1) {
607 (void) write(close_on_sig, "a", 1);
608 (void) close(close_on_sig);
911 * passed the test above, we would go into poll and hang.
912 * To avoid this we use the sig_fd as an additional poll fd.
913 * The signal handler writes into the other end of this pipe
914 * when the child dies so that the poll will always see that
915 * input and proceed. We just loop around at that point and
916 * then notice the dead flag.
917 */
918
919 ret = poll(pollfds,
920 sizeof (pollfds) / sizeof (struct pollfd), -1);
921
922 if (ret == -1 && errno != EINTR) {
923 perror("poll failed");
924 break;
925 }
926
927 if (errno == EINTR && dead) {
928 break;
929 }
930
931 /* event from master side stderr */
932 if (pollfds[1].revents) {
933 if (pollfds[1].revents &
934 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
935 if (process_output(stderr_fd, STDERR_FILENO)
936 != 0)
937 break;
938 } else {
939 pollerr = pollfds[1].revents;
940 break;
941 }
942 }
943
944 /* event from master side stdout */
945 if (pollfds[0].revents) {
946 if (pollfds[0].revents &
947 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
948 if (process_output(stdout_fd, STDOUT_FILENO)
949 != 0)
950 break;
951 } else {
952 pollerr = pollfds[0].revents;
953 break;
954 }
955 }
956
957 /* event from user STDIN side */
958 if (pollfds[2].revents) {
959 if (pollfds[2].revents &
960 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
961 /*
962 * stdin fd is stdin of the target; so,
963 * the thing we'll write the user data *to*.
964 *
965 * Also, unlike on the output side, we
966 * close the pipe on a zero-length message.
967 */
968 int res;
969
970 if (raw_mode)
971 res = process_raw_input(stdin_fd,
972 appin_fd);
1102 /* Get the login command for the target zone. */
1103 bzero(result_buf, sizeof (result_buf));
1104
1105 if (forced_login) {
1106 if (brand_get_forcedlogin_cmd(bh, login,
1107 result_buf, sizeof (result_buf)) != 0)
1108 return (NULL);
1109 } else {
1110 if (brand_get_login_cmd(bh, login,
1111 result_buf, sizeof (result_buf)) != 0)
1112 return (NULL);
1113 }
1114
1115 /*
1116 * We got back a string that we'd like to execute. But since
1117 * we're not doing the execution via a shell we'll need to convert
1118 * the exec string to an array of strings. We'll do that here
1119 * but we're going to be very simplistic about it and break stuff
1120 * up based on spaces. We're not even going to support any kind
1121 * of quoting or escape characters. It's truly amazing that
1122 * there is no library function in Illumos to do this for us.
1123 */
1124
1125 /*
1126 * Be paranoid. Since we're deliniating based on spaces make
1127 * sure there are no adjacent spaces.
1128 */
1129 if (strstr(result_buf, " ") != NULL)
1130 return (NULL);
1131
1132 /* Remove any trailing whitespace. */
1133 n = strlen(result_buf);
1134 if (result_buf[n - 1] == ' ')
1135 result_buf[n - 1] = '\0';
1136
1137 /* Count how many elements there are in the exec string. */
1138 ptr = result_buf;
1139 for (n = 2; ((ptr = strchr(ptr + 1, (int)' ')) != NULL); n++)
1140 ;
1141
1142 /* Allocate the argv array that we're going to return. */
1143 if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
1144 return (NULL);
1145
1146 /* Tokenize the exec string and return. */
1147 a = 0;
1148 new_argv[a++] = result_buf;
1149 if (n > 2) {
1150 (void) strtok_r(result_buf, " ", &lasts);
1151 while ((new_argv[a++] = strtok_r(NULL, " ", &lasts)) != NULL)
1152 ;
1153 } else {
1154 new_argv[a++] = NULL;
1155 }
1156 assert(n == a);
1157 return (new_argv);
1158 }
1159
1160 /*
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
1163 * 'login -z <from_zonename> -f' (-z is an undocumented option which tells
1164 * login that we're coming from another zone, and to disregard its CONSOLE
1165 * checks).
1166 */
1167 static char **
1168 prep_args(brand_handle_t bh, char *zonename, const char *login, char **argv)
1169 {
1170 int argc = 0, i;
1171 size_t subshell_len = 1;
1172 char *subshell = NULL, *supath = NULL;
1173 char **new_argv = NULL;
1174
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 }
1186
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];
1194
1195 if (zone_get_zonepath(zonename, zonepath,
1196 sizeof (zonepath)) != Z_OK) {
1197 zerror(gettext("unable to determine zone "
1198 "path"));
1199 return (NULL);
1200 }
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"));
1226 return (NULL);
1227 }
1228 return (argv);
1229 }
1230
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)
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]);
1278 }
1279 }
1280
1281 if (failsafe) {
1282 int a = 0, n = 4;
1283
1284 if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
1285 return (NULL);
1286
1287 new_argv[a++] = FAILSAFESHELL;
1288 new_argv[a++] = "-c";
1289 new_argv[a++] = subshell;
1290 new_argv[a++] = NULL;
1291 assert(a == n);
1292 } else {
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++] = "-";
1302 } else {
1303 n--;
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);
1310 }
1311
1312 return (new_argv);
1313 }
1314
1315 /*
1316 * Helper routine for prep_env below.
1317 */
1318 static char *
1319 add_env(char *name, char *value)
1320 {
1321 size_t sz = strlen(name) + strlen(value) + 2; /* name, =, value, NUL */
1322 char *str;
1323
1324 if ((str = malloc(sz)) == NULL)
1325 return (NULL);
1326
1327 (void) snprintf(str, sz, "%s=%s", name, value);
1328 return (str);
1329 }
1330
1331 /*
1332 * Prepare envp array for exec'd process.
1333 */
1334 static char **
1335 prep_env()
1336 {
1337 int e = 0, size = 1;
1338 char **new_env, *estr;
1339 char *term = getenv("TERM");
1340 char *path;
1341
1342 size++; /* for $PATH */
1343 if (term != NULL)
1344 size++;
1345
1346 /*
1347 * In failsafe mode we set $HOME, since '-l' isn't valid in this mode.
1348 * We also set $SHELL, since neither login nor su will be around to do
1349 * it.
1350 */
1351 if (failsafe)
1352 size += 2;
1353
1354 if ((new_env = malloc(sizeof (char *) * size)) == NULL)
1355 return (NULL);
1356
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)
1363 return (NULL);
1364 new_env[e++] = estr;
1365
1366 if (term != NULL) {
1367 if ((estr = add_env("TERM", term)) == NULL)
1368 return (NULL);
1369 new_env[e++] = estr;
1370 }
1371
1372 if (failsafe) {
1373 if ((estr = add_env("HOME", "/")) == NULL)
1374 return (NULL);
1375 new_env[e++] = estr;
1376
1377 if ((estr = add_env("SHELL", FAILSAFESHELL)) == NULL)
1378 return (NULL);
1379 new_env[e++] = estr;
1380 }
1381
1382 new_env[e++] = NULL;
1864 uid_t uid;
1865 struct passwd *nptr;
1866
1867 /*
1868 * Authorizations are checked to restrict access based on the
1869 * requested operation and zone name, It is assumed that the
1870 * program is running with all privileges, but that the real
1871 * user ID is that of the user or role on whose behalf we are
1872 * operating. So we start by getting the username that will be
1873 * used for subsequent authorization checks.
1874 */
1875
1876 uid = getuid();
1877 if ((nptr = getpwuid(uid)) == NULL) {
1878 zerror(gettext("could not get user name."));
1879 _exit(1);
1880 }
1881 return (nptr->pw_name);
1882 }
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
1919 int
1920 main(int argc, char **argv)
1921 {
1922 int arg, console = 0, imode = 0;
1923 int estatus = 0;
1924 zoneid_t zoneid;
1925 zone_state_t st;
1926 char *login = "root";
1927 int iflag = 0;
1928 int lflag = 0;
1929 int nflag = 0;
1930 char *zonename = NULL;
1931 char **proc_args = NULL;
1932 char **new_args, **new_env;
1933 sigset_t block_cld;
1934 siginfo_t si;
1935 char devroot[MAXPATHLEN];
1936 char *slavename, slaveshortname[MAXPATHLEN];
1937 priv_set_t *privset;
1938 int tmpl_fd;
1939 char default_brand[MAXNAMELEN];
1940 struct stat sb;
1941 char kernzone[ZONENAME_MAX];
1942 brand_handle_t bh;
1943 char user_cmd[MAXPATHLEN];
1944 char authname[MAXAUTHS];
1945
1946 (void) setlocale(LC_ALL, "");
1947 (void) textdomain(TEXT_DOMAIN);
1948
1949 (void) getpname(argv[0]);
1950 username = get_username();
1951
1952 while ((arg = getopt(argc, argv, "diNnECIR:Se:l:Q")) != EOF) {
1953 switch (arg) {
1954 case 'C':
1955 console = 1;
1956 break;
1957 case 'E':
1958 nocmdchar = 1;
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;
1970 case 'R': /* undocumented */
1971 if (*optarg != '/') {
1972 zerror(gettext("root path must be absolute."));
1973 exit(2);
1974 }
1975 if (stat(optarg, &sb) == -1 || !S_ISDIR(sb.st_mode)) {
1976 zerror(
1977 gettext("root path must be a directory."));
1978 exit(2);
1979 }
1980 zonecfg_set_root(optarg);
1981 break;
1982 case 'Q':
1983 quiet = 1;
1984 break;
1985 case 'S':
1986 failsafe = 1;
1987 break;
1988 case 'd':
1989 connect_flags |= ZLOGIN_DISCONNECT;
1990 break;
1991 case 'e':
1992 set_cmdchar(optarg);
1993 break;
1994 case 'i':
1995 iflag = 1;
1996 break;
1997 case 'l':
1998 login = optarg;
1999 lflag = 1;
2000 break;
2001 case 'N':
2002 /* NOHUP - do not send EOF */
2003 connect_flags ^= ZLOGIN_ZFD_EOF;
2004 break;
2005 case 'n':
2006 nflag = 1;
2007 break;
2008 default:
2009 usage();
2010 }
2011 }
2012
2013 if (console != 0) {
2014
2015 /*
2016 * The only connect option in console mode is ZLOGIN_DISCONNECT
2017 */
2018 if (imode == 0)
2019 connect_flags &= ZLOGIN_DISCONNECT;
2020
2021 if (lflag != 0) {
2022 zerror(gettext(
2023 "-l may not be specified for console login"));
2024 usage();
2025 }
2026
2027 if (nflag != 0) {
2028 zerror(gettext(
2029 "-n may not be specified for console login"));
2030 usage();
2031 }
2032
2033 if (failsafe != 0) {
2034 zerror(gettext(
2035 "-S may not be specified for console login"));
2036 usage();
2037 }
2038
2039 if (zonecfg_in_alt_root()) {
2040 zerror(gettext(
2041 "-R may not be specified for console login"));
2042 exit(2);
2043 }
2044
2045 }
2046
2047 if (iflag != 0 && nflag != 0) {
2048 zerror(gettext("-i and -n flags are incompatible"));
2049 usage();
2050 }
2051
2052 if (failsafe != 0 && lflag != 0) {
2053 zerror(gettext("-l may not be specified for failsafe login"));
2054 usage();
2055 }
2056
2057 if (!console && (connect_flags & ZLOGIN_DISCONNECT) != 0) {
2058 zerror(gettext(
2059 "-d may only be specified with console login"));
2060 usage();
2061 }
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
2068 if (optind == (argc - 1)) {
2069 /*
2070 * zone name, no process name; this should be an interactive
2071 * as long as STDIN is really a tty.
2072 */
2073 if (nflag != 0) {
2074 zerror(gettext(
2075 "-n may not be specified for interactive login"));
2076 usage();
2077 }
2078 if (isatty(STDIN_FILENO))
2079 interactive = 1;
2080 zonename = argv[optind];
2081 } else if (optind < (argc - 1)) {
2082 if (console) {
2083 zerror(gettext("Commands may not be specified for "
2084 "console login."));
2085 usage();
2086 }
2087 /* zone name and process name, and possibly some args */
2088 zonename = argv[optind];
2089 proc_args = &argv[optind + 1];
2090 if (iflag && isatty(STDIN_FILENO))
2091 interactive = 1;
2092 } else {
2093 usage();
2094 }
2095
2096 if (getzoneid() != GLOBAL_ZONEID) {
2097 zerror(gettext("'%s' may only be used from the global zone"),
2098 pname);
2099 return (1);
2100 }
2101
2102 if (strcmp(zonename, GLOBAL_ZONENAME) == 0) {
2103 zerror(gettext("'%s' not applicable to the global zone"),
2104 pname);
2105 return (1);
2106 }
2107
2108 if (zone_get_state(zonename, &st) != Z_OK) {
2109 zerror(gettext("zone '%s' unknown"), zonename);
2110 return (1);
2111 }
2157 } else {
2158 (void) snprintf(authname, MAXAUTHS, "%s%s%s",
2159 ZONE_LOGIN_AUTH, KV_OBJECT, zonename);
2160 if (failsafe || !interactive) {
2161 zerror(gettext("%s is not authorized for "
2162 "failsafe or non-interactive login "
2163 "to %s zone."), username, zonename);
2164 return (1);
2165 } else if (chkauthattr(authname, username) == 0) {
2166 zerror(gettext("%s is not authorized "
2167 " to login to %s zone."),
2168 username, zonename);
2169 return (1);
2170 }
2171 }
2172 } else {
2173 forced_login = B_TRUE;
2174 }
2175
2176 /*
2177 * The console (or standalong interactive mode) is a separate case from
2178 * the rest of the code; handle it first.
2179 */
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
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,
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) {
2260 reset_tty();
2261 zperror(gettext("failed to set stdin pty to raw mode"));
2262 return (1);
2263 }
2264
2265 (void) sigset(SIGWINCH, sigwinch);
2266 (void) sigwinch(0);
2267
2268 if (imode) {
2269 /* Allow EOF mode toggling via SIGUSR1 */
2270 (void) sigset(SIGUSR1, sigusr1);
2271 }
2272
2273 /*
2274 * Run the I/O loop until we get disconnected.
2275 */
2276 doio(masterfd, -1, masterfd, gz_stderr_fd, -1, B_FALSE);
2277 reset_tty();
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 }
2287
2288 return (0);
2289 }
2290
2291 if (st != ZONE_STATE_RUNNING && st != ZONE_STATE_MOUNTED) {
2292 zerror(gettext("login allowed only to running zones "
2293 "(%s is '%s')."), zonename, zone_state_str(st));
2294 return (1);
2295 }
2296
2297 (void) strlcpy(kernzone, zonename, sizeof (kernzone));
2298 if (zonecfg_in_alt_root()) {
2299 FILE *fp = zonecfg_open_scratch("", B_FALSE);
2300
2301 if (fp == NULL || zonecfg_find_scratch(fp, zonename,
2302 zonecfg_get_root(), kernzone, sizeof (kernzone)) == -1) {
2303 zerror(gettext("cannot find scratch zone %s"),
2304 zonename);
2305 if (fp != NULL)
2306 zonecfg_close_scratch(fp);
2334 * the zone as native if it is cluster. Cluster zones can be
2335 * native for the purpose of LU or upgrade, and the cluster
2336 * brand may not exist in the miniroot (such as in net install
2337 * upgrade).
2338 */
2339 if (zonecfg_default_brand(default_brand,
2340 sizeof (default_brand)) != Z_OK) {
2341 zerror(gettext("unable to determine default brand"));
2342 return (1);
2343 }
2344 if (zonecfg_in_alt_root() &&
2345 strcmp(zonebrand, CLUSTER_BRAND_NAME) == 0) {
2346 (void) strlcpy(zonebrand, default_brand, sizeof (zonebrand));
2347 }
2348
2349 if ((bh = brand_open(zonebrand)) == NULL) {
2350 zerror(gettext("could not open brand for zone %s"), zonename);
2351 return (1);
2352 }
2353
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 }
2369 }
2370
2371 /*
2372 * Get the brand specific user_cmd. This command is used to get
2373 * a passwd(4) entry for login.
2374 */
2375 if (!interactive && !failsafe) {
2376 if (zone_get_user_cmd(bh, login, user_cmd,
2377 sizeof (user_cmd)) == NULL) {
2378 zerror(gettext("could not get user_cmd for zone %s"),
2379 zonename);
2380 brand_close(bh);
2381 return (1);
2382 }
2383 }
2384 brand_close(bh);
2385
2386 if ((new_env = prep_env()) == NULL) {
2387 zperror(gettext("could not assemble new environment"));
2388 return (1);
2389 }
2390
2496
2497 /*
2498 * Close all fds except for the slave pty.
2499 */
2500 (void) fdwalk(close_func, &slavefd);
2501
2502 /*
2503 * Temporarily dup slavefd to stderr; that way if we have
2504 * to print out that zone_enter failed, the output will
2505 * have somewhere to go.
2506 */
2507 if (slavefd != STDERR_FILENO)
2508 (void) dup2(slavefd, STDERR_FILENO);
2509
2510 if (zone_enter(zoneid) == -1) {
2511 zerror(gettext("could not enter zone %s: %s"),
2512 zonename, strerror(errno));
2513 return (1);
2514 }
2515
2516 /* Note: we're now inside the zone, can't use gettext anymore */
2517
2518 if (slavefd != STDERR_FILENO)
2519 (void) close(STDERR_FILENO);
2520
2521 /*
2522 * We take pains to get this process into a new process
2523 * group, and subsequently a new session. In this way,
2524 * we'll have a session which doesn't yet have a controlling
2525 * terminal. When we open the slave, it will become the
2526 * controlling terminal; no PIDs concerning pgrps or sids
2527 * will leak inappropriately into the zone.
2528 */
2529 (void) setpgrp();
2530
2531 /*
2532 * We need the slave pty to be referenced from the zone's
2533 * /dev in order to ensure that the devt's, etc are all
2534 * correct. Otherwise we break ttyname and the like.
2535 */
2536 if ((newslave = open(slavename, O_RDWR)) == -1) {
2537 (void) close(slavefd);
2539 }
2540 (void) close(slavefd);
2541 slavefd = newslave;
2542
2543 /*
2544 * dup the slave to the various FDs, so that when the
2545 * spawned process does a write/read it maps to the slave
2546 * pty.
2547 */
2548 (void) dup2(slavefd, STDIN_FILENO);
2549 (void) dup2(slavefd, STDOUT_FILENO);
2550 (void) dup2(slavefd, STDERR_FILENO);
2551 if (slavefd != STDIN_FILENO && slavefd != STDOUT_FILENO &&
2552 slavefd != STDERR_FILENO) {
2553 (void) close(slavefd);
2554 }
2555
2556 /*
2557 * In failsafe mode, we don't use login(1), so don't try
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.
2569 */
2570 if (!failsafe && (strcmp(zonebrand, "lx") != 0))
2571 if (setup_utmpx(slaveshortname) == -1)
2572 return (1);
2573
2574 /*
2575 * The child needs to run as root to
2576 * execute the brand's login program.
2577 */
2578 if (setuid(0) == -1) {
2579 zperror("insufficient privilege");
2580 return (1);
2581 }
2582
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);
2590 }
2591
2592 (void) ct_tmpl_clear(tmpl_fd);
2593 (void) close(tmpl_fd);
2594
2595 /*
2596 * The rest is only for the parent process.
2597 */
2598 (void) sigset(SIGWINCH, sigwinch);
2599
2600 postfork_dropprivs();
2601
2602 (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL);
2603 doio(masterfd, -1, masterfd, -1, -1, B_FALSE);
2604
2605 reset_tty();
2606 if (!quiet)
2607 (void) fprintf(stderr,
2608 gettext("\n[Connection to zone '%s' %s closed]\n"),
2609 zonename, slaveshortname);
2610
2611 if (pollerr != 0) {
2612 (void) fprintf(stderr, gettext("Error: connection closed due "
2613 "to unexpected pollevents=0x%x.\n"), pollerr);
2614 return (EPIPE);
2615 }
2616
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);
2629 }
|