Annotation of src/usr.bin/ssh/mux.c, Revision 1.9
1.9 ! djm 1: /* $OpenBSD: mux.c,v 1.8 2009/08/20 23:54:28 dtucker Exp $ */
1.1 djm 2: /*
3: * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: /* ssh session multiplexing support */
19:
1.2 djm 20: /*
21: * TODO:
22: * 1. partial reads in muxserver_accept_control (maybe make channels
23: * from accepted connections)
24: * 2. Better signalling from master to slave, especially passing of
25: * error messages
26: * 3. Better fall-back from mux slave error to new connection.
27: * 3. Add/delete forwardings via slave
28: * 4. ExitOnForwardingFailure (after #3 obviously)
29: * 5. Maybe extension mechanisms for multi-X11/multi-agent forwarding
30: * 6. Document the mux mini-protocol somewhere.
1.3 djm 31: * 7. Support ~^Z in mux slaves.
32: * 8. Inspect or control sessions in master.
33: * 9. If we ever support the "signal" channel request, send signals on
34: * sessions in master.
1.2 djm 35: */
36:
1.1 djm 37: #include <sys/types.h>
38: #include <sys/param.h>
39: #include <sys/queue.h>
40: #include <sys/stat.h>
41: #include <sys/socket.h>
42: #include <sys/un.h>
43:
44: #include <errno.h>
45: #include <fcntl.h>
46: #include <signal.h>
47: #include <stdarg.h>
48: #include <stddef.h>
49: #include <stdlib.h>
50: #include <stdio.h>
51: #include <string.h>
52: #include <unistd.h>
53: #include <util.h>
54: #include <paths.h>
55:
56: #include "xmalloc.h"
57: #include "log.h"
58: #include "ssh.h"
59: #include "pathnames.h"
60: #include "misc.h"
61: #include "match.h"
62: #include "buffer.h"
63: #include "channels.h"
64: #include "msg.h"
65: #include "packet.h"
66: #include "monitor_fdpass.h"
67: #include "sshpty.h"
68: #include "key.h"
69: #include "readconf.h"
70: #include "clientloop.h"
71:
72: /* from ssh.c */
73: extern int tty_flag;
1.9 ! djm 74: extern int force_tty_flag;
1.1 djm 75: extern Options options;
76: extern int stdin_null_flag;
77: extern char *host;
1.8 dtucker 78: extern int subsystem_flag;
1.1 djm 79: extern Buffer command;
80:
1.2 djm 81: /* Context for session open confirmation callback */
82: struct mux_session_confirm_ctx {
83: int want_tty;
84: int want_subsys;
85: int want_x_fwd;
86: int want_agent_fwd;
87: Buffer cmd;
88: char *term;
89: struct termios tio;
90: char **env;
91: };
92:
1.1 djm 93: /* fd to control socket */
94: int muxserver_sock = -1;
95:
96: /* Multiplexing control command */
97: u_int muxclient_command = 0;
98:
99: /* Set when signalled. */
100: static volatile sig_atomic_t muxclient_terminate = 0;
101:
102: /* PID of multiplex server */
103: static u_int muxserver_pid = 0;
104:
105:
106: /* ** Multiplexing master support */
107:
108: /* Prepare a mux master to listen on a Unix domain socket. */
109: void
110: muxserver_listen(void)
111: {
112: struct sockaddr_un addr;
113: mode_t old_umask;
114:
115: if (options.control_path == NULL ||
116: options.control_master == SSHCTL_MASTER_NO)
117: return;
118:
119: debug("setting up multiplex master socket");
120:
121: memset(&addr, '\0', sizeof(addr));
122: addr.sun_family = AF_UNIX;
123: addr.sun_len = offsetof(struct sockaddr_un, sun_path) +
124: strlen(options.control_path) + 1;
125:
126: if (strlcpy(addr.sun_path, options.control_path,
127: sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
128: fatal("ControlPath too long");
129:
130: if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
131: fatal("%s socket(): %s", __func__, strerror(errno));
132:
133: old_umask = umask(0177);
134: if (bind(muxserver_sock, (struct sockaddr *)&addr, addr.sun_len) == -1) {
135: muxserver_sock = -1;
1.5 djm 136: if (errno == EINVAL || errno == EADDRINUSE) {
137: error("ControlSocket %s already exists, "
138: "disabling multiplexing", options.control_path);
139: close(muxserver_sock);
140: muxserver_sock = -1;
141: xfree(options.control_path);
142: options.control_path = NULL;
143: options.control_master = SSHCTL_MASTER_NO;
144: return;
145: } else
1.1 djm 146: fatal("%s bind(): %s", __func__, strerror(errno));
147: }
148: umask(old_umask);
149:
150: if (listen(muxserver_sock, 64) == -1)
151: fatal("%s listen(): %s", __func__, strerror(errno));
152:
153: set_nonblock(muxserver_sock);
154: }
155:
156: /* Callback on open confirmation in mux master for a mux client session. */
157: static void
1.2 djm 158: mux_session_confirm(int id, void *arg)
1.1 djm 159: {
160: struct mux_session_confirm_ctx *cctx = arg;
161: const char *display;
162: Channel *c;
163: int i;
164:
165: if (cctx == NULL)
166: fatal("%s: cctx == NULL", __func__);
167: if ((c = channel_lookup(id)) == NULL)
168: fatal("%s: no channel for id %d", __func__, id);
169:
170: display = getenv("DISPLAY");
171: if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
172: char *proto, *data;
173: /* Get reasonable local authentication information. */
174: client_x11_get_proto(display, options.xauth_location,
175: options.forward_x11_trusted, &proto, &data);
176: /* Request forwarding with authentication spoofing. */
177: debug("Requesting X11 forwarding with authentication spoofing.");
178: x11_request_forwarding_with_spoofing(id, display, proto, data);
179: /* XXX wait for reply */
180: }
181:
182: if (cctx->want_agent_fwd && options.forward_agent) {
183: debug("Requesting authentication agent forwarding.");
184: channel_request_start(id, "auth-agent-req@openssh.com", 0);
185: packet_send();
186: }
187:
188: client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
189: cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env);
190:
191: c->open_confirm_ctx = NULL;
192: buffer_free(&cctx->cmd);
193: xfree(cctx->term);
194: if (cctx->env != NULL) {
195: for (i = 0; cctx->env[i] != NULL; i++)
196: xfree(cctx->env[i]);
197: xfree(cctx->env);
198: }
199: xfree(cctx);
200: }
201:
202: /*
203: * Accept a connection on the mux master socket and process the
204: * client's request. Returns flag indicating whether mux master should
205: * begin graceful close.
206: */
207: int
208: muxserver_accept_control(void)
209: {
210: Buffer m;
211: Channel *c;
212: int client_fd, new_fd[3], ver, allowed, window, packetmax;
213: socklen_t addrlen;
214: struct sockaddr_storage addr;
215: struct mux_session_confirm_ctx *cctx;
216: char *cmd;
1.2 djm 217: u_int i, j, len, env_len, mux_command, flags, escape_char;
1.1 djm 218: uid_t euid;
219: gid_t egid;
220: int start_close = 0;
221:
222: /*
223: * Accept connection on control socket
224: */
225: memset(&addr, 0, sizeof(addr));
226: addrlen = sizeof(addr);
227: if ((client_fd = accept(muxserver_sock,
228: (struct sockaddr*)&addr, &addrlen)) == -1) {
229: error("%s accept: %s", __func__, strerror(errno));
230: return 0;
231: }
232:
233: if (getpeereid(client_fd, &euid, &egid) < 0) {
234: error("%s getpeereid failed: %s", __func__, strerror(errno));
235: close(client_fd);
236: return 0;
237: }
238: if ((euid != 0) && (getuid() != euid)) {
239: error("control mode uid mismatch: peer euid %u != uid %u",
240: (u_int) euid, (u_int) getuid());
241: close(client_fd);
242: return 0;
243: }
244:
245: /* XXX handle asynchronously */
246: unset_nonblock(client_fd);
247:
248: /* Read command */
249: buffer_init(&m);
250: if (ssh_msg_recv(client_fd, &m) == -1) {
251: error("%s: client msg_recv failed", __func__);
252: close(client_fd);
253: buffer_free(&m);
254: return 0;
255: }
256: if ((ver = buffer_get_char(&m)) != SSHMUX_VER) {
257: error("%s: wrong client version %d", __func__, ver);
258: buffer_free(&m);
259: close(client_fd);
260: return 0;
261: }
262:
263: allowed = 1;
264: mux_command = buffer_get_int(&m);
265: flags = buffer_get_int(&m);
266:
267: buffer_clear(&m);
268:
269: switch (mux_command) {
270: case SSHMUX_COMMAND_OPEN:
271: if (options.control_master == SSHCTL_MASTER_ASK ||
272: options.control_master == SSHCTL_MASTER_AUTO_ASK)
273: allowed = ask_permission("Allow shared connection "
274: "to %s? ", host);
275: /* continue below */
276: break;
277: case SSHMUX_COMMAND_TERMINATE:
278: if (options.control_master == SSHCTL_MASTER_ASK ||
279: options.control_master == SSHCTL_MASTER_AUTO_ASK)
280: allowed = ask_permission("Terminate shared connection "
281: "to %s? ", host);
282: if (allowed)
283: start_close = 1;
284: /* FALLTHROUGH */
285: case SSHMUX_COMMAND_ALIVE_CHECK:
286: /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */
287: buffer_clear(&m);
288: buffer_put_int(&m, allowed);
289: buffer_put_int(&m, getpid());
290: if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
291: error("%s: client msg_send failed", __func__);
292: close(client_fd);
293: buffer_free(&m);
294: return start_close;
295: }
296: buffer_free(&m);
297: close(client_fd);
298: return start_close;
299: default:
300: error("Unsupported command %d", mux_command);
301: buffer_free(&m);
302: close(client_fd);
303: return 0;
304: }
305:
306: /* Reply for SSHMUX_COMMAND_OPEN */
307: buffer_clear(&m);
308: buffer_put_int(&m, allowed);
309: buffer_put_int(&m, getpid());
310: if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
311: error("%s: client msg_send failed", __func__);
312: close(client_fd);
313: buffer_free(&m);
314: return 0;
315: }
316:
317: if (!allowed) {
318: error("Refused control connection");
319: close(client_fd);
320: buffer_free(&m);
321: return 0;
322: }
323:
324: buffer_clear(&m);
325: if (ssh_msg_recv(client_fd, &m) == -1) {
326: error("%s: client msg_recv failed", __func__);
327: close(client_fd);
328: buffer_free(&m);
329: return 0;
330: }
331: if ((ver = buffer_get_char(&m)) != SSHMUX_VER) {
332: error("%s: wrong client version %d", __func__, ver);
333: buffer_free(&m);
334: close(client_fd);
335: return 0;
336: }
337:
338: cctx = xcalloc(1, sizeof(*cctx));
339: cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0;
340: cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0;
341: cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0;
342: cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0;
343: cctx->term = buffer_get_string(&m, &len);
1.2 djm 344: escape_char = buffer_get_int(&m);
1.1 djm 345:
346: cmd = buffer_get_string(&m, &len);
347: buffer_init(&cctx->cmd);
348: buffer_append(&cctx->cmd, cmd, strlen(cmd));
349:
350: env_len = buffer_get_int(&m);
351: env_len = MIN(env_len, 4096);
352: debug3("%s: receiving %d env vars", __func__, env_len);
353: if (env_len != 0) {
354: cctx->env = xcalloc(env_len + 1, sizeof(*cctx->env));
355: for (i = 0; i < env_len; i++)
356: cctx->env[i] = buffer_get_string(&m, &len);
357: cctx->env[i] = NULL;
358: }
359:
360: debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__,
361: cctx->want_tty, cctx->want_subsys, cmd);
362: xfree(cmd);
363:
364: /* Gather fds from client */
365: for(i = 0; i < 3; i++) {
366: if ((new_fd[i] = mm_receive_fd(client_fd)) == -1) {
367: error("%s: failed to receive fd %d from slave",
368: __func__, i);
369: for (j = 0; j < i; j++)
370: close(new_fd[j]);
371: for (j = 0; j < env_len; j++)
372: xfree(cctx->env[j]);
373: if (env_len > 0)
374: xfree(cctx->env);
375: xfree(cctx->term);
376: buffer_free(&cctx->cmd);
377: close(client_fd);
378: xfree(cctx);
379: return 0;
380: }
381: }
382:
383: debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__,
384: new_fd[0], new_fd[1], new_fd[2]);
385:
386: /* Try to pick up ttymodes from client before it goes raw */
387: if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
388: error("%s: tcgetattr: %s", __func__, strerror(errno));
389:
390: /* This roundtrip is just for synchronisation of ttymodes */
391: buffer_clear(&m);
392: if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
393: error("%s: client msg_send failed", __func__);
394: close(client_fd);
395: close(new_fd[0]);
396: close(new_fd[1]);
397: close(new_fd[2]);
398: buffer_free(&m);
399: xfree(cctx->term);
400: if (env_len != 0) {
401: for (i = 0; i < env_len; i++)
402: xfree(cctx->env[i]);
403: xfree(cctx->env);
404: }
405: return 0;
406: }
407: buffer_free(&m);
408:
409: /* enable nonblocking unless tty */
410: if (!isatty(new_fd[0]))
411: set_nonblock(new_fd[0]);
412: if (!isatty(new_fd[1]))
413: set_nonblock(new_fd[1]);
414: if (!isatty(new_fd[2]))
415: set_nonblock(new_fd[2]);
416:
417: set_nonblock(client_fd);
418:
419: window = CHAN_SES_WINDOW_DEFAULT;
420: packetmax = CHAN_SES_PACKET_DEFAULT;
421: if (cctx->want_tty) {
422: window >>= 1;
423: packetmax >>= 1;
424: }
425:
426: c = channel_new("session", SSH_CHANNEL_OPENING,
427: new_fd[0], new_fd[1], new_fd[2], window, packetmax,
428: CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
429:
430: c->ctl_fd = client_fd;
1.2 djm 431: if (cctx->want_tty && escape_char != 0xffffffff) {
432: channel_register_filter(c->self,
433: client_simple_escape_filter, NULL,
1.4 djm 434: client_filter_cleanup,
1.2 djm 435: client_new_escape_filter_ctx((int)escape_char));
436: }
1.1 djm 437:
438: debug3("%s: channel_new: %d", __func__, c->self);
439:
440: channel_send_open(c->self);
1.2 djm 441: channel_register_open_confirm(c->self, mux_session_confirm, cctx);
1.1 djm 442: return 0;
443: }
444:
445: /* ** Multiplexing client support */
446:
447: /* Exit signal handler */
448: static void
449: control_client_sighandler(int signo)
450: {
451: muxclient_terminate = signo;
452: }
453:
454: /*
455: * Relay signal handler - used to pass some signals from mux client to
456: * mux master.
457: */
458: static void
459: control_client_sigrelay(int signo)
460: {
461: int save_errno = errno;
462:
463: if (muxserver_pid > 1)
464: kill(muxserver_pid, signo);
465:
466: errno = save_errno;
467: }
468:
469: /* Check mux client environment variables before passing them to mux master. */
470: static int
471: env_permitted(char *env)
472: {
473: int i, ret;
474: char name[1024], *cp;
475:
476: if ((cp = strchr(env, '=')) == NULL || cp == env)
477: return (0);
478: ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
479: if (ret <= 0 || (size_t)ret >= sizeof(name))
480: fatal("env_permitted: name '%.100s...' too long", env);
481:
482: for (i = 0; i < options.num_send_env; i++)
483: if (match_pattern(name, options.send_env[i]))
484: return (1);
485:
486: return (0);
487: }
488:
489: /* Multiplex client main loop. */
490: void
491: muxclient(const char *path)
492: {
493: struct sockaddr_un addr;
494: int i, r, fd, sock, exitval[2], num_env;
495: Buffer m;
496: char *term;
497: extern char **environ;
1.5 djm 498: u_int allowed, flags;
1.1 djm 499:
500: if (muxclient_command == 0)
501: muxclient_command = SSHMUX_COMMAND_OPEN;
502:
503: switch (options.control_master) {
504: case SSHCTL_MASTER_AUTO:
505: case SSHCTL_MASTER_AUTO_ASK:
506: debug("auto-mux: Trying existing master");
507: /* FALLTHROUGH */
508: case SSHCTL_MASTER_NO:
509: break;
510: default:
511: return;
512: }
513:
514: memset(&addr, '\0', sizeof(addr));
515: addr.sun_family = AF_UNIX;
516: addr.sun_len = offsetof(struct sockaddr_un, sun_path) +
517: strlen(path) + 1;
518:
519: if (strlcpy(addr.sun_path, path,
520: sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
521: fatal("ControlPath too long");
522:
523: if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
524: fatal("%s socket(): %s", __func__, strerror(errno));
525:
526: if (connect(sock, (struct sockaddr *)&addr, addr.sun_len) == -1) {
527: if (muxclient_command != SSHMUX_COMMAND_OPEN) {
528: fatal("Control socket connect(%.100s): %s", path,
529: strerror(errno));
530: }
531: if (errno == ENOENT)
532: debug("Control socket \"%.100s\" does not exist", path);
533: else {
534: error("Control socket connect(%.100s): %s", path,
535: strerror(errno));
536: }
537: close(sock);
538: return;
539: }
540:
541: if (stdin_null_flag) {
542: if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
543: fatal("open(/dev/null): %s", strerror(errno));
544: if (dup2(fd, STDIN_FILENO) == -1)
545: fatal("dup2: %s", strerror(errno));
546: if (fd > STDERR_FILENO)
547: close(fd);
548: }
549:
550: term = getenv("TERM");
551:
552: flags = 0;
553: if (tty_flag)
554: flags |= SSHMUX_FLAG_TTY;
555: if (subsystem_flag)
556: flags |= SSHMUX_FLAG_SUBSYS;
557: if (options.forward_x11)
558: flags |= SSHMUX_FLAG_X11_FWD;
559: if (options.forward_agent)
560: flags |= SSHMUX_FLAG_AGENT_FWD;
561:
562: signal(SIGPIPE, SIG_IGN);
563:
564: buffer_init(&m);
565:
566: /* Send our command to server */
567: buffer_put_int(&m, muxclient_command);
568: buffer_put_int(&m, flags);
1.5 djm 569: if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) {
570: error("%s: msg_send", __func__);
571: muxerr:
572: close(sock);
573: buffer_free(&m);
574: if (muxclient_command != SSHMUX_COMMAND_OPEN)
575: cleanup_exit(255);
576: logit("Falling back to non-multiplexed connection");
577: xfree(options.control_path);
578: options.control_path = NULL;
579: options.control_master = SSHCTL_MASTER_NO;
580: return;
581: }
1.1 djm 582: buffer_clear(&m);
583:
584: /* Get authorisation status and PID of controlee */
1.5 djm 585: if (ssh_msg_recv(sock, &m) == -1) {
1.7 dtucker 586: error("%s: Did not receive reply from master", __func__);
1.5 djm 587: goto muxerr;
588: }
589: if (buffer_get_char(&m) != SSHMUX_VER) {
1.7 dtucker 590: error("%s: Master replied with wrong version", __func__);
1.5 djm 591: goto muxerr;
592: }
593: if (buffer_get_int_ret(&allowed, &m) != 0) {
594: error("%s: bad server reply", __func__);
595: goto muxerr;
596: }
597: if (allowed != 1) {
598: error("Connection to master denied");
599: goto muxerr;
600: }
1.1 djm 601: muxserver_pid = buffer_get_int(&m);
602:
603: buffer_clear(&m);
604:
605: switch (muxclient_command) {
606: case SSHMUX_COMMAND_ALIVE_CHECK:
607: fprintf(stderr, "Master running (pid=%d)\r\n",
608: muxserver_pid);
609: exit(0);
610: case SSHMUX_COMMAND_TERMINATE:
611: fprintf(stderr, "Exit request sent.\r\n");
612: exit(0);
613: case SSHMUX_COMMAND_OPEN:
1.2 djm 614: buffer_put_cstring(&m, term ? term : "");
615: if (options.escape_char == SSH_ESCAPECHAR_NONE)
616: buffer_put_int(&m, 0xffffffff);
617: else
618: buffer_put_int(&m, options.escape_char);
619: buffer_append(&command, "\0", 1);
620: buffer_put_cstring(&m, buffer_ptr(&command));
621:
622: if (options.num_send_env == 0 || environ == NULL) {
623: buffer_put_int(&m, 0);
624: } else {
625: /* Pass environment */
626: num_env = 0;
627: for (i = 0; environ[i] != NULL; i++) {
628: if (env_permitted(environ[i]))
629: num_env++; /* Count */
630: }
631: buffer_put_int(&m, num_env);
632: for (i = 0; environ[i] != NULL && num_env >= 0; i++) {
633: if (env_permitted(environ[i])) {
634: num_env--;
635: buffer_put_cstring(&m, environ[i]);
636: }
637: }
638: }
1.1 djm 639: break;
640: default:
1.2 djm 641: fatal("unrecognised muxclient_command %d", muxclient_command);
1.1 djm 642: }
643:
1.5 djm 644: if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) {
645: error("%s: msg_send", __func__);
646: goto muxerr;
647: }
1.1 djm 648:
649: if (mm_send_fd(sock, STDIN_FILENO) == -1 ||
650: mm_send_fd(sock, STDOUT_FILENO) == -1 ||
1.5 djm 651: mm_send_fd(sock, STDERR_FILENO) == -1) {
652: error("%s: send fds failed", __func__);
653: goto muxerr;
654: }
655:
656: /*
657: * Mux errors are non-recoverable from this point as the master
658: * has ownership of the session now.
659: */
1.1 djm 660:
661: /* Wait for reply, so master has a chance to gather ttymodes */
662: buffer_clear(&m);
663: if (ssh_msg_recv(sock, &m) == -1)
664: fatal("%s: msg_recv", __func__);
665: if (buffer_get_char(&m) != SSHMUX_VER)
666: fatal("%s: wrong version", __func__);
667: buffer_free(&m);
668:
669: signal(SIGHUP, control_client_sighandler);
670: signal(SIGINT, control_client_sighandler);
671: signal(SIGTERM, control_client_sighandler);
672: signal(SIGWINCH, control_client_sigrelay);
673:
674: if (tty_flag)
1.9 ! djm 675: enter_raw_mode(force_tty_flag);
1.1 djm 676:
677: /*
678: * Stick around until the controlee closes the client_fd.
679: * Before it does, it is expected to write this process' exit
680: * value (one int). This process must read the value and wait for
681: * the closure of the client_fd; if this one closes early, the
682: * multiplex master will terminate early too (possibly losing data).
683: */
684: exitval[0] = 0;
685: for (i = 0; !muxclient_terminate && i < (int)sizeof(exitval);) {
686: r = read(sock, (char *)exitval + i, sizeof(exitval) - i);
687: if (r == 0) {
688: debug2("Received EOF from master");
689: break;
690: }
691: if (r == -1) {
692: if (errno == EINTR)
693: continue;
694: fatal("%s: read %s", __func__, strerror(errno));
695: }
696: i += r;
697: }
698:
699: close(sock);
1.9 ! djm 700: leave_raw_mode(force_tty_flag);
1.1 djm 701: if (i > (int)sizeof(int))
702: fatal("%s: master returned too much data (%d > %lu)",
1.6 dtucker 703: __func__, i, (u_long)sizeof(int));
1.1 djm 704: if (muxclient_terminate) {
705: debug2("Exiting on signal %d", muxclient_terminate);
706: exitval[0] = 255;
707: } else if (i < (int)sizeof(int)) {
708: debug2("Control master terminated unexpectedly");
709: exitval[0] = 255;
710: } else
711: debug2("Received exit status from master %d", exitval[0]);
712:
713: if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
714: fprintf(stderr, "Shared connection to %s closed.\r\n", host);
715:
716: exit(exitval[0]);
717: }