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