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