Print this page
Reduce lint
OS-5388 zoneadmd comes up asynchronously so zlogin can happen too soon
Reviewed by: Josh Wilsdon <jwilsdon@joyent.com>
OS-5198 zlogin must handle args when su binary is missing
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
OS-5185 zlogin fails to execute command when 'su' is missing
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
OS-4863 regression in zlogin non-tty mode handling [tighten parsing]
OS-4863 regression in zlogin non-tty mode handling
Reviewed by: Josh Wilsdon <jwilsdon@joyent.com>
OS-4792 zlogin errors when trying to attach to a container using log-driver
OS-4569 zlogin doesn't properly quote arguments
OS-4577 regression in zlogin argument handling [backout OS-4569]
OS-4569 zlogin doesn't properly quote arguments
OS-4136 would like SIGUSR to zlogin to switch in and out of '-N' modes
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
OS-4166 zlogin to zfd needs TIOCSWINSZ support
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
OS-4109 'zlogin -I' should close /dev/zfd/0 when it exits
OS-3876 custr could allow management of a static buffer
OS-3879 want custr to have a printf function
Reviewed by: Joshua M. Clulow <josh@sysmgr.org>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
OS-3869 'zlogin -Q -i <zonename> <command>' does not return exit status of <command>
OS-3777 zlogin -I needs to work with docker run when in logging mode
OS-3764 'zlogin -i <zonename> /native/usr/vm/sbin/dockerexec /bin/sh' merges argv[] into single argument
OS-3741 zlogin -I has strange echo behavior
OS-3727 Would like to be able to selectively close descriptors when using zlogin -I
OS-3728 zlogin -I and zoneadmd zfd logging can be streamlined
OS-3718 non-interactive zlogin fails to open /dev/tty, tcgetpgrp() on stderr fails
OS-3524 in order to support interaction with docker containers, need to be able to connect to stdio for init from GZ
OS-3525 in order to support 'docker logs' need to be able to get stdio from zone to log file
OS-3529 would like zlogin -i
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
OS-3388 'zlogin <zonename> <command>' does not work for LX branded zones
OS-2834 ship lx brand
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/zlogin/zlogin.c
+++ new/usr/src/cmd/zlogin/zlogin.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
|
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2013 DEY Storage Systems, Inc.
24 24 * Copyright (c) 2014 Gary Mills
25 25 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
26 + * Copyright 2016 Joyent, Inc.
26 27 */
27 28
28 29 /*
29 - * zlogin provides three types of login which allow users in the global
30 + * zlogin provides five types of login which allow users in the global
30 31 * zone to access non-global zones.
31 32 *
32 33 * - "interactive login" is similar to rlogin(1); for example, the user could
33 34 * issue 'zlogin my-zone' or 'zlogin -e ^ -l me my-zone'. The user is
34 35 * granted a new pty (which is then shoved into the zone), and an I/O
35 36 * loop between parent and child processes takes care of the interactive
36 37 * session. In this mode, login(1) (and its -c option, which means
37 38 * "already authenticated") is employed to take care of the initialization
38 39 * of the user's session.
39 40 *
40 41 * - "non-interactive login" is similar to su(1M); the user could issue
41 42 * 'zlogin my-zone ls -l' and the command would be run as specified.
42 43 * In this mode, zlogin sets up pipes as the communication channel, and
43 44 * 'su' is used to do the login setup work.
44 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 + *
45 53 * - "console login" is the equivalent to accessing the tip line for a
46 54 * zone. For example, the user can issue 'zlogin -C my-zone'.
47 55 * In this mode, zlogin contacts the zoneadmd process via unix domain
48 56 * socket. If zoneadmd is not running, it starts it. This allows the
49 57 * console to be available anytime the zone is installed, regardless of
50 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.
51 62 */
52 63
53 64 #include <sys/socket.h>
54 65 #include <sys/termios.h>
55 66 #include <sys/utsname.h>
56 67 #include <sys/stat.h>
57 68 #include <sys/types.h>
58 69 #include <sys/contract/process.h>
59 70 #include <sys/ctfs.h>
60 71 #include <sys/brand.h>
61 72 #include <sys/wait.h>
62 73 #include <alloca.h>
63 74 #include <assert.h>
64 75 #include <ctype.h>
65 76 #include <paths.h>
66 77 #include <door.h>
67 78 #include <errno.h>
68 79 #include <nss_dbdefs.h>
69 80 #include <poll.h>
70 81 #include <priv.h>
71 82 #include <pwd.h>
72 83 #include <unistd.h>
73 84 #include <utmpx.h>
74 85 #include <sac.h>
75 86 #include <signal.h>
76 87 #include <stdarg.h>
77 88 #include <stdio.h>
78 89 #include <stdlib.h>
79 90 #include <string.h>
80 91 #include <strings.h>
81 92 #include <stropts.h>
82 93 #include <wait.h>
83 94 #include <zone.h>
84 95 #include <fcntl.h>
|
↓ open down ↓ |
24 lines elided |
↑ open up ↑ |
85 96 #include <libdevinfo.h>
86 97 #include <libintl.h>
87 98 #include <locale.h>
88 99 #include <libzonecfg.h>
89 100 #include <libcontract.h>
90 101 #include <libbrand.h>
91 102 #include <auth_list.h>
92 103 #include <auth_attr.h>
93 104 #include <secdb.h>
94 105
95 -static int masterfd;
106 +static int masterfd = -1;
107 +static int ctlfd = -1;
96 108 static struct termios save_termios;
97 109 static struct termios effective_termios;
98 110 static int save_fd;
99 111 static struct winsize winsize;
100 112 static volatile int dead;
101 113 static volatile pid_t child_pid = -1;
102 114 static int interactive = 0;
103 115 static priv_set_t *dropprivs;
116 +static unsigned int connect_flags = 0;
104 117
105 118 static int nocmdchar = 0;
106 119 static int failsafe = 0;
107 -static int disconnect = 0;
108 120 static char cmdchar = '~';
109 121 static int quiet = 0;
122 +static char zonebrand[MAXNAMELEN];
110 123
111 124 static int pollerr = 0;
112 125
113 126 static const char *pname;
114 127 static char *username;
115 128
116 129 /*
117 130 * When forced_login is true, the user is not prompted
118 131 * for an authentication password in the target zone.
119 132 */
120 133 static boolean_t forced_login = B_FALSE;
121 134
122 135 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
123 136 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
124 137 #endif
125 138
126 -#define SUPATH "/usr/bin/su"
139 +#define SUPATH1 "/usr/bin/su"
140 +#define SUPATH2 "/bin/su"
127 141 #define FAILSAFESHELL "/sbin/sh"
128 142 #define DEFAULTSHELL "/sbin/sh"
129 143 #define DEF_PATH "/usr/sbin:/usr/bin"
144 +#define LX_DEF_PATH "/bin:/usr/sbin:/usr/bin"
130 145
146 +#define MAX_RETRY 30
147 +
131 148 #define CLUSTER_BRAND_NAME "cluster"
132 149
133 150 /*
134 151 * The ZLOGIN_BUFSIZ is larger than PIPE_BUF so we can be sure we're clearing
135 152 * out the pipe when the child is exiting. The ZLOGIN_RDBUFSIZ must be less
136 153 * than ZLOGIN_BUFSIZ (because we share the buffer in doio). This value is
137 154 * also chosen in conjunction with the HI_WATER setting to make sure we
138 155 * don't fill up the pipe. We can write FIFOHIWAT (16k) into the pipe before
139 156 * blocking. By having ZLOGIN_RDBUFSIZ set to 1k and HI_WATER set to 8k, we
140 157 * know we can always write a ZLOGIN_RDBUFSIZ chunk into the pipe when there
141 158 * is less than HI_WATER data already in the pipe.
142 159 */
143 160 #define ZLOGIN_BUFSIZ 8192
144 161 #define ZLOGIN_RDBUFSIZ 1024
145 162 #define HI_WATER 8192
|
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
146 163
147 164 /*
148 165 * See canonify() below. CANONIFY_LEN is the maximum length that a
149 166 * "canonical" sequence will expand to (backslash, three octal digits, NUL).
150 167 */
151 168 #define CANONIFY_LEN 5
152 169
153 170 static void
154 171 usage(void)
155 172 {
156 - (void) fprintf(stderr, gettext("usage: %s [ -dnQCES ] [ -e cmdchar ] "
173 + (void) fprintf(stderr, gettext("usage: %s [-dinCEINQS] [-e cmdchar] "
157 174 "[-l user] zonename [command [args ...] ]\n"), pname);
158 175 exit(2);
159 176 }
160 177
161 178 static const char *
162 179 getpname(const char *arg0)
163 180 {
164 181 const char *p = strrchr(arg0, '/');
165 182
166 183 if (p == NULL)
167 184 p = arg0;
168 185 else
169 186 p++;
170 187
171 188 pname = p;
172 189 return (p);
173 190 }
174 191
175 192 static void
176 193 zerror(const char *fmt, ...)
177 194 {
178 195 va_list alist;
179 196
180 197 (void) fprintf(stderr, "%s: ", pname);
181 198 va_start(alist, fmt);
182 199 (void) vfprintf(stderr, fmt, alist);
183 200 va_end(alist);
184 201 (void) fprintf(stderr, "\n");
185 202 }
186 203
187 204 static void
188 205 zperror(const char *str)
189 206 {
190 207 const char *estr;
191 208
192 209 if ((estr = strerror(errno)) != NULL)
193 210 (void) fprintf(stderr, "%s: %s: %s\n", pname, str, estr);
194 211 else
195 212 (void) fprintf(stderr, "%s: %s: errno %d\n", pname, str, errno);
196 213 }
197 214
198 215 /*
199 216 * The first part of our privilege dropping scheme needs to be called before
200 217 * fork(), since we must have it for security; we don't want to be surprised
201 218 * later that we couldn't allocate the privset.
202 219 */
203 220 static int
204 221 prefork_dropprivs()
205 222 {
206 223 if ((dropprivs = priv_allocset()) == NULL)
207 224 return (1);
208 225
209 226 priv_basicset(dropprivs);
210 227 (void) priv_delset(dropprivs, PRIV_PROC_INFO);
211 228 (void) priv_delset(dropprivs, PRIV_PROC_FORK);
212 229 (void) priv_delset(dropprivs, PRIV_PROC_EXEC);
213 230 (void) priv_delset(dropprivs, PRIV_FILE_LINK_ANY);
214 231
215 232 /*
216 233 * We need to keep the basic privilege PROC_SESSION and all unknown
217 234 * basic privileges as well as the privileges PROC_ZONE and
218 235 * PROC_OWNER in order to query session information and
219 236 * send signals.
220 237 */
221 238 if (interactive == 0) {
222 239 (void) priv_addset(dropprivs, PRIV_PROC_ZONE);
223 240 (void) priv_addset(dropprivs, PRIV_PROC_OWNER);
224 241 } else {
225 242 (void) priv_delset(dropprivs, PRIV_PROC_SESSION);
226 243 }
227 244
228 245 return (0);
229 246 }
230 247
231 248 /*
232 249 * The second part of the privilege drop. We are paranoid about being attacked
233 250 * by the zone, so we drop all privileges. This should prevent a compromise
234 251 * which gets us to fork(), exec(), symlink(), etc.
235 252 */
236 253 static void
237 254 postfork_dropprivs()
238 255 {
239 256 if ((setppriv(PRIV_SET, PRIV_PERMITTED, dropprivs)) == -1) {
240 257 zperror(gettext("Warning: could not set permitted privileges"));
|
↓ open down ↓ |
74 lines elided |
↑ open up ↑ |
241 258 }
242 259 if ((setppriv(PRIV_SET, PRIV_LIMIT, dropprivs)) == -1) {
243 260 zperror(gettext("Warning: could not set limit privileges"));
244 261 }
245 262 if ((setppriv(PRIV_SET, PRIV_INHERITABLE, dropprivs)) == -1) {
246 263 zperror(gettext("Warning: could not set inheritable "
247 264 "privileges"));
248 265 }
249 266 }
250 267
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 268 static int
256 -get_console_master(const char *zname)
269 +connect_zone_sock(const char *zname, const char *suffix, boolean_t verbose)
257 270 {
258 271 int sockfd = -1;
259 272 struct sockaddr_un servaddr;
260 - char clientid[MAXPATHLEN];
261 - char handshake[MAXPATHLEN], c;
262 - int msglen;
263 - int i = 0, err = 0;
264 273
265 274 if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
266 - zperror(gettext("could not create socket"));
275 + if (verbose)
276 + zperror(gettext("could not create socket"));
267 277 return (-1);
268 278 }
269 279
270 280 bzero(&servaddr, sizeof (servaddr));
271 281 servaddr.sun_family = AF_UNIX;
272 282 (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
273 - "%s/%s.console_sock", ZONES_TMPDIR, zname);
274 -
283 + "%s/%s.%s", ZONES_TMPDIR, zname, suffix);
275 284 if (connect(sockfd, (struct sockaddr *)&servaddr,
276 285 sizeof (servaddr)) == -1) {
277 - zperror(gettext("Could not connect to zone console"));
278 - goto bad;
286 + if (verbose)
287 + zperror(gettext("Could not connect to zone"));
288 + (void) close(sockfd);
289 + return (-1);
279 290 }
280 - masterfd = sockfd;
291 + return (sockfd);
292 +}
281 293
282 - msglen = snprintf(clientid, sizeof (clientid), "IDENT %lu %s %d\n",
283 - getpid(), setlocale(LC_MESSAGES, NULL), disconnect);
284 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 +
285 306 if (msglen >= sizeof (clientid) || msglen < 0) {
286 307 zerror("protocol error");
287 - goto bad;
308 + return (-1);
288 309 }
289 310
290 - if (write(masterfd, clientid, msglen) != msglen) {
311 + if (write(sockfd, clientid, msglen) != msglen) {
291 312 zerror("protocol error");
292 - goto bad;
313 + return (-1);
293 314 }
294 315
295 - bzero(handshake, sizeof (handshake));
296 -
297 316 /*
298 317 * Take care not to accumulate more than our fill, and leave room for
299 318 * the NUL at the end.
300 319 */
301 - while ((err = read(masterfd, &c, 1)) == 1) {
320 + bzero(handshake, sizeof (handshake));
321 + while ((err = read(sockfd, &c, 1)) == 1) {
302 322 if (i >= (sizeof (handshake) - 1))
303 323 break;
304 324 if (c == '\n')
305 325 break;
306 326 handshake[i] = c;
307 327 i++;
308 328 }
309 329
310 330 /*
311 - * If something went wrong during the handshake we bail; perhaps
312 - * the server died off.
331 + * If something went wrong during the handshake we bail.
332 + * Perhaps the server died off.
313 333 */
314 334 if (err == -1) {
315 - zperror(gettext("Could not connect to zone console"));
316 - goto bad;
335 + zperror(gettext("Could not connect to zone"));
336 + return (-1);
317 337 }
318 338
319 - if (strncmp(handshake, "OK", sizeof (handshake)) == 0)
320 - return (0);
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 + }
321 344
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);
345 + return (0);
328 346 }
329 347
330 -
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 +}
331 373 /*
332 374 * Routines to handle pty creation upon zone entry and to shuttle I/O back
333 375 * and forth between the two terminals. We also compute and store the
334 376 * name of the slave terminal associated with the master side.
335 377 */
336 378 static int
337 379 get_master_pty()
338 380 {
339 381 if ((masterfd = open("/dev/ptmx", O_RDWR|O_NONBLOCK)) < 0) {
340 382 zperror(gettext("failed to obtain a pseudo-tty"));
341 383 return (-1);
342 384 }
343 385 if (tcgetattr(STDIN_FILENO, &save_termios) == -1) {
344 386 zperror(gettext("failed to get terminal settings from stdin"));
345 387 return (-1);
346 388 }
347 389 (void) ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&winsize);
348 390
349 391 return (0);
350 392 }
351 393
352 394 /*
353 395 * This is a bit tricky; normally a pts device will belong to the zone it
354 396 * is granted to. But in the case of "entering" a zone, we need to establish
355 397 * the pty before entering the zone so that we can vector I/O to and from it
356 398 * from the global zone.
357 399 *
358 400 * We use the zonept() call to let the ptm driver know what we are up to;
359 401 * the only other hairy bit is the setting of zoneslavename (which happens
360 402 * above, in get_master_pty()).
361 403 */
362 404 static int
363 405 init_slave_pty(zoneid_t zoneid, char *devroot)
364 406 {
365 407 int slavefd = -1;
366 408 char *slavename, zoneslavename[MAXPATHLEN];
367 409
368 410 /*
369 411 * Set slave permissions, zone the pts, then unlock it.
370 412 */
371 413 if (grantpt(masterfd) != 0) {
372 414 zperror(gettext("grantpt failed"));
373 415 return (-1);
374 416 }
375 417
376 418 if (unlockpt(masterfd) != 0) {
377 419 zperror(gettext("unlockpt failed"));
378 420 return (-1);
379 421 }
380 422
381 423 /*
382 424 * We must open the slave side before zoning this pty; otherwise
383 425 * the kernel would refuse us the open-- zoning a pty makes it
384 426 * inaccessible to the global zone. Note we are trying to open
385 427 * the device node via the $ZONEROOT/dev path for this pty.
386 428 *
387 429 * Later we'll close the slave out when once we've opened it again
388 430 * from within the target zone. Blarg.
389 431 */
390 432 if ((slavename = ptsname(masterfd)) == NULL) {
391 433 zperror(gettext("failed to get name for pseudo-tty"));
392 434 return (-1);
393 435 }
394 436
395 437 (void) snprintf(zoneslavename, sizeof (zoneslavename), "%s%s",
396 438 devroot, slavename);
397 439
398 440 if ((slavefd = open(zoneslavename, O_RDWR)) < 0) {
399 441 zerror(gettext("failed to open %s: %s"), zoneslavename,
400 442 strerror(errno));
401 443 return (-1);
402 444 }
403 445
404 446 /*
405 447 * Push hardware emulation (ptem), line discipline (ldterm),
406 448 * and V7/4BSD/Xenix compatibility (ttcompat) modules.
407 449 */
408 450 if (ioctl(slavefd, I_PUSH, "ptem") == -1) {
409 451 zperror(gettext("failed to push ptem module"));
410 452 if (!failsafe)
411 453 goto bad;
412 454 }
413 455
414 456 /*
415 457 * Anchor the stream to prevent malicious I_POPs; we prefer to do
416 458 * this prior to entering the zone so that we can detect any errors
417 459 * early, and so that we can set the anchor from the global zone.
418 460 */
419 461 if (ioctl(slavefd, I_ANCHOR) == -1) {
420 462 zperror(gettext("failed to set stream anchor"));
421 463 if (!failsafe)
422 464 goto bad;
423 465 }
424 466
425 467 if (ioctl(slavefd, I_PUSH, "ldterm") == -1) {
426 468 zperror(gettext("failed to push ldterm module"));
427 469 if (!failsafe)
428 470 goto bad;
429 471 }
430 472 if (ioctl(slavefd, I_PUSH, "ttcompat") == -1) {
431 473 zperror(gettext("failed to push ttcompat module"));
432 474 if (!failsafe)
433 475 goto bad;
434 476 }
435 477
436 478 /*
437 479 * Propagate terminal settings from the external term to the new one.
438 480 */
439 481 if (tcsetattr(slavefd, TCSAFLUSH, &save_termios) == -1) {
440 482 zperror(gettext("failed to set terminal settings"));
441 483 if (!failsafe)
442 484 goto bad;
443 485 }
444 486 (void) ioctl(slavefd, TIOCSWINSZ, (char *)&winsize);
445 487
446 488 if (zonept(masterfd, zoneid) != 0) {
447 489 zperror(gettext("could not set zoneid of pty"));
448 490 goto bad;
449 491 }
450 492
451 493 return (slavefd);
452 494
453 495 bad:
454 496 (void) close(slavefd);
455 497 return (-1);
456 498 }
457 499
458 500 /*
459 501 * Place terminal into raw mode.
460 502 */
461 503 static int
462 504 set_tty_rawmode(int fd)
463 505 {
464 506 struct termios term;
465 507 if (tcgetattr(fd, &term) < 0) {
466 508 zperror(gettext("failed to get user terminal settings"));
467 509 return (-1);
468 510 }
469 511
470 512 /* Stash for later, so we can revert back to previous mode */
471 513 save_termios = term;
472 514 save_fd = fd;
473 515
474 516 /* disable 8->7 bit strip, start/stop, enable any char to restart */
475 517 term.c_iflag &= ~(ISTRIP|IXON|IXANY);
476 518 /* disable NL->CR, CR->NL, ignore CR, UPPER->lower */
477 519 term.c_iflag &= ~(INLCR|ICRNL|IGNCR|IUCLC);
478 520 /* disable output post-processing */
479 521 term.c_oflag &= ~OPOST;
480 522 /* disable canonical mode, signal chars, echo & extended functions */
481 523 term.c_lflag &= ~(ICANON|ISIG|ECHO|IEXTEN);
482 524
483 525 term.c_cc[VMIN] = 1; /* byte-at-a-time */
484 526 term.c_cc[VTIME] = 0;
485 527
486 528 if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)) {
487 529 zperror(gettext("failed to set user terminal to raw mode"));
488 530 return (-1);
489 531 }
490 532
491 533 /*
492 534 * We need to know the value of VEOF so that we can properly process for
493 535 * client-side ~<EOF>. But we have obliterated VEOF in term,
494 536 * because VMIN overloads the same array slot in non-canonical mode.
495 537 * Stupid @&^%!
496 538 *
497 539 * So here we construct the "effective" termios from the current
498 540 * terminal settings, and the corrected VEOF and VEOL settings.
499 541 */
500 542 if (tcgetattr(STDIN_FILENO, &effective_termios) < 0) {
501 543 zperror(gettext("failed to get user terminal settings"));
502 544 return (-1);
503 545 }
504 546 effective_termios.c_cc[VEOF] = save_termios.c_cc[VEOF];
505 547 effective_termios.c_cc[VEOL] = save_termios.c_cc[VEOL];
506 548
507 549 return (0);
508 550 }
|
↓ open down ↓ |
168 lines elided |
↑ open up ↑ |
509 551
510 552 /*
511 553 * Copy terminal window size from our terminal to the pts.
512 554 */
513 555 /*ARGSUSED*/
514 556 static void
515 557 sigwinch(int s)
516 558 {
517 559 struct winsize ws;
518 560
519 - if (ioctl(0, TIOCGWINSZ, &ws) == 0)
520 - (void) ioctl(masterfd, TIOCSWINSZ, &ws);
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 + }
521 571 }
522 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 +
523 589 static volatile int close_on_sig = -1;
524 590
525 591 static void
526 592 /*ARGSUSED*/
527 593 sigcld(int s)
528 594 {
529 595 int status;
530 596 pid_t pid;
531 597
532 598 /*
533 599 * Peek at the exit status. If this isn't the process we cared
534 600 * about, then just reap it.
535 601 */
536 602 if ((pid = waitpid(child_pid, &status, WNOHANG|WNOWAIT)) != -1) {
537 603 if (pid == child_pid &&
538 604 (WIFEXITED(status) || WIFSIGNALED(status))) {
539 605 dead = 1;
540 606 if (close_on_sig != -1) {
541 607 (void) write(close_on_sig, "a", 1);
542 608 (void) close(close_on_sig);
543 609 close_on_sig = -1;
544 610 }
545 611 } else {
546 612 (void) waitpid(pid, &status, WNOHANG);
547 613 }
548 614 }
549 615 }
550 616
551 617 /*
552 618 * Some signals (currently, SIGINT) must be forwarded on to the process
553 619 * group of the child process.
554 620 */
555 621 static void
556 622 sig_forward(int s)
557 623 {
558 624 if (child_pid != -1) {
559 625 (void) sigsend(P_PGID, child_pid, s);
560 626 }
561 627 }
562 628
563 629 /*
564 630 * reset terminal settings for global environment
565 631 */
566 632 static void
567 633 reset_tty()
568 634 {
569 635 (void) tcsetattr(save_fd, TCSADRAIN, &save_termios);
570 636 }
571 637
572 638 /*
573 639 * Convert character to printable representation, for display with locally
574 640 * echoed command characters (like when we need to display ~^D)
575 641 */
576 642 static void
577 643 canonify(char c, char *cc)
578 644 {
579 645 if (isprint(c)) {
580 646 cc[0] = c;
581 647 cc[1] = '\0';
582 648 } else if (c >= 0 && c <= 31) { /* ^@ through ^_ */
583 649 cc[0] = '^';
584 650 cc[1] = c + '@';
585 651 cc[2] = '\0';
586 652 } else {
587 653 cc[0] = '\\';
588 654 cc[1] = ((c >> 6) & 7) + '0';
589 655 cc[2] = ((c >> 3) & 7) + '0';
590 656 cc[3] = (c & 7) + '0';
591 657 cc[4] = '\0';
592 658 }
593 659 }
594 660
595 661 /*
596 662 * process_user_input watches the input stream for the escape sequence for
597 663 * 'quit' (by default, tilde-period). Because we might be fed just one
598 664 * keystroke at a time, state associated with the user input (are we at the
599 665 * beginning of the line? are we locally echoing the next character?) is
600 666 * maintained by beginning_of_line and local_echo across calls to the routine.
601 667 * If the write to outfd fails, we'll try to read from infd in an attempt
602 668 * to prevent deadlock between the two processes.
603 669 *
604 670 * This routine returns -1 when the 'quit' escape sequence has been issued,
605 671 * or an error is encountered, 1 if stdin is EOF, and 0 otherwise.
606 672 */
607 673 static int
608 674 process_user_input(int outfd, int infd)
609 675 {
610 676 static boolean_t beginning_of_line = B_TRUE;
611 677 static boolean_t local_echo = B_FALSE;
612 678 char ibuf[ZLOGIN_BUFSIZ];
613 679 int nbytes;
614 680 char *buf = ibuf;
615 681 char c = *buf;
616 682
617 683 nbytes = read(STDIN_FILENO, ibuf, ZLOGIN_RDBUFSIZ);
618 684 if (nbytes == -1 && (errno != EINTR || dead))
619 685 return (-1);
620 686
621 687 if (nbytes == -1) /* The read was interrupted. */
622 688 return (0);
623 689
624 690 /* 0 read means EOF, close the pipe to the child */
625 691 if (nbytes == 0)
626 692 return (1);
627 693
628 694 for (c = *buf; nbytes > 0; c = *buf, --nbytes) {
629 695 buf++;
630 696 if (beginning_of_line && !nocmdchar) {
631 697 beginning_of_line = B_FALSE;
632 698 if (c == cmdchar) {
633 699 local_echo = B_TRUE;
634 700 continue;
635 701 }
636 702 } else if (local_echo) {
637 703 local_echo = B_FALSE;
638 704 if (c == '.' || c == effective_termios.c_cc[VEOF]) {
639 705 char cc[CANONIFY_LEN];
640 706
641 707 canonify(c, cc);
642 708 (void) write(STDOUT_FILENO, &cmdchar, 1);
643 709 (void) write(STDOUT_FILENO, cc, strlen(cc));
644 710 return (-1);
645 711 }
646 712 }
647 713 retry:
648 714 if (write(outfd, &c, 1) <= 0) {
649 715 /*
650 716 * Since the fd we are writing to is opened with
651 717 * O_NONBLOCK it is possible to get EAGAIN if the
652 718 * pipe is full. One way this could happen is if we
653 719 * are writing a lot of data into the pipe in this loop
654 720 * and the application on the other end is echoing that
655 721 * data back out to its stdout. The output pipe can
656 722 * fill up since we are stuck here in this loop and not
657 723 * draining the other pipe. We can try to read some of
658 724 * the data to see if we can drain the pipe so that the
659 725 * application can continue to make progress. The read
660 726 * is non-blocking so we won't hang here. We also wait
661 727 * a bit before retrying since there could be other
662 728 * reasons why the pipe is full and we don't want to
663 729 * continuously retry.
664 730 */
665 731 if (errno == EAGAIN) {
666 732 struct timespec rqtp;
667 733 int ln;
668 734 char obuf[ZLOGIN_BUFSIZ];
669 735
670 736 if ((ln = read(infd, obuf, ZLOGIN_BUFSIZ)) > 0)
671 737 (void) write(STDOUT_FILENO, obuf, ln);
672 738
673 739 /* sleep for 10 milliseconds */
674 740 rqtp.tv_sec = 0;
675 741 rqtp.tv_nsec = MSEC2NSEC(10);
676 742 (void) nanosleep(&rqtp, NULL);
677 743 if (!dead)
678 744 goto retry;
679 745 }
680 746
681 747 return (-1);
682 748 }
683 749 beginning_of_line = (c == '\r' || c == '\n' ||
684 750 c == effective_termios.c_cc[VKILL] ||
685 751 c == effective_termios.c_cc[VEOL] ||
686 752 c == effective_termios.c_cc[VSUSP] ||
687 753 c == effective_termios.c_cc[VINTR]);
688 754 }
689 755 return (0);
690 756 }
691 757
692 758 /*
693 759 * This function prevents deadlock between zlogin and the application in the
694 760 * zone that it is talking to. This can happen when we read from zlogin's
695 761 * stdin and write the data down the pipe to the application. If the pipe
696 762 * is full, we'll block in the write. Because zlogin could be blocked in
697 763 * the write, it would never read the application's stdout/stderr so the
698 764 * application can then block on those writes (when the pipe fills up). If the
699 765 * the application gets blocked this way, it can never get around to reading
700 766 * its stdin so that zlogin can unblock from its write. Once in this state,
701 767 * the two processes are deadlocked.
702 768 *
703 769 * To prevent this, we want to verify that we can write into the pipe before we
704 770 * read from our stdin. If the pipe already is pretty full, we bypass the read
705 771 * for now. We'll circle back here again after the poll() so that we can
706 772 * try again. When this function is called, we already know there is data
707 773 * ready to read on STDIN_FILENO. We return -1 if there is a problem, 1 if
708 774 * stdin is EOF, and 0 if everything is ok (even though we might not have
709 775 * read/written any data into the pipe on this iteration).
710 776 */
711 777 static int
712 778 process_raw_input(int stdin_fd, int appin_fd)
713 779 {
714 780 int cc;
715 781 struct stat64 sb;
716 782 char ibuf[ZLOGIN_RDBUFSIZ];
717 783
718 784 /* Check how much data is already in the pipe */
719 785 if (fstat64(appin_fd, &sb) == -1) {
720 786 perror("stat failed");
721 787 return (-1);
722 788 }
723 789
724 790 if (dead)
725 791 return (-1);
726 792
727 793 /*
728 794 * The pipe already has a lot of data in it, don't write any more
729 795 * right now.
730 796 */
731 797 if (sb.st_size >= HI_WATER)
732 798 return (0);
733 799
734 800 cc = read(STDIN_FILENO, ibuf, ZLOGIN_RDBUFSIZ);
735 801 if (cc == -1 && (errno != EINTR || dead))
736 802 return (-1);
737 803
738 804 if (cc == -1) /* The read was interrupted. */
739 805 return (0);
740 806
741 807 /* 0 read means EOF, close the pipe to the child */
742 808 if (cc == 0)
743 809 return (1);
744 810
745 811 /*
746 812 * stdin_fd is stdin of the target; so, the thing we'll write the user
747 813 * data *to*.
748 814 */
749 815 if (write(stdin_fd, ibuf, cc) == -1)
750 816 return (-1);
751 817
752 818 return (0);
753 819 }
754 820
755 821 /*
756 822 * Write the output from the application running in the zone. We can get
757 823 * a signal during the write (usually it would be SIGCHLD when the application
758 824 * has exited) so we loop to make sure we have written all of the data we read.
759 825 */
760 826 static int
761 827 process_output(int in_fd, int out_fd)
762 828 {
763 829 int wrote = 0;
764 830 int cc;
765 831 char ibuf[ZLOGIN_BUFSIZ];
766 832
767 833 cc = read(in_fd, ibuf, ZLOGIN_BUFSIZ);
768 834 if (cc == -1 && (errno != EINTR || dead))
769 835 return (-1);
770 836 if (cc == 0) /* EOF */
771 837 return (-1);
772 838 if (cc == -1) /* The read was interrupted. */
773 839 return (0);
774 840
775 841 do {
776 842 int len;
777 843
778 844 len = write(out_fd, ibuf + wrote, cc - wrote);
779 845 if (len == -1 && errno != EINTR)
780 846 return (-1);
781 847 if (len != -1)
782 848 wrote += len;
783 849 } while (wrote < cc);
784 850
785 851 return (0);
786 852 }
787 853
788 854 /*
789 855 * This is the main I/O loop, and is shared across all zlogin modes.
790 856 * Parameters:
791 857 * stdin_fd: The fd representing 'stdin' for the slave side; input to
792 858 * the zone will be written here.
793 859 *
794 860 * appin_fd: The fd representing the other end of the 'stdin' pipe (when
795 861 * we're running non-interactive); used in process_raw_input
796 862 * to ensure we don't fill up the application's stdin pipe.
797 863 *
798 864 * stdout_fd: The fd representing 'stdout' for the slave side; output
799 865 * from the zone will arrive here.
800 866 *
801 867 * stderr_fd: The fd representing 'stderr' for the slave side; output
802 868 * from the zone will arrive here.
803 869 *
804 870 * raw_mode: If TRUE, then no processing (for example, for '~.') will
805 871 * be performed on the input coming from STDIN.
806 872 *
807 873 * stderr_fd may be specified as -1 if there is no stderr (only non-interactive
808 874 * mode supplies a stderr).
809 875 *
810 876 */
811 877 static void
812 878 doio(int stdin_fd, int appin_fd, int stdout_fd, int stderr_fd, int sig_fd,
813 879 boolean_t raw_mode)
814 880 {
815 881 struct pollfd pollfds[4];
816 882 char ibuf[ZLOGIN_BUFSIZ];
817 883 int cc, ret;
818 884
819 885 /* read from stdout of zone and write to stdout of global zone */
820 886 pollfds[0].fd = stdout_fd;
821 887 pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
822 888
823 889 /* read from stderr of zone and write to stderr of global zone */
824 890 pollfds[1].fd = stderr_fd;
825 891 pollfds[1].events = pollfds[0].events;
826 892
827 893 /* read from stdin of global zone and write to stdin of zone */
828 894 pollfds[2].fd = STDIN_FILENO;
829 895 pollfds[2].events = pollfds[0].events;
830 896
831 897 /* read from signalling pipe so we know when child dies */
832 898 pollfds[3].fd = sig_fd;
833 899 pollfds[3].events = pollfds[0].events;
834 900
835 901 for (;;) {
836 902 pollfds[0].revents = pollfds[1].revents =
837 903 pollfds[2].revents = pollfds[3].revents = 0;
838 904
839 905 if (dead)
840 906 break;
841 907
842 908 /*
843 909 * There is a race condition here where we can receive the
844 910 * child death signal, set the dead flag, but since we have
845 911 * passed the test above, we would go into poll and hang.
846 912 * To avoid this we use the sig_fd as an additional poll fd.
847 913 * The signal handler writes into the other end of this pipe
848 914 * when the child dies so that the poll will always see that
849 915 * input and proceed. We just loop around at that point and
850 916 * then notice the dead flag.
851 917 */
852 918
853 919 ret = poll(pollfds,
854 920 sizeof (pollfds) / sizeof (struct pollfd), -1);
|
↓ open down ↓ |
322 lines elided |
↑ open up ↑ |
855 921
856 922 if (ret == -1 && errno != EINTR) {
857 923 perror("poll failed");
858 924 break;
859 925 }
860 926
861 927 if (errno == EINTR && dead) {
862 928 break;
863 929 }
864 930
865 - /* event from master side stdout */
866 - if (pollfds[0].revents) {
867 - if (pollfds[0].revents &
931 + /* event from master side stderr */
932 + if (pollfds[1].revents) {
933 + if (pollfds[1].revents &
868 934 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
869 - if (process_output(stdout_fd, STDOUT_FILENO)
935 + if (process_output(stderr_fd, STDERR_FILENO)
870 936 != 0)
871 937 break;
872 938 } else {
873 - pollerr = pollfds[0].revents;
939 + pollerr = pollfds[1].revents;
874 940 break;
875 941 }
876 942 }
877 943
878 - /* event from master side stderr */
879 - if (pollfds[1].revents) {
880 - if (pollfds[1].revents &
944 + /* event from master side stdout */
945 + if (pollfds[0].revents) {
946 + if (pollfds[0].revents &
881 947 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
882 - if (process_output(stderr_fd, STDERR_FILENO)
948 + if (process_output(stdout_fd, STDOUT_FILENO)
883 949 != 0)
884 950 break;
885 951 } else {
886 - pollerr = pollfds[1].revents;
952 + pollerr = pollfds[0].revents;
887 953 break;
888 954 }
889 955 }
890 956
891 957 /* event from user STDIN side */
892 958 if (pollfds[2].revents) {
893 959 if (pollfds[2].revents &
894 960 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
895 961 /*
896 962 * stdin fd is stdin of the target; so,
897 963 * the thing we'll write the user data *to*.
898 964 *
899 965 * Also, unlike on the output side, we
900 966 * close the pipe on a zero-length message.
901 967 */
902 968 int res;
903 969
904 970 if (raw_mode)
905 971 res = process_raw_input(stdin_fd,
906 972 appin_fd);
907 973 else
908 974 res = process_user_input(stdin_fd,
909 975 stdout_fd);
910 976
911 977 if (res < 0)
912 978 break;
913 979 if (res > 0) {
914 980 /* EOF (close) child's stdin_fd */
915 981 pollfds[2].fd = -1;
916 982 while ((res = close(stdin_fd)) != 0 &&
917 983 errno == EINTR)
918 984 ;
919 985 if (res != 0)
920 986 break;
921 987 }
922 988
923 989 } else if (raw_mode && pollfds[2].revents & POLLHUP) {
924 990 /*
925 991 * It's OK to get a POLLHUP on STDIN-- it
926 992 * always happens if you do:
927 993 *
928 994 * echo foo | zlogin <zone> <command>
929 995 *
930 996 * We reset fd to -1 in this case to clear
931 997 * the condition and close the pipe (EOF) to
932 998 * the other side in order to wrap things up.
933 999 */
934 1000 int res;
935 1001
936 1002 pollfds[2].fd = -1;
937 1003 while ((res = close(stdin_fd)) != 0 &&
938 1004 errno == EINTR)
939 1005 ;
940 1006 if (res != 0)
941 1007 break;
942 1008 } else {
943 1009 pollerr = pollfds[2].revents;
944 1010 break;
945 1011 }
946 1012 }
947 1013 }
948 1014
949 1015 /*
950 1016 * We are in the midst of dying, but try to poll with a short
951 1017 * timeout to see if we can catch the last bit of I/O from the
952 1018 * children.
953 1019 */
954 1020 retry:
955 1021 pollfds[0].revents = pollfds[1].revents = 0;
956 1022 (void) poll(pollfds, 2, 100);
957 1023 if (pollfds[0].revents &
958 1024 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
959 1025 if ((cc = read(stdout_fd, ibuf, ZLOGIN_BUFSIZ)) > 0) {
960 1026 (void) write(STDOUT_FILENO, ibuf, cc);
961 1027 goto retry;
962 1028 }
963 1029 }
964 1030 if (pollfds[1].revents &
965 1031 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
966 1032 if ((cc = read(stderr_fd, ibuf, ZLOGIN_BUFSIZ)) > 0) {
967 1033 (void) write(STDERR_FILENO, ibuf, cc);
968 1034 goto retry;
969 1035 }
970 1036 }
971 1037 }
972 1038
973 1039 /*
974 1040 * Fetch the user_cmd brand hook for getting a user's passwd(4) entry.
975 1041 */
976 1042 static const char *
977 1043 zone_get_user_cmd(brand_handle_t bh, const char *login, char *user_cmd,
978 1044 size_t len)
979 1045 {
980 1046 bzero(user_cmd, sizeof (user_cmd));
981 1047 if (brand_get_user_cmd(bh, login, user_cmd, len) != 0)
982 1048 return (NULL);
983 1049
984 1050 return (user_cmd);
985 1051 }
986 1052
987 1053 /* From libc */
988 1054 extern int str2passwd(const char *, int, void *, char *, int);
989 1055
990 1056 /*
991 1057 * exec() the user_cmd brand hook, and convert the output string to a
992 1058 * struct passwd. This is to be called after zone_enter().
993 1059 *
994 1060 */
995 1061 static struct passwd *
996 1062 zone_get_user_pw(const char *user_cmd, struct passwd *pwent, char *pwbuf,
997 1063 int pwbuflen)
998 1064 {
999 1065 char pwline[NSS_BUFLEN_PASSWD];
1000 1066 char *cin = NULL;
1001 1067 FILE *fin;
1002 1068 int status;
1003 1069
1004 1070 assert(getzoneid() != GLOBAL_ZONEID);
1005 1071
1006 1072 if ((fin = popen(user_cmd, "r")) == NULL)
1007 1073 return (NULL);
1008 1074
1009 1075 while (cin == NULL && !feof(fin))
1010 1076 cin = fgets(pwline, sizeof (pwline), fin);
1011 1077
1012 1078 if (cin == NULL) {
1013 1079 (void) pclose(fin);
1014 1080 return (NULL);
1015 1081 }
1016 1082
1017 1083 status = pclose(fin);
1018 1084 if (!WIFEXITED(status))
1019 1085 return (NULL);
1020 1086 if (WEXITSTATUS(status) != 0)
1021 1087 return (NULL);
1022 1088
1023 1089 if (str2passwd(pwline, sizeof (pwline), pwent, pwbuf, pwbuflen) == 0)
1024 1090 return (pwent);
1025 1091 else
1026 1092 return (NULL);
1027 1093 }
1028 1094
1029 1095 static char **
1030 1096 zone_login_cmd(brand_handle_t bh, const char *login)
1031 1097 {
1032 1098 static char result_buf[ARG_MAX];
1033 1099 char **new_argv, *ptr, *lasts;
1034 1100 int n, a;
1035 1101
1036 1102 /* Get the login command for the target zone. */
1037 1103 bzero(result_buf, sizeof (result_buf));
1038 1104
1039 1105 if (forced_login) {
1040 1106 if (brand_get_forcedlogin_cmd(bh, login,
1041 1107 result_buf, sizeof (result_buf)) != 0)
1042 1108 return (NULL);
1043 1109 } else {
1044 1110 if (brand_get_login_cmd(bh, login,
1045 1111 result_buf, sizeof (result_buf)) != 0)
|
↓ open down ↓ |
149 lines elided |
↑ open up ↑ |
1046 1112 return (NULL);
1047 1113 }
1048 1114
1049 1115 /*
1050 1116 * We got back a string that we'd like to execute. But since
1051 1117 * we're not doing the execution via a shell we'll need to convert
1052 1118 * the exec string to an array of strings. We'll do that here
1053 1119 * but we're going to be very simplistic about it and break stuff
1054 1120 * up based on spaces. We're not even going to support any kind
1055 1121 * of quoting or escape characters. It's truly amazing that
1056 - * there is no library function in OpenSolaris to do this for us.
1122 + * there is no library function in Illumos to do this for us.
1057 1123 */
1058 1124
1059 1125 /*
1060 1126 * Be paranoid. Since we're deliniating based on spaces make
1061 1127 * sure there are no adjacent spaces.
1062 1128 */
1063 1129 if (strstr(result_buf, " ") != NULL)
1064 1130 return (NULL);
1065 1131
1066 1132 /* Remove any trailing whitespace. */
1067 1133 n = strlen(result_buf);
1068 1134 if (result_buf[n - 1] == ' ')
1069 1135 result_buf[n - 1] = '\0';
1070 1136
1071 1137 /* Count how many elements there are in the exec string. */
1072 1138 ptr = result_buf;
1073 1139 for (n = 2; ((ptr = strchr(ptr + 1, (int)' ')) != NULL); n++)
1074 1140 ;
1075 1141
1076 1142 /* Allocate the argv array that we're going to return. */
1077 1143 if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
1078 1144 return (NULL);
1079 1145
1080 1146 /* Tokenize the exec string and return. */
1081 1147 a = 0;
1082 1148 new_argv[a++] = result_buf;
1083 1149 if (n > 2) {
1084 1150 (void) strtok_r(result_buf, " ", &lasts);
|
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
1085 1151 while ((new_argv[a++] = strtok_r(NULL, " ", &lasts)) != NULL)
1086 1152 ;
1087 1153 } else {
1088 1154 new_argv[a++] = NULL;
1089 1155 }
1090 1156 assert(n == a);
1091 1157 return (new_argv);
1092 1158 }
1093 1159
1094 1160 /*
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
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
1097 1163 * 'login -z <from_zonename> -f' (-z is an undocumented option which tells
1098 1164 * login that we're coming from another zone, and to disregard its CONSOLE
1099 1165 * checks).
1100 1166 */
1101 1167 static char **
1102 -prep_args(brand_handle_t bh, const char *login, char **argv)
1168 +prep_args(brand_handle_t bh, char *zonename, const char *login, char **argv)
1103 1169 {
1104 - int argc = 0, a = 0, i, n = -1;
1105 - char **new_argv;
1170 + int argc = 0, i;
1171 + size_t subshell_len = 1;
1172 + char *subshell = NULL, *supath = NULL;
1173 + char **new_argv = NULL;
1106 1174
1107 - if (argv != NULL) {
1108 - size_t subshell_len = 1;
1109 - char *subshell;
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 + }
1110 1186
1111 - while (argv[argc] != NULL)
1112 - argc++;
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];
1113 1194
1114 - for (i = 0; i < argc; i++) {
1115 - subshell_len += strlen(argv[i]) + 1;
1195 + if (zone_get_zonepath(zonename, zonepath,
1196 + sizeof (zonepath)) != Z_OK) {
1197 + zerror(gettext("unable to determine zone "
1198 + "path"));
1199 + return (NULL);
1116 1200 }
1117 - if ((subshell = calloc(1, subshell_len)) == NULL)
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"));
1118 1226 return (NULL);
1227 + }
1228 + return (argv);
1229 + }
1119 1230
1120 - for (i = 0; i < argc; i++) {
1121 - (void) strcat(subshell, argv[i]);
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)
1122 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]);
1123 1278 }
1279 + }
1124 1280
1125 - if (failsafe) {
1126 - n = 4;
1127 - if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
1128 - return (NULL);
1281 + if (failsafe) {
1282 + int a = 0, n = 4;
1129 1283
1130 - new_argv[a++] = FAILSAFESHELL;
1131 - } else {
1132 - n = 5;
1133 - if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
1134 - return (NULL);
1284 + if ((new_argv = malloc(sizeof (char *) * n)) == NULL)
1285 + return (NULL);
1135 1286
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 - }
1287 + new_argv[a++] = FAILSAFESHELL;
1143 1288 new_argv[a++] = "-c";
1144 1289 new_argv[a++] = subshell;
1145 1290 new_argv[a++] = NULL;
1146 1291 assert(a == n);
1147 1292 } 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);
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++] = "-";
1155 1302 } else {
1156 - new_argv = zone_login_cmd(bh, login);
1303 + n--;
1157 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);
1158 1310 }
1159 1311
1160 1312 return (new_argv);
1161 1313 }
1162 1314
1163 1315 /*
1164 1316 * Helper routine for prep_env below.
1165 1317 */
1166 1318 static char *
1167 1319 add_env(char *name, char *value)
1168 1320 {
1169 1321 size_t sz = strlen(name) + strlen(value) + 2; /* name, =, value, NUL */
1170 1322 char *str;
1171 1323
1172 1324 if ((str = malloc(sz)) == NULL)
1173 1325 return (NULL);
1174 1326
1175 1327 (void) snprintf(str, sz, "%s=%s", name, value);
1176 1328 return (str);
1177 1329 }
|
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
1178 1330
1179 1331 /*
1180 1332 * Prepare envp array for exec'd process.
1181 1333 */
1182 1334 static char **
1183 1335 prep_env()
1184 1336 {
1185 1337 int e = 0, size = 1;
1186 1338 char **new_env, *estr;
1187 1339 char *term = getenv("TERM");
1340 + char *path;
1188 1341
1189 1342 size++; /* for $PATH */
1190 1343 if (term != NULL)
1191 1344 size++;
1192 1345
1193 1346 /*
1194 1347 * In failsafe mode we set $HOME, since '-l' isn't valid in this mode.
1195 1348 * We also set $SHELL, since neither login nor su will be around to do
1196 1349 * it.
1197 1350 */
1198 1351 if (failsafe)
1199 1352 size += 2;
1200 1353
1201 1354 if ((new_env = malloc(sizeof (char *) * size)) == NULL)
1202 1355 return (NULL);
1203 1356
1204 - if ((estr = add_env("PATH", DEF_PATH)) == NULL)
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)
1205 1363 return (NULL);
1206 1364 new_env[e++] = estr;
1207 1365
1208 1366 if (term != NULL) {
1209 1367 if ((estr = add_env("TERM", term)) == NULL)
1210 1368 return (NULL);
1211 1369 new_env[e++] = estr;
1212 1370 }
1213 1371
1214 1372 if (failsafe) {
1215 1373 if ((estr = add_env("HOME", "/")) == NULL)
1216 1374 return (NULL);
1217 1375 new_env[e++] = estr;
1218 1376
1219 1377 if ((estr = add_env("SHELL", FAILSAFESHELL)) == NULL)
1220 1378 return (NULL);
1221 1379 new_env[e++] = estr;
1222 1380 }
1223 1381
1224 1382 new_env[e++] = NULL;
1225 1383
1226 1384 assert(e == size);
1227 1385
1228 1386 return (new_env);
1229 1387 }
1230 1388
1231 1389 /*
1232 1390 * Finish the preparation of the envp array for exec'd non-interactive
1233 1391 * zlogins. This is called in the child process *after* we zone_enter(), since
1234 1392 * it derives things we can only know within the zone, such as $HOME, $SHELL,
1235 1393 * etc. We need only do this in the non-interactive, mode, since otherwise
1236 1394 * login(1) will do it. We don't do this in failsafe mode, since it presents
1237 1395 * additional ways in which the command could fail, and we'd prefer to avoid
1238 1396 * that.
1239 1397 */
1240 1398 static char **
1241 1399 prep_env_noninteractive(const char *user_cmd, char **env)
1242 1400 {
1243 1401 size_t size;
1244 1402 char **new_env;
1245 1403 int e, i;
1246 1404 char *estr;
1247 1405 char varmail[LOGNAME_MAX + 11]; /* strlen(/var/mail/) = 10, NUL */
1248 1406 char pwbuf[NSS_BUFLEN_PASSWD + 1];
1249 1407 struct passwd pwent;
1250 1408 struct passwd *pw = NULL;
1251 1409
1252 1410 assert(env != NULL);
1253 1411 assert(failsafe == 0);
1254 1412
1255 1413 /*
1256 1414 * Exec the "user_cmd" brand hook to get a pwent for the
1257 1415 * login user. If this fails, HOME will be set to "/", SHELL
1258 1416 * will be set to $DEFAULTSHELL, and we will continue to exec
1259 1417 * SUPATH <login> -c <cmd>.
1260 1418 */
1261 1419 pw = zone_get_user_pw(user_cmd, &pwent, pwbuf, sizeof (pwbuf));
1262 1420
1263 1421 /*
1264 1422 * Get existing envp size.
1265 1423 */
1266 1424 for (size = 0; env[size] != NULL; size++)
1267 1425 ;
1268 1426
1269 1427 e = size;
1270 1428
1271 1429 /*
1272 1430 * Finish filling out the environment; we duplicate the environment
1273 1431 * setup described in login(1), for lack of a better precedent.
1274 1432 */
1275 1433 if (pw != NULL)
1276 1434 size += 3; /* LOGNAME, HOME, MAIL */
1277 1435 else
1278 1436 size += 1; /* HOME */
1279 1437
1280 1438 size++; /* always fill in SHELL */
1281 1439 size++; /* terminating NULL */
1282 1440
1283 1441 if ((new_env = malloc(sizeof (char *) * size)) == NULL)
1284 1442 goto malloc_fail;
1285 1443
1286 1444 /*
1287 1445 * Copy existing elements of env into new_env.
1288 1446 */
1289 1447 for (i = 0; env[i] != NULL; i++) {
1290 1448 if ((new_env[i] = strdup(env[i])) == NULL)
1291 1449 goto malloc_fail;
1292 1450 }
1293 1451 assert(e == i);
1294 1452
1295 1453 if (pw != NULL) {
1296 1454 if ((estr = add_env("LOGNAME", pw->pw_name)) == NULL)
1297 1455 goto malloc_fail;
1298 1456 new_env[e++] = estr;
1299 1457
1300 1458 if ((estr = add_env("HOME", pw->pw_dir)) == NULL)
1301 1459 goto malloc_fail;
1302 1460 new_env[e++] = estr;
1303 1461
1304 1462 if (chdir(pw->pw_dir) != 0)
1305 1463 zerror(gettext("Could not chdir to home directory "
1306 1464 "%s: %s"), pw->pw_dir, strerror(errno));
1307 1465
1308 1466 (void) snprintf(varmail, sizeof (varmail), "/var/mail/%s",
1309 1467 pw->pw_name);
1310 1468 if ((estr = add_env("MAIL", varmail)) == NULL)
1311 1469 goto malloc_fail;
1312 1470 new_env[e++] = estr;
1313 1471 } else {
1314 1472 if ((estr = add_env("HOME", "/")) == NULL)
1315 1473 goto malloc_fail;
1316 1474 new_env[e++] = estr;
1317 1475 }
1318 1476
1319 1477 if (pw != NULL && strlen(pw->pw_shell) > 0) {
1320 1478 if ((estr = add_env("SHELL", pw->pw_shell)) == NULL)
1321 1479 goto malloc_fail;
1322 1480 new_env[e++] = estr;
1323 1481 } else {
1324 1482 if ((estr = add_env("SHELL", DEFAULTSHELL)) == NULL)
1325 1483 goto malloc_fail;
1326 1484 new_env[e++] = estr;
1327 1485 }
1328 1486
1329 1487 new_env[e++] = NULL; /* add terminating NULL */
1330 1488
1331 1489 assert(e == size);
1332 1490 return (new_env);
1333 1491
1334 1492 malloc_fail:
1335 1493 zperror(gettext("failed to allocate memory for process environment"));
1336 1494 return (NULL);
1337 1495 }
1338 1496
1339 1497 static int
1340 1498 close_func(void *slavefd, int fd)
1341 1499 {
1342 1500 if (fd != *(int *)slavefd)
1343 1501 (void) close(fd);
1344 1502 return (0);
1345 1503 }
1346 1504
1347 1505 static void
1348 1506 set_cmdchar(char *cmdcharstr)
1349 1507 {
1350 1508 char c;
1351 1509 long lc;
1352 1510
1353 1511 if ((c = *cmdcharstr) != '\\') {
1354 1512 cmdchar = c;
1355 1513 return;
1356 1514 }
1357 1515
1358 1516 c = cmdcharstr[1];
1359 1517 if (c == '\0' || c == '\\') {
1360 1518 cmdchar = '\\';
1361 1519 return;
1362 1520 }
1363 1521
1364 1522 if (c < '0' || c > '7') {
1365 1523 zerror(gettext("Unrecognized escape character option %s"),
1366 1524 cmdcharstr);
1367 1525 usage();
1368 1526 }
1369 1527
1370 1528 lc = strtol(cmdcharstr + 1, NULL, 8);
1371 1529 if (lc < 0 || lc > 255) {
1372 1530 zerror(gettext("Octal escape character '%s' too large"),
1373 1531 cmdcharstr);
1374 1532 usage();
1375 1533 }
1376 1534 cmdchar = (char)lc;
1377 1535 }
1378 1536
1379 1537 static int
1380 1538 setup_utmpx(char *slavename)
1381 1539 {
1382 1540 struct utmpx ut;
1383 1541
1384 1542 bzero(&ut, sizeof (ut));
1385 1543 (void) strncpy(ut.ut_user, ".zlogin", sizeof (ut.ut_user));
1386 1544 (void) strncpy(ut.ut_line, slavename, sizeof (ut.ut_line));
1387 1545 ut.ut_pid = getpid();
1388 1546 ut.ut_id[0] = 'z';
1389 1547 ut.ut_id[1] = ut.ut_id[2] = ut.ut_id[3] = (char)SC_WILDC;
1390 1548 ut.ut_type = LOGIN_PROCESS;
1391 1549 (void) time(&ut.ut_tv.tv_sec);
1392 1550
1393 1551 if (makeutx(&ut) == NULL) {
1394 1552 zerror(gettext("makeutx failed"));
1395 1553 return (-1);
1396 1554 }
1397 1555 return (0);
1398 1556 }
1399 1557
1400 1558 static void
1401 1559 release_lock_file(int lockfd)
1402 1560 {
1403 1561 (void) close(lockfd);
1404 1562 }
1405 1563
1406 1564 static int
1407 1565 grab_lock_file(const char *zone_name, int *lockfd)
1408 1566 {
1409 1567 char pathbuf[PATH_MAX];
1410 1568 struct flock flock;
1411 1569
1412 1570 if (mkdir(ZONES_TMPDIR, S_IRWXU) < 0 && errno != EEXIST) {
1413 1571 zerror(gettext("could not mkdir %s: %s"), ZONES_TMPDIR,
1414 1572 strerror(errno));
1415 1573 return (-1);
1416 1574 }
1417 1575 (void) chmod(ZONES_TMPDIR, S_IRWXU);
1418 1576 (void) snprintf(pathbuf, sizeof (pathbuf), "%s/%s.zoneadm.lock",
1419 1577 ZONES_TMPDIR, zone_name);
1420 1578
1421 1579 if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
1422 1580 zerror(gettext("could not open %s: %s"), pathbuf,
1423 1581 strerror(errno));
1424 1582 return (-1);
1425 1583 }
1426 1584 /*
1427 1585 * Lock the file to synchronize with other zoneadmds
1428 1586 */
1429 1587 flock.l_type = F_WRLCK;
1430 1588 flock.l_whence = SEEK_SET;
1431 1589 flock.l_start = (off_t)0;
1432 1590 flock.l_len = (off_t)0;
1433 1591 if (fcntl(*lockfd, F_SETLKW, &flock) < 0) {
1434 1592 zerror(gettext("unable to lock %s: %s"), pathbuf,
1435 1593 strerror(errno));
1436 1594 release_lock_file(*lockfd);
1437 1595 return (-1);
1438 1596 }
1439 1597 return (Z_OK);
1440 1598 }
1441 1599
1442 1600 static int
1443 1601 start_zoneadmd(const char *zone_name)
1444 1602 {
1445 1603 pid_t retval;
1446 1604 int pstatus = 0, error = -1, lockfd, doorfd;
1447 1605 struct door_info info;
1448 1606 char doorpath[MAXPATHLEN];
1449 1607
1450 1608 (void) snprintf(doorpath, sizeof (doorpath), ZONE_DOOR_PATH, zone_name);
1451 1609
1452 1610 if (grab_lock_file(zone_name, &lockfd) != Z_OK)
1453 1611 return (-1);
1454 1612 /*
1455 1613 * We must do the door check with the lock held. Otherwise, we
1456 1614 * might race against another zoneadm/zlogin process and wind
1457 1615 * up with two processes trying to start zoneadmd at the same
1458 1616 * time. zoneadmd will detect this, and fail, but we prefer this
1459 1617 * to be as seamless as is practical, from a user perspective.
1460 1618 */
1461 1619 if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
1462 1620 if (errno != ENOENT) {
1463 1621 zerror("failed to open %s: %s", doorpath,
1464 1622 strerror(errno));
1465 1623 goto out;
1466 1624 }
1467 1625 } else {
1468 1626 /*
1469 1627 * Seems to be working ok.
1470 1628 */
1471 1629 if (door_info(doorfd, &info) == 0 &&
1472 1630 ((info.di_attributes & DOOR_REVOKED) == 0)) {
1473 1631 error = 0;
1474 1632 goto out;
1475 1633 }
1476 1634 }
1477 1635
1478 1636 if ((child_pid = fork()) == -1) {
1479 1637 zperror(gettext("could not fork"));
1480 1638 goto out;
1481 1639 } else if (child_pid == 0) {
1482 1640 /* child process */
1483 1641 (void) execl("/usr/lib/zones/zoneadmd", "zoneadmd", "-z",
1484 1642 zone_name, NULL);
1485 1643 zperror(gettext("could not exec zoneadmd"));
1486 1644 _exit(1);
1487 1645 }
1488 1646
1489 1647 /* parent process */
1490 1648 do {
1491 1649 retval = waitpid(child_pid, &pstatus, 0);
1492 1650 } while (retval != child_pid);
1493 1651 if (WIFSIGNALED(pstatus) ||
1494 1652 (WIFEXITED(pstatus) && WEXITSTATUS(pstatus) != 0)) {
1495 1653 zerror(gettext("could not start %s"), "zoneadmd");
1496 1654 goto out;
1497 1655 }
1498 1656 error = 0;
1499 1657 out:
1500 1658 release_lock_file(lockfd);
1501 1659 (void) close(doorfd);
1502 1660 return (error);
1503 1661 }
1504 1662
1505 1663 static int
1506 1664 init_template(void)
1507 1665 {
1508 1666 int fd;
1509 1667 int err = 0;
1510 1668
1511 1669 fd = open64(CTFS_ROOT "/process/template", O_RDWR);
1512 1670 if (fd == -1)
1513 1671 return (-1);
1514 1672
1515 1673 /*
1516 1674 * zlogin doesn't do anything with the contract.
1517 1675 * Deliver no events, don't inherit, and allow it to be orphaned.
1518 1676 */
1519 1677 err |= ct_tmpl_set_critical(fd, 0);
1520 1678 err |= ct_tmpl_set_informative(fd, 0);
1521 1679 err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
1522 1680 err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
1523 1681 if (err || ct_tmpl_activate(fd)) {
1524 1682 (void) close(fd);
1525 1683 return (-1);
1526 1684 }
1527 1685
1528 1686 return (fd);
1529 1687 }
1530 1688
1531 1689 static int
1532 1690 noninteractive_login(char *zonename, const char *user_cmd, zoneid_t zoneid,
1533 1691 char **new_args, char **new_env)
1534 1692 {
1535 1693 pid_t retval;
1536 1694 int stdin_pipe[2], stdout_pipe[2], stderr_pipe[2], dead_child_pipe[2];
1537 1695 int child_status;
1538 1696 int tmpl_fd;
1539 1697 sigset_t block_cld;
1540 1698
1541 1699 if ((tmpl_fd = init_template()) == -1) {
1542 1700 reset_tty();
1543 1701 zperror(gettext("could not create contract"));
1544 1702 return (1);
1545 1703 }
1546 1704
1547 1705 if (pipe(stdin_pipe) != 0) {
1548 1706 zperror(gettext("could not create STDIN pipe"));
1549 1707 return (1);
1550 1708 }
1551 1709 /*
1552 1710 * When the user types ^D, we get a zero length message on STDIN.
1553 1711 * We need to echo that down the pipe to send it to the other side;
1554 1712 * but by default, pipes don't propagate zero-length messages. We
1555 1713 * toggle that behavior off using I_SWROPT. See streamio(7i).
1556 1714 */
1557 1715 if (ioctl(stdin_pipe[0], I_SWROPT, SNDZERO) != 0) {
1558 1716 zperror(gettext("could not configure STDIN pipe"));
1559 1717 return (1);
1560 1718
1561 1719 }
1562 1720 if (pipe(stdout_pipe) != 0) {
1563 1721 zperror(gettext("could not create STDOUT pipe"));
1564 1722 return (1);
1565 1723 }
1566 1724 if (pipe(stderr_pipe) != 0) {
1567 1725 zperror(gettext("could not create STDERR pipe"));
1568 1726 return (1);
1569 1727 }
1570 1728
1571 1729 if (pipe(dead_child_pipe) != 0) {
1572 1730 zperror(gettext("could not create signalling pipe"));
1573 1731 return (1);
1574 1732 }
1575 1733 close_on_sig = dead_child_pipe[0];
1576 1734
1577 1735 /*
1578 1736 * If any of the pipe FD's winds up being less than STDERR, then we
1579 1737 * have a mess on our hands-- and we are lacking some of the I/O
1580 1738 * streams we would expect anyway. So we bail.
1581 1739 */
1582 1740 if (stdin_pipe[0] <= STDERR_FILENO ||
1583 1741 stdin_pipe[1] <= STDERR_FILENO ||
1584 1742 stdout_pipe[0] <= STDERR_FILENO ||
1585 1743 stdout_pipe[1] <= STDERR_FILENO ||
1586 1744 stderr_pipe[0] <= STDERR_FILENO ||
1587 1745 stderr_pipe[1] <= STDERR_FILENO ||
1588 1746 dead_child_pipe[0] <= STDERR_FILENO ||
1589 1747 dead_child_pipe[1] <= STDERR_FILENO) {
1590 1748 zperror(gettext("process lacks valid STDIN, STDOUT, STDERR"));
1591 1749 return (1);
1592 1750 }
1593 1751
1594 1752 if (prefork_dropprivs() != 0) {
1595 1753 zperror(gettext("could not allocate privilege set"));
1596 1754 return (1);
1597 1755 }
1598 1756
1599 1757 (void) sigset(SIGCLD, sigcld);
1600 1758 (void) sigemptyset(&block_cld);
1601 1759 (void) sigaddset(&block_cld, SIGCLD);
1602 1760 (void) sigprocmask(SIG_BLOCK, &block_cld, NULL);
1603 1761
1604 1762 if ((child_pid = fork()) == -1) {
1605 1763 (void) ct_tmpl_clear(tmpl_fd);
1606 1764 (void) close(tmpl_fd);
1607 1765 zperror(gettext("could not fork"));
1608 1766 return (1);
1609 1767 } else if (child_pid == 0) { /* child process */
1610 1768 (void) ct_tmpl_clear(tmpl_fd);
1611 1769
1612 1770 /*
1613 1771 * Do a dance to get the pipes hooked up as FD's 0, 1 and 2.
1614 1772 */
1615 1773 (void) close(STDIN_FILENO);
1616 1774 (void) close(STDOUT_FILENO);
1617 1775 (void) close(STDERR_FILENO);
1618 1776 (void) dup2(stdin_pipe[1], STDIN_FILENO);
1619 1777 (void) dup2(stdout_pipe[1], STDOUT_FILENO);
1620 1778 (void) dup2(stderr_pipe[1], STDERR_FILENO);
1621 1779 (void) closefrom(STDERR_FILENO + 1);
1622 1780
1623 1781 (void) sigset(SIGCLD, SIG_DFL);
1624 1782 (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL);
1625 1783 /*
1626 1784 * In case any of stdin, stdout or stderr are streams,
1627 1785 * anchor them to prevent malicious I_POPs.
1628 1786 */
1629 1787 (void) ioctl(STDIN_FILENO, I_ANCHOR);
1630 1788 (void) ioctl(STDOUT_FILENO, I_ANCHOR);
1631 1789 (void) ioctl(STDERR_FILENO, I_ANCHOR);
1632 1790
1633 1791 if (zone_enter(zoneid) == -1) {
1634 1792 zerror(gettext("could not enter zone %s: %s"),
1635 1793 zonename, strerror(errno));
1636 1794 _exit(1);
1637 1795 }
1638 1796
1639 1797 /*
1640 1798 * For non-native zones, tell libc where it can find locale
1641 1799 * specific getttext() messages.
1642 1800 */
1643 1801 if (access("/.SUNWnative/usr/lib/locale", R_OK) == 0)
1644 1802 (void) bindtextdomain(TEXT_DOMAIN,
1645 1803 "/.SUNWnative/usr/lib/locale");
1646 1804 else if (access("/native/usr/lib/locale", R_OK) == 0)
1647 1805 (void) bindtextdomain(TEXT_DOMAIN,
1648 1806 "/native/usr/lib/locale");
1649 1807
1650 1808 if (!failsafe)
1651 1809 new_env = prep_env_noninteractive(user_cmd, new_env);
1652 1810
1653 1811 if (new_env == NULL) {
1654 1812 _exit(1);
1655 1813 }
1656 1814
1657 1815 /*
1658 1816 * Move into a new process group; the zone_enter will have
1659 1817 * placed us into zsched's session, and we want to be in
1660 1818 * a unique process group.
1661 1819 */
1662 1820 (void) setpgid(getpid(), getpid());
1663 1821
1664 1822 /*
1665 1823 * The child needs to run as root to
1666 1824 * execute the su program.
1667 1825 */
1668 1826 if (setuid(0) == -1) {
1669 1827 zperror(gettext("insufficient privilege"));
1670 1828 return (1);
1671 1829 }
1672 1830
1673 1831 (void) execve(new_args[0], new_args, new_env);
1674 1832 zperror(gettext("exec failure"));
1675 1833 _exit(1);
1676 1834 }
1677 1835 /* parent */
1678 1836
1679 1837 /* close pipe sides written by child */
1680 1838 (void) close(stdout_pipe[1]);
1681 1839 (void) close(stderr_pipe[1]);
1682 1840
1683 1841 (void) sigset(SIGINT, sig_forward);
1684 1842
1685 1843 postfork_dropprivs();
1686 1844
1687 1845 (void) ct_tmpl_clear(tmpl_fd);
1688 1846 (void) close(tmpl_fd);
1689 1847
1690 1848 (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL);
1691 1849 doio(stdin_pipe[0], stdin_pipe[1], stdout_pipe[0], stderr_pipe[0],
1692 1850 dead_child_pipe[1], B_TRUE);
1693 1851 do {
1694 1852 retval = waitpid(child_pid, &child_status, 0);
1695 1853 if (retval == -1) {
1696 1854 child_status = 0;
1697 1855 }
1698 1856 } while (retval != child_pid && errno != ECHILD);
1699 1857
1700 1858 return (WEXITSTATUS(child_status));
1701 1859 }
1702 1860
1703 1861 static char *
1704 1862 get_username()
1705 1863 {
1706 1864 uid_t uid;
1707 1865 struct passwd *nptr;
1708 1866
1709 1867 /*
1710 1868 * Authorizations are checked to restrict access based on the
1711 1869 * requested operation and zone name, It is assumed that the
1712 1870 * program is running with all privileges, but that the real
1713 1871 * user ID is that of the user or role on whose behalf we are
1714 1872 * operating. So we start by getting the username that will be
1715 1873 * used for subsequent authorization checks.
|
↓ open down ↓ |
501 lines elided |
↑ open up ↑ |
1716 1874 */
1717 1875
1718 1876 uid = getuid();
1719 1877 if ((nptr = getpwuid(uid)) == NULL) {
1720 1878 zerror(gettext("could not get user name."));
1721 1879 _exit(1);
1722 1880 }
1723 1881 return (nptr->pw_name);
1724 1882 }
1725 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 +
1726 1919 int
1727 1920 main(int argc, char **argv)
1728 1921 {
1729 - int arg, console = 0;
1922 + int arg, console = 0, imode = 0;
1923 + int estatus = 0;
1730 1924 zoneid_t zoneid;
1731 1925 zone_state_t st;
1732 1926 char *login = "root";
1927 + int iflag = 0;
1733 1928 int lflag = 0;
1734 1929 int nflag = 0;
1735 1930 char *zonename = NULL;
1736 1931 char **proc_args = NULL;
1737 1932 char **new_args, **new_env;
1738 1933 sigset_t block_cld;
1934 + siginfo_t si;
1739 1935 char devroot[MAXPATHLEN];
1740 1936 char *slavename, slaveshortname[MAXPATHLEN];
1741 1937 priv_set_t *privset;
1742 1938 int tmpl_fd;
1743 - char zonebrand[MAXNAMELEN];
1744 1939 char default_brand[MAXNAMELEN];
1745 1940 struct stat sb;
1746 1941 char kernzone[ZONENAME_MAX];
1747 1942 brand_handle_t bh;
1748 1943 char user_cmd[MAXPATHLEN];
1749 1944 char authname[MAXAUTHS];
1750 1945
1751 1946 (void) setlocale(LC_ALL, "");
1752 1947 (void) textdomain(TEXT_DOMAIN);
1753 1948
1754 1949 (void) getpname(argv[0]);
1755 1950 username = get_username();
1756 1951
1757 - while ((arg = getopt(argc, argv, "dnECR:Se:l:Q")) != EOF) {
1952 + while ((arg = getopt(argc, argv, "diNnECIR:Se:l:Q")) != EOF) {
1758 1953 switch (arg) {
1759 1954 case 'C':
1760 1955 console = 1;
1761 1956 break;
1762 1957 case 'E':
1763 1958 nocmdchar = 1;
1764 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;
1765 1970 case 'R': /* undocumented */
1766 1971 if (*optarg != '/') {
1767 1972 zerror(gettext("root path must be absolute."));
1768 1973 exit(2);
1769 1974 }
1770 1975 if (stat(optarg, &sb) == -1 || !S_ISDIR(sb.st_mode)) {
1771 1976 zerror(
1772 1977 gettext("root path must be a directory."));
1773 1978 exit(2);
1774 1979 }
1775 1980 zonecfg_set_root(optarg);
1776 1981 break;
1777 1982 case 'Q':
1778 1983 quiet = 1;
1779 1984 break;
1780 1985 case 'S':
1781 1986 failsafe = 1;
1782 1987 break;
1783 1988 case 'd':
1784 - disconnect = 1;
1989 + connect_flags |= ZLOGIN_DISCONNECT;
1785 1990 break;
1786 1991 case 'e':
1787 1992 set_cmdchar(optarg);
1788 1993 break;
1994 + case 'i':
1995 + iflag = 1;
1996 + break;
1789 1997 case 'l':
1790 1998 login = optarg;
1791 1999 lflag = 1;
1792 2000 break;
2001 + case 'N':
2002 + /* NOHUP - do not send EOF */
2003 + connect_flags ^= ZLOGIN_ZFD_EOF;
2004 + break;
1793 2005 case 'n':
1794 2006 nflag = 1;
1795 2007 break;
1796 2008 default:
1797 2009 usage();
1798 2010 }
1799 2011 }
1800 2012
1801 2013 if (console != 0) {
1802 2014
2015 + /*
2016 + * The only connect option in console mode is ZLOGIN_DISCONNECT
2017 + */
2018 + if (imode == 0)
2019 + connect_flags &= ZLOGIN_DISCONNECT;
2020 +
1803 2021 if (lflag != 0) {
1804 2022 zerror(gettext(
1805 2023 "-l may not be specified for console login"));
1806 2024 usage();
1807 2025 }
1808 2026
1809 2027 if (nflag != 0) {
1810 2028 zerror(gettext(
1811 2029 "-n may not be specified for console login"));
1812 2030 usage();
1813 2031 }
1814 2032
1815 2033 if (failsafe != 0) {
1816 2034 zerror(gettext(
1817 2035 "-S may not be specified for console login"));
1818 2036 usage();
|
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
1819 2037 }
1820 2038
1821 2039 if (zonecfg_in_alt_root()) {
1822 2040 zerror(gettext(
1823 2041 "-R may not be specified for console login"));
1824 2042 exit(2);
1825 2043 }
1826 2044
1827 2045 }
1828 2046
2047 + if (iflag != 0 && nflag != 0) {
2048 + zerror(gettext("-i and -n flags are incompatible"));
2049 + usage();
2050 + }
2051 +
1829 2052 if (failsafe != 0 && lflag != 0) {
1830 2053 zerror(gettext("-l may not be specified for failsafe login"));
1831 2054 usage();
1832 2055 }
1833 2056
1834 - if (!console && disconnect != 0) {
2057 + if (!console && (connect_flags & ZLOGIN_DISCONNECT) != 0) {
1835 2058 zerror(gettext(
1836 2059 "-d may only be specified with console login"));
1837 2060 usage();
1838 2061 }
1839 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 +
1840 2068 if (optind == (argc - 1)) {
1841 2069 /*
1842 2070 * zone name, no process name; this should be an interactive
1843 2071 * as long as STDIN is really a tty.
1844 2072 */
1845 2073 if (nflag != 0) {
1846 2074 zerror(gettext(
1847 2075 "-n may not be specified for interactive login"));
1848 2076 usage();
1849 2077 }
1850 2078 if (isatty(STDIN_FILENO))
1851 2079 interactive = 1;
|
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
1852 2080 zonename = argv[optind];
1853 2081 } else if (optind < (argc - 1)) {
1854 2082 if (console) {
1855 2083 zerror(gettext("Commands may not be specified for "
1856 2084 "console login."));
1857 2085 usage();
1858 2086 }
1859 2087 /* zone name and process name, and possibly some args */
1860 2088 zonename = argv[optind];
1861 2089 proc_args = &argv[optind + 1];
1862 - interactive = 0;
2090 + if (iflag && isatty(STDIN_FILENO))
2091 + interactive = 1;
1863 2092 } else {
1864 2093 usage();
1865 2094 }
1866 2095
1867 2096 if (getzoneid() != GLOBAL_ZONEID) {
1868 2097 zerror(gettext("'%s' may only be used from the global zone"),
1869 2098 pname);
1870 2099 return (1);
1871 2100 }
1872 2101
1873 2102 if (strcmp(zonename, GLOBAL_ZONENAME) == 0) {
1874 2103 zerror(gettext("'%s' not applicable to the global zone"),
1875 2104 pname);
1876 2105 return (1);
1877 2106 }
1878 2107
1879 2108 if (zone_get_state(zonename, &st) != Z_OK) {
1880 2109 zerror(gettext("zone '%s' unknown"), zonename);
1881 2110 return (1);
1882 2111 }
1883 2112
1884 2113 if (st < ZONE_STATE_INSTALLED) {
1885 2114 zerror(gettext("cannot login to a zone which is '%s'"),
1886 2115 zone_state_str(st));
1887 2116 return (1);
1888 2117 }
1889 2118
1890 2119 /*
1891 2120 * In both console and non-console cases, we require all privs.
1892 2121 * In the console case, because we may need to startup zoneadmd.
1893 2122 * In the non-console case in order to do zone_enter(2), zonept()
1894 2123 * and other tasks.
1895 2124 */
1896 2125
1897 2126 if ((privset = priv_allocset()) == NULL) {
1898 2127 zperror(gettext("priv_allocset failed"));
1899 2128 return (1);
1900 2129 }
1901 2130
1902 2131 if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1903 2132 zperror(gettext("getppriv failed"));
1904 2133 priv_freeset(privset);
1905 2134 return (1);
1906 2135 }
1907 2136
1908 2137 if (priv_isfullset(privset) == B_FALSE) {
1909 2138 zerror(gettext("You lack sufficient privilege to run "
1910 2139 "this command (all privs required)"));
1911 2140 priv_freeset(privset);
1912 2141 return (1);
1913 2142 }
1914 2143 priv_freeset(privset);
1915 2144
1916 2145 /*
1917 2146 * Check if user is authorized for requested usage of the zone
1918 2147 */
1919 2148
1920 2149 (void) snprintf(authname, MAXAUTHS, "%s%s%s",
1921 2150 ZONE_MANAGE_AUTH, KV_OBJECT, zonename);
1922 2151 if (chkauthattr(authname, username) == 0) {
1923 2152 if (console) {
1924 2153 zerror(gettext("%s is not authorized for console "
1925 2154 "access to %s zone."),
1926 2155 username, zonename);
1927 2156 return (1);
1928 2157 } else {
1929 2158 (void) snprintf(authname, MAXAUTHS, "%s%s%s",
1930 2159 ZONE_LOGIN_AUTH, KV_OBJECT, zonename);
1931 2160 if (failsafe || !interactive) {
1932 2161 zerror(gettext("%s is not authorized for "
1933 2162 "failsafe or non-interactive login "
1934 2163 "to %s zone."), username, zonename);
1935 2164 return (1);
1936 2165 } else if (chkauthattr(authname, username) == 0) {
1937 2166 zerror(gettext("%s is not authorized "
|
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
1938 2167 " to login to %s zone."),
1939 2168 username, zonename);
1940 2169 return (1);
1941 2170 }
1942 2171 }
1943 2172 } else {
1944 2173 forced_login = B_TRUE;
1945 2174 }
1946 2175
1947 2176 /*
1948 - * The console is a separate case from the rest of the code; handle
1949 - * it first.
2177 + * The console (or standalong interactive mode) is a separate case from
2178 + * the rest of the code; handle it first.
1950 2179 */
1951 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 +
1952 2202 /*
1953 2203 * Ensure that zoneadmd for this zone is running.
1954 2204 */
1955 2205 if (start_zoneadmd(zonename) == -1)
1956 2206 return (1);
1957 2207
1958 2208 /*
1959 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.
1960 2214 */
1961 - if (get_console_master(zonename) == -1)
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);
1962 2226 return (1);
2227 + }
1963 2228
1964 - if (!quiet)
1965 - (void) printf(
1966 - gettext("[Connected to zone '%s' console]\n"),
1967 - zonename);
2229 + if (handshake_zone_sock(masterfd, connect_flags) != 0) {
2230 + (void) close(masterfd);
2231 + return (1);
2232 + }
1968 2233
1969 - if (set_tty_rawmode(STDIN_FILENO) == -1) {
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) {
1970 2260 reset_tty();
1971 2261 zperror(gettext("failed to set stdin pty to raw mode"));
1972 2262 return (1);
1973 2263 }
1974 2264
1975 2265 (void) sigset(SIGWINCH, sigwinch);
1976 2266 (void) sigwinch(0);
1977 2267
2268 + if (imode) {
2269 + /* Allow EOF mode toggling via SIGUSR1 */
2270 + (void) sigset(SIGUSR1, sigusr1);
2271 + }
2272 +
1978 2273 /*
1979 2274 * Run the I/O loop until we get disconnected.
1980 2275 */
1981 - doio(masterfd, -1, masterfd, -1, -1, B_FALSE);
2276 + doio(masterfd, -1, masterfd, gz_stderr_fd, -1, B_FALSE);
1982 2277 reset_tty();
1983 - if (!quiet)
1984 - (void) printf(
1985 - gettext("\n[Connection to zone '%s' console "
1986 - "closed]\n"), zonename);
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 + }
1987 2287
1988 2288 return (0);
1989 2289 }
1990 2290
1991 2291 if (st != ZONE_STATE_RUNNING && st != ZONE_STATE_MOUNTED) {
1992 2292 zerror(gettext("login allowed only to running zones "
1993 2293 "(%s is '%s')."), zonename, zone_state_str(st));
1994 2294 return (1);
1995 2295 }
1996 2296
1997 2297 (void) strlcpy(kernzone, zonename, sizeof (kernzone));
1998 2298 if (zonecfg_in_alt_root()) {
1999 2299 FILE *fp = zonecfg_open_scratch("", B_FALSE);
2000 2300
2001 2301 if (fp == NULL || zonecfg_find_scratch(fp, zonename,
2002 2302 zonecfg_get_root(), kernzone, sizeof (kernzone)) == -1) {
2003 2303 zerror(gettext("cannot find scratch zone %s"),
2004 2304 zonename);
2005 2305 if (fp != NULL)
2006 2306 zonecfg_close_scratch(fp);
2007 2307 return (1);
2008 2308 }
2009 2309 zonecfg_close_scratch(fp);
2010 2310 }
2011 2311
2012 2312 if ((zoneid = getzoneidbyname(kernzone)) == -1) {
2013 2313 zerror(gettext("failed to get zoneid for zone '%s'"),
2014 2314 zonename);
2015 2315 return (1);
2016 2316 }
2017 2317
2018 2318 /*
2019 2319 * We need the zone root path only if we are setting up a pty.
2020 2320 */
2021 2321 if (zone_get_devroot(zonename, devroot, sizeof (devroot)) == -1) {
2022 2322 zerror(gettext("could not get dev path for zone %s"),
2023 2323 zonename);
2024 2324 return (1);
2025 2325 }
2026 2326
2027 2327 if (zone_get_brand(zonename, zonebrand, sizeof (zonebrand)) != Z_OK) {
2028 2328 zerror(gettext("could not get brand for zone %s"), zonename);
2029 2329 return (1);
2030 2330 }
2031 2331 /*
2032 2332 * In the alternate root environment, the only supported
2033 2333 * operations are mount and unmount. In this case, just treat
2034 2334 * the zone as native if it is cluster. Cluster zones can be
2035 2335 * native for the purpose of LU or upgrade, and the cluster
2036 2336 * brand may not exist in the miniroot (such as in net install
2037 2337 * upgrade).
2038 2338 */
2039 2339 if (zonecfg_default_brand(default_brand,
2040 2340 sizeof (default_brand)) != Z_OK) {
2041 2341 zerror(gettext("unable to determine default brand"));
2042 2342 return (1);
2043 2343 }
|
↓ open down ↓ |
47 lines elided |
↑ open up ↑ |
2044 2344 if (zonecfg_in_alt_root() &&
2045 2345 strcmp(zonebrand, CLUSTER_BRAND_NAME) == 0) {
2046 2346 (void) strlcpy(zonebrand, default_brand, sizeof (zonebrand));
2047 2347 }
2048 2348
2049 2349 if ((bh = brand_open(zonebrand)) == NULL) {
2050 2350 zerror(gettext("could not open brand for zone %s"), zonename);
2051 2351 return (1);
2052 2352 }
2053 2353
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);
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 + }
2058 2369 }
2370 +
2059 2371 /*
2060 2372 * Get the brand specific user_cmd. This command is used to get
2061 2373 * a passwd(4) entry for login.
2062 2374 */
2063 2375 if (!interactive && !failsafe) {
2064 2376 if (zone_get_user_cmd(bh, login, user_cmd,
2065 2377 sizeof (user_cmd)) == NULL) {
2066 2378 zerror(gettext("could not get user_cmd for zone %s"),
2067 2379 zonename);
2068 2380 brand_close(bh);
2069 2381 return (1);
2070 2382 }
2071 2383 }
2072 2384 brand_close(bh);
2073 2385
2074 2386 if ((new_env = prep_env()) == NULL) {
2075 2387 zperror(gettext("could not assemble new environment"));
2076 2388 return (1);
2077 2389 }
2078 2390
2079 2391 if (!interactive) {
2080 2392 if (nflag) {
2081 2393 int nfd;
2082 2394
2083 2395 if ((nfd = open(_PATH_DEVNULL, O_RDONLY)) < 0) {
2084 2396 zperror(gettext("failed to open null device"));
2085 2397 return (1);
2086 2398 }
2087 2399 if (nfd != STDIN_FILENO) {
2088 2400 if (dup2(nfd, STDIN_FILENO) < 0) {
2089 2401 zperror(gettext(
2090 2402 "failed to dup2 null device"));
2091 2403 return (1);
2092 2404 }
2093 2405 (void) close(nfd);
2094 2406 }
2095 2407 /* /dev/null is now standard input */
2096 2408 }
2097 2409 return (noninteractive_login(zonename, user_cmd, zoneid,
2098 2410 new_args, new_env));
2099 2411 }
2100 2412
2101 2413 if (zonecfg_in_alt_root()) {
2102 2414 zerror(gettext("cannot use interactive login with scratch "
2103 2415 "zone"));
2104 2416 return (1);
2105 2417 }
2106 2418
2107 2419 /*
2108 2420 * Things are more complex in interactive mode; we get the
2109 2421 * master side of the pty, then place the user's terminal into
2110 2422 * raw mode.
2111 2423 */
2112 2424 if (get_master_pty() == -1) {
2113 2425 zerror(gettext("could not setup master pty device"));
2114 2426 return (1);
2115 2427 }
2116 2428
2117 2429 /*
2118 2430 * Compute the "short name" of the pts. /dev/pts/2 --> pts/2
2119 2431 */
2120 2432 if ((slavename = ptsname(masterfd)) == NULL) {
2121 2433 zperror(gettext("failed to get name for pseudo-tty"));
2122 2434 return (1);
2123 2435 }
2124 2436 if (strncmp(slavename, "/dev/", strlen("/dev/")) == 0)
2125 2437 (void) strlcpy(slaveshortname, slavename + strlen("/dev/"),
2126 2438 sizeof (slaveshortname));
2127 2439 else
2128 2440 (void) strlcpy(slaveshortname, slavename,
2129 2441 sizeof (slaveshortname));
2130 2442
2131 2443 if (!quiet)
2132 2444 (void) printf(gettext("[Connected to zone '%s' %s]\n"),
2133 2445 zonename, slaveshortname);
2134 2446
2135 2447 if (set_tty_rawmode(STDIN_FILENO) == -1) {
2136 2448 reset_tty();
2137 2449 zperror(gettext("failed to set stdin pty to raw mode"));
2138 2450 return (1);
2139 2451 }
2140 2452
2141 2453 if (prefork_dropprivs() != 0) {
2142 2454 reset_tty();
2143 2455 zperror(gettext("could not allocate privilege set"));
2144 2456 return (1);
2145 2457 }
2146 2458
2147 2459 /*
2148 2460 * We must mask SIGCLD until after we have coped with the fork
2149 2461 * sufficiently to deal with it; otherwise we can race and receive the
2150 2462 * signal before child_pid has been initialized (yes, this really
2151 2463 * happens).
2152 2464 */
2153 2465 (void) sigset(SIGCLD, sigcld);
2154 2466 (void) sigemptyset(&block_cld);
2155 2467 (void) sigaddset(&block_cld, SIGCLD);
2156 2468 (void) sigprocmask(SIG_BLOCK, &block_cld, NULL);
2157 2469
2158 2470 /*
2159 2471 * We activate the contract template at the last minute to
2160 2472 * avoid intermediate functions that could be using fork(2)
2161 2473 * internally.
2162 2474 */
2163 2475 if ((tmpl_fd = init_template()) == -1) {
2164 2476 reset_tty();
2165 2477 zperror(gettext("could not create contract"));
2166 2478 return (1);
2167 2479 }
2168 2480
2169 2481 if ((child_pid = fork()) == -1) {
2170 2482 (void) ct_tmpl_clear(tmpl_fd);
2171 2483 reset_tty();
2172 2484 zperror(gettext("could not fork"));
2173 2485 return (1);
2174 2486 } else if (child_pid == 0) { /* child process */
2175 2487 int slavefd, newslave;
2176 2488
2177 2489 (void) ct_tmpl_clear(tmpl_fd);
2178 2490 (void) close(tmpl_fd);
2179 2491
2180 2492 (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL);
2181 2493
2182 2494 if ((slavefd = init_slave_pty(zoneid, devroot)) == -1)
2183 2495 return (1);
2184 2496
2185 2497 /*
2186 2498 * Close all fds except for the slave pty.
2187 2499 */
2188 2500 (void) fdwalk(close_func, &slavefd);
2189 2501
2190 2502 /*
2191 2503 * Temporarily dup slavefd to stderr; that way if we have
2192 2504 * to print out that zone_enter failed, the output will
2193 2505 * have somewhere to go.
|
↓ open down ↓ |
125 lines elided |
↑ open up ↑ |
2194 2506 */
2195 2507 if (slavefd != STDERR_FILENO)
2196 2508 (void) dup2(slavefd, STDERR_FILENO);
2197 2509
2198 2510 if (zone_enter(zoneid) == -1) {
2199 2511 zerror(gettext("could not enter zone %s: %s"),
2200 2512 zonename, strerror(errno));
2201 2513 return (1);
2202 2514 }
2203 2515
2516 + /* Note: we're now inside the zone, can't use gettext anymore */
2517 +
2204 2518 if (slavefd != STDERR_FILENO)
2205 2519 (void) close(STDERR_FILENO);
2206 2520
2207 2521 /*
2208 2522 * We take pains to get this process into a new process
2209 2523 * group, and subsequently a new session. In this way,
2210 2524 * we'll have a session which doesn't yet have a controlling
2211 2525 * terminal. When we open the slave, it will become the
2212 2526 * controlling terminal; no PIDs concerning pgrps or sids
2213 2527 * will leak inappropriately into the zone.
2214 2528 */
2215 2529 (void) setpgrp();
2216 2530
2217 2531 /*
2218 2532 * We need the slave pty to be referenced from the zone's
2219 2533 * /dev in order to ensure that the devt's, etc are all
2220 2534 * correct. Otherwise we break ttyname and the like.
2221 2535 */
2222 2536 if ((newslave = open(slavename, O_RDWR)) == -1) {
2223 2537 (void) close(slavefd);
2224 2538 return (1);
2225 2539 }
2226 2540 (void) close(slavefd);
2227 2541 slavefd = newslave;
2228 2542
2229 2543 /*
2230 2544 * dup the slave to the various FDs, so that when the
2231 2545 * spawned process does a write/read it maps to the slave
2232 2546 * pty.
2233 2547 */
2234 2548 (void) dup2(slavefd, STDIN_FILENO);
|
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
2235 2549 (void) dup2(slavefd, STDOUT_FILENO);
2236 2550 (void) dup2(slavefd, STDERR_FILENO);
2237 2551 if (slavefd != STDIN_FILENO && slavefd != STDOUT_FILENO &&
2238 2552 slavefd != STDERR_FILENO) {
2239 2553 (void) close(slavefd);
2240 2554 }
2241 2555
2242 2556 /*
2243 2557 * In failsafe mode, we don't use login(1), so don't try
2244 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.
2245 2569 */
2246 - if (!failsafe)
2570 + if (!failsafe && (strcmp(zonebrand, "lx") != 0))
2247 2571 if (setup_utmpx(slaveshortname) == -1)
2248 2572 return (1);
2249 2573
2250 2574 /*
2251 2575 * The child needs to run as root to
2252 2576 * execute the brand's login program.
2253 2577 */
2254 2578 if (setuid(0) == -1) {
2255 - zperror(gettext("insufficient privilege"));
2579 + zperror("insufficient privilege");
2256 2580 return (1);
2257 2581 }
2258 2582
2259 - (void) execve(new_args[0], new_args, new_env);
2260 - zperror(gettext("exec failure"));
2261 - return (1);
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);
2262 2590 }
2263 2591
2264 2592 (void) ct_tmpl_clear(tmpl_fd);
2265 2593 (void) close(tmpl_fd);
2266 2594
2267 2595 /*
2268 2596 * The rest is only for the parent process.
2269 2597 */
2270 2598 (void) sigset(SIGWINCH, sigwinch);
2271 2599
2272 2600 postfork_dropprivs();
2273 2601
2274 2602 (void) sigprocmask(SIG_UNBLOCK, &block_cld, NULL);
2275 2603 doio(masterfd, -1, masterfd, -1, -1, B_FALSE);
|
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
2276 2604
2277 2605 reset_tty();
2278 2606 if (!quiet)
2279 2607 (void) fprintf(stderr,
2280 2608 gettext("\n[Connection to zone '%s' %s closed]\n"),
2281 2609 zonename, slaveshortname);
2282 2610
2283 2611 if (pollerr != 0) {
2284 2612 (void) fprintf(stderr, gettext("Error: connection closed due "
2285 2613 "to unexpected pollevents=0x%x.\n"), pollerr);
2286 - return (1);
2614 + return (EPIPE);
2287 2615 }
2288 2616
2289 - return (0);
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);
2290 2629 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX