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