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