xref: /titanic_51/usr/src/cmd/zoneadmd/zcons.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Console support for zones requires a significant infrastructure.  The
31  * core pieces are contained in this file, but other portions of note
32  * are in the zlogin(1M) command, the zcons(7D) driver, and in the
33  * devfsadm(1M) misc_link generator.
34  *
35  * Care is taken to make the console behave in an "intuitive" fashion for
36  * administrators.  Essentially, we try as much as possible to mimic the
37  * experience of using a system via a tip line and system controller.
38  *
39  * The zone console architecture looks like this:
40  *
41  *                                      Global Zone | Non-Global Zone
42  *                        .--------------.          |
43  *        .-----------.   | zoneadmd -z  |          | .--------. .---------.
44  *        | zlogin -C |   |     myzone   |          | | ttymon | | syslogd |
45  *        `-----------'   `--------------'          | `--------' `---------'
46  *                  |       |       | |             |      |       |
47  *  User            |       |       | |             |      V       V
48  * - - - - - - - - -|- - - -|- - - -|-|- - - - - - -|- - /dev/zconsole - - -
49  *  Kernel          V       V       | |                        |
50  *               [AF_UNIX Socket]   | `--------. .-------------'
51  *                                  |          | |
52  *                                  |          V V
53  *                                  |     +-----------+
54  *                                  |     |  ldterm,  |
55  *                                  |     |   etc.    |
56  *                                  |     +-----------+
57  *                                  |     +-[Anchor]--+
58  *                                  |     |   ptem    |
59  *                                  V     +-----------+
60  *                           +---master---+---slave---+
61  *                           |                        |
62  *                           |      zcons driver      |
63  *                           |    zonename="myzone"   |
64  *                           +------------------------+
65  *
66  * There are basically three major tasks which the console subsystem in
67  * zoneadmd accomplishes:
68  *
69  * - Setup and teardown of zcons driver instances.  One zcons instance
70  *   is maintained per zone; we take advantage of the libdevice APIs
71  *   to online new instances of zcons as needed.  Care is taken to
72  *   prune and manage these appropriately; see init_console_dev() and
73  *   destroy_console_dev().  The end result is the creation of the
74  *   zcons(7D) instance and an open file descriptor to the master side.
75  *   zcons instances are associated with zones via their zonename device
76  *   property.  This the console instance to persist across reboots,
77  *   and while the zone is halted.
78  *
79  * - Initialization of the slave side of the console.  This is
80  *   accomplished by pushing various STREAMS modules onto the console.
81  *   The ptem(7M) module gets special treatment, and is anchored into
82  *   place using the I_ANCHOR facility.  This is so that the zcons driver
83  *   always has terminal semantics, as would a real hardware terminal.
84  *   This means that ttymon(1M) works unmodified;  at boot time, ttymon
85  *   will do its own plumbing of the console stream, and will even
86  *   I_POP modules off.  Hence the anchor, which assures that ptem will
87  *   never be I_POP'd.
88  *
89  * - Acting as a server for 'zlogin -C' instances.  When zlogin -C is
90  *   run, zlogin connects to zoneadmd via unix domain socket.  zoneadmd
91  *   functions as a two-way proxy for console I/O, relaying user input
92  *   to the master side of the console, and relaying output from the
93  *   zone to the user.
94  */
95 
96 #include <sys/types.h>
97 #include <sys/socket.h>
98 #include <sys/stat.h>
99 #include <sys/termios.h>
100 #include <sys/zcons.h>
101 
102 #include <assert.h>
103 #include <ctype.h>
104 #include <errno.h>
105 #include <fcntl.h>
106 #include <stdarg.h>
107 #include <stdio.h>
108 #include <stdlib.h>
109 #include <strings.h>
110 #include <stropts.h>
111 #include <thread.h>
112 #include <ucred.h>
113 #include <unistd.h>
114 #include <zone.h>
115 
116 #include <libdevinfo.h>
117 #include <libdevice.h>
118 #include <libzonecfg.h>
119 
120 #include <syslog.h>
121 
122 #include "zoneadmd.h"
123 
124 #define	ZCONSNEX_DEVTREEPATH	"/pseudo/zconsnex@1"
125 #define	ZCONSNEX_FILEPATH	"/devices/pseudo/zconsnex@1"
126 
127 #define	CONSOLE_SOCKPATH	ZONES_TMPDIR "/%s.console_sock"
128 
129 static int	slavefd = -1;	/* slave side of console */
130 static int	serverfd = -1;	/* console server unix domain socket fd */
131 
132 static struct termios base_termios = {	/* from init.c */
133 	BRKINT|ICRNL|IXON|IMAXBEL,			/* iflag */
134 	OPOST|ONLCR|TAB3,				/* oflag */
135 	CS8|CREAD|B9600,				/* cflag */
136 	ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN,	/* lflag */
137 	CINTR, CQUIT, CERASE, CKILL, CEOF, 0, 0, 0,
138 	0, 0, 0, 0, 0, 0, 0, 0,
139 	0, 0, 0
140 };
141 
142 /*
143  * The eventstream is a simple one-directional flow of messages from the
144  * door server to the console subsystem, implemented with a pipe.
145  * It is used to wake up the console poller when it needs to take action,
146  * message the user, die off, etc.
147  */
148 static int eventstream[2];
149 
150 int
151 eventstream_init()
152 {
153 	if (pipe(eventstream) == -1)
154 		return (-1);
155 	return (0);
156 }
157 
158 void
159 eventstream_write(zone_evt_t evt)
160 {
161 	(void) write(eventstream[0], &evt, sizeof (evt));
162 }
163 
164 static zone_evt_t
165 eventstream_read(void)
166 {
167 	zone_evt_t evt = Z_EVT_NULL;
168 
169 	(void) read(eventstream[1], &evt, sizeof (evt));
170 	return (evt);
171 }
172 
173 /*
174  * count_console_devs() and its helper count_cb() do a walk of the
175  * subtree of the device tree where zone console nodes are represented.
176  * The goal is to count zone console instances already setup for a zone
177  * with the given name.  More than 1 is anomolous, and our caller will
178  * have to deal with that if we find that's the case.
179  *
180  * Note: this algorithm is a linear search of nodes in the zconsnex subtree
181  * of the device tree, and could be a scalability problem, but I don't see
182  * how to avoid it.
183  */
184 
185 /*
186  * cb_data is shared by count_cb and destroy_cb for simplicity.
187  */
188 struct cb_data {
189 	zlog_t *zlogp;
190 	int found;
191 	int killed;
192 };
193 
194 static int
195 count_cb(di_node_t node, void *arg)
196 {
197 	struct cb_data *cb = (struct cb_data *)arg;
198 	char *prop_data;
199 
200 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zonename",
201 	    &prop_data) != -1) {
202 		assert(prop_data != NULL);
203 		if (strcmp(prop_data, zone_name) == 0) {
204 			cb->found++;
205 			return (DI_WALK_CONTINUE);
206 		}
207 	}
208 	return (DI_WALK_CONTINUE);
209 }
210 
211 static int
212 count_console_devs(zlog_t *zlogp)
213 {
214 	di_node_t root;
215 	struct cb_data cb;
216 
217 	bzero(&cb, sizeof (cb));
218 	cb.zlogp = zlogp;
219 
220 	if ((root = di_init(ZCONSNEX_DEVTREEPATH, DINFOCPYALL)) ==
221 	    DI_NODE_NIL) {
222 		zerror(zlogp, B_TRUE, "%s failed", "di_init");
223 		return (-1);
224 	}
225 
226 	(void) di_walk_node(root, DI_WALK_CLDFIRST, (void *)&cb, count_cb);
227 	di_fini(root);
228 	return (cb.found);
229 }
230 
231 /*
232  * destroy_console_devs() and its helper destroy_cb() tears down any console
233  * instances associated with this zone.  If things went very wrong, we
234  * might have more than one console instance hanging around.  This routine
235  * hunts down and tries to remove all of them.  Of course, if the console
236  * is open, the instance will not detach, which is a potential issue.
237  */
238 static int
239 destroy_cb(di_node_t node, void *arg)
240 {
241 	struct cb_data *cb = (struct cb_data *)arg;
242 	char *prop_data;
243 	char *tmp;
244 	char devpath[MAXPATHLEN];
245 	devctl_hdl_t hdl;
246 
247 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zonename",
248 	    &prop_data) == -1)
249 		return (DI_WALK_CONTINUE);
250 
251 	assert(prop_data != NULL);
252 	if (strcmp(prop_data, zone_name) != 0) {
253 		/* this is the console for a different zone */
254 		return (DI_WALK_CONTINUE);
255 	}
256 
257 	cb->found++;
258 	tmp = di_devfs_path(node);
259 	(void) snprintf(devpath, sizeof (devpath), "/devices/%s", tmp);
260 	di_devfs_path_free(tmp);
261 
262 	if ((hdl = devctl_device_acquire(devpath, 0)) == NULL) {
263 		zerror(cb->zlogp, B_TRUE, "WARNING: console %s found, "
264 		    "but it could not be controlled.", devpath);
265 		return (DI_WALK_CONTINUE);
266 	}
267 	if (devctl_device_remove(hdl) == 0) {
268 		cb->killed++;
269 	} else {
270 		zerror(cb->zlogp, B_TRUE, "WARNING: console %s found, "
271 		    "but it could not be removed.", devpath);
272 	}
273 	devctl_release(hdl);
274 	return (DI_WALK_CONTINUE);
275 }
276 
277 static int
278 destroy_console_devs(zlog_t *zlogp)
279 {
280 	di_node_t root;
281 	struct cb_data cb;
282 
283 	bzero(&cb, sizeof (cb));
284 	cb.zlogp = zlogp;
285 
286 	if ((root = di_init(ZCONSNEX_DEVTREEPATH, DINFOCPYALL)) ==
287 	    DI_NODE_NIL) {
288 		zerror(zlogp, B_TRUE, "%s failed", "di_init");
289 		return (-1);
290 	}
291 
292 	(void) di_walk_node(root, DI_WALK_CLDFIRST, (void *)&cb, destroy_cb);
293 	if (cb.found > 1) {
294 		zerror(zlogp, B_FALSE, "WARNING: multiple zone console "
295 		    "instances detected for zone '%s'; %d of %d "
296 		    "successfully removed.",
297 		    zone_name, cb.killed, cb.found);
298 	}
299 
300 	di_fini(root);
301 	return (0);
302 }
303 
304 /*
305  * init_console_dev() drives the device-tree configuration of the zone
306  * console device.  The general strategy is to use the libdevice (devctl)
307  * interfaces to instantiate a new zone console node.  We do a lot of
308  * sanity checking, and are careful to reuse a console if one exists.
309  *
310  * Once the device is in the device tree, we kick devfsadm via di_init_devs()
311  * to ensure that the appropriate symlinks (to the master and slave console
312  * devices) are placed in /dev in the global zone.
313  */
314 static int
315 init_console_dev(zlog_t *zlogp)
316 {
317 	devctl_hdl_t bus_hdl = NULL, dev_hdl = NULL;
318 	devctl_ddef_t ddef_hdl = NULL;
319 	di_devlink_handle_t dl = NULL;
320 	int rv = -1, ndevs;
321 
322 	/*
323 	 * Don't re-setup console if it is working and ready already; just
324 	 * skip ahead to making devlinks, which we do for sanity's sake.
325 	 */
326 	ndevs = count_console_devs(zlogp);
327 	if (ndevs == 1) {
328 		goto devlinks;
329 	} else if (ndevs > 1 || ndevs == -1) {
330 		/*
331 		 * For now, this seems like a reasonable but harsh punishment.
332 		 * If needed, we could try to get clever and delete all but
333 		 * the console which is pointed at by the current symlink.
334 		 */
335 		if (destroy_console_devs(zlogp) == -1) {
336 			goto error;
337 		}
338 	}
339 
340 	/*
341 	 * Time to make the consoles!
342 	 */
343 	if ((bus_hdl = devctl_bus_acquire(ZCONSNEX_FILEPATH, 0)) == NULL) {
344 		zerror(zlogp, B_TRUE, "%s failed", "devctl_bus_acquire");
345 		goto error;
346 	}
347 	if ((ddef_hdl = devctl_ddef_alloc("zcons", 0)) == NULL) {
348 		zerror(zlogp, B_TRUE, "failed to allocate ddef handle");
349 		goto error;
350 	}
351 	/*
352 	 * Set three properties on this node; the first is the name of the
353 	 * zone; the second is a flag which lets pseudo know that it is
354 	 * OK to automatically allocate an instance # for this device;
355 	 * the third tells the device framework not to auto-detach this
356 	 * node-- we need the node to still be there when we ask devfsadmd
357 	 * to make links, and when we need to open it.
358 	 */
359 	if (devctl_ddef_string(ddef_hdl, "zonename", zone_name) == -1) {
360 		zerror(zlogp, B_TRUE, "failed to create zonename property");
361 		goto error;
362 	}
363 	if (devctl_ddef_int(ddef_hdl, "auto-assign-instance", 1) == -1) {
364 		zerror(zlogp, B_TRUE, "failed to create auto-assign-instance "
365 		    "property");
366 		goto error;
367 	}
368 	if (devctl_ddef_int(ddef_hdl, "ddi-no-autodetach", 1) == -1) {
369 		zerror(zlogp, B_TRUE, "failed to create ddi-no-auto-detach "
370 		    "property");
371 		goto error;
372 	}
373 	if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl) == -1) {
374 		zerror(zlogp, B_TRUE, "failed to create console node");
375 		goto error;
376 	}
377 
378 devlinks:
379 	if ((dl = di_devlink_init("zcons", DI_MAKE_LINK)) != NULL) {
380 		(void) di_devlink_fini(&dl);
381 	} else {
382 		zerror(zlogp, B_TRUE, "failed to create devlinks");
383 		goto error;
384 	}
385 
386 	rv = 0;
387 error:
388 	if (ddef_hdl)
389 		devctl_ddef_free(ddef_hdl);
390 	if (bus_hdl)
391 		devctl_release(bus_hdl);
392 	if (dev_hdl)
393 		devctl_release(dev_hdl);
394 	return (rv);
395 }
396 
397 /*
398  * prep_console_slave() takes care of setting up the console slave device
399  * (the side that the zone will eventually open). It is a helper for
400  * init_console_slave().
401  *
402  * We have to mknod and setup the console device; then the slave side is
403  * opened, and the appropriate STREAMS modules are pushed on.  A wrinkle is that
404  * 'ptem' must be anchored in place (see streamio(7i) since we always want the
405  * console to have terminal semantics.
406  */
407 static int
408 prep_console_slave(zlog_t *zlogp, char *zonepath)
409 {
410 	char slavename[MAXPATHLEN];
411 	char zoneslavename[MAXPATHLEN];
412 	struct stat st;
413 
414 	assert(slavefd == -1);
415 
416 	(void) snprintf(slavename, sizeof (slavename),
417 	    "/dev/zcons/%s/%s", zone_name, ZCONS_SLAVE_NAME);
418 
419 	(void) snprintf(zoneslavename, sizeof (zoneslavename),
420 	    "%s/dev/zconsole", zonepath);
421 
422 	/*
423 	 * We mknod the zone console in $zonepath/dev/; someday it would
424 	 * be nice to not have to manually mknod this stuff-- if possible,
425 	 * we could move this into devfsadm.
426 	 */
427 	if (stat(slavename, &st) == -1) {
428 		zerror(zlogp, B_TRUE, "failed to stat %s", slavename);
429 		goto error;
430 	}
431 	(void) unlink(zoneslavename);
432 	if (mknod(zoneslavename, st.st_mode, st.st_rdev) == -1) {
433 		zerror(zlogp, B_TRUE, "failed to mknod %s", zoneslavename);
434 		goto error;
435 	}
436 	(void) chown(zoneslavename, st.st_uid, st.st_gid);
437 	if ((slavefd = open(zoneslavename, O_RDWR | O_NOCTTY)) < 0) {
438 		zerror(zlogp, B_TRUE, "failed to open %s", zoneslavename);
439 		return (-1);
440 	}
441 
442 	/*
443 	 * Just to make sure the whole stream is pristine.
444 	 */
445 	(void) ioctl(slavefd, I_FLUSH, FLUSHRW);
446 
447 	/*
448 	 * Push hardware emulation (ptem) module; we would rather not, but
449 	 * are forced to push ldterm and ttcompat here.  Ultimately ttymon
450 	 * will pop them off, so we ANCHOR only ptem.
451 	 *
452 	 * We need to use __I_PUSH_NOCTTY instead of I_PUSH here, otherwise
453 	 * we'll end up having the slave device as *our* controling terminal.
454 	 */
455 	if (ioctl(slavefd, __I_PUSH_NOCTTY, "ptem") == -1) {
456 		zerror(zlogp, B_TRUE, "failed to push ptem module");
457 		goto error;
458 	}
459 
460 	/*
461 	 * Anchor the stream to prevent malicious or accidental I_POP of ptem.
462 	 */
463 	if (ioctl(slavefd, I_ANCHOR) == -1) {
464 		zerror(zlogp, B_TRUE, "failed to set stream anchor");
465 		goto error;
466 	}
467 
468 	if (ioctl(slavefd, __I_PUSH_NOCTTY, "ldterm") == -1) {
469 		zerror(zlogp, B_TRUE, "failed to push ldterm module");
470 		goto error;
471 	}
472 	if (ioctl(slavefd, __I_PUSH_NOCTTY, "ttcompat") == -1) {
473 		zerror(zlogp, B_TRUE, "failed to push ttcompat module");
474 		goto error;
475 	}
476 
477 	/*
478 	 * Setup default terminal settings
479 	 */
480 	if (tcsetattr(slavefd, TCSAFLUSH, &base_termios) == -1) {
481 		zerror(zlogp, B_TRUE, "failed to set base terminal settings");
482 		goto error;
483 	}
484 
485 	return (0);
486 error:
487 	(void) close(slavefd);
488 	slavefd = -1;
489 	return (-1);
490 }
491 
492 /*
493  * init_console_slave() sets up the console slave device; the device node
494  * itself has already been set up in the device tree; the primary job
495  * here is to do some STREAMS plumbing (via prep_console_slave()) and then
496  * to establish some symlinks.  Eventually we should move that functionality
497  * into devfsadm.
498  */
499 int
500 init_console_slave(zlog_t *zlogp)
501 {
502 	char zonepath[MAXPATHLEN];
503 
504 	if (slavefd != -1)
505 		return (0);
506 
507 	if (zone_get_zonepath(zone_name, zonepath, sizeof (zonepath)) != Z_OK) {
508 		zerror(zlogp, B_TRUE, "unable to determine zone root");
509 		return (-1);
510 	}
511 
512 	if (prep_console_slave(zlogp, zonepath) == -1) {
513 		zerror(zlogp, B_FALSE, "could not prep console slave");
514 		return (-1);
515 	}
516 
517 	return (0);
518 }
519 
520 void
521 destroy_console_slave(void)
522 {
523 	(void) close(slavefd);
524 	slavefd = -1;
525 }
526 
527 /*
528  * Restore initial terminal attributes to the zone console.
529  */
530 void
531 reset_slave_terminal(zlog_t *zlogp)
532 {
533 	assert(slavefd != -1);
534 
535 	/* Probably not fatal, so we drive on if it fails */
536 	if (tcsetattr(slavefd, TCSAFLUSH, &base_termios) == -1) {
537 		zerror(zlogp, B_TRUE, "WARNING: failed to set terminal "
538 		    "settings.");
539 	}
540 }
541 
542 static int
543 init_console_sock(zlog_t *zlogp)
544 {
545 	int servfd;
546 	struct sockaddr_un servaddr;
547 
548 	bzero(&servaddr, sizeof (servaddr));
549 	servaddr.sun_family = AF_UNIX;
550 	(void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
551 	    CONSOLE_SOCKPATH, zone_name);
552 
553 	if ((servfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
554 		zerror(zlogp, B_TRUE, "console setup: could not create socket");
555 		return (-1);
556 	}
557 	(void) unlink(servaddr.sun_path);
558 
559 	if (bind(servfd, (struct sockaddr *)&servaddr,
560 	    sizeof (servaddr)) == -1) {
561 		zerror(zlogp, B_TRUE,
562 		    "console setup: could not bind to socket");
563 		goto out;
564 	}
565 
566 	if (listen(servfd, 4) == -1) {
567 		zerror(zlogp, B_TRUE,
568 		    "console setup: could not listen on socket");
569 		goto out;
570 	}
571 	return (servfd);
572 
573 out:
574 	(void) unlink(servaddr.sun_path);
575 	(void) close(servfd);
576 	return (-1);
577 }
578 
579 static void
580 destroy_console_sock(int servfd)
581 {
582 	char path[MAXPATHLEN];
583 
584 	(void) snprintf(path, sizeof (path), CONSOLE_SOCKPATH, zone_name);
585 	(void) unlink(path);
586 	(void) shutdown(servfd, SHUT_RDWR);
587 	(void) close(servfd);
588 }
589 
590 /*
591  * Read the "ident" string from the client's descriptor; this routine also
592  * tolerates being called with pid=NULL, for times when you want to "eat"
593  * the ident string from a client without saving it.
594  */
595 static int
596 get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len)
597 {
598 	char buf[BUFSIZ], *bufp;
599 	size_t buflen = sizeof (buf);
600 	char c = '\0';
601 	int i = 0, r;
602 
603 	/* "eat up the ident string" case, for simplicity */
604 	if (pid == NULL) {
605 		assert(locale == NULL && locale_len == 0);
606 		while (read(clifd, &c, 1) == 1) {
607 			if (c == '\n')
608 				return (0);
609 		}
610 	}
611 
612 	bzero(buf, sizeof (buf));
613 	while ((buflen > 1) && (r = read(clifd, &c, 1)) == 1) {
614 		buflen--;
615 		if (c == '\n')
616 			break;
617 
618 		buf[i] = c;
619 		i++;
620 	}
621 	if (r == -1)
622 		return (-1);
623 
624 	/*
625 	 * We've filled the buffer, but still haven't seen \n.  Keep eating
626 	 * until we find it; we don't expect this to happen, but this is
627 	 * defensive.
628 	 */
629 	if (c != '\n') {
630 		while ((r = read(clifd, &c, sizeof (c))) > 0)
631 			if (c == '\n')
632 				break;
633 	}
634 
635 	/*
636 	 * Parse buffer for message of the form: IDENT <pid> <locale>
637 	 */
638 	bufp = buf;
639 	if (strncmp(bufp, "IDENT ", 6) != 0)
640 		return (-1);
641 	bufp += 6;
642 	errno = 0;
643 	*pid = strtoll(bufp, &bufp, 10);
644 	if (errno != 0)
645 		return (-1);
646 
647 	while (*bufp != '\0' && isspace(*bufp))
648 		bufp++;
649 	(void) strlcpy(locale, bufp, locale_len);
650 
651 	return (0);
652 }
653 
654 static int
655 accept_client(int servfd, pid_t *pid, char *locale, size_t locale_len)
656 {
657 	int connfd;
658 	struct sockaddr_un cliaddr;
659 	socklen_t clilen;
660 
661 	clilen = sizeof (cliaddr);
662 	connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
663 	if (connfd == -1)
664 		return (-1);
665 	if (get_client_ident(connfd, pid, locale, locale_len) == -1) {
666 		(void) shutdown(connfd, SHUT_RDWR);
667 		(void) close(connfd);
668 		return (-1);
669 	}
670 	(void) write(connfd, "OK\n", 3);
671 	return (connfd);
672 }
673 
674 static void
675 reject_client(int servfd, pid_t clientpid)
676 {
677 	int connfd;
678 	struct sockaddr_un cliaddr;
679 	socklen_t clilen;
680 	char nak[MAXPATHLEN];
681 
682 	clilen = sizeof (cliaddr);
683 	connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
684 
685 	/*
686 	 * After hear its ident string, tell client to get lost.
687 	 */
688 	if (get_client_ident(connfd, NULL, NULL, 0) == 0) {
689 		(void) snprintf(nak, sizeof (nak), "%lu\n",
690 		    clientpid);
691 		(void) write(connfd, nak, strlen(nak));
692 	}
693 	(void) shutdown(connfd, SHUT_RDWR);
694 	(void) close(connfd);
695 }
696 
697 static void
698 event_message(int clifd, char *clilocale, zone_evt_t evt)
699 {
700 	char msg[BUFSIZ];
701 	char *str;
702 	const char *fmt;
703 
704 	if (clifd == -1)
705 		return;
706 
707 	switch (evt) {
708 	case Z_EVT_ZONE_BOOTING:
709 		str = "Zone booting up";
710 		break;
711 	case Z_EVT_ZONE_READIED:
712 		str = "Zone readied";
713 		break;
714 	case Z_EVT_ZONE_HALTED:
715 		str = "Zone halted";
716 		break;
717 	case Z_EVT_ZONE_REBOOTING:
718 		str = "Zone rebooting";
719 		break;
720 	case Z_EVT_ZONE_UNINSTALLING:
721 		str = "Zone is being uninstalled.  Disconnecting...";
722 		break;
723 	default:
724 		return;
725 	}
726 	str = localize_msg(clilocale, str);
727 	fmt = localize_msg(clilocale, "\r\n[NOTICE: %s]\r\n");
728 	(void) snprintf(msg, sizeof (msg), fmt, str);
729 	(void) write(clifd, msg, strlen(msg));
730 }
731 
732 /*
733  * Check to see if the client at the other end of the socket is still
734  * alive; we know it is not if it throws EPIPE at us when we try to write
735  * an otherwise harmless 0-length message to it.
736  */
737 static int
738 test_client(int clifd)
739 {
740 	if ((write(clifd, "", 0) == -1) && errno == EPIPE)
741 		return (-1);
742 	return (0);
743 }
744 
745 /*
746  * This routine drives the console I/O loop.  It polls for input from the
747  * master side of the console (output to the console), and from the client
748  * (input from the console user).  Additionally, it polls on the server fd,
749  * and disconnects any clients that might try to hook up with the zone while
750  * the console is in use.
751  *
752  * When the client first calls us up, it is expected to send a line giving
753  * its "identity"; this consists of the string 'IDENT <pid> <locale>'.
754  * This is so that we can report that the console is busy along with
755  * some diagnostics about who has it busy; the locale is used so that
756  * asynchronous messages about zone state (like the NOTICE: zone halted
757  * messages) can be output in the user's locale.
758  */
759 static void
760 do_console_io(zlog_t *zlogp, int consfd, int servfd)
761 {
762 	struct pollfd pollfds[4];
763 	char ibuf[BUFSIZ];
764 	int cc, ret;
765 	int clifd = -1;
766 	int pollerr = 0;
767 	char clilocale[MAXPATHLEN];
768 	pid_t clipid = 0;
769 
770 	/* console side, watch for read events */
771 	pollfds[0].fd = consfd;
772 	pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND |
773 	    POLLPRI | POLLERR | POLLHUP | POLLNVAL;
774 
775 	/* client side, watch for read events */
776 	pollfds[1].fd = clifd;
777 	pollfds[1].events = pollfds[0].events;
778 
779 	/* the server socket; watch for events (new connections) */
780 	pollfds[2].fd = servfd;
781 	pollfds[2].events = pollfds[0].events;
782 
783 	/* the eventstram; watch for events (e.g.: zone halted) */
784 	pollfds[3].fd = eventstream[1];
785 	pollfds[3].events = pollfds[0].events;
786 
787 	for (;;) {
788 		pollfds[0].revents = pollfds[1].revents = 0;
789 		pollfds[2].revents = pollfds[3].revents = 0;
790 
791 		ret = poll(pollfds,
792 		    sizeof (pollfds) / sizeof (struct pollfd), -1);
793 		if (ret == -1 && errno != EINTR) {
794 			zerror(zlogp, B_TRUE, "poll failed");
795 			/* we are hosed, close connection */
796 			break;
797 		}
798 
799 		/* event from console side */
800 		if (pollfds[0].revents) {
801 			if (pollfds[0].revents &
802 			    (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
803 				errno = 0;
804 				cc = read(consfd, ibuf, BUFSIZ);
805 				if (cc <= 0 && (errno != EINTR) &&
806 				    (errno != EAGAIN))
807 					break;
808 				/*
809 				 * Lose I/O if no one is listening
810 				 */
811 				if (clifd != -1 && cc > 0)
812 					(void) write(clifd, ibuf, cc);
813 			} else {
814 				pollerr = pollfds[0].revents;
815 				zerror(zlogp, B_FALSE,
816 				    "closing connection with (console) "
817 				    "pollerr %d\n", pollerr);
818 				break;
819 			}
820 		}
821 
822 		/* event from client side */
823 		if (pollfds[1].revents) {
824 			if (pollfds[1].revents &
825 			    (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
826 				errno = 0;
827 				cc = read(clifd, ibuf, BUFSIZ);
828 				if (cc <= 0 && (errno != EINTR) &&
829 				    (errno != EAGAIN))
830 					break;
831 				(void) write(consfd, ibuf, cc);
832 			} else {
833 				pollerr = pollfds[1].revents;
834 				zerror(zlogp, B_FALSE,
835 				    "closing connection with (client) "
836 				    "pollerr %d\n", pollerr);
837 				break;
838 			}
839 		}
840 
841 		/* event from server socket */
842 		if (pollfds[2].revents &&
843 		    (pollfds[2].revents & (POLLIN | POLLRDNORM))) {
844 			if (clifd != -1) {
845 				/*
846 				 * Test the client to see if it is really
847 				 * still alive.  If it has died but we
848 				 * haven't yet detected that, we might
849 				 * deny a legitimate connect attempt.  If it
850 				 * is dead, we break out; once we tear down
851 				 * the old connection, the new connection
852 				 * will happen.
853 				 */
854 				if (test_client(clifd) == -1) {
855 					break;
856 				}
857 				/* we're already handling a client */
858 				reject_client(servfd, clipid);
859 
860 
861 			} else if ((clifd = accept_client(servfd, &clipid,
862 			    clilocale, sizeof (clilocale))) != -1) {
863 				pollfds[1].fd = clifd;
864 
865 			} else {
866 				break;
867 			}
868 		}
869 
870 		/*
871 		 * Watch for events on the eventstream.  This is how we get
872 		 * notified of the zone halting, etc.  It provides us a
873 		 * "wakeup" from poll when important things happen, which
874 		 * is good.
875 		 */
876 		if (pollfds[3].revents) {
877 			int evt = eventstream_read();
878 			/*
879 			 * After we drain out the event, if we aren't servicing
880 			 * a console client, we hop back out to our caller,
881 			 * which will check to see if it is time to shutdown
882 			 * the daemon, or if we should take another console
883 			 * service lap.
884 			 */
885 			if (clifd == -1) {
886 				break;
887 			}
888 			event_message(clifd, clilocale, evt);
889 			/*
890 			 * Special handling for the message that the zone is
891 			 * uninstalling; we boot the client, then break out
892 			 * of this function.  When we return to the
893 			 * serve_console loop, we will see that the zone is
894 			 * in a state < READY, and so zoneadmd will shutdown.
895 			 */
896 			if (evt == Z_EVT_ZONE_UNINSTALLING) {
897 				break;
898 			}
899 		}
900 
901 	}
902 
903 	if (clifd != -1) {
904 		(void) shutdown(clifd, SHUT_RDWR);
905 		(void) close(clifd);
906 	}
907 }
908 
909 int
910 init_console(zlog_t *zlogp)
911 {
912 	if (init_console_dev(zlogp) == -1) {
913 		zerror(zlogp, B_FALSE,
914 		    "console setup: device initialization failed");
915 		return (-1);
916 	}
917 
918 	if ((serverfd = init_console_sock(zlogp)) == -1) {
919 		zerror(zlogp, B_FALSE,
920 		    "console setup: socket initialization failed");
921 		return (-1);
922 	}
923 	return (0);
924 }
925 
926 /*
927  * serve_console() is the master loop for driving console I/O.  It is also the
928  * routine which is ultimately responsible for "pulling the plug" on zoneadmd
929  * when it realizes that the daemon should shut down.
930  *
931  * The rules for shutdown are: there must be no console client, and the zone
932  * state must be < ready.  However, we need to give things a chance to actually
933  * get going when the daemon starts up-- otherwise the daemon would immediately
934  * exit on startup if the zone was in the installed state, so we first drop
935  * into the do_console_io() loop in order to give *something* a chance to
936  * happen.
937  */
938 void
939 serve_console(zlog_t *zlogp)
940 {
941 	int masterfd;
942 	zone_state_t zstate;
943 	char conspath[MAXPATHLEN];
944 
945 	(void) snprintf(conspath, sizeof (conspath),
946 	    "/dev/zcons/%s/%s", zone_name, ZCONS_MASTER_NAME);
947 
948 	for (;;) {
949 		masterfd = open(conspath, O_RDWR|O_NONBLOCK|O_NOCTTY);
950 		if (masterfd == -1) {
951 			zerror(zlogp, B_TRUE, "failed to open console master");
952 			(void) mutex_lock(&lock);
953 			goto death;
954 		}
955 
956 		/*
957 		 * Setting RPROTDIS on the stream means that the control
958 		 * portion of messages received (which we don't care about)
959 		 * will be discarded by the stream head.  If we allowed such
960 		 * messages, we wouldn't be able to use read(2), as it fails
961 		 * (EBADMSG) when a message with a control element is received.
962 		 */
963 		if (ioctl(masterfd, I_SRDOPT, RNORM|RPROTDIS) == -1) {
964 			zerror(zlogp, B_TRUE, "failed to set options on "
965 			    "console master");
966 			(void) mutex_lock(&lock);
967 			goto death;
968 		}
969 
970 		do_console_io(zlogp, masterfd, serverfd);
971 
972 		/*
973 		 * We would prefer not to do this, but hostile zone processes
974 		 * can cause the stream to become tainted, and reads will
975 		 * fail.  So, in case something has gone seriously ill,
976 		 * we dismantle the stream and reopen the console when we
977 		 * take another lap.
978 		 */
979 		(void) close(masterfd);
980 
981 		(void) mutex_lock(&lock);
982 		/*
983 		 * We need to set death_throes (see below) atomically with
984 		 * respect to noticing that (a) we have no console client and
985 		 * (b) the zone is not installed.  Otherwise we could get a
986 		 * request to boot during this time.  Once we set death_throes,
987 		 * any incoming door stuff will be turned away.
988 		 */
989 		if (zone_get_state(zone_name, &zstate) == Z_OK) {
990 			if (zstate < ZONE_STATE_READY)
991 				goto death;
992 		} else {
993 			zerror(zlogp, B_FALSE,
994 			    "unable to determine state of zone");
995 			goto death;
996 		}
997 		/*
998 		 * Even if zone_get_state() fails, stay conservative, and
999 		 * take another lap.
1000 		 */
1001 		(void) mutex_unlock(&lock);
1002 	}
1003 
1004 death:
1005 	assert(MUTEX_HELD(&lock));
1006 	in_death_throes = B_TRUE;
1007 	(void) mutex_unlock(&lock);
1008 
1009 	destroy_console_sock(serverfd);
1010 	(void) destroy_console_devs(zlogp);
1011 }
1012