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 /* 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. 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. 35 */ 36 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 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 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; 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 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 157 mux_session_confirm(int id, void *arg) 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; 216 u_int i, j, len, env_len, mux_command, flags, escape_char; 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); 343 escape_char = buffer_get_int(&m); 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; 430 if (cctx->want_tty && escape_char != 0xffffffff) { 431 channel_register_filter(c->self, 432 client_simple_escape_filter, NULL, 433 client_filter_cleanup, 434 client_new_escape_filter_ctx((int)escape_char)); 435 } 436 437 debug3("%s: channel_new: %d", __func__, c->self); 438 439 channel_send_open(c->self); 440 channel_register_open_confirm(c->self, mux_session_confirm, cctx); 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; 497 u_int allowed, flags; 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); 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 } 581 buffer_clear(&m); 582 583 /* Get authorisation status and PID of controlee */ 584 if (ssh_msg_recv(sock, &m) == -1) { 585 error("%s: Did not receive reply from master", __func__); 586 goto muxerr; 587 } 588 if (buffer_get_char(&m) != SSHMUX_VER) { 589 error("%s: Master replied with 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 } 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: 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 } 638 break; 639 default: 640 fatal("unrecognised muxclient_command %d", muxclient_command); 641 } 642 643 if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) { 644 error("%s: msg_send", __func__); 645 goto muxerr; 646 } 647 648 if (mm_send_fd(sock, STDIN_FILENO) == -1 || 649 mm_send_fd(sock, STDOUT_FILENO) == -1 || 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 */ 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, (u_long)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 } 717