1323136Sdes/* $OpenBSD: mux.c,v 1.64 2017/01/21 11:32:04 guenther Exp $ */ 2180750Sdes/* 3180750Sdes * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> 4180750Sdes * 5180750Sdes * Permission to use, copy, modify, and distribute this software for any 6180750Sdes * purpose with or without fee is hereby granted, provided that the above 7180750Sdes * copyright notice and this permission notice appear in all copies. 8180750Sdes * 9180750Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10180750Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11180750Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12180750Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13180750Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14180750Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15180750Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16180750Sdes */ 17180750Sdes 18180750Sdes/* ssh session multiplexing support */ 19180750Sdes 20180750Sdes/* 21180750Sdes * TODO: 22204917Sdes * - Better signalling from master to slave, especially passing of 23180750Sdes * error messages 24204917Sdes * - Better fall-back from mux slave error to new connection. 25204917Sdes * - ExitOnForwardingFailure 26204917Sdes * - Maybe extension mechanisms for multi-X11/multi-agent forwarding 27204917Sdes * - Support ~^Z in mux slaves. 28204917Sdes * - Inspect or control sessions in master. 29204917Sdes * - If we ever support the "signal" channel request, send signals on 30204917Sdes * sessions in master. 31180750Sdes */ 32180750Sdes 33204917Sdes#include "includes.h" 34263691Sdes__RCSID("$FreeBSD: stable/11/crypto/openssh/mux.c 323136 2017-09-02 23:39:51Z des $"); 35204917Sdes 36180750Sdes#include <sys/types.h> 37180750Sdes#include <sys/stat.h> 38180750Sdes#include <sys/socket.h> 39180750Sdes#include <sys/un.h> 40180750Sdes 41180750Sdes#include <errno.h> 42180750Sdes#include <fcntl.h> 43180750Sdes#include <signal.h> 44180750Sdes#include <stdarg.h> 45180750Sdes#include <stddef.h> 46180750Sdes#include <stdlib.h> 47180750Sdes#include <stdio.h> 48180750Sdes#include <string.h> 49180750Sdes#include <unistd.h> 50180750Sdes#ifdef HAVE_PATHS_H 51180750Sdes#include <paths.h> 52180750Sdes#endif 53180750Sdes 54204917Sdes#ifdef HAVE_POLL_H 55204917Sdes#include <poll.h> 56204917Sdes#else 57204917Sdes# ifdef HAVE_SYS_POLL_H 58204917Sdes# include <sys/poll.h> 59204917Sdes# endif 60204917Sdes#endif 61204917Sdes 62180750Sdes#ifdef HAVE_UTIL_H 63180750Sdes# include <util.h> 64180750Sdes#endif 65180750Sdes 66180750Sdes#include "openbsd-compat/sys-queue.h" 67180750Sdes#include "xmalloc.h" 68180750Sdes#include "log.h" 69180750Sdes#include "ssh.h" 70215116Sdes#include "ssh2.h" 71180750Sdes#include "pathnames.h" 72180750Sdes#include "misc.h" 73180750Sdes#include "match.h" 74180750Sdes#include "buffer.h" 75180750Sdes#include "channels.h" 76180750Sdes#include "msg.h" 77180750Sdes#include "packet.h" 78180750Sdes#include "monitor_fdpass.h" 79180750Sdes#include "sshpty.h" 80180750Sdes#include "key.h" 81180750Sdes#include "readconf.h" 82180750Sdes#include "clientloop.h" 83323134Sdes#include "ssherr.h" 84180750Sdes 85180750Sdes/* from ssh.c */ 86180750Sdesextern int tty_flag; 87180750Sdesextern Options options; 88180750Sdesextern int stdin_null_flag; 89180750Sdesextern char *host; 90204917Sdesextern int subsystem_flag; 91180750Sdesextern Buffer command; 92204917Sdesextern volatile sig_atomic_t quit_pending; 93180750Sdes 94180750Sdes/* Context for session open confirmation callback */ 95180750Sdesstruct mux_session_confirm_ctx { 96204917Sdes u_int want_tty; 97204917Sdes u_int want_subsys; 98204917Sdes u_int want_x_fwd; 99204917Sdes u_int want_agent_fwd; 100180750Sdes Buffer cmd; 101180750Sdes char *term; 102180750Sdes struct termios tio; 103180750Sdes char **env; 104215116Sdes u_int rid; 105180750Sdes}; 106180750Sdes 107294328Sdes/* Context for stdio fwd open confirmation callback */ 108294328Sdesstruct mux_stdio_confirm_ctx { 109294328Sdes u_int rid; 110294328Sdes}; 111294328Sdes 112215116Sdes/* Context for global channel callback */ 113215116Sdesstruct mux_channel_confirm_ctx { 114215116Sdes u_int cid; /* channel id */ 115215116Sdes u_int rid; /* request id */ 116215116Sdes int fid; /* forward id */ 117215116Sdes}; 118215116Sdes 119180750Sdes/* fd to control socket */ 120180750Sdesint muxserver_sock = -1; 121180750Sdes 122204917Sdes/* client request id */ 123204917Sdesu_int muxclient_request_id = 0; 124204917Sdes 125180750Sdes/* Multiplexing control command */ 126180750Sdesu_int muxclient_command = 0; 127180750Sdes 128180750Sdes/* Set when signalled. */ 129180750Sdesstatic volatile sig_atomic_t muxclient_terminate = 0; 130180750Sdes 131180750Sdes/* PID of multiplex server */ 132180750Sdesstatic u_int muxserver_pid = 0; 133180750Sdes 134204917Sdesstatic Channel *mux_listener_channel = NULL; 135180750Sdes 136204917Sdesstruct mux_master_state { 137204917Sdes int hello_rcvd; 138204917Sdes}; 139180750Sdes 140204917Sdes/* mux protocol messages */ 141204917Sdes#define MUX_MSG_HELLO 0x00000001 142204917Sdes#define MUX_C_NEW_SESSION 0x10000002 143204917Sdes#define MUX_C_ALIVE_CHECK 0x10000004 144204917Sdes#define MUX_C_TERMINATE 0x10000005 145204917Sdes#define MUX_C_OPEN_FWD 0x10000006 146204917Sdes#define MUX_C_CLOSE_FWD 0x10000007 147204917Sdes#define MUX_C_NEW_STDIO_FWD 0x10000008 148226046Sdes#define MUX_C_STOP_LISTENING 0x10000009 149323134Sdes#define MUX_C_PROXY 0x1000000f 150204917Sdes#define MUX_S_OK 0x80000001 151204917Sdes#define MUX_S_PERMISSION_DENIED 0x80000002 152204917Sdes#define MUX_S_FAILURE 0x80000003 153204917Sdes#define MUX_S_EXIT_MESSAGE 0x80000004 154204917Sdes#define MUX_S_ALIVE 0x80000005 155204917Sdes#define MUX_S_SESSION_OPENED 0x80000006 156215116Sdes#define MUX_S_REMOTE_PORT 0x80000007 157226046Sdes#define MUX_S_TTY_ALLOC_FAIL 0x80000008 158323134Sdes#define MUX_S_PROXY 0x8000000f 159204917Sdes 160204917Sdes/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ 161204917Sdes#define MUX_FWD_LOCAL 1 162204917Sdes#define MUX_FWD_REMOTE 2 163204917Sdes#define MUX_FWD_DYNAMIC 3 164204917Sdes 165215116Sdesstatic void mux_session_confirm(int, int, void *); 166294328Sdesstatic void mux_stdio_confirm(int, int, void *); 167204917Sdes 168204917Sdesstatic int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); 169204917Sdesstatic int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); 170204917Sdesstatic int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *); 171204917Sdesstatic int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *); 172204917Sdesstatic int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); 173204917Sdesstatic int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); 174204917Sdesstatic int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); 175226046Sdesstatic int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *); 176323134Sdesstatic int process_mux_proxy(u_int, Channel *, Buffer *, Buffer *); 177204917Sdes 178204917Sdesstatic const struct { 179204917Sdes u_int type; 180204917Sdes int (*handler)(u_int, Channel *, Buffer *, Buffer *); 181204917Sdes} mux_master_handlers[] = { 182204917Sdes { MUX_MSG_HELLO, process_mux_master_hello }, 183204917Sdes { MUX_C_NEW_SESSION, process_mux_new_session }, 184204917Sdes { MUX_C_ALIVE_CHECK, process_mux_alive_check }, 185204917Sdes { MUX_C_TERMINATE, process_mux_terminate }, 186204917Sdes { MUX_C_OPEN_FWD, process_mux_open_fwd }, 187204917Sdes { MUX_C_CLOSE_FWD, process_mux_close_fwd }, 188204917Sdes { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, 189226046Sdes { MUX_C_STOP_LISTENING, process_mux_stop_listening }, 190323134Sdes { MUX_C_PROXY, process_mux_proxy }, 191204917Sdes { 0, NULL } 192204917Sdes}; 193204917Sdes 194204917Sdes/* Cleanup callback fired on closure of mux slave _session_ channel */ 195204917Sdes/* ARGSUSED */ 196255767Sdesstatic void 197204917Sdesmux_master_session_cleanup_cb(int cid, void *unused) 198204917Sdes{ 199204917Sdes Channel *cc, *c = channel_by_id(cid); 200204917Sdes 201204917Sdes debug3("%s: entering for channel %d", __func__, cid); 202204917Sdes if (c == NULL) 203204917Sdes fatal("%s: channel_by_id(%i) == NULL", __func__, cid); 204204917Sdes if (c->ctl_chan != -1) { 205204917Sdes if ((cc = channel_by_id(c->ctl_chan)) == NULL) 206204917Sdes fatal("%s: channel %d missing control channel %d", 207204917Sdes __func__, c->self, c->ctl_chan); 208204917Sdes c->ctl_chan = -1; 209204917Sdes cc->remote_id = -1; 210204917Sdes chan_rcvd_oclose(cc); 211204917Sdes } 212204917Sdes channel_cancel_cleanup(c->self); 213204917Sdes} 214204917Sdes 215204917Sdes/* Cleanup callback fired on closure of mux slave _control_ channel */ 216204917Sdes/* ARGSUSED */ 217204917Sdesstatic void 218204917Sdesmux_master_control_cleanup_cb(int cid, void *unused) 219204917Sdes{ 220204917Sdes Channel *sc, *c = channel_by_id(cid); 221204917Sdes 222204917Sdes debug3("%s: entering for channel %d", __func__, cid); 223204917Sdes if (c == NULL) 224204917Sdes fatal("%s: channel_by_id(%i) == NULL", __func__, cid); 225204917Sdes if (c->remote_id != -1) { 226204917Sdes if ((sc = channel_by_id(c->remote_id)) == NULL) 227215116Sdes fatal("%s: channel %d missing session channel %d", 228204917Sdes __func__, c->self, c->remote_id); 229204917Sdes c->remote_id = -1; 230204917Sdes sc->ctl_chan = -1; 231255767Sdes if (sc->type != SSH_CHANNEL_OPEN && 232255767Sdes sc->type != SSH_CHANNEL_OPENING) { 233204917Sdes debug2("%s: channel %d: not open", __func__, sc->self); 234204917Sdes chan_mark_dead(sc); 235204917Sdes } else { 236204917Sdes if (sc->istate == CHAN_INPUT_OPEN) 237204917Sdes chan_read_failed(sc); 238204917Sdes if (sc->ostate == CHAN_OUTPUT_OPEN) 239204917Sdes chan_write_failed(sc); 240204917Sdes } 241204917Sdes } 242204917Sdes channel_cancel_cleanup(c->self); 243204917Sdes} 244204917Sdes 245204917Sdes/* Check mux client environment variables before passing them to mux master. */ 246204917Sdesstatic int 247204917Sdesenv_permitted(char *env) 248204917Sdes{ 249204917Sdes int i, ret; 250204917Sdes char name[1024], *cp; 251204917Sdes 252204917Sdes if ((cp = strchr(env, '=')) == NULL || cp == env) 253204917Sdes return 0; 254204917Sdes ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env); 255204917Sdes if (ret <= 0 || (size_t)ret >= sizeof(name)) { 256204917Sdes error("env_permitted: name '%.100s...' too long", env); 257204917Sdes return 0; 258204917Sdes } 259204917Sdes 260204917Sdes for (i = 0; i < options.num_send_env; i++) 261204917Sdes if (match_pattern(name, options.send_env[i])) 262204917Sdes return 1; 263204917Sdes 264204917Sdes return 0; 265204917Sdes} 266204917Sdes 267204917Sdes/* Mux master protocol message handlers */ 268204917Sdes 269204917Sdesstatic int 270204917Sdesprocess_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r) 271204917Sdes{ 272204917Sdes u_int ver; 273204917Sdes struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; 274204917Sdes 275204917Sdes if (state == NULL) 276204917Sdes fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self); 277204917Sdes if (state->hello_rcvd) { 278204917Sdes error("%s: HELLO received twice", __func__); 279204917Sdes return -1; 280204917Sdes } 281204917Sdes if (buffer_get_int_ret(&ver, m) != 0) { 282204917Sdes malf: 283204917Sdes error("%s: malformed message", __func__); 284204917Sdes return -1; 285204917Sdes } 286204917Sdes if (ver != SSHMUX_VER) { 287204917Sdes error("Unsupported multiplexing protocol version %d " 288204917Sdes "(expected %d)", ver, SSHMUX_VER); 289204917Sdes return -1; 290204917Sdes } 291204917Sdes debug2("%s: channel %d slave version %u", __func__, c->self, ver); 292204917Sdes 293204917Sdes /* No extensions are presently defined */ 294204917Sdes while (buffer_len(m) > 0) { 295204917Sdes char *name = buffer_get_string_ret(m, NULL); 296204917Sdes char *value = buffer_get_string_ret(m, NULL); 297204917Sdes 298204917Sdes if (name == NULL || value == NULL) { 299255767Sdes free(name); 300255767Sdes free(value); 301204917Sdes goto malf; 302204917Sdes } 303204917Sdes debug2("Unrecognised slave extension \"%s\"", name); 304255767Sdes free(name); 305255767Sdes free(value); 306204917Sdes } 307204917Sdes state->hello_rcvd = 1; 308204917Sdes return 0; 309204917Sdes} 310204917Sdes 311204917Sdesstatic int 312204917Sdesprocess_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) 313204917Sdes{ 314204917Sdes Channel *nc; 315204917Sdes struct mux_session_confirm_ctx *cctx; 316204917Sdes char *reserved, *cmd, *cp; 317204917Sdes u_int i, j, len, env_len, escape_char, window, packetmax; 318204917Sdes int new_fd[3]; 319204917Sdes 320204917Sdes /* Reply for SSHMUX_COMMAND_OPEN */ 321204917Sdes cctx = xcalloc(1, sizeof(*cctx)); 322204917Sdes cctx->term = NULL; 323215116Sdes cctx->rid = rid; 324204917Sdes cmd = reserved = NULL; 325240075Sdes cctx->env = NULL; 326240075Sdes env_len = 0; 327204917Sdes if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || 328204917Sdes buffer_get_int_ret(&cctx->want_tty, m) != 0 || 329204917Sdes buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 || 330204917Sdes buffer_get_int_ret(&cctx->want_agent_fwd, m) != 0 || 331204917Sdes buffer_get_int_ret(&cctx->want_subsys, m) != 0 || 332204917Sdes buffer_get_int_ret(&escape_char, m) != 0 || 333204917Sdes (cctx->term = buffer_get_string_ret(m, &len)) == NULL || 334204917Sdes (cmd = buffer_get_string_ret(m, &len)) == NULL) { 335204917Sdes malf: 336255767Sdes free(cmd); 337255767Sdes free(reserved); 338240075Sdes for (j = 0; j < env_len; j++) 339255767Sdes free(cctx->env[j]); 340255767Sdes free(cctx->env); 341255767Sdes free(cctx->term); 342255767Sdes free(cctx); 343204917Sdes error("%s: malformed message", __func__); 344204917Sdes return -1; 345204917Sdes } 346255767Sdes free(reserved); 347204917Sdes reserved = NULL; 348204917Sdes 349204917Sdes while (buffer_len(m) > 0) { 350204917Sdes#define MUX_MAX_ENV_VARS 4096 351240075Sdes if ((cp = buffer_get_string_ret(m, &len)) == NULL) 352204917Sdes goto malf; 353204917Sdes if (!env_permitted(cp)) { 354255767Sdes free(cp); 355204917Sdes continue; 356204917Sdes } 357294336Sdes cctx->env = xreallocarray(cctx->env, env_len + 2, 358204917Sdes sizeof(*cctx->env)); 359204917Sdes cctx->env[env_len++] = cp; 360204917Sdes cctx->env[env_len] = NULL; 361204917Sdes if (env_len > MUX_MAX_ENV_VARS) { 362204917Sdes error(">%d environment variables received, ignoring " 363204917Sdes "additional", MUX_MAX_ENV_VARS); 364204917Sdes break; 365204917Sdes } 366204917Sdes } 367204917Sdes 368204917Sdes debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, " 369204917Sdes "term \"%s\", cmd \"%s\", env %u", __func__, c->self, 370204917Sdes cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd, 371204917Sdes cctx->want_subsys, cctx->term, cmd, env_len); 372204917Sdes 373204917Sdes buffer_init(&cctx->cmd); 374204917Sdes buffer_append(&cctx->cmd, cmd, strlen(cmd)); 375255767Sdes free(cmd); 376204917Sdes cmd = NULL; 377204917Sdes 378204917Sdes /* Gather fds from client */ 379204917Sdes for(i = 0; i < 3; i++) { 380204917Sdes if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { 381204917Sdes error("%s: failed to receive fd %d from slave", 382204917Sdes __func__, i); 383204917Sdes for (j = 0; j < i; j++) 384204917Sdes close(new_fd[j]); 385204917Sdes for (j = 0; j < env_len; j++) 386255767Sdes free(cctx->env[j]); 387255767Sdes free(cctx->env); 388255767Sdes free(cctx->term); 389204917Sdes buffer_free(&cctx->cmd); 390255767Sdes free(cctx); 391204917Sdes 392204917Sdes /* prepare reply */ 393204917Sdes buffer_put_int(r, MUX_S_FAILURE); 394204917Sdes buffer_put_int(r, rid); 395204917Sdes buffer_put_cstring(r, 396204917Sdes "did not receive file descriptors"); 397204917Sdes return -1; 398204917Sdes } 399204917Sdes } 400204917Sdes 401204917Sdes debug3("%s: got fds stdin %d, stdout %d, stderr %d", __func__, 402204917Sdes new_fd[0], new_fd[1], new_fd[2]); 403204917Sdes 404204917Sdes /* XXX support multiple child sessions in future */ 405204917Sdes if (c->remote_id != -1) { 406204917Sdes debug2("%s: session already open", __func__); 407204917Sdes /* prepare reply */ 408204917Sdes buffer_put_int(r, MUX_S_FAILURE); 409204917Sdes buffer_put_int(r, rid); 410204917Sdes buffer_put_cstring(r, "Multiple sessions not supported"); 411204917Sdes cleanup: 412204917Sdes close(new_fd[0]); 413204917Sdes close(new_fd[1]); 414204917Sdes close(new_fd[2]); 415255767Sdes free(cctx->term); 416204917Sdes if (env_len != 0) { 417204917Sdes for (i = 0; i < env_len; i++) 418255767Sdes free(cctx->env[i]); 419255767Sdes free(cctx->env); 420204917Sdes } 421204917Sdes buffer_free(&cctx->cmd); 422255767Sdes free(cctx); 423204917Sdes return 0; 424204917Sdes } 425204917Sdes 426204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 427204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 428204917Sdes if (!ask_permission("Allow shared connection to %s? ", host)) { 429204917Sdes debug2("%s: session refused by user", __func__); 430204917Sdes /* prepare reply */ 431204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 432204917Sdes buffer_put_int(r, rid); 433204917Sdes buffer_put_cstring(r, "Permission denied"); 434204917Sdes goto cleanup; 435204917Sdes } 436204917Sdes } 437204917Sdes 438204917Sdes /* Try to pick up ttymodes from client before it goes raw */ 439204917Sdes if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) 440204917Sdes error("%s: tcgetattr: %s", __func__, strerror(errno)); 441204917Sdes 442204917Sdes /* enable nonblocking unless tty */ 443204917Sdes if (!isatty(new_fd[0])) 444204917Sdes set_nonblock(new_fd[0]); 445204917Sdes if (!isatty(new_fd[1])) 446204917Sdes set_nonblock(new_fd[1]); 447204917Sdes if (!isatty(new_fd[2])) 448204917Sdes set_nonblock(new_fd[2]); 449204917Sdes 450204917Sdes window = CHAN_SES_WINDOW_DEFAULT; 451204917Sdes packetmax = CHAN_SES_PACKET_DEFAULT; 452204917Sdes if (cctx->want_tty) { 453204917Sdes window >>= 1; 454204917Sdes packetmax >>= 1; 455204917Sdes } 456204917Sdes 457204917Sdes nc = channel_new("session", SSH_CHANNEL_OPENING, 458204917Sdes new_fd[0], new_fd[1], new_fd[2], window, packetmax, 459204917Sdes CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); 460204917Sdes 461204917Sdes nc->ctl_chan = c->self; /* link session -> control channel */ 462204917Sdes c->remote_id = nc->self; /* link control -> session channel */ 463204917Sdes 464204917Sdes if (cctx->want_tty && escape_char != 0xffffffff) { 465204917Sdes channel_register_filter(nc->self, 466204917Sdes client_simple_escape_filter, NULL, 467204917Sdes client_filter_cleanup, 468204917Sdes client_new_escape_filter_ctx((int)escape_char)); 469204917Sdes } 470204917Sdes 471204917Sdes debug2("%s: channel_new: %d linked to control channel %d", 472204917Sdes __func__, nc->self, nc->ctl_chan); 473204917Sdes 474204917Sdes channel_send_open(nc->self); 475204917Sdes channel_register_open_confirm(nc->self, mux_session_confirm, cctx); 476215116Sdes c->mux_pause = 1; /* stop handling messages until open_confirm done */ 477215116Sdes channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); 478204917Sdes 479215116Sdes /* reply is deferred, sent by mux_session_confirm */ 480204917Sdes return 0; 481204917Sdes} 482204917Sdes 483204917Sdesstatic int 484204917Sdesprocess_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r) 485204917Sdes{ 486204917Sdes debug2("%s: channel %d: alive check", __func__, c->self); 487204917Sdes 488204917Sdes /* prepare reply */ 489204917Sdes buffer_put_int(r, MUX_S_ALIVE); 490204917Sdes buffer_put_int(r, rid); 491204917Sdes buffer_put_int(r, (u_int)getpid()); 492204917Sdes 493204917Sdes return 0; 494204917Sdes} 495204917Sdes 496204917Sdesstatic int 497204917Sdesprocess_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r) 498204917Sdes{ 499204917Sdes debug2("%s: channel %d: terminate request", __func__, c->self); 500204917Sdes 501204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 502204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 503204917Sdes if (!ask_permission("Terminate shared connection to %s? ", 504204917Sdes host)) { 505204917Sdes debug2("%s: termination refused by user", __func__); 506204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 507204917Sdes buffer_put_int(r, rid); 508204917Sdes buffer_put_cstring(r, "Permission denied"); 509204917Sdes return 0; 510204917Sdes } 511204917Sdes } 512204917Sdes 513204917Sdes quit_pending = 1; 514204917Sdes buffer_put_int(r, MUX_S_OK); 515204917Sdes buffer_put_int(r, rid); 516204917Sdes /* XXX exit happens too soon - message never makes it to client */ 517204917Sdes return 0; 518204917Sdes} 519204917Sdes 520204917Sdesstatic char * 521294328Sdesformat_forward(u_int ftype, struct Forward *fwd) 522204917Sdes{ 523204917Sdes char *ret; 524204917Sdes 525204917Sdes switch (ftype) { 526204917Sdes case MUX_FWD_LOCAL: 527204917Sdes xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d", 528294328Sdes (fwd->listen_path != NULL) ? fwd->listen_path : 529204917Sdes (fwd->listen_host == NULL) ? 530294328Sdes (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") : 531204917Sdes fwd->listen_host, fwd->listen_port, 532294328Sdes (fwd->connect_path != NULL) ? fwd->connect_path : 533204917Sdes fwd->connect_host, fwd->connect_port); 534204917Sdes break; 535204917Sdes case MUX_FWD_DYNAMIC: 536204917Sdes xasprintf(&ret, "dynamic forward %.200s:%d -> *", 537204917Sdes (fwd->listen_host == NULL) ? 538294328Sdes (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") : 539204917Sdes fwd->listen_host, fwd->listen_port); 540204917Sdes break; 541204917Sdes case MUX_FWD_REMOTE: 542204917Sdes xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d", 543294328Sdes (fwd->listen_path != NULL) ? fwd->listen_path : 544204917Sdes (fwd->listen_host == NULL) ? 545204917Sdes "LOCALHOST" : fwd->listen_host, 546204917Sdes fwd->listen_port, 547294328Sdes (fwd->connect_path != NULL) ? fwd->connect_path : 548204917Sdes fwd->connect_host, fwd->connect_port); 549204917Sdes break; 550204917Sdes default: 551204917Sdes fatal("%s: unknown forward type %u", __func__, ftype); 552204917Sdes } 553204917Sdes return ret; 554204917Sdes} 555204917Sdes 556204917Sdesstatic int 557204917Sdescompare_host(const char *a, const char *b) 558204917Sdes{ 559204917Sdes if (a == NULL && b == NULL) 560204917Sdes return 1; 561204917Sdes if (a == NULL || b == NULL) 562204917Sdes return 0; 563204917Sdes return strcmp(a, b) == 0; 564204917Sdes} 565204917Sdes 566204917Sdesstatic int 567294328Sdescompare_forward(struct Forward *a, struct Forward *b) 568204917Sdes{ 569204917Sdes if (!compare_host(a->listen_host, b->listen_host)) 570204917Sdes return 0; 571294328Sdes if (!compare_host(a->listen_path, b->listen_path)) 572294328Sdes return 0; 573204917Sdes if (a->listen_port != b->listen_port) 574204917Sdes return 0; 575204917Sdes if (!compare_host(a->connect_host, b->connect_host)) 576204917Sdes return 0; 577294328Sdes if (!compare_host(a->connect_path, b->connect_path)) 578294328Sdes return 0; 579204917Sdes if (a->connect_port != b->connect_port) 580204917Sdes return 0; 581204917Sdes 582204917Sdes return 1; 583204917Sdes} 584204917Sdes 585215116Sdesstatic void 586215116Sdesmux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) 587215116Sdes{ 588215116Sdes struct mux_channel_confirm_ctx *fctx = ctxt; 589215116Sdes char *failmsg = NULL; 590294328Sdes struct Forward *rfwd; 591215116Sdes Channel *c; 592215116Sdes Buffer out; 593215116Sdes 594215116Sdes if ((c = channel_by_id(fctx->cid)) == NULL) { 595215116Sdes /* no channel for reply */ 596215116Sdes error("%s: unknown channel", __func__); 597215116Sdes return; 598215116Sdes } 599215116Sdes buffer_init(&out); 600294336Sdes if (fctx->fid >= options.num_remote_forwards || 601294336Sdes (options.remote_forwards[fctx->fid].connect_path == NULL && 602294336Sdes options.remote_forwards[fctx->fid].connect_host == NULL)) { 603215116Sdes xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid); 604215116Sdes goto fail; 605215116Sdes } 606215116Sdes rfwd = &options.remote_forwards[fctx->fid]; 607215116Sdes debug("%s: %s for: listen %d, connect %s:%d", __func__, 608215116Sdes type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", 609294328Sdes rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path : 610294328Sdes rfwd->connect_host, rfwd->connect_port); 611215116Sdes if (type == SSH2_MSG_REQUEST_SUCCESS) { 612215116Sdes if (rfwd->listen_port == 0) { 613215116Sdes rfwd->allocated_port = packet_get_int(); 614294336Sdes debug("Allocated port %u for mux remote forward" 615215116Sdes " to %s:%d", rfwd->allocated_port, 616215116Sdes rfwd->connect_host, rfwd->connect_port); 617215116Sdes buffer_put_int(&out, MUX_S_REMOTE_PORT); 618215116Sdes buffer_put_int(&out, fctx->rid); 619215116Sdes buffer_put_int(&out, rfwd->allocated_port); 620240075Sdes channel_update_permitted_opens(rfwd->handle, 621240075Sdes rfwd->allocated_port); 622215116Sdes } else { 623215116Sdes buffer_put_int(&out, MUX_S_OK); 624215116Sdes buffer_put_int(&out, fctx->rid); 625215116Sdes } 626215116Sdes goto out; 627215116Sdes } else { 628240075Sdes if (rfwd->listen_port == 0) 629240075Sdes channel_update_permitted_opens(rfwd->handle, -1); 630294328Sdes if (rfwd->listen_path != NULL) 631294328Sdes xasprintf(&failmsg, "remote port forwarding failed for " 632294328Sdes "listen path %s", rfwd->listen_path); 633294328Sdes else 634294328Sdes xasprintf(&failmsg, "remote port forwarding failed for " 635294328Sdes "listen port %d", rfwd->listen_port); 636294336Sdes 637294336Sdes debug2("%s: clearing registered forwarding for listen %d, " 638294336Sdes "connect %s:%d", __func__, rfwd->listen_port, 639294336Sdes rfwd->connect_path ? rfwd->connect_path : 640294336Sdes rfwd->connect_host, rfwd->connect_port); 641294336Sdes 642294336Sdes free(rfwd->listen_host); 643294336Sdes free(rfwd->listen_path); 644294336Sdes free(rfwd->connect_host); 645294336Sdes free(rfwd->connect_path); 646294336Sdes memset(rfwd, 0, sizeof(*rfwd)); 647215116Sdes } 648215116Sdes fail: 649215116Sdes error("%s: %s", __func__, failmsg); 650215116Sdes buffer_put_int(&out, MUX_S_FAILURE); 651215116Sdes buffer_put_int(&out, fctx->rid); 652215116Sdes buffer_put_cstring(&out, failmsg); 653255767Sdes free(failmsg); 654215116Sdes out: 655215116Sdes buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out)); 656215116Sdes buffer_free(&out); 657215116Sdes if (c->mux_pause <= 0) 658215116Sdes fatal("%s: mux_pause %d", __func__, c->mux_pause); 659215116Sdes c->mux_pause = 0; /* start processing messages again */ 660215116Sdes} 661215116Sdes 662204917Sdesstatic int 663204917Sdesprocess_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 664204917Sdes{ 665294328Sdes struct Forward fwd; 666204917Sdes char *fwd_desc = NULL; 667294328Sdes char *listen_addr, *connect_addr; 668204917Sdes u_int ftype; 669255767Sdes u_int lport, cport; 670204917Sdes int i, ret = 0, freefwd = 1; 671204917Sdes 672294496Sdes memset(&fwd, 0, sizeof(fwd)); 673294496Sdes 674294328Sdes /* XXX - lport/cport check redundant */ 675204917Sdes if (buffer_get_int_ret(&ftype, m) != 0 || 676294328Sdes (listen_addr = buffer_get_string_ret(m, NULL)) == NULL || 677255767Sdes buffer_get_int_ret(&lport, m) != 0 || 678294328Sdes (connect_addr = buffer_get_string_ret(m, NULL)) == NULL || 679255767Sdes buffer_get_int_ret(&cport, m) != 0 || 680294328Sdes (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) || 681294328Sdes (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) { 682204917Sdes error("%s: malformed message", __func__); 683204917Sdes ret = -1; 684204917Sdes goto out; 685204917Sdes } 686294328Sdes if (*listen_addr == '\0') { 687294328Sdes free(listen_addr); 688294328Sdes listen_addr = NULL; 689204917Sdes } 690294328Sdes if (*connect_addr == '\0') { 691294328Sdes free(connect_addr); 692294328Sdes connect_addr = NULL; 693204917Sdes } 694204917Sdes 695294328Sdes memset(&fwd, 0, sizeof(fwd)); 696294328Sdes fwd.listen_port = lport; 697294328Sdes if (fwd.listen_port == PORT_STREAMLOCAL) 698294328Sdes fwd.listen_path = listen_addr; 699294328Sdes else 700294328Sdes fwd.listen_host = listen_addr; 701294328Sdes fwd.connect_port = cport; 702294328Sdes if (fwd.connect_port == PORT_STREAMLOCAL) 703294328Sdes fwd.connect_path = connect_addr; 704294328Sdes else 705294328Sdes fwd.connect_host = connect_addr; 706294328Sdes 707204917Sdes debug2("%s: channel %d: request %s", __func__, c->self, 708204917Sdes (fwd_desc = format_forward(ftype, &fwd))); 709204917Sdes 710204917Sdes if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE && 711204917Sdes ftype != MUX_FWD_DYNAMIC) { 712204917Sdes logit("%s: invalid forwarding type %u", __func__, ftype); 713204917Sdes invalid: 714294328Sdes free(listen_addr); 715294328Sdes free(connect_addr); 716204917Sdes buffer_put_int(r, MUX_S_FAILURE); 717204917Sdes buffer_put_int(r, rid); 718204917Sdes buffer_put_cstring(r, "Invalid forwarding request"); 719204917Sdes return 0; 720204917Sdes } 721294328Sdes if (ftype == MUX_FWD_DYNAMIC && fwd.listen_path) { 722294328Sdes logit("%s: streamlocal and dynamic forwards " 723294328Sdes "are mutually exclusive", __func__); 724294328Sdes goto invalid; 725294328Sdes } 726294328Sdes if (fwd.listen_port != PORT_STREAMLOCAL && fwd.listen_port >= 65536) { 727204917Sdes logit("%s: invalid listen port %u", __func__, 728204917Sdes fwd.listen_port); 729204917Sdes goto invalid; 730204917Sdes } 731294328Sdes if ((fwd.connect_port != PORT_STREAMLOCAL && fwd.connect_port >= 65536) 732294328Sdes || (ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) { 733204917Sdes logit("%s: invalid connect port %u", __func__, 734204917Sdes fwd.connect_port); 735204917Sdes goto invalid; 736204917Sdes } 737294328Sdes if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL && fwd.connect_path == NULL) { 738204917Sdes logit("%s: missing connect host", __func__); 739204917Sdes goto invalid; 740204917Sdes } 741204917Sdes 742204917Sdes /* Skip forwards that have already been requested */ 743204917Sdes switch (ftype) { 744204917Sdes case MUX_FWD_LOCAL: 745204917Sdes case MUX_FWD_DYNAMIC: 746204917Sdes for (i = 0; i < options.num_local_forwards; i++) { 747204917Sdes if (compare_forward(&fwd, 748204917Sdes options.local_forwards + i)) { 749204917Sdes exists: 750204917Sdes debug2("%s: found existing forwarding", 751204917Sdes __func__); 752204917Sdes buffer_put_int(r, MUX_S_OK); 753204917Sdes buffer_put_int(r, rid); 754204917Sdes goto out; 755204917Sdes } 756204917Sdes } 757204917Sdes break; 758204917Sdes case MUX_FWD_REMOTE: 759204917Sdes for (i = 0; i < options.num_remote_forwards; i++) { 760204917Sdes if (compare_forward(&fwd, 761215116Sdes options.remote_forwards + i)) { 762215116Sdes if (fwd.listen_port != 0) 763215116Sdes goto exists; 764215116Sdes debug2("%s: found allocated port", 765215116Sdes __func__); 766215116Sdes buffer_put_int(r, MUX_S_REMOTE_PORT); 767215116Sdes buffer_put_int(r, rid); 768215116Sdes buffer_put_int(r, 769215116Sdes options.remote_forwards[i].allocated_port); 770215116Sdes goto out; 771215116Sdes } 772204917Sdes } 773204917Sdes break; 774204917Sdes } 775204917Sdes 776204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 777204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 778204917Sdes if (!ask_permission("Open %s on %s?", fwd_desc, host)) { 779204917Sdes debug2("%s: forwarding refused by user", __func__); 780204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 781204917Sdes buffer_put_int(r, rid); 782204917Sdes buffer_put_cstring(r, "Permission denied"); 783204917Sdes goto out; 784204917Sdes } 785204917Sdes } 786204917Sdes 787204917Sdes if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { 788294328Sdes if (!channel_setup_local_fwd_listener(&fwd, 789294328Sdes &options.fwd_opts)) { 790204917Sdes fail: 791204917Sdes logit("slave-requested %s failed", fwd_desc); 792204917Sdes buffer_put_int(r, MUX_S_FAILURE); 793204917Sdes buffer_put_int(r, rid); 794204917Sdes buffer_put_cstring(r, "Port forwarding failed"); 795204917Sdes goto out; 796204917Sdes } 797204917Sdes add_local_forward(&options, &fwd); 798204917Sdes freefwd = 0; 799204917Sdes } else { 800215116Sdes struct mux_channel_confirm_ctx *fctx; 801215116Sdes 802294328Sdes fwd.handle = channel_request_remote_forwarding(&fwd); 803240075Sdes if (fwd.handle < 0) 804204917Sdes goto fail; 805204917Sdes add_remote_forward(&options, &fwd); 806215116Sdes fctx = xcalloc(1, sizeof(*fctx)); 807215116Sdes fctx->cid = c->self; 808215116Sdes fctx->rid = rid; 809215116Sdes fctx->fid = options.num_remote_forwards - 1; 810215116Sdes client_register_global_confirm(mux_confirm_remote_forward, 811215116Sdes fctx); 812204917Sdes freefwd = 0; 813215116Sdes c->mux_pause = 1; /* wait for mux_confirm_remote_forward */ 814215116Sdes /* delayed reply in mux_confirm_remote_forward */ 815215116Sdes goto out; 816204917Sdes } 817204917Sdes buffer_put_int(r, MUX_S_OK); 818204917Sdes buffer_put_int(r, rid); 819204917Sdes out: 820255767Sdes free(fwd_desc); 821204917Sdes if (freefwd) { 822255767Sdes free(fwd.listen_host); 823294328Sdes free(fwd.listen_path); 824255767Sdes free(fwd.connect_host); 825294328Sdes free(fwd.connect_path); 826204917Sdes } 827204917Sdes return ret; 828204917Sdes} 829204917Sdes 830204917Sdesstatic int 831204917Sdesprocess_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 832204917Sdes{ 833294328Sdes struct Forward fwd, *found_fwd; 834204917Sdes char *fwd_desc = NULL; 835240075Sdes const char *error_reason = NULL; 836294328Sdes char *listen_addr = NULL, *connect_addr = NULL; 837204917Sdes u_int ftype; 838294328Sdes int i, ret = 0; 839255767Sdes u_int lport, cport; 840204917Sdes 841294496Sdes memset(&fwd, 0, sizeof(fwd)); 842294496Sdes 843204917Sdes if (buffer_get_int_ret(&ftype, m) != 0 || 844294328Sdes (listen_addr = buffer_get_string_ret(m, NULL)) == NULL || 845255767Sdes buffer_get_int_ret(&lport, m) != 0 || 846294328Sdes (connect_addr = buffer_get_string_ret(m, NULL)) == NULL || 847255767Sdes buffer_get_int_ret(&cport, m) != 0 || 848294328Sdes (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) || 849294328Sdes (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) { 850204917Sdes error("%s: malformed message", __func__); 851204917Sdes ret = -1; 852204917Sdes goto out; 853204917Sdes } 854204917Sdes 855294328Sdes if (*listen_addr == '\0') { 856294328Sdes free(listen_addr); 857294328Sdes listen_addr = NULL; 858204917Sdes } 859294328Sdes if (*connect_addr == '\0') { 860294328Sdes free(connect_addr); 861294328Sdes connect_addr = NULL; 862204917Sdes } 863204917Sdes 864294328Sdes memset(&fwd, 0, sizeof(fwd)); 865294328Sdes fwd.listen_port = lport; 866294328Sdes if (fwd.listen_port == PORT_STREAMLOCAL) 867294328Sdes fwd.listen_path = listen_addr; 868294328Sdes else 869294328Sdes fwd.listen_host = listen_addr; 870294328Sdes fwd.connect_port = cport; 871294328Sdes if (fwd.connect_port == PORT_STREAMLOCAL) 872294328Sdes fwd.connect_path = connect_addr; 873294328Sdes else 874294328Sdes fwd.connect_host = connect_addr; 875294328Sdes 876240075Sdes debug2("%s: channel %d: request cancel %s", __func__, c->self, 877204917Sdes (fwd_desc = format_forward(ftype, &fwd))); 878204917Sdes 879240075Sdes /* make sure this has been requested */ 880240075Sdes found_fwd = NULL; 881240075Sdes switch (ftype) { 882240075Sdes case MUX_FWD_LOCAL: 883240075Sdes case MUX_FWD_DYNAMIC: 884240075Sdes for (i = 0; i < options.num_local_forwards; i++) { 885240075Sdes if (compare_forward(&fwd, 886240075Sdes options.local_forwards + i)) { 887240075Sdes found_fwd = options.local_forwards + i; 888240075Sdes break; 889240075Sdes } 890240075Sdes } 891240075Sdes break; 892240075Sdes case MUX_FWD_REMOTE: 893240075Sdes for (i = 0; i < options.num_remote_forwards; i++) { 894240075Sdes if (compare_forward(&fwd, 895240075Sdes options.remote_forwards + i)) { 896240075Sdes found_fwd = options.remote_forwards + i; 897240075Sdes break; 898240075Sdes } 899240075Sdes } 900240075Sdes break; 901240075Sdes } 902204917Sdes 903240075Sdes if (found_fwd == NULL) 904240075Sdes error_reason = "port not forwarded"; 905240075Sdes else if (ftype == MUX_FWD_REMOTE) { 906240075Sdes /* 907240075Sdes * This shouldn't fail unless we confused the host/port 908240075Sdes * between options.remote_forwards and permitted_opens. 909240075Sdes * However, for dynamic allocated listen ports we need 910294328Sdes * to use the actual listen port. 911240075Sdes */ 912294328Sdes if (channel_request_rforward_cancel(found_fwd) == -1) 913240075Sdes error_reason = "port not in permitted opens"; 914240075Sdes } else { /* local and dynamic forwards */ 915240075Sdes /* Ditto */ 916294328Sdes if (channel_cancel_lport_listener(&fwd, fwd.connect_port, 917294328Sdes &options.fwd_opts) == -1) 918240075Sdes error_reason = "port not found"; 919240075Sdes } 920240075Sdes 921240075Sdes if (error_reason == NULL) { 922240075Sdes buffer_put_int(r, MUX_S_OK); 923240075Sdes buffer_put_int(r, rid); 924240075Sdes 925255767Sdes free(found_fwd->listen_host); 926294328Sdes free(found_fwd->listen_path); 927255767Sdes free(found_fwd->connect_host); 928294328Sdes free(found_fwd->connect_path); 929240075Sdes found_fwd->listen_host = found_fwd->connect_host = NULL; 930294328Sdes found_fwd->listen_path = found_fwd->connect_path = NULL; 931240075Sdes found_fwd->listen_port = found_fwd->connect_port = 0; 932240075Sdes } else { 933240075Sdes buffer_put_int(r, MUX_S_FAILURE); 934240075Sdes buffer_put_int(r, rid); 935240075Sdes buffer_put_cstring(r, error_reason); 936240075Sdes } 937204917Sdes out: 938255767Sdes free(fwd_desc); 939294328Sdes free(listen_addr); 940294328Sdes free(connect_addr); 941204917Sdes 942204917Sdes return ret; 943204917Sdes} 944204917Sdes 945204917Sdesstatic int 946204917Sdesprocess_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 947204917Sdes{ 948204917Sdes Channel *nc; 949204917Sdes char *reserved, *chost; 950204917Sdes u_int cport, i, j; 951204917Sdes int new_fd[2]; 952294328Sdes struct mux_stdio_confirm_ctx *cctx; 953204917Sdes 954204917Sdes chost = reserved = NULL; 955204917Sdes if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || 956204917Sdes (chost = buffer_get_string_ret(m, NULL)) == NULL || 957204917Sdes buffer_get_int_ret(&cport, m) != 0) { 958255767Sdes free(reserved); 959255767Sdes free(chost); 960204917Sdes error("%s: malformed message", __func__); 961204917Sdes return -1; 962204917Sdes } 963255767Sdes free(reserved); 964204917Sdes 965204917Sdes debug2("%s: channel %d: request stdio fwd to %s:%u", 966204917Sdes __func__, c->self, chost, cport); 967204917Sdes 968204917Sdes /* Gather fds from client */ 969204917Sdes for(i = 0; i < 2; i++) { 970204917Sdes if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { 971204917Sdes error("%s: failed to receive fd %d from slave", 972204917Sdes __func__, i); 973204917Sdes for (j = 0; j < i; j++) 974204917Sdes close(new_fd[j]); 975255767Sdes free(chost); 976204917Sdes 977204917Sdes /* prepare reply */ 978204917Sdes buffer_put_int(r, MUX_S_FAILURE); 979204917Sdes buffer_put_int(r, rid); 980204917Sdes buffer_put_cstring(r, 981204917Sdes "did not receive file descriptors"); 982204917Sdes return -1; 983204917Sdes } 984204917Sdes } 985204917Sdes 986204917Sdes debug3("%s: got fds stdin %d, stdout %d", __func__, 987204917Sdes new_fd[0], new_fd[1]); 988204917Sdes 989204917Sdes /* XXX support multiple child sessions in future */ 990204917Sdes if (c->remote_id != -1) { 991204917Sdes debug2("%s: session already open", __func__); 992204917Sdes /* prepare reply */ 993204917Sdes buffer_put_int(r, MUX_S_FAILURE); 994204917Sdes buffer_put_int(r, rid); 995204917Sdes buffer_put_cstring(r, "Multiple sessions not supported"); 996204917Sdes cleanup: 997204917Sdes close(new_fd[0]); 998204917Sdes close(new_fd[1]); 999255767Sdes free(chost); 1000204917Sdes return 0; 1001204917Sdes } 1002204917Sdes 1003204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 1004204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 1005221420Sdes if (!ask_permission("Allow forward to %s:%u? ", 1006204917Sdes chost, cport)) { 1007204917Sdes debug2("%s: stdio fwd refused by user", __func__); 1008204917Sdes /* prepare reply */ 1009204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 1010204917Sdes buffer_put_int(r, rid); 1011204917Sdes buffer_put_cstring(r, "Permission denied"); 1012204917Sdes goto cleanup; 1013204917Sdes } 1014204917Sdes } 1015204917Sdes 1016204917Sdes /* enable nonblocking unless tty */ 1017204917Sdes if (!isatty(new_fd[0])) 1018204917Sdes set_nonblock(new_fd[0]); 1019204917Sdes if (!isatty(new_fd[1])) 1020204917Sdes set_nonblock(new_fd[1]); 1021204917Sdes 1022204917Sdes nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]); 1023204917Sdes 1024204917Sdes nc->ctl_chan = c->self; /* link session -> control channel */ 1025204917Sdes c->remote_id = nc->self; /* link control -> session channel */ 1026204917Sdes 1027204917Sdes debug2("%s: channel_new: %d linked to control channel %d", 1028204917Sdes __func__, nc->self, nc->ctl_chan); 1029204917Sdes 1030215116Sdes channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); 1031204917Sdes 1032294328Sdes cctx = xcalloc(1, sizeof(*cctx)); 1033294328Sdes cctx->rid = rid; 1034294328Sdes channel_register_open_confirm(nc->self, mux_stdio_confirm, cctx); 1035294328Sdes c->mux_pause = 1; /* stop handling messages until open_confirm done */ 1036204917Sdes 1037294328Sdes /* reply is deferred, sent by mux_session_confirm */ 1038204917Sdes return 0; 1039204917Sdes} 1040204917Sdes 1041294328Sdes/* Callback on open confirmation in mux master for a mux stdio fwd session. */ 1042294328Sdesstatic void 1043294328Sdesmux_stdio_confirm(int id, int success, void *arg) 1044294328Sdes{ 1045294328Sdes struct mux_stdio_confirm_ctx *cctx = arg; 1046294328Sdes Channel *c, *cc; 1047294328Sdes Buffer reply; 1048294328Sdes 1049294328Sdes if (cctx == NULL) 1050294328Sdes fatal("%s: cctx == NULL", __func__); 1051294328Sdes if ((c = channel_by_id(id)) == NULL) 1052294328Sdes fatal("%s: no channel for id %d", __func__, id); 1053294328Sdes if ((cc = channel_by_id(c->ctl_chan)) == NULL) 1054294328Sdes fatal("%s: channel %d lacks control channel %d", __func__, 1055294328Sdes id, c->ctl_chan); 1056294328Sdes 1057294328Sdes if (!success) { 1058294328Sdes debug3("%s: sending failure reply", __func__); 1059294328Sdes /* prepare reply */ 1060294328Sdes buffer_init(&reply); 1061294328Sdes buffer_put_int(&reply, MUX_S_FAILURE); 1062294328Sdes buffer_put_int(&reply, cctx->rid); 1063294328Sdes buffer_put_cstring(&reply, "Session open refused by peer"); 1064294328Sdes goto done; 1065294328Sdes } 1066294328Sdes 1067294328Sdes debug3("%s: sending success reply", __func__); 1068294328Sdes /* prepare reply */ 1069294328Sdes buffer_init(&reply); 1070294328Sdes buffer_put_int(&reply, MUX_S_SESSION_OPENED); 1071294328Sdes buffer_put_int(&reply, cctx->rid); 1072294328Sdes buffer_put_int(&reply, c->self); 1073294328Sdes 1074294328Sdes done: 1075294328Sdes /* Send reply */ 1076294328Sdes buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); 1077294328Sdes buffer_free(&reply); 1078294328Sdes 1079294328Sdes if (cc->mux_pause <= 0) 1080294328Sdes fatal("%s: mux_pause %d", __func__, cc->mux_pause); 1081294328Sdes cc->mux_pause = 0; /* start processing messages again */ 1082294328Sdes c->open_confirm_ctx = NULL; 1083294328Sdes free(cctx); 1084294328Sdes} 1085294328Sdes 1086226046Sdesstatic int 1087226046Sdesprocess_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r) 1088226046Sdes{ 1089226046Sdes debug("%s: channel %d: stop listening", __func__, c->self); 1090226046Sdes 1091226046Sdes if (options.control_master == SSHCTL_MASTER_ASK || 1092226046Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 1093226046Sdes if (!ask_permission("Disable further multiplexing on shared " 1094226046Sdes "connection to %s? ", host)) { 1095226046Sdes debug2("%s: stop listen refused by user", __func__); 1096226046Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 1097226046Sdes buffer_put_int(r, rid); 1098226046Sdes buffer_put_cstring(r, "Permission denied"); 1099226046Sdes return 0; 1100226046Sdes } 1101226046Sdes } 1102226046Sdes 1103226046Sdes if (mux_listener_channel != NULL) { 1104226046Sdes channel_free(mux_listener_channel); 1105226046Sdes client_stop_mux(); 1106255767Sdes free(options.control_path); 1107226046Sdes options.control_path = NULL; 1108226046Sdes mux_listener_channel = NULL; 1109226046Sdes muxserver_sock = -1; 1110226046Sdes } 1111226046Sdes 1112226046Sdes /* prepare reply */ 1113226046Sdes buffer_put_int(r, MUX_S_OK); 1114226046Sdes buffer_put_int(r, rid); 1115226046Sdes 1116226046Sdes return 0; 1117226046Sdes} 1118226046Sdes 1119323134Sdesstatic int 1120323134Sdesprocess_mux_proxy(u_int rid, Channel *c, Buffer *m, Buffer *r) 1121323134Sdes{ 1122323134Sdes debug("%s: channel %d: proxy request", __func__, c->self); 1123323134Sdes 1124323134Sdes c->mux_rcb = channel_proxy_downstream; 1125323134Sdes buffer_put_int(r, MUX_S_PROXY); 1126323134Sdes buffer_put_int(r, rid); 1127323134Sdes 1128323134Sdes return 0; 1129323134Sdes} 1130323134Sdes 1131204917Sdes/* Channel callbacks fired on read/write from mux slave fd */ 1132204917Sdesstatic int 1133204917Sdesmux_master_read_cb(Channel *c) 1134204917Sdes{ 1135204917Sdes struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; 1136204917Sdes Buffer in, out; 1137294328Sdes const u_char *ptr; 1138204917Sdes u_int type, rid, have, i; 1139204917Sdes int ret = -1; 1140204917Sdes 1141204917Sdes /* Setup ctx and */ 1142204917Sdes if (c->mux_ctx == NULL) { 1143215116Sdes state = xcalloc(1, sizeof(*state)); 1144204917Sdes c->mux_ctx = state; 1145204917Sdes channel_register_cleanup(c->self, 1146204917Sdes mux_master_control_cleanup_cb, 0); 1147204917Sdes 1148204917Sdes /* Send hello */ 1149204917Sdes buffer_init(&out); 1150204917Sdes buffer_put_int(&out, MUX_MSG_HELLO); 1151204917Sdes buffer_put_int(&out, SSHMUX_VER); 1152204917Sdes /* no extensions */ 1153204917Sdes buffer_put_string(&c->output, buffer_ptr(&out), 1154204917Sdes buffer_len(&out)); 1155204917Sdes buffer_free(&out); 1156204917Sdes debug3("%s: channel %d: hello sent", __func__, c->self); 1157204917Sdes return 0; 1158204917Sdes } 1159204917Sdes 1160204917Sdes buffer_init(&in); 1161204917Sdes buffer_init(&out); 1162204917Sdes 1163204917Sdes /* Channel code ensures that we receive whole packets */ 1164204917Sdes if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) { 1165204917Sdes malf: 1166204917Sdes error("%s: malformed message", __func__); 1167204917Sdes goto out; 1168204917Sdes } 1169204917Sdes buffer_append(&in, ptr, have); 1170204917Sdes 1171204917Sdes if (buffer_get_int_ret(&type, &in) != 0) 1172204917Sdes goto malf; 1173204917Sdes debug3("%s: channel %d packet type 0x%08x len %u", 1174204917Sdes __func__, c->self, type, buffer_len(&in)); 1175204917Sdes 1176204917Sdes if (type == MUX_MSG_HELLO) 1177204917Sdes rid = 0; 1178204917Sdes else { 1179204917Sdes if (!state->hello_rcvd) { 1180204917Sdes error("%s: expected MUX_MSG_HELLO(0x%08x), " 1181204917Sdes "received 0x%08x", __func__, MUX_MSG_HELLO, type); 1182204917Sdes goto out; 1183204917Sdes } 1184204917Sdes if (buffer_get_int_ret(&rid, &in) != 0) 1185204917Sdes goto malf; 1186204917Sdes } 1187204917Sdes 1188204917Sdes for (i = 0; mux_master_handlers[i].handler != NULL; i++) { 1189204917Sdes if (type == mux_master_handlers[i].type) { 1190204917Sdes ret = mux_master_handlers[i].handler(rid, c, &in, &out); 1191204917Sdes break; 1192204917Sdes } 1193204917Sdes } 1194204917Sdes if (mux_master_handlers[i].handler == NULL) { 1195204917Sdes error("%s: unsupported mux message 0x%08x", __func__, type); 1196204917Sdes buffer_put_int(&out, MUX_S_FAILURE); 1197204917Sdes buffer_put_int(&out, rid); 1198204917Sdes buffer_put_cstring(&out, "unsupported request"); 1199204917Sdes ret = 0; 1200204917Sdes } 1201204917Sdes /* Enqueue reply packet */ 1202204917Sdes if (buffer_len(&out) != 0) { 1203204917Sdes buffer_put_string(&c->output, buffer_ptr(&out), 1204204917Sdes buffer_len(&out)); 1205204917Sdes } 1206204917Sdes out: 1207204917Sdes buffer_free(&in); 1208204917Sdes buffer_free(&out); 1209204917Sdes return ret; 1210204917Sdes} 1211204917Sdes 1212204917Sdesvoid 1213204917Sdesmux_exit_message(Channel *c, int exitval) 1214204917Sdes{ 1215204917Sdes Buffer m; 1216204917Sdes Channel *mux_chan; 1217204917Sdes 1218255767Sdes debug3("%s: channel %d: exit message, exitval %d", __func__, c->self, 1219204917Sdes exitval); 1220204917Sdes 1221204917Sdes if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) 1222204917Sdes fatal("%s: channel %d missing mux channel %d", 1223204917Sdes __func__, c->self, c->ctl_chan); 1224204917Sdes 1225204917Sdes /* Append exit message packet to control socket output queue */ 1226204917Sdes buffer_init(&m); 1227204917Sdes buffer_put_int(&m, MUX_S_EXIT_MESSAGE); 1228204917Sdes buffer_put_int(&m, c->self); 1229204917Sdes buffer_put_int(&m, exitval); 1230204917Sdes 1231204917Sdes buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); 1232204917Sdes buffer_free(&m); 1233204917Sdes} 1234204917Sdes 1235226046Sdesvoid 1236226046Sdesmux_tty_alloc_failed(Channel *c) 1237226046Sdes{ 1238226046Sdes Buffer m; 1239226046Sdes Channel *mux_chan; 1240226046Sdes 1241226046Sdes debug3("%s: channel %d: TTY alloc failed", __func__, c->self); 1242226046Sdes 1243226046Sdes if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) 1244226046Sdes fatal("%s: channel %d missing mux channel %d", 1245226046Sdes __func__, c->self, c->ctl_chan); 1246226046Sdes 1247226046Sdes /* Append exit message packet to control socket output queue */ 1248226046Sdes buffer_init(&m); 1249226046Sdes buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL); 1250226046Sdes buffer_put_int(&m, c->self); 1251226046Sdes 1252226046Sdes buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); 1253226046Sdes buffer_free(&m); 1254226046Sdes} 1255226046Sdes 1256180750Sdes/* Prepare a mux master to listen on a Unix domain socket. */ 1257180750Sdesvoid 1258180750Sdesmuxserver_listen(void) 1259180750Sdes{ 1260180750Sdes mode_t old_umask; 1261221420Sdes char *orig_control_path = options.control_path; 1262221420Sdes char rbuf[16+1]; 1263221420Sdes u_int i, r; 1264294328Sdes int oerrno; 1265180750Sdes 1266180750Sdes if (options.control_path == NULL || 1267180750Sdes options.control_master == SSHCTL_MASTER_NO) 1268180750Sdes return; 1269180750Sdes 1270180750Sdes debug("setting up multiplex master socket"); 1271180750Sdes 1272221420Sdes /* 1273221420Sdes * Use a temporary path before listen so we can pseudo-atomically 1274221420Sdes * establish the listening socket in its final location to avoid 1275221420Sdes * other processes racing in between bind() and listen() and hitting 1276221420Sdes * an unready socket. 1277221420Sdes */ 1278221420Sdes for (i = 0; i < sizeof(rbuf) - 1; i++) { 1279221420Sdes r = arc4random_uniform(26+26+10); 1280221420Sdes rbuf[i] = (r < 26) ? 'a' + r : 1281221420Sdes (r < 26*2) ? 'A' + r - 26 : 1282221420Sdes '0' + r - 26 - 26; 1283221420Sdes } 1284221420Sdes rbuf[sizeof(rbuf) - 1] = '\0'; 1285221420Sdes options.control_path = NULL; 1286221420Sdes xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf); 1287221420Sdes debug3("%s: temporary control path %s", __func__, options.control_path); 1288221420Sdes 1289180750Sdes old_umask = umask(0177); 1290294328Sdes muxserver_sock = unix_listener(options.control_path, 64, 0); 1291294328Sdes oerrno = errno; 1292294328Sdes umask(old_umask); 1293294328Sdes if (muxserver_sock < 0) { 1294294328Sdes if (oerrno == EINVAL || oerrno == EADDRINUSE) { 1295180750Sdes error("ControlSocket %s already exists, " 1296180750Sdes "disabling multiplexing", options.control_path); 1297221420Sdes disable_mux_master: 1298226046Sdes if (muxserver_sock != -1) { 1299226046Sdes close(muxserver_sock); 1300226046Sdes muxserver_sock = -1; 1301226046Sdes } 1302255767Sdes free(orig_control_path); 1303255767Sdes free(options.control_path); 1304180750Sdes options.control_path = NULL; 1305180750Sdes options.control_master = SSHCTL_MASTER_NO; 1306180750Sdes return; 1307294328Sdes } else { 1308294328Sdes /* unix_listener() logs the error */ 1309294328Sdes cleanup_exit(255); 1310294328Sdes } 1311180750Sdes } 1312180750Sdes 1313221420Sdes /* Now atomically "move" the mux socket into position */ 1314221420Sdes if (link(options.control_path, orig_control_path) != 0) { 1315221420Sdes if (errno != EEXIST) { 1316323129Sdes fatal("%s: link mux listener %s => %s: %s", __func__, 1317221420Sdes options.control_path, orig_control_path, 1318221420Sdes strerror(errno)); 1319221420Sdes } 1320221420Sdes error("ControlSocket %s already exists, disabling multiplexing", 1321221420Sdes orig_control_path); 1322221420Sdes unlink(options.control_path); 1323221420Sdes goto disable_mux_master; 1324221420Sdes } 1325221420Sdes unlink(options.control_path); 1326255767Sdes free(options.control_path); 1327221420Sdes options.control_path = orig_control_path; 1328221420Sdes 1329180750Sdes set_nonblock(muxserver_sock); 1330204917Sdes 1331204917Sdes mux_listener_channel = channel_new("mux listener", 1332204917Sdes SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, 1333204917Sdes CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 1334221420Sdes 0, options.control_path, 1); 1335204917Sdes mux_listener_channel->mux_rcb = mux_master_read_cb; 1336204917Sdes debug3("%s: mux listener channel %d fd %d", __func__, 1337204917Sdes mux_listener_channel->self, mux_listener_channel->sock); 1338180750Sdes} 1339180750Sdes 1340180750Sdes/* Callback on open confirmation in mux master for a mux client session. */ 1341180750Sdesstatic void 1342215116Sdesmux_session_confirm(int id, int success, void *arg) 1343180750Sdes{ 1344180750Sdes struct mux_session_confirm_ctx *cctx = arg; 1345180750Sdes const char *display; 1346215116Sdes Channel *c, *cc; 1347180750Sdes int i; 1348215116Sdes Buffer reply; 1349180750Sdes 1350180750Sdes if (cctx == NULL) 1351180750Sdes fatal("%s: cctx == NULL", __func__); 1352204917Sdes if ((c = channel_by_id(id)) == NULL) 1353180750Sdes fatal("%s: no channel for id %d", __func__, id); 1354215116Sdes if ((cc = channel_by_id(c->ctl_chan)) == NULL) 1355215116Sdes fatal("%s: channel %d lacks control channel %d", __func__, 1356215116Sdes id, c->ctl_chan); 1357180750Sdes 1358215116Sdes if (!success) { 1359215116Sdes debug3("%s: sending failure reply", __func__); 1360215116Sdes /* prepare reply */ 1361215116Sdes buffer_init(&reply); 1362215116Sdes buffer_put_int(&reply, MUX_S_FAILURE); 1363215116Sdes buffer_put_int(&reply, cctx->rid); 1364215116Sdes buffer_put_cstring(&reply, "Session open refused by peer"); 1365215116Sdes goto done; 1366215116Sdes } 1367215116Sdes 1368180750Sdes display = getenv("DISPLAY"); 1369180750Sdes if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { 1370180750Sdes char *proto, *data; 1371215116Sdes 1372180750Sdes /* Get reasonable local authentication information. */ 1373296633Sdes if (client_x11_get_proto(display, options.xauth_location, 1374215116Sdes options.forward_x11_trusted, options.forward_x11_timeout, 1375296633Sdes &proto, &data) == 0) { 1376296633Sdes /* Request forwarding with authentication spoofing. */ 1377296633Sdes debug("Requesting X11 forwarding with authentication " 1378296633Sdes "spoofing."); 1379296633Sdes x11_request_forwarding_with_spoofing(id, display, proto, 1380296633Sdes data, 1); 1381296633Sdes /* XXX exit_on_forward_failure */ 1382296633Sdes client_expect_confirm(id, "X11 forwarding", 1383296633Sdes CONFIRM_WARN); 1384296633Sdes } 1385180750Sdes } 1386180750Sdes 1387180750Sdes if (cctx->want_agent_fwd && options.forward_agent) { 1388180750Sdes debug("Requesting authentication agent forwarding."); 1389180750Sdes channel_request_start(id, "auth-agent-req@openssh.com", 0); 1390180750Sdes packet_send(); 1391180750Sdes } 1392180750Sdes 1393180750Sdes client_session2_setup(id, cctx->want_tty, cctx->want_subsys, 1394180750Sdes cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); 1395180750Sdes 1396215116Sdes debug3("%s: sending success reply", __func__); 1397215116Sdes /* prepare reply */ 1398215116Sdes buffer_init(&reply); 1399215116Sdes buffer_put_int(&reply, MUX_S_SESSION_OPENED); 1400215116Sdes buffer_put_int(&reply, cctx->rid); 1401215116Sdes buffer_put_int(&reply, c->self); 1402215116Sdes 1403215116Sdes done: 1404215116Sdes /* Send reply */ 1405215116Sdes buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); 1406215116Sdes buffer_free(&reply); 1407215116Sdes 1408215116Sdes if (cc->mux_pause <= 0) 1409215116Sdes fatal("%s: mux_pause %d", __func__, cc->mux_pause); 1410215116Sdes cc->mux_pause = 0; /* start processing messages again */ 1411180750Sdes c->open_confirm_ctx = NULL; 1412180750Sdes buffer_free(&cctx->cmd); 1413255767Sdes free(cctx->term); 1414180750Sdes if (cctx->env != NULL) { 1415180750Sdes for (i = 0; cctx->env[i] != NULL; i++) 1416255767Sdes free(cctx->env[i]); 1417255767Sdes free(cctx->env); 1418180750Sdes } 1419255767Sdes free(cctx); 1420180750Sdes} 1421180750Sdes 1422204917Sdes/* ** Multiplexing client support */ 1423204917Sdes 1424204917Sdes/* Exit signal handler */ 1425204917Sdesstatic void 1426204917Sdescontrol_client_sighandler(int signo) 1427204917Sdes{ 1428204917Sdes muxclient_terminate = signo; 1429204917Sdes} 1430204917Sdes 1431180750Sdes/* 1432204917Sdes * Relay signal handler - used to pass some signals from mux client to 1433204917Sdes * mux master. 1434180750Sdes */ 1435204917Sdesstatic void 1436204917Sdescontrol_client_sigrelay(int signo) 1437180750Sdes{ 1438204917Sdes int save_errno = errno; 1439180750Sdes 1440204917Sdes if (muxserver_pid > 1) 1441204917Sdes kill(muxserver_pid, signo); 1442204917Sdes 1443204917Sdes errno = save_errno; 1444204917Sdes} 1445204917Sdes 1446204917Sdesstatic int 1447204917Sdesmux_client_read(int fd, Buffer *b, u_int need) 1448204917Sdes{ 1449204917Sdes u_int have; 1450204917Sdes ssize_t len; 1451204917Sdes u_char *p; 1452204917Sdes struct pollfd pfd; 1453204917Sdes 1454204917Sdes pfd.fd = fd; 1455204917Sdes pfd.events = POLLIN; 1456204917Sdes p = buffer_append_space(b, need); 1457204917Sdes for (have = 0; have < need; ) { 1458204917Sdes if (muxclient_terminate) { 1459204917Sdes errno = EINTR; 1460204917Sdes return -1; 1461204917Sdes } 1462204917Sdes len = read(fd, p + have, need - have); 1463204917Sdes if (len < 0) { 1464204917Sdes switch (errno) { 1465204917Sdes#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) 1466204917Sdes case EWOULDBLOCK: 1467204917Sdes#endif 1468204917Sdes case EAGAIN: 1469204917Sdes (void)poll(&pfd, 1, -1); 1470204917Sdes /* FALLTHROUGH */ 1471204917Sdes case EINTR: 1472204917Sdes continue; 1473204917Sdes default: 1474204917Sdes return -1; 1475204917Sdes } 1476204917Sdes } 1477204917Sdes if (len == 0) { 1478204917Sdes errno = EPIPE; 1479204917Sdes return -1; 1480204917Sdes } 1481204917Sdes have += (u_int)len; 1482180750Sdes } 1483204917Sdes return 0; 1484204917Sdes} 1485180750Sdes 1486204917Sdesstatic int 1487204917Sdesmux_client_write_packet(int fd, Buffer *m) 1488204917Sdes{ 1489204917Sdes Buffer queue; 1490204917Sdes u_int have, need; 1491204917Sdes int oerrno, len; 1492204917Sdes u_char *ptr; 1493204917Sdes struct pollfd pfd; 1494204917Sdes 1495204917Sdes pfd.fd = fd; 1496204917Sdes pfd.events = POLLOUT; 1497204917Sdes buffer_init(&queue); 1498204917Sdes buffer_put_string(&queue, buffer_ptr(m), buffer_len(m)); 1499204917Sdes 1500204917Sdes need = buffer_len(&queue); 1501204917Sdes ptr = buffer_ptr(&queue); 1502204917Sdes 1503204917Sdes for (have = 0; have < need; ) { 1504204917Sdes if (muxclient_terminate) { 1505204917Sdes buffer_free(&queue); 1506204917Sdes errno = EINTR; 1507204917Sdes return -1; 1508204917Sdes } 1509204917Sdes len = write(fd, ptr + have, need - have); 1510204917Sdes if (len < 0) { 1511204917Sdes switch (errno) { 1512204917Sdes#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) 1513204917Sdes case EWOULDBLOCK: 1514204917Sdes#endif 1515204917Sdes case EAGAIN: 1516204917Sdes (void)poll(&pfd, 1, -1); 1517204917Sdes /* FALLTHROUGH */ 1518204917Sdes case EINTR: 1519204917Sdes continue; 1520204917Sdes default: 1521204917Sdes oerrno = errno; 1522204917Sdes buffer_free(&queue); 1523204917Sdes errno = oerrno; 1524204917Sdes return -1; 1525204917Sdes } 1526204917Sdes } 1527204917Sdes if (len == 0) { 1528204917Sdes buffer_free(&queue); 1529204917Sdes errno = EPIPE; 1530204917Sdes return -1; 1531204917Sdes } 1532204917Sdes have += (u_int)len; 1533180750Sdes } 1534204917Sdes buffer_free(&queue); 1535204917Sdes return 0; 1536204917Sdes} 1537204917Sdes 1538204917Sdesstatic int 1539204917Sdesmux_client_read_packet(int fd, Buffer *m) 1540204917Sdes{ 1541204917Sdes Buffer queue; 1542204917Sdes u_int need, have; 1543294328Sdes const u_char *ptr; 1544204917Sdes int oerrno; 1545204917Sdes 1546204917Sdes buffer_init(&queue); 1547204917Sdes if (mux_client_read(fd, &queue, 4) != 0) { 1548204917Sdes if ((oerrno = errno) == EPIPE) 1549255767Sdes debug3("%s: read header failed: %s", __func__, 1550255767Sdes strerror(errno)); 1551255767Sdes buffer_free(&queue); 1552204917Sdes errno = oerrno; 1553204917Sdes return -1; 1554180750Sdes } 1555204917Sdes need = get_u32(buffer_ptr(&queue)); 1556204917Sdes if (mux_client_read(fd, &queue, need) != 0) { 1557204917Sdes oerrno = errno; 1558204917Sdes debug3("%s: read body failed: %s", __func__, strerror(errno)); 1559255767Sdes buffer_free(&queue); 1560204917Sdes errno = oerrno; 1561204917Sdes return -1; 1562204917Sdes } 1563204917Sdes ptr = buffer_get_string_ptr(&queue, &have); 1564204917Sdes buffer_append(m, ptr, have); 1565204917Sdes buffer_free(&queue); 1566204917Sdes return 0; 1567204917Sdes} 1568180750Sdes 1569204917Sdesstatic int 1570204917Sdesmux_client_hello_exchange(int fd) 1571204917Sdes{ 1572204917Sdes Buffer m; 1573204917Sdes u_int type, ver; 1574180750Sdes 1575180750Sdes buffer_init(&m); 1576204917Sdes buffer_put_int(&m, MUX_MSG_HELLO); 1577204917Sdes buffer_put_int(&m, SSHMUX_VER); 1578204917Sdes /* no extensions */ 1579204917Sdes 1580204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1581204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1582204917Sdes 1583204917Sdes buffer_clear(&m); 1584204917Sdes 1585204917Sdes /* Read their HELLO */ 1586204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1587180750Sdes buffer_free(&m); 1588204917Sdes return -1; 1589180750Sdes } 1590204917Sdes 1591204917Sdes type = buffer_get_int(&m); 1592204917Sdes if (type != MUX_MSG_HELLO) 1593204917Sdes fatal("%s: expected HELLO (%u) received %u", 1594204917Sdes __func__, MUX_MSG_HELLO, type); 1595204917Sdes ver = buffer_get_int(&m); 1596204917Sdes if (ver != SSHMUX_VER) 1597204917Sdes fatal("Unsupported multiplexing protocol version %d " 1598204917Sdes "(expected %d)", ver, SSHMUX_VER); 1599204917Sdes debug2("%s: master version %u", __func__, ver); 1600204917Sdes /* No extensions are presently defined */ 1601204917Sdes while (buffer_len(&m) > 0) { 1602204917Sdes char *name = buffer_get_string(&m, NULL); 1603204917Sdes char *value = buffer_get_string(&m, NULL); 1604204917Sdes 1605204917Sdes debug2("Unrecognised master extension \"%s\"", name); 1606255767Sdes free(name); 1607255767Sdes free(value); 1608204917Sdes } 1609204917Sdes buffer_free(&m); 1610204917Sdes return 0; 1611204917Sdes} 1612204917Sdes 1613204917Sdesstatic u_int 1614204917Sdesmux_client_request_alive(int fd) 1615204917Sdes{ 1616204917Sdes Buffer m; 1617204917Sdes char *e; 1618204917Sdes u_int pid, type, rid; 1619204917Sdes 1620204917Sdes debug3("%s: entering", __func__); 1621204917Sdes 1622204917Sdes buffer_init(&m); 1623204917Sdes buffer_put_int(&m, MUX_C_ALIVE_CHECK); 1624204917Sdes buffer_put_int(&m, muxclient_request_id); 1625204917Sdes 1626204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1627204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1628204917Sdes 1629204917Sdes buffer_clear(&m); 1630204917Sdes 1631204917Sdes /* Read their reply */ 1632204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1633180750Sdes buffer_free(&m); 1634180750Sdes return 0; 1635180750Sdes } 1636180750Sdes 1637204917Sdes type = buffer_get_int(&m); 1638204917Sdes if (type != MUX_S_ALIVE) { 1639204917Sdes e = buffer_get_string(&m, NULL); 1640204917Sdes fatal("%s: master returned error: %s", __func__, e); 1641204917Sdes } 1642180750Sdes 1643204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1644204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1645204917Sdes __func__, muxclient_request_id, rid); 1646204917Sdes pid = buffer_get_int(&m); 1647204917Sdes buffer_free(&m); 1648204917Sdes 1649204917Sdes debug3("%s: done pid = %u", __func__, pid); 1650204917Sdes 1651204917Sdes muxclient_request_id++; 1652204917Sdes 1653204917Sdes return pid; 1654204917Sdes} 1655204917Sdes 1656204917Sdesstatic void 1657204917Sdesmux_client_request_terminate(int fd) 1658204917Sdes{ 1659204917Sdes Buffer m; 1660204917Sdes char *e; 1661204917Sdes u_int type, rid; 1662204917Sdes 1663204917Sdes debug3("%s: entering", __func__); 1664204917Sdes 1665204917Sdes buffer_init(&m); 1666204917Sdes buffer_put_int(&m, MUX_C_TERMINATE); 1667204917Sdes buffer_put_int(&m, muxclient_request_id); 1668204917Sdes 1669204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1670204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1671204917Sdes 1672180750Sdes buffer_clear(&m); 1673180750Sdes 1674204917Sdes /* Read their reply */ 1675204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1676204917Sdes /* Remote end exited already */ 1677204917Sdes if (errno == EPIPE) { 1678180750Sdes buffer_free(&m); 1679204917Sdes return; 1680180750Sdes } 1681204917Sdes fatal("%s: read from master failed: %s", 1682204917Sdes __func__, strerror(errno)); 1683204917Sdes } 1684204917Sdes 1685204917Sdes type = buffer_get_int(&m); 1686204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1687204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1688204917Sdes __func__, muxclient_request_id, rid); 1689204917Sdes switch (type) { 1690204917Sdes case MUX_S_OK: 1691204917Sdes break; 1692204917Sdes case MUX_S_PERMISSION_DENIED: 1693204917Sdes e = buffer_get_string(&m, NULL); 1694204917Sdes fatal("Master refused termination request: %s", e); 1695204917Sdes case MUX_S_FAILURE: 1696204917Sdes e = buffer_get_string(&m, NULL); 1697204917Sdes fatal("%s: termination request failed: %s", __func__, e); 1698180750Sdes default: 1699204917Sdes fatal("%s: unexpected response from master 0x%08x", 1700204917Sdes __func__, type); 1701180750Sdes } 1702204917Sdes buffer_free(&m); 1703204917Sdes muxclient_request_id++; 1704204917Sdes} 1705180750Sdes 1706204917Sdesstatic int 1707294328Sdesmux_client_forward(int fd, int cancel_flag, u_int ftype, struct Forward *fwd) 1708204917Sdes{ 1709204917Sdes Buffer m; 1710204917Sdes char *e, *fwd_desc; 1711204917Sdes u_int type, rid; 1712204917Sdes 1713204917Sdes fwd_desc = format_forward(ftype, fwd); 1714240075Sdes debug("Requesting %s %s", 1715240075Sdes cancel_flag ? "cancellation of" : "forwarding of", fwd_desc); 1716255767Sdes free(fwd_desc); 1717204917Sdes 1718204917Sdes buffer_init(&m); 1719240075Sdes buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD); 1720204917Sdes buffer_put_int(&m, muxclient_request_id); 1721204917Sdes buffer_put_int(&m, ftype); 1722294328Sdes if (fwd->listen_path != NULL) { 1723294328Sdes buffer_put_cstring(&m, fwd->listen_path); 1724294328Sdes } else { 1725294328Sdes buffer_put_cstring(&m, 1726294332Sdes fwd->listen_host == NULL ? "" : 1727294332Sdes (*fwd->listen_host == '\0' ? "*" : fwd->listen_host)); 1728294328Sdes } 1729204917Sdes buffer_put_int(&m, fwd->listen_port); 1730294328Sdes if (fwd->connect_path != NULL) { 1731294328Sdes buffer_put_cstring(&m, fwd->connect_path); 1732294328Sdes } else { 1733294328Sdes buffer_put_cstring(&m, 1734294328Sdes fwd->connect_host == NULL ? "" : fwd->connect_host); 1735294328Sdes } 1736204917Sdes buffer_put_int(&m, fwd->connect_port); 1737204917Sdes 1738204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1739204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1740204917Sdes 1741180750Sdes buffer_clear(&m); 1742204917Sdes 1743204917Sdes /* Read their reply */ 1744204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1745180750Sdes buffer_free(&m); 1746204917Sdes return -1; 1747180750Sdes } 1748180750Sdes 1749204917Sdes type = buffer_get_int(&m); 1750204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1751204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1752204917Sdes __func__, muxclient_request_id, rid); 1753204917Sdes switch (type) { 1754204917Sdes case MUX_S_OK: 1755204917Sdes break; 1756215116Sdes case MUX_S_REMOTE_PORT: 1757240075Sdes if (cancel_flag) 1758240075Sdes fatal("%s: got MUX_S_REMOTE_PORT for cancel", __func__); 1759215116Sdes fwd->allocated_port = buffer_get_int(&m); 1760294336Sdes verbose("Allocated port %u for remote forward to %s:%d", 1761215116Sdes fwd->allocated_port, 1762215116Sdes fwd->connect_host ? fwd->connect_host : "", 1763215116Sdes fwd->connect_port); 1764215116Sdes if (muxclient_command == SSHMUX_COMMAND_FORWARD) 1765296633Sdes fprintf(stdout, "%i\n", fwd->allocated_port); 1766215116Sdes break; 1767204917Sdes case MUX_S_PERMISSION_DENIED: 1768204917Sdes e = buffer_get_string(&m, NULL); 1769180750Sdes buffer_free(&m); 1770204917Sdes error("Master refused forwarding request: %s", e); 1771204917Sdes return -1; 1772204917Sdes case MUX_S_FAILURE: 1773204917Sdes e = buffer_get_string(&m, NULL); 1774204917Sdes buffer_free(&m); 1775221420Sdes error("%s: forwarding request failed: %s", __func__, e); 1776204917Sdes return -1; 1777204917Sdes default: 1778204917Sdes fatal("%s: unexpected response from master 0x%08x", 1779204917Sdes __func__, type); 1780180750Sdes } 1781204917Sdes buffer_free(&m); 1782180750Sdes 1783204917Sdes muxclient_request_id++; 1784204917Sdes return 0; 1785204917Sdes} 1786204917Sdes 1787204917Sdesstatic int 1788240075Sdesmux_client_forwards(int fd, int cancel_flag) 1789204917Sdes{ 1790240075Sdes int i, ret = 0; 1791204917Sdes 1792240075Sdes debug3("%s: %s forwardings: %d local, %d remote", __func__, 1793240075Sdes cancel_flag ? "cancel" : "request", 1794204917Sdes options.num_local_forwards, options.num_remote_forwards); 1795204917Sdes 1796204917Sdes /* XXX ExitOnForwardingFailure */ 1797204917Sdes for (i = 0; i < options.num_local_forwards; i++) { 1798240075Sdes if (mux_client_forward(fd, cancel_flag, 1799204917Sdes options.local_forwards[i].connect_port == 0 ? 1800204917Sdes MUX_FWD_DYNAMIC : MUX_FWD_LOCAL, 1801204917Sdes options.local_forwards + i) != 0) 1802240075Sdes ret = -1; 1803180750Sdes } 1804204917Sdes for (i = 0; i < options.num_remote_forwards; i++) { 1805240075Sdes if (mux_client_forward(fd, cancel_flag, MUX_FWD_REMOTE, 1806204917Sdes options.remote_forwards + i) != 0) 1807240075Sdes ret = -1; 1808180750Sdes } 1809240075Sdes return ret; 1810204917Sdes} 1811180750Sdes 1812204917Sdesstatic int 1813204917Sdesmux_client_request_session(int fd) 1814204917Sdes{ 1815204917Sdes Buffer m; 1816204917Sdes char *e, *term; 1817204917Sdes u_int i, rid, sid, esid, exitval, type, exitval_seen; 1818204917Sdes extern char **environ; 1819226046Sdes int devnull, rawmode; 1820180750Sdes 1821204917Sdes debug3("%s: entering", __func__); 1822180750Sdes 1823204917Sdes if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { 1824204917Sdes error("%s: master alive request failed", __func__); 1825204917Sdes return -1; 1826180750Sdes } 1827180750Sdes 1828204917Sdes signal(SIGPIPE, SIG_IGN); 1829180750Sdes 1830204917Sdes if (stdin_null_flag) { 1831204917Sdes if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) 1832204917Sdes fatal("open(/dev/null): %s", strerror(errno)); 1833204917Sdes if (dup2(devnull, STDIN_FILENO) == -1) 1834204917Sdes fatal("dup2: %s", strerror(errno)); 1835204917Sdes if (devnull > STDERR_FILENO) 1836204917Sdes close(devnull); 1837180750Sdes } 1838180750Sdes 1839204917Sdes term = getenv("TERM"); 1840180750Sdes 1841204917Sdes buffer_init(&m); 1842204917Sdes buffer_put_int(&m, MUX_C_NEW_SESSION); 1843204917Sdes buffer_put_int(&m, muxclient_request_id); 1844204917Sdes buffer_put_cstring(&m, ""); /* reserved */ 1845204917Sdes buffer_put_int(&m, tty_flag); 1846204917Sdes buffer_put_int(&m, options.forward_x11); 1847204917Sdes buffer_put_int(&m, options.forward_agent); 1848204917Sdes buffer_put_int(&m, subsystem_flag); 1849204917Sdes buffer_put_int(&m, options.escape_char == SSH_ESCAPECHAR_NONE ? 1850204917Sdes 0xffffffff : (u_int)options.escape_char); 1851204917Sdes buffer_put_cstring(&m, term == NULL ? "" : term); 1852204917Sdes buffer_put_string(&m, buffer_ptr(&command), buffer_len(&command)); 1853180750Sdes 1854204917Sdes if (options.num_send_env > 0 && environ != NULL) { 1855204917Sdes /* Pass environment */ 1856204917Sdes for (i = 0; environ[i] != NULL; i++) { 1857204917Sdes if (env_permitted(environ[i])) { 1858204917Sdes buffer_put_cstring(&m, environ[i]); 1859204917Sdes } 1860180750Sdes } 1861180750Sdes } 1862180750Sdes 1863204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1864204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1865180750Sdes 1866204917Sdes /* Send the stdio file descriptors */ 1867204917Sdes if (mm_send_fd(fd, STDIN_FILENO) == -1 || 1868204917Sdes mm_send_fd(fd, STDOUT_FILENO) == -1 || 1869204917Sdes mm_send_fd(fd, STDERR_FILENO) == -1) 1870204917Sdes fatal("%s: send fds failed", __func__); 1871180750Sdes 1872204917Sdes debug3("%s: session request sent", __func__); 1873204917Sdes 1874204917Sdes /* Read their reply */ 1875204917Sdes buffer_clear(&m); 1876204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1877204917Sdes error("%s: read from master failed: %s", 1878204917Sdes __func__, strerror(errno)); 1879204917Sdes buffer_free(&m); 1880204917Sdes return -1; 1881180750Sdes } 1882180750Sdes 1883204917Sdes type = buffer_get_int(&m); 1884204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1885204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1886204917Sdes __func__, muxclient_request_id, rid); 1887204917Sdes switch (type) { 1888204917Sdes case MUX_S_SESSION_OPENED: 1889204917Sdes sid = buffer_get_int(&m); 1890204917Sdes debug("%s: master session id: %u", __func__, sid); 1891204917Sdes break; 1892204917Sdes case MUX_S_PERMISSION_DENIED: 1893204917Sdes e = buffer_get_string(&m, NULL); 1894204917Sdes buffer_free(&m); 1895221420Sdes error("Master refused session request: %s", e); 1896204917Sdes return -1; 1897204917Sdes case MUX_S_FAILURE: 1898204917Sdes e = buffer_get_string(&m, NULL); 1899204917Sdes buffer_free(&m); 1900221420Sdes error("%s: session request failed: %s", __func__, e); 1901204917Sdes return -1; 1902204917Sdes default: 1903204917Sdes buffer_free(&m); 1904204917Sdes error("%s: unexpected response from master 0x%08x", 1905204917Sdes __func__, type); 1906204917Sdes return -1; 1907180750Sdes } 1908204917Sdes muxclient_request_id++; 1909180750Sdes 1910296633Sdes if (pledge("stdio proc tty", NULL) == -1) 1911296633Sdes fatal("%s pledge(): %s", __func__, strerror(errno)); 1912296633Sdes platform_pledge_mux(); 1913296633Sdes 1914204917Sdes signal(SIGHUP, control_client_sighandler); 1915204917Sdes signal(SIGINT, control_client_sighandler); 1916204917Sdes signal(SIGTERM, control_client_sighandler); 1917204917Sdes signal(SIGWINCH, control_client_sigrelay); 1918180750Sdes 1919226046Sdes rawmode = tty_flag; 1920204917Sdes if (tty_flag) 1921226046Sdes enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); 1922180750Sdes 1923204917Sdes /* 1924204917Sdes * Stick around until the controlee closes the client_fd. 1925204917Sdes * Before it does, it is expected to write an exit message. 1926204917Sdes * This process must read the value and wait for the closure of 1927204917Sdes * the client_fd; if this one closes early, the multiplex master will 1928204917Sdes * terminate early too (possibly losing data). 1929204917Sdes */ 1930204917Sdes for (exitval = 255, exitval_seen = 0;;) { 1931204917Sdes buffer_clear(&m); 1932204917Sdes if (mux_client_read_packet(fd, &m) != 0) 1933204917Sdes break; 1934204917Sdes type = buffer_get_int(&m); 1935226046Sdes switch (type) { 1936226046Sdes case MUX_S_TTY_ALLOC_FAIL: 1937226046Sdes if ((esid = buffer_get_int(&m)) != sid) 1938226046Sdes fatal("%s: tty alloc fail on unknown session: " 1939226046Sdes "my id %u theirs %u", 1940226046Sdes __func__, sid, esid); 1941226046Sdes leave_raw_mode(options.request_tty == 1942226046Sdes REQUEST_TTY_FORCE); 1943226046Sdes rawmode = 0; 1944226046Sdes continue; 1945226046Sdes case MUX_S_EXIT_MESSAGE: 1946226046Sdes if ((esid = buffer_get_int(&m)) != sid) 1947226046Sdes fatal("%s: exit on unknown session: " 1948226046Sdes "my id %u theirs %u", 1949226046Sdes __func__, sid, esid); 1950226046Sdes if (exitval_seen) 1951226046Sdes fatal("%s: exitval sent twice", __func__); 1952226046Sdes exitval = buffer_get_int(&m); 1953226046Sdes exitval_seen = 1; 1954226046Sdes continue; 1955226046Sdes default: 1956204917Sdes e = buffer_get_string(&m, NULL); 1957204917Sdes fatal("%s: master returned error: %s", __func__, e); 1958204917Sdes } 1959204917Sdes } 1960180750Sdes 1961204917Sdes close(fd); 1962226046Sdes if (rawmode) 1963226046Sdes leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); 1964180750Sdes 1965204917Sdes if (muxclient_terminate) { 1966255767Sdes debug2("Exiting on signal %ld", (long)muxclient_terminate); 1967204917Sdes exitval = 255; 1968204917Sdes } else if (!exitval_seen) { 1969204917Sdes debug2("Control master terminated unexpectedly"); 1970204917Sdes exitval = 255; 1971204917Sdes } else 1972204917Sdes debug2("Received exit status from master %d", exitval); 1973180750Sdes 1974204917Sdes if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) 1975204917Sdes fprintf(stderr, "Shared connection to %s closed.\r\n", host); 1976180750Sdes 1977204917Sdes exit(exitval); 1978180750Sdes} 1979180750Sdes 1980180750Sdesstatic int 1981323134Sdesmux_client_proxy(int fd) 1982323134Sdes{ 1983323134Sdes Buffer m; 1984323134Sdes char *e; 1985323134Sdes u_int type, rid; 1986323134Sdes 1987323134Sdes buffer_init(&m); 1988323134Sdes buffer_put_int(&m, MUX_C_PROXY); 1989323134Sdes buffer_put_int(&m, muxclient_request_id); 1990323134Sdes if (mux_client_write_packet(fd, &m) != 0) 1991323134Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1992323134Sdes 1993323134Sdes buffer_clear(&m); 1994323134Sdes 1995323134Sdes /* Read their reply */ 1996323134Sdes if (mux_client_read_packet(fd, &m) != 0) { 1997323134Sdes buffer_free(&m); 1998323134Sdes return 0; 1999323134Sdes } 2000323134Sdes type = buffer_get_int(&m); 2001323134Sdes if (type != MUX_S_PROXY) { 2002323134Sdes e = buffer_get_string(&m, NULL); 2003323134Sdes fatal("%s: master returned error: %s", __func__, e); 2004323134Sdes } 2005323134Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 2006323134Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 2007323134Sdes __func__, muxclient_request_id, rid); 2008323134Sdes buffer_free(&m); 2009323134Sdes 2010323134Sdes debug3("%s: done", __func__); 2011323134Sdes muxclient_request_id++; 2012323134Sdes return 0; 2013323134Sdes} 2014323134Sdes 2015323134Sdesstatic int 2016204917Sdesmux_client_request_stdio_fwd(int fd) 2017180750Sdes{ 2018204917Sdes Buffer m; 2019204917Sdes char *e; 2020204917Sdes u_int type, rid, sid; 2021204917Sdes int devnull; 2022180750Sdes 2023204917Sdes debug3("%s: entering", __func__); 2024180750Sdes 2025204917Sdes if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { 2026204917Sdes error("%s: master alive request failed", __func__); 2027204917Sdes return -1; 2028204917Sdes } 2029180750Sdes 2030204917Sdes signal(SIGPIPE, SIG_IGN); 2031204917Sdes 2032204917Sdes if (stdin_null_flag) { 2033204917Sdes if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) 2034204917Sdes fatal("open(/dev/null): %s", strerror(errno)); 2035204917Sdes if (dup2(devnull, STDIN_FILENO) == -1) 2036204917Sdes fatal("dup2: %s", strerror(errno)); 2037204917Sdes if (devnull > STDERR_FILENO) 2038204917Sdes close(devnull); 2039204917Sdes } 2040204917Sdes 2041204917Sdes buffer_init(&m); 2042204917Sdes buffer_put_int(&m, MUX_C_NEW_STDIO_FWD); 2043204917Sdes buffer_put_int(&m, muxclient_request_id); 2044204917Sdes buffer_put_cstring(&m, ""); /* reserved */ 2045323129Sdes buffer_put_cstring(&m, options.stdio_forward_host); 2046323129Sdes buffer_put_int(&m, options.stdio_forward_port); 2047204917Sdes 2048204917Sdes if (mux_client_write_packet(fd, &m) != 0) 2049204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 2050204917Sdes 2051204917Sdes /* Send the stdio file descriptors */ 2052204917Sdes if (mm_send_fd(fd, STDIN_FILENO) == -1 || 2053204917Sdes mm_send_fd(fd, STDOUT_FILENO) == -1) 2054204917Sdes fatal("%s: send fds failed", __func__); 2055204917Sdes 2056296633Sdes if (pledge("stdio proc tty", NULL) == -1) 2057296633Sdes fatal("%s pledge(): %s", __func__, strerror(errno)); 2058296633Sdes platform_pledge_mux(); 2059296633Sdes 2060204917Sdes debug3("%s: stdio forward request sent", __func__); 2061204917Sdes 2062204917Sdes /* Read their reply */ 2063204917Sdes buffer_clear(&m); 2064204917Sdes 2065204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 2066204917Sdes error("%s: read from master failed: %s", 2067204917Sdes __func__, strerror(errno)); 2068204917Sdes buffer_free(&m); 2069204917Sdes return -1; 2070204917Sdes } 2071204917Sdes 2072204917Sdes type = buffer_get_int(&m); 2073204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 2074204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 2075204917Sdes __func__, muxclient_request_id, rid); 2076204917Sdes switch (type) { 2077204917Sdes case MUX_S_SESSION_OPENED: 2078204917Sdes sid = buffer_get_int(&m); 2079204917Sdes debug("%s: master session id: %u", __func__, sid); 2080204917Sdes break; 2081204917Sdes case MUX_S_PERMISSION_DENIED: 2082204917Sdes e = buffer_get_string(&m, NULL); 2083204917Sdes buffer_free(&m); 2084221420Sdes fatal("Master refused stdio forwarding request: %s", e); 2085204917Sdes case MUX_S_FAILURE: 2086204917Sdes e = buffer_get_string(&m, NULL); 2087204917Sdes buffer_free(&m); 2088294328Sdes fatal("Stdio forwarding request failed: %s", e); 2089204917Sdes default: 2090204917Sdes buffer_free(&m); 2091204917Sdes error("%s: unexpected response from master 0x%08x", 2092204917Sdes __func__, type); 2093204917Sdes return -1; 2094204917Sdes } 2095204917Sdes muxclient_request_id++; 2096204917Sdes 2097204917Sdes signal(SIGHUP, control_client_sighandler); 2098204917Sdes signal(SIGINT, control_client_sighandler); 2099204917Sdes signal(SIGTERM, control_client_sighandler); 2100204917Sdes signal(SIGWINCH, control_client_sigrelay); 2101204917Sdes 2102204917Sdes /* 2103204917Sdes * Stick around until the controlee closes the client_fd. 2104204917Sdes */ 2105204917Sdes buffer_clear(&m); 2106204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 2107204917Sdes if (errno == EPIPE || 2108204917Sdes (errno == EINTR && muxclient_terminate != 0)) 2109204917Sdes return 0; 2110204917Sdes fatal("%s: mux_client_read_packet: %s", 2111204917Sdes __func__, strerror(errno)); 2112204917Sdes } 2113204917Sdes fatal("%s: master returned unexpected message %u", __func__, type); 2114180750Sdes} 2115180750Sdes 2116226046Sdesstatic void 2117226046Sdesmux_client_request_stop_listening(int fd) 2118226046Sdes{ 2119226046Sdes Buffer m; 2120226046Sdes char *e; 2121226046Sdes u_int type, rid; 2122226046Sdes 2123226046Sdes debug3("%s: entering", __func__); 2124226046Sdes 2125226046Sdes buffer_init(&m); 2126226046Sdes buffer_put_int(&m, MUX_C_STOP_LISTENING); 2127226046Sdes buffer_put_int(&m, muxclient_request_id); 2128226046Sdes 2129226046Sdes if (mux_client_write_packet(fd, &m) != 0) 2130226046Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 2131226046Sdes 2132226046Sdes buffer_clear(&m); 2133226046Sdes 2134226046Sdes /* Read their reply */ 2135226046Sdes if (mux_client_read_packet(fd, &m) != 0) 2136226046Sdes fatal("%s: read from master failed: %s", 2137226046Sdes __func__, strerror(errno)); 2138226046Sdes 2139226046Sdes type = buffer_get_int(&m); 2140226046Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 2141226046Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 2142226046Sdes __func__, muxclient_request_id, rid); 2143226046Sdes switch (type) { 2144226046Sdes case MUX_S_OK: 2145226046Sdes break; 2146226046Sdes case MUX_S_PERMISSION_DENIED: 2147226046Sdes e = buffer_get_string(&m, NULL); 2148226046Sdes fatal("Master refused stop listening request: %s", e); 2149226046Sdes case MUX_S_FAILURE: 2150226046Sdes e = buffer_get_string(&m, NULL); 2151226046Sdes fatal("%s: stop listening request failed: %s", __func__, e); 2152226046Sdes default: 2153226046Sdes fatal("%s: unexpected response from master 0x%08x", 2154226046Sdes __func__, type); 2155226046Sdes } 2156226046Sdes buffer_free(&m); 2157226046Sdes muxclient_request_id++; 2158226046Sdes} 2159226046Sdes 2160180750Sdes/* Multiplex client main loop. */ 2161323134Sdesint 2162180750Sdesmuxclient(const char *path) 2163180750Sdes{ 2164180750Sdes struct sockaddr_un addr; 2165204917Sdes int sock; 2166204917Sdes u_int pid; 2167180750Sdes 2168204917Sdes if (muxclient_command == 0) { 2169323129Sdes if (options.stdio_forward_host != NULL) 2170204917Sdes muxclient_command = SSHMUX_COMMAND_STDIO_FWD; 2171204917Sdes else 2172204917Sdes muxclient_command = SSHMUX_COMMAND_OPEN; 2173204917Sdes } 2174180750Sdes 2175180750Sdes switch (options.control_master) { 2176180750Sdes case SSHCTL_MASTER_AUTO: 2177180750Sdes case SSHCTL_MASTER_AUTO_ASK: 2178180750Sdes debug("auto-mux: Trying existing master"); 2179180750Sdes /* FALLTHROUGH */ 2180180750Sdes case SSHCTL_MASTER_NO: 2181180750Sdes break; 2182180750Sdes default: 2183323134Sdes return -1; 2184180750Sdes } 2185180750Sdes 2186180750Sdes memset(&addr, '\0', sizeof(addr)); 2187180750Sdes addr.sun_family = AF_UNIX; 2188180750Sdes 2189180750Sdes if (strlcpy(addr.sun_path, path, 2190180750Sdes sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) 2191323134Sdes fatal("ControlPath too long ('%s' >= %u bytes)", path, 2192323134Sdes (unsigned int)sizeof(addr.sun_path)); 2193180750Sdes 2194180750Sdes if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) 2195180750Sdes fatal("%s socket(): %s", __func__, strerror(errno)); 2196180750Sdes 2197323136Sdes if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { 2198204917Sdes switch (muxclient_command) { 2199204917Sdes case SSHMUX_COMMAND_OPEN: 2200204917Sdes case SSHMUX_COMMAND_STDIO_FWD: 2201204917Sdes break; 2202204917Sdes default: 2203180750Sdes fatal("Control socket connect(%.100s): %s", path, 2204180750Sdes strerror(errno)); 2205180750Sdes } 2206221420Sdes if (errno == ECONNREFUSED && 2207221420Sdes options.control_master != SSHCTL_MASTER_NO) { 2208221420Sdes debug("Stale control socket %.100s, unlinking", path); 2209221420Sdes unlink(path); 2210221420Sdes } else if (errno == ENOENT) { 2211180750Sdes debug("Control socket \"%.100s\" does not exist", path); 2212221420Sdes } else { 2213180750Sdes error("Control socket connect(%.100s): %s", path, 2214180750Sdes strerror(errno)); 2215180750Sdes } 2216180750Sdes close(sock); 2217323134Sdes return -1; 2218180750Sdes } 2219204917Sdes set_nonblock(sock); 2220180750Sdes 2221204917Sdes if (mux_client_hello_exchange(sock) != 0) { 2222204917Sdes error("%s: master hello exchange failed", __func__); 2223180750Sdes close(sock); 2224323134Sdes return -1; 2225180750Sdes } 2226180750Sdes 2227180750Sdes switch (muxclient_command) { 2228180750Sdes case SSHMUX_COMMAND_ALIVE_CHECK: 2229204917Sdes if ((pid = mux_client_request_alive(sock)) == 0) 2230204917Sdes fatal("%s: master alive check failed", __func__); 2231296633Sdes fprintf(stderr, "Master running (pid=%u)\r\n", pid); 2232180750Sdes exit(0); 2233180750Sdes case SSHMUX_COMMAND_TERMINATE: 2234204917Sdes mux_client_request_terminate(sock); 2235323134Sdes if (options.log_level != SYSLOG_LEVEL_QUIET) 2236323134Sdes fprintf(stderr, "Exit request sent.\r\n"); 2237180750Sdes exit(0); 2238215116Sdes case SSHMUX_COMMAND_FORWARD: 2239240075Sdes if (mux_client_forwards(sock, 0) != 0) 2240215116Sdes fatal("%s: master forward request failed", __func__); 2241215116Sdes exit(0); 2242180750Sdes case SSHMUX_COMMAND_OPEN: 2243240075Sdes if (mux_client_forwards(sock, 0) != 0) { 2244204917Sdes error("%s: master forward request failed", __func__); 2245323134Sdes return -1; 2246180750Sdes } 2247204917Sdes mux_client_request_session(sock); 2248323134Sdes return -1; 2249204917Sdes case SSHMUX_COMMAND_STDIO_FWD: 2250204917Sdes mux_client_request_stdio_fwd(sock); 2251204917Sdes exit(0); 2252226046Sdes case SSHMUX_COMMAND_STOP: 2253226046Sdes mux_client_request_stop_listening(sock); 2254323134Sdes if (options.log_level != SYSLOG_LEVEL_QUIET) 2255323134Sdes fprintf(stderr, "Stop listening request sent.\r\n"); 2256226046Sdes exit(0); 2257240075Sdes case SSHMUX_COMMAND_CANCEL_FWD: 2258240075Sdes if (mux_client_forwards(sock, 1) != 0) 2259240075Sdes error("%s: master cancel forward request failed", 2260240075Sdes __func__); 2261240075Sdes exit(0); 2262323134Sdes case SSHMUX_COMMAND_PROXY: 2263323134Sdes mux_client_proxy(sock); 2264323134Sdes return (sock); 2265180750Sdes default: 2266180750Sdes fatal("unrecognised muxclient_command %d", muxclient_command); 2267180750Sdes } 2268180750Sdes} 2269