1323124Sdes/* $OpenBSD: mux.c,v 1.60 2016/06/03 03:14:41 dtucker 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" 34294666Sdes__RCSID("$FreeBSD: stable/10/crypto/openssh/mux.c 323124 2017-09-01 22:52:18Z 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" 83180750Sdes 84180750Sdes/* from ssh.c */ 85180750Sdesextern int tty_flag; 86180750Sdesextern Options options; 87180750Sdesextern int stdin_null_flag; 88180750Sdesextern char *host; 89204917Sdesextern int subsystem_flag; 90180750Sdesextern Buffer command; 91204917Sdesextern volatile sig_atomic_t quit_pending; 92180750Sdes 93180750Sdes/* Context for session open confirmation callback */ 94180750Sdesstruct mux_session_confirm_ctx { 95204917Sdes u_int want_tty; 96204917Sdes u_int want_subsys; 97204917Sdes u_int want_x_fwd; 98204917Sdes u_int want_agent_fwd; 99180750Sdes Buffer cmd; 100180750Sdes char *term; 101180750Sdes struct termios tio; 102180750Sdes char **env; 103215116Sdes u_int rid; 104180750Sdes}; 105180750Sdes 106295367Sdes/* Context for stdio fwd open confirmation callback */ 107295367Sdesstruct mux_stdio_confirm_ctx { 108295367Sdes u_int rid; 109295367Sdes}; 110295367Sdes 111215116Sdes/* Context for global channel callback */ 112215116Sdesstruct mux_channel_confirm_ctx { 113215116Sdes u_int cid; /* channel id */ 114215116Sdes u_int rid; /* request id */ 115215116Sdes int fid; /* forward id */ 116215116Sdes}; 117215116Sdes 118180750Sdes/* fd to control socket */ 119180750Sdesint muxserver_sock = -1; 120180750Sdes 121204917Sdes/* client request id */ 122204917Sdesu_int muxclient_request_id = 0; 123204917Sdes 124180750Sdes/* Multiplexing control command */ 125180750Sdesu_int muxclient_command = 0; 126180750Sdes 127180750Sdes/* Set when signalled. */ 128180750Sdesstatic volatile sig_atomic_t muxclient_terminate = 0; 129180750Sdes 130180750Sdes/* PID of multiplex server */ 131180750Sdesstatic u_int muxserver_pid = 0; 132180750Sdes 133204917Sdesstatic Channel *mux_listener_channel = NULL; 134180750Sdes 135204917Sdesstruct mux_master_state { 136204917Sdes int hello_rcvd; 137204917Sdes}; 138180750Sdes 139204917Sdes/* mux protocol messages */ 140204917Sdes#define MUX_MSG_HELLO 0x00000001 141204917Sdes#define MUX_C_NEW_SESSION 0x10000002 142204917Sdes#define MUX_C_ALIVE_CHECK 0x10000004 143204917Sdes#define MUX_C_TERMINATE 0x10000005 144204917Sdes#define MUX_C_OPEN_FWD 0x10000006 145204917Sdes#define MUX_C_CLOSE_FWD 0x10000007 146204917Sdes#define MUX_C_NEW_STDIO_FWD 0x10000008 147226046Sdes#define MUX_C_STOP_LISTENING 0x10000009 148204917Sdes#define MUX_S_OK 0x80000001 149204917Sdes#define MUX_S_PERMISSION_DENIED 0x80000002 150204917Sdes#define MUX_S_FAILURE 0x80000003 151204917Sdes#define MUX_S_EXIT_MESSAGE 0x80000004 152204917Sdes#define MUX_S_ALIVE 0x80000005 153204917Sdes#define MUX_S_SESSION_OPENED 0x80000006 154215116Sdes#define MUX_S_REMOTE_PORT 0x80000007 155226046Sdes#define MUX_S_TTY_ALLOC_FAIL 0x80000008 156204917Sdes 157204917Sdes/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ 158204917Sdes#define MUX_FWD_LOCAL 1 159204917Sdes#define MUX_FWD_REMOTE 2 160204917Sdes#define MUX_FWD_DYNAMIC 3 161204917Sdes 162215116Sdesstatic void mux_session_confirm(int, int, void *); 163295367Sdesstatic void mux_stdio_confirm(int, int, void *); 164204917Sdes 165204917Sdesstatic int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); 166204917Sdesstatic int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); 167204917Sdesstatic int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *); 168204917Sdesstatic int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *); 169204917Sdesstatic int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); 170204917Sdesstatic int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); 171204917Sdesstatic int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); 172226046Sdesstatic int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *); 173204917Sdes 174204917Sdesstatic const struct { 175204917Sdes u_int type; 176204917Sdes int (*handler)(u_int, Channel *, Buffer *, Buffer *); 177204917Sdes} mux_master_handlers[] = { 178204917Sdes { MUX_MSG_HELLO, process_mux_master_hello }, 179204917Sdes { MUX_C_NEW_SESSION, process_mux_new_session }, 180204917Sdes { MUX_C_ALIVE_CHECK, process_mux_alive_check }, 181204917Sdes { MUX_C_TERMINATE, process_mux_terminate }, 182204917Sdes { MUX_C_OPEN_FWD, process_mux_open_fwd }, 183204917Sdes { MUX_C_CLOSE_FWD, process_mux_close_fwd }, 184204917Sdes { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, 185226046Sdes { MUX_C_STOP_LISTENING, process_mux_stop_listening }, 186204917Sdes { 0, NULL } 187204917Sdes}; 188204917Sdes 189204917Sdes/* Cleanup callback fired on closure of mux slave _session_ channel */ 190204917Sdes/* ARGSUSED */ 191255767Sdesstatic void 192204917Sdesmux_master_session_cleanup_cb(int cid, void *unused) 193204917Sdes{ 194204917Sdes Channel *cc, *c = channel_by_id(cid); 195204917Sdes 196204917Sdes debug3("%s: entering for channel %d", __func__, cid); 197204917Sdes if (c == NULL) 198204917Sdes fatal("%s: channel_by_id(%i) == NULL", __func__, cid); 199204917Sdes if (c->ctl_chan != -1) { 200204917Sdes if ((cc = channel_by_id(c->ctl_chan)) == NULL) 201204917Sdes fatal("%s: channel %d missing control channel %d", 202204917Sdes __func__, c->self, c->ctl_chan); 203204917Sdes c->ctl_chan = -1; 204204917Sdes cc->remote_id = -1; 205204917Sdes chan_rcvd_oclose(cc); 206204917Sdes } 207204917Sdes channel_cancel_cleanup(c->self); 208204917Sdes} 209204917Sdes 210204917Sdes/* Cleanup callback fired on closure of mux slave _control_ channel */ 211204917Sdes/* ARGSUSED */ 212204917Sdesstatic void 213204917Sdesmux_master_control_cleanup_cb(int cid, void *unused) 214204917Sdes{ 215204917Sdes Channel *sc, *c = channel_by_id(cid); 216204917Sdes 217204917Sdes debug3("%s: entering for channel %d", __func__, cid); 218204917Sdes if (c == NULL) 219204917Sdes fatal("%s: channel_by_id(%i) == NULL", __func__, cid); 220204917Sdes if (c->remote_id != -1) { 221204917Sdes if ((sc = channel_by_id(c->remote_id)) == NULL) 222215116Sdes fatal("%s: channel %d missing session channel %d", 223204917Sdes __func__, c->self, c->remote_id); 224204917Sdes c->remote_id = -1; 225204917Sdes sc->ctl_chan = -1; 226255767Sdes if (sc->type != SSH_CHANNEL_OPEN && 227255767Sdes sc->type != SSH_CHANNEL_OPENING) { 228204917Sdes debug2("%s: channel %d: not open", __func__, sc->self); 229204917Sdes chan_mark_dead(sc); 230204917Sdes } else { 231204917Sdes if (sc->istate == CHAN_INPUT_OPEN) 232204917Sdes chan_read_failed(sc); 233204917Sdes if (sc->ostate == CHAN_OUTPUT_OPEN) 234204917Sdes chan_write_failed(sc); 235204917Sdes } 236204917Sdes } 237204917Sdes channel_cancel_cleanup(c->self); 238204917Sdes} 239204917Sdes 240204917Sdes/* Check mux client environment variables before passing them to mux master. */ 241204917Sdesstatic int 242204917Sdesenv_permitted(char *env) 243204917Sdes{ 244204917Sdes int i, ret; 245204917Sdes char name[1024], *cp; 246204917Sdes 247204917Sdes if ((cp = strchr(env, '=')) == NULL || cp == env) 248204917Sdes return 0; 249204917Sdes ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env); 250204917Sdes if (ret <= 0 || (size_t)ret >= sizeof(name)) { 251204917Sdes error("env_permitted: name '%.100s...' too long", env); 252204917Sdes return 0; 253204917Sdes } 254204917Sdes 255204917Sdes for (i = 0; i < options.num_send_env; i++) 256204917Sdes if (match_pattern(name, options.send_env[i])) 257204917Sdes return 1; 258204917Sdes 259204917Sdes return 0; 260204917Sdes} 261204917Sdes 262204917Sdes/* Mux master protocol message handlers */ 263204917Sdes 264204917Sdesstatic int 265204917Sdesprocess_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r) 266204917Sdes{ 267204917Sdes u_int ver; 268204917Sdes struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; 269204917Sdes 270204917Sdes if (state == NULL) 271204917Sdes fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self); 272204917Sdes if (state->hello_rcvd) { 273204917Sdes error("%s: HELLO received twice", __func__); 274204917Sdes return -1; 275204917Sdes } 276204917Sdes if (buffer_get_int_ret(&ver, m) != 0) { 277204917Sdes malf: 278204917Sdes error("%s: malformed message", __func__); 279204917Sdes return -1; 280204917Sdes } 281204917Sdes if (ver != SSHMUX_VER) { 282204917Sdes error("Unsupported multiplexing protocol version %d " 283204917Sdes "(expected %d)", ver, SSHMUX_VER); 284204917Sdes return -1; 285204917Sdes } 286204917Sdes debug2("%s: channel %d slave version %u", __func__, c->self, ver); 287204917Sdes 288204917Sdes /* No extensions are presently defined */ 289204917Sdes while (buffer_len(m) > 0) { 290204917Sdes char *name = buffer_get_string_ret(m, NULL); 291204917Sdes char *value = buffer_get_string_ret(m, NULL); 292204917Sdes 293204917Sdes if (name == NULL || value == NULL) { 294255767Sdes free(name); 295255767Sdes free(value); 296204917Sdes goto malf; 297204917Sdes } 298204917Sdes debug2("Unrecognised slave extension \"%s\"", name); 299255767Sdes free(name); 300255767Sdes free(value); 301204917Sdes } 302204917Sdes state->hello_rcvd = 1; 303204917Sdes return 0; 304204917Sdes} 305204917Sdes 306204917Sdesstatic int 307204917Sdesprocess_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) 308204917Sdes{ 309204917Sdes Channel *nc; 310204917Sdes struct mux_session_confirm_ctx *cctx; 311204917Sdes char *reserved, *cmd, *cp; 312204917Sdes u_int i, j, len, env_len, escape_char, window, packetmax; 313204917Sdes int new_fd[3]; 314204917Sdes 315204917Sdes /* Reply for SSHMUX_COMMAND_OPEN */ 316204917Sdes cctx = xcalloc(1, sizeof(*cctx)); 317204917Sdes cctx->term = NULL; 318215116Sdes cctx->rid = rid; 319204917Sdes cmd = reserved = NULL; 320240075Sdes cctx->env = NULL; 321240075Sdes env_len = 0; 322204917Sdes if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || 323204917Sdes buffer_get_int_ret(&cctx->want_tty, m) != 0 || 324204917Sdes buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 || 325204917Sdes buffer_get_int_ret(&cctx->want_agent_fwd, m) != 0 || 326204917Sdes buffer_get_int_ret(&cctx->want_subsys, m) != 0 || 327204917Sdes buffer_get_int_ret(&escape_char, m) != 0 || 328204917Sdes (cctx->term = buffer_get_string_ret(m, &len)) == NULL || 329204917Sdes (cmd = buffer_get_string_ret(m, &len)) == NULL) { 330204917Sdes malf: 331255767Sdes free(cmd); 332255767Sdes free(reserved); 333240075Sdes for (j = 0; j < env_len; j++) 334255767Sdes free(cctx->env[j]); 335255767Sdes free(cctx->env); 336255767Sdes free(cctx->term); 337255767Sdes free(cctx); 338204917Sdes error("%s: malformed message", __func__); 339204917Sdes return -1; 340204917Sdes } 341255767Sdes free(reserved); 342204917Sdes reserved = NULL; 343204917Sdes 344204917Sdes while (buffer_len(m) > 0) { 345204917Sdes#define MUX_MAX_ENV_VARS 4096 346240075Sdes if ((cp = buffer_get_string_ret(m, &len)) == NULL) 347204917Sdes goto malf; 348204917Sdes if (!env_permitted(cp)) { 349255767Sdes free(cp); 350204917Sdes continue; 351204917Sdes } 352295367Sdes cctx->env = xreallocarray(cctx->env, env_len + 2, 353204917Sdes sizeof(*cctx->env)); 354204917Sdes cctx->env[env_len++] = cp; 355204917Sdes cctx->env[env_len] = NULL; 356204917Sdes if (env_len > MUX_MAX_ENV_VARS) { 357204917Sdes error(">%d environment variables received, ignoring " 358204917Sdes "additional", MUX_MAX_ENV_VARS); 359204917Sdes break; 360204917Sdes } 361204917Sdes } 362204917Sdes 363204917Sdes debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, " 364204917Sdes "term \"%s\", cmd \"%s\", env %u", __func__, c->self, 365204917Sdes cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd, 366204917Sdes cctx->want_subsys, cctx->term, cmd, env_len); 367204917Sdes 368204917Sdes buffer_init(&cctx->cmd); 369204917Sdes buffer_append(&cctx->cmd, cmd, strlen(cmd)); 370255767Sdes free(cmd); 371204917Sdes cmd = NULL; 372204917Sdes 373204917Sdes /* Gather fds from client */ 374204917Sdes for(i = 0; i < 3; i++) { 375204917Sdes if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { 376204917Sdes error("%s: failed to receive fd %d from slave", 377204917Sdes __func__, i); 378204917Sdes for (j = 0; j < i; j++) 379204917Sdes close(new_fd[j]); 380204917Sdes for (j = 0; j < env_len; j++) 381255767Sdes free(cctx->env[j]); 382255767Sdes free(cctx->env); 383255767Sdes free(cctx->term); 384204917Sdes buffer_free(&cctx->cmd); 385255767Sdes free(cctx); 386204917Sdes 387204917Sdes /* prepare reply */ 388204917Sdes buffer_put_int(r, MUX_S_FAILURE); 389204917Sdes buffer_put_int(r, rid); 390204917Sdes buffer_put_cstring(r, 391204917Sdes "did not receive file descriptors"); 392204917Sdes return -1; 393204917Sdes } 394204917Sdes } 395204917Sdes 396204917Sdes debug3("%s: got fds stdin %d, stdout %d, stderr %d", __func__, 397204917Sdes new_fd[0], new_fd[1], new_fd[2]); 398204917Sdes 399204917Sdes /* XXX support multiple child sessions in future */ 400204917Sdes if (c->remote_id != -1) { 401204917Sdes debug2("%s: session already open", __func__); 402204917Sdes /* prepare reply */ 403204917Sdes buffer_put_int(r, MUX_S_FAILURE); 404204917Sdes buffer_put_int(r, rid); 405204917Sdes buffer_put_cstring(r, "Multiple sessions not supported"); 406204917Sdes cleanup: 407204917Sdes close(new_fd[0]); 408204917Sdes close(new_fd[1]); 409204917Sdes close(new_fd[2]); 410255767Sdes free(cctx->term); 411204917Sdes if (env_len != 0) { 412204917Sdes for (i = 0; i < env_len; i++) 413255767Sdes free(cctx->env[i]); 414255767Sdes free(cctx->env); 415204917Sdes } 416204917Sdes buffer_free(&cctx->cmd); 417255767Sdes free(cctx); 418204917Sdes return 0; 419204917Sdes } 420204917Sdes 421204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 422204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 423204917Sdes if (!ask_permission("Allow shared connection to %s? ", host)) { 424204917Sdes debug2("%s: session refused by user", __func__); 425204917Sdes /* prepare reply */ 426204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 427204917Sdes buffer_put_int(r, rid); 428204917Sdes buffer_put_cstring(r, "Permission denied"); 429204917Sdes goto cleanup; 430204917Sdes } 431204917Sdes } 432204917Sdes 433204917Sdes /* Try to pick up ttymodes from client before it goes raw */ 434204917Sdes if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) 435204917Sdes error("%s: tcgetattr: %s", __func__, strerror(errno)); 436204917Sdes 437204917Sdes /* enable nonblocking unless tty */ 438204917Sdes if (!isatty(new_fd[0])) 439204917Sdes set_nonblock(new_fd[0]); 440204917Sdes if (!isatty(new_fd[1])) 441204917Sdes set_nonblock(new_fd[1]); 442204917Sdes if (!isatty(new_fd[2])) 443204917Sdes set_nonblock(new_fd[2]); 444204917Sdes 445204917Sdes window = CHAN_SES_WINDOW_DEFAULT; 446204917Sdes packetmax = CHAN_SES_PACKET_DEFAULT; 447204917Sdes if (cctx->want_tty) { 448204917Sdes window >>= 1; 449204917Sdes packetmax >>= 1; 450204917Sdes } 451204917Sdes 452204917Sdes nc = channel_new("session", SSH_CHANNEL_OPENING, 453204917Sdes new_fd[0], new_fd[1], new_fd[2], window, packetmax, 454204917Sdes CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); 455204917Sdes 456204917Sdes nc->ctl_chan = c->self; /* link session -> control channel */ 457204917Sdes c->remote_id = nc->self; /* link control -> session channel */ 458204917Sdes 459204917Sdes if (cctx->want_tty && escape_char != 0xffffffff) { 460204917Sdes channel_register_filter(nc->self, 461204917Sdes client_simple_escape_filter, NULL, 462204917Sdes client_filter_cleanup, 463204917Sdes client_new_escape_filter_ctx((int)escape_char)); 464204917Sdes } 465204917Sdes 466204917Sdes debug2("%s: channel_new: %d linked to control channel %d", 467204917Sdes __func__, nc->self, nc->ctl_chan); 468204917Sdes 469204917Sdes channel_send_open(nc->self); 470204917Sdes channel_register_open_confirm(nc->self, mux_session_confirm, cctx); 471215116Sdes c->mux_pause = 1; /* stop handling messages until open_confirm done */ 472215116Sdes channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); 473204917Sdes 474215116Sdes /* reply is deferred, sent by mux_session_confirm */ 475204917Sdes return 0; 476204917Sdes} 477204917Sdes 478204917Sdesstatic int 479204917Sdesprocess_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r) 480204917Sdes{ 481204917Sdes debug2("%s: channel %d: alive check", __func__, c->self); 482204917Sdes 483204917Sdes /* prepare reply */ 484204917Sdes buffer_put_int(r, MUX_S_ALIVE); 485204917Sdes buffer_put_int(r, rid); 486204917Sdes buffer_put_int(r, (u_int)getpid()); 487204917Sdes 488204917Sdes return 0; 489204917Sdes} 490204917Sdes 491204917Sdesstatic int 492204917Sdesprocess_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r) 493204917Sdes{ 494204917Sdes debug2("%s: channel %d: terminate request", __func__, c->self); 495204917Sdes 496204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 497204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 498204917Sdes if (!ask_permission("Terminate shared connection to %s? ", 499204917Sdes host)) { 500204917Sdes debug2("%s: termination refused by user", __func__); 501204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 502204917Sdes buffer_put_int(r, rid); 503204917Sdes buffer_put_cstring(r, "Permission denied"); 504204917Sdes return 0; 505204917Sdes } 506204917Sdes } 507204917Sdes 508204917Sdes quit_pending = 1; 509204917Sdes buffer_put_int(r, MUX_S_OK); 510204917Sdes buffer_put_int(r, rid); 511204917Sdes /* XXX exit happens too soon - message never makes it to client */ 512204917Sdes return 0; 513204917Sdes} 514204917Sdes 515204917Sdesstatic char * 516295367Sdesformat_forward(u_int ftype, struct Forward *fwd) 517204917Sdes{ 518204917Sdes char *ret; 519204917Sdes 520204917Sdes switch (ftype) { 521204917Sdes case MUX_FWD_LOCAL: 522204917Sdes xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d", 523295367Sdes (fwd->listen_path != NULL) ? fwd->listen_path : 524204917Sdes (fwd->listen_host == NULL) ? 525295367Sdes (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") : 526204917Sdes fwd->listen_host, fwd->listen_port, 527295367Sdes (fwd->connect_path != NULL) ? fwd->connect_path : 528204917Sdes fwd->connect_host, fwd->connect_port); 529204917Sdes break; 530204917Sdes case MUX_FWD_DYNAMIC: 531204917Sdes xasprintf(&ret, "dynamic forward %.200s:%d -> *", 532204917Sdes (fwd->listen_host == NULL) ? 533295367Sdes (options.fwd_opts.gateway_ports ? "*" : "LOCALHOST") : 534204917Sdes fwd->listen_host, fwd->listen_port); 535204917Sdes break; 536204917Sdes case MUX_FWD_REMOTE: 537204917Sdes xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d", 538295367Sdes (fwd->listen_path != NULL) ? fwd->listen_path : 539204917Sdes (fwd->listen_host == NULL) ? 540204917Sdes "LOCALHOST" : fwd->listen_host, 541204917Sdes fwd->listen_port, 542295367Sdes (fwd->connect_path != NULL) ? fwd->connect_path : 543204917Sdes fwd->connect_host, fwd->connect_port); 544204917Sdes break; 545204917Sdes default: 546204917Sdes fatal("%s: unknown forward type %u", __func__, ftype); 547204917Sdes } 548204917Sdes return ret; 549204917Sdes} 550204917Sdes 551204917Sdesstatic int 552204917Sdescompare_host(const char *a, const char *b) 553204917Sdes{ 554204917Sdes if (a == NULL && b == NULL) 555204917Sdes return 1; 556204917Sdes if (a == NULL || b == NULL) 557204917Sdes return 0; 558204917Sdes return strcmp(a, b) == 0; 559204917Sdes} 560204917Sdes 561204917Sdesstatic int 562295367Sdescompare_forward(struct Forward *a, struct Forward *b) 563204917Sdes{ 564204917Sdes if (!compare_host(a->listen_host, b->listen_host)) 565204917Sdes return 0; 566295367Sdes if (!compare_host(a->listen_path, b->listen_path)) 567295367Sdes return 0; 568204917Sdes if (a->listen_port != b->listen_port) 569204917Sdes return 0; 570204917Sdes if (!compare_host(a->connect_host, b->connect_host)) 571204917Sdes return 0; 572295367Sdes if (!compare_host(a->connect_path, b->connect_path)) 573295367Sdes return 0; 574204917Sdes if (a->connect_port != b->connect_port) 575204917Sdes return 0; 576204917Sdes 577204917Sdes return 1; 578204917Sdes} 579204917Sdes 580215116Sdesstatic void 581215116Sdesmux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) 582215116Sdes{ 583215116Sdes struct mux_channel_confirm_ctx *fctx = ctxt; 584215116Sdes char *failmsg = NULL; 585295367Sdes struct Forward *rfwd; 586215116Sdes Channel *c; 587215116Sdes Buffer out; 588215116Sdes 589215116Sdes if ((c = channel_by_id(fctx->cid)) == NULL) { 590215116Sdes /* no channel for reply */ 591215116Sdes error("%s: unknown channel", __func__); 592215116Sdes return; 593215116Sdes } 594215116Sdes buffer_init(&out); 595295367Sdes if (fctx->fid >= options.num_remote_forwards || 596295367Sdes (options.remote_forwards[fctx->fid].connect_path == NULL && 597295367Sdes options.remote_forwards[fctx->fid].connect_host == NULL)) { 598215116Sdes xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid); 599215116Sdes goto fail; 600215116Sdes } 601215116Sdes rfwd = &options.remote_forwards[fctx->fid]; 602215116Sdes debug("%s: %s for: listen %d, connect %s:%d", __func__, 603215116Sdes type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", 604295367Sdes rfwd->listen_port, rfwd->connect_path ? rfwd->connect_path : 605295367Sdes rfwd->connect_host, rfwd->connect_port); 606215116Sdes if (type == SSH2_MSG_REQUEST_SUCCESS) { 607215116Sdes if (rfwd->listen_port == 0) { 608215116Sdes rfwd->allocated_port = packet_get_int(); 609295367Sdes debug("Allocated port %u for mux remote forward" 610215116Sdes " to %s:%d", rfwd->allocated_port, 611215116Sdes rfwd->connect_host, rfwd->connect_port); 612215116Sdes buffer_put_int(&out, MUX_S_REMOTE_PORT); 613215116Sdes buffer_put_int(&out, fctx->rid); 614215116Sdes buffer_put_int(&out, rfwd->allocated_port); 615240075Sdes channel_update_permitted_opens(rfwd->handle, 616240075Sdes rfwd->allocated_port); 617215116Sdes } else { 618215116Sdes buffer_put_int(&out, MUX_S_OK); 619215116Sdes buffer_put_int(&out, fctx->rid); 620215116Sdes } 621215116Sdes goto out; 622215116Sdes } else { 623240075Sdes if (rfwd->listen_port == 0) 624240075Sdes channel_update_permitted_opens(rfwd->handle, -1); 625295367Sdes if (rfwd->listen_path != NULL) 626295367Sdes xasprintf(&failmsg, "remote port forwarding failed for " 627295367Sdes "listen path %s", rfwd->listen_path); 628295367Sdes else 629295367Sdes xasprintf(&failmsg, "remote port forwarding failed for " 630295367Sdes "listen port %d", rfwd->listen_port); 631295367Sdes 632295367Sdes debug2("%s: clearing registered forwarding for listen %d, " 633295367Sdes "connect %s:%d", __func__, rfwd->listen_port, 634295367Sdes rfwd->connect_path ? rfwd->connect_path : 635295367Sdes rfwd->connect_host, rfwd->connect_port); 636295367Sdes 637295367Sdes free(rfwd->listen_host); 638295367Sdes free(rfwd->listen_path); 639295367Sdes free(rfwd->connect_host); 640295367Sdes free(rfwd->connect_path); 641295367Sdes memset(rfwd, 0, sizeof(*rfwd)); 642215116Sdes } 643215116Sdes fail: 644215116Sdes error("%s: %s", __func__, failmsg); 645215116Sdes buffer_put_int(&out, MUX_S_FAILURE); 646215116Sdes buffer_put_int(&out, fctx->rid); 647215116Sdes buffer_put_cstring(&out, failmsg); 648255767Sdes free(failmsg); 649215116Sdes out: 650215116Sdes buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out)); 651215116Sdes buffer_free(&out); 652215116Sdes if (c->mux_pause <= 0) 653215116Sdes fatal("%s: mux_pause %d", __func__, c->mux_pause); 654215116Sdes c->mux_pause = 0; /* start processing messages again */ 655215116Sdes} 656215116Sdes 657204917Sdesstatic int 658204917Sdesprocess_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 659204917Sdes{ 660295367Sdes struct Forward fwd; 661204917Sdes char *fwd_desc = NULL; 662295367Sdes char *listen_addr, *connect_addr; 663204917Sdes u_int ftype; 664255767Sdes u_int lport, cport; 665204917Sdes int i, ret = 0, freefwd = 1; 666204917Sdes 667287144Sdelphij memset(&fwd, 0, sizeof(fwd)); 668287144Sdelphij 669295367Sdes /* XXX - lport/cport check redundant */ 670204917Sdes if (buffer_get_int_ret(&ftype, m) != 0 || 671295367Sdes (listen_addr = buffer_get_string_ret(m, NULL)) == NULL || 672255767Sdes buffer_get_int_ret(&lport, m) != 0 || 673295367Sdes (connect_addr = buffer_get_string_ret(m, NULL)) == NULL || 674255767Sdes buffer_get_int_ret(&cport, m) != 0 || 675295367Sdes (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) || 676295367Sdes (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) { 677204917Sdes error("%s: malformed message", __func__); 678204917Sdes ret = -1; 679204917Sdes goto out; 680204917Sdes } 681295367Sdes if (*listen_addr == '\0') { 682295367Sdes free(listen_addr); 683295367Sdes listen_addr = NULL; 684204917Sdes } 685295367Sdes if (*connect_addr == '\0') { 686295367Sdes free(connect_addr); 687295367Sdes connect_addr = NULL; 688204917Sdes } 689204917Sdes 690295367Sdes memset(&fwd, 0, sizeof(fwd)); 691295367Sdes fwd.listen_port = lport; 692295367Sdes if (fwd.listen_port == PORT_STREAMLOCAL) 693295367Sdes fwd.listen_path = listen_addr; 694295367Sdes else 695295367Sdes fwd.listen_host = listen_addr; 696295367Sdes fwd.connect_port = cport; 697295367Sdes if (fwd.connect_port == PORT_STREAMLOCAL) 698295367Sdes fwd.connect_path = connect_addr; 699295367Sdes else 700295367Sdes fwd.connect_host = connect_addr; 701295367Sdes 702204917Sdes debug2("%s: channel %d: request %s", __func__, c->self, 703204917Sdes (fwd_desc = format_forward(ftype, &fwd))); 704204917Sdes 705204917Sdes if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE && 706204917Sdes ftype != MUX_FWD_DYNAMIC) { 707204917Sdes logit("%s: invalid forwarding type %u", __func__, ftype); 708204917Sdes invalid: 709295367Sdes free(listen_addr); 710295367Sdes free(connect_addr); 711204917Sdes buffer_put_int(r, MUX_S_FAILURE); 712204917Sdes buffer_put_int(r, rid); 713204917Sdes buffer_put_cstring(r, "Invalid forwarding request"); 714204917Sdes return 0; 715204917Sdes } 716295367Sdes if (ftype == MUX_FWD_DYNAMIC && fwd.listen_path) { 717295367Sdes logit("%s: streamlocal and dynamic forwards " 718295367Sdes "are mutually exclusive", __func__); 719295367Sdes goto invalid; 720295367Sdes } 721295367Sdes if (fwd.listen_port != PORT_STREAMLOCAL && fwd.listen_port >= 65536) { 722204917Sdes logit("%s: invalid listen port %u", __func__, 723204917Sdes fwd.listen_port); 724204917Sdes goto invalid; 725204917Sdes } 726295367Sdes if ((fwd.connect_port != PORT_STREAMLOCAL && fwd.connect_port >= 65536) 727295367Sdes || (ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) { 728204917Sdes logit("%s: invalid connect port %u", __func__, 729204917Sdes fwd.connect_port); 730204917Sdes goto invalid; 731204917Sdes } 732295367Sdes if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL && fwd.connect_path == NULL) { 733204917Sdes logit("%s: missing connect host", __func__); 734204917Sdes goto invalid; 735204917Sdes } 736204917Sdes 737204917Sdes /* Skip forwards that have already been requested */ 738204917Sdes switch (ftype) { 739204917Sdes case MUX_FWD_LOCAL: 740204917Sdes case MUX_FWD_DYNAMIC: 741204917Sdes for (i = 0; i < options.num_local_forwards; i++) { 742204917Sdes if (compare_forward(&fwd, 743204917Sdes options.local_forwards + i)) { 744204917Sdes exists: 745204917Sdes debug2("%s: found existing forwarding", 746204917Sdes __func__); 747204917Sdes buffer_put_int(r, MUX_S_OK); 748204917Sdes buffer_put_int(r, rid); 749204917Sdes goto out; 750204917Sdes } 751204917Sdes } 752204917Sdes break; 753204917Sdes case MUX_FWD_REMOTE: 754204917Sdes for (i = 0; i < options.num_remote_forwards; i++) { 755204917Sdes if (compare_forward(&fwd, 756215116Sdes options.remote_forwards + i)) { 757215116Sdes if (fwd.listen_port != 0) 758215116Sdes goto exists; 759215116Sdes debug2("%s: found allocated port", 760215116Sdes __func__); 761215116Sdes buffer_put_int(r, MUX_S_REMOTE_PORT); 762215116Sdes buffer_put_int(r, rid); 763215116Sdes buffer_put_int(r, 764215116Sdes options.remote_forwards[i].allocated_port); 765215116Sdes goto out; 766215116Sdes } 767204917Sdes } 768204917Sdes break; 769204917Sdes } 770204917Sdes 771204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 772204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 773204917Sdes if (!ask_permission("Open %s on %s?", fwd_desc, host)) { 774204917Sdes debug2("%s: forwarding refused by user", __func__); 775204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 776204917Sdes buffer_put_int(r, rid); 777204917Sdes buffer_put_cstring(r, "Permission denied"); 778204917Sdes goto out; 779204917Sdes } 780204917Sdes } 781204917Sdes 782204917Sdes if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { 783295367Sdes if (!channel_setup_local_fwd_listener(&fwd, 784295367Sdes &options.fwd_opts)) { 785204917Sdes fail: 786204917Sdes logit("slave-requested %s failed", fwd_desc); 787204917Sdes buffer_put_int(r, MUX_S_FAILURE); 788204917Sdes buffer_put_int(r, rid); 789204917Sdes buffer_put_cstring(r, "Port forwarding failed"); 790204917Sdes goto out; 791204917Sdes } 792204917Sdes add_local_forward(&options, &fwd); 793204917Sdes freefwd = 0; 794204917Sdes } else { 795215116Sdes struct mux_channel_confirm_ctx *fctx; 796215116Sdes 797295367Sdes fwd.handle = channel_request_remote_forwarding(&fwd); 798240075Sdes if (fwd.handle < 0) 799204917Sdes goto fail; 800204917Sdes add_remote_forward(&options, &fwd); 801215116Sdes fctx = xcalloc(1, sizeof(*fctx)); 802215116Sdes fctx->cid = c->self; 803215116Sdes fctx->rid = rid; 804215116Sdes fctx->fid = options.num_remote_forwards - 1; 805215116Sdes client_register_global_confirm(mux_confirm_remote_forward, 806215116Sdes fctx); 807204917Sdes freefwd = 0; 808215116Sdes c->mux_pause = 1; /* wait for mux_confirm_remote_forward */ 809215116Sdes /* delayed reply in mux_confirm_remote_forward */ 810215116Sdes goto out; 811204917Sdes } 812204917Sdes buffer_put_int(r, MUX_S_OK); 813204917Sdes buffer_put_int(r, rid); 814204917Sdes out: 815255767Sdes free(fwd_desc); 816204917Sdes if (freefwd) { 817255767Sdes free(fwd.listen_host); 818295367Sdes free(fwd.listen_path); 819255767Sdes free(fwd.connect_host); 820295367Sdes free(fwd.connect_path); 821204917Sdes } 822204917Sdes return ret; 823204917Sdes} 824204917Sdes 825204917Sdesstatic int 826204917Sdesprocess_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 827204917Sdes{ 828295367Sdes struct Forward fwd, *found_fwd; 829204917Sdes char *fwd_desc = NULL; 830240075Sdes const char *error_reason = NULL; 831295367Sdes char *listen_addr = NULL, *connect_addr = NULL; 832204917Sdes u_int ftype; 833295367Sdes int i, ret = 0; 834255767Sdes u_int lport, cport; 835204917Sdes 836287144Sdelphij memset(&fwd, 0, sizeof(fwd)); 837287144Sdelphij 838204917Sdes if (buffer_get_int_ret(&ftype, m) != 0 || 839295367Sdes (listen_addr = buffer_get_string_ret(m, NULL)) == NULL || 840255767Sdes buffer_get_int_ret(&lport, m) != 0 || 841295367Sdes (connect_addr = buffer_get_string_ret(m, NULL)) == NULL || 842255767Sdes buffer_get_int_ret(&cport, m) != 0 || 843295367Sdes (lport != (u_int)PORT_STREAMLOCAL && lport > 65535) || 844295367Sdes (cport != (u_int)PORT_STREAMLOCAL && cport > 65535)) { 845204917Sdes error("%s: malformed message", __func__); 846204917Sdes ret = -1; 847204917Sdes goto out; 848204917Sdes } 849204917Sdes 850295367Sdes if (*listen_addr == '\0') { 851295367Sdes free(listen_addr); 852295367Sdes listen_addr = NULL; 853204917Sdes } 854295367Sdes if (*connect_addr == '\0') { 855295367Sdes free(connect_addr); 856295367Sdes connect_addr = NULL; 857204917Sdes } 858204917Sdes 859295367Sdes memset(&fwd, 0, sizeof(fwd)); 860295367Sdes fwd.listen_port = lport; 861295367Sdes if (fwd.listen_port == PORT_STREAMLOCAL) 862295367Sdes fwd.listen_path = listen_addr; 863295367Sdes else 864295367Sdes fwd.listen_host = listen_addr; 865295367Sdes fwd.connect_port = cport; 866295367Sdes if (fwd.connect_port == PORT_STREAMLOCAL) 867295367Sdes fwd.connect_path = connect_addr; 868295367Sdes else 869295367Sdes fwd.connect_host = connect_addr; 870295367Sdes 871240075Sdes debug2("%s: channel %d: request cancel %s", __func__, c->self, 872204917Sdes (fwd_desc = format_forward(ftype, &fwd))); 873204917Sdes 874240075Sdes /* make sure this has been requested */ 875240075Sdes found_fwd = NULL; 876240075Sdes switch (ftype) { 877240075Sdes case MUX_FWD_LOCAL: 878240075Sdes case MUX_FWD_DYNAMIC: 879240075Sdes for (i = 0; i < options.num_local_forwards; i++) { 880240075Sdes if (compare_forward(&fwd, 881240075Sdes options.local_forwards + i)) { 882240075Sdes found_fwd = options.local_forwards + i; 883240075Sdes break; 884240075Sdes } 885240075Sdes } 886240075Sdes break; 887240075Sdes case MUX_FWD_REMOTE: 888240075Sdes for (i = 0; i < options.num_remote_forwards; i++) { 889240075Sdes if (compare_forward(&fwd, 890240075Sdes options.remote_forwards + i)) { 891240075Sdes found_fwd = options.remote_forwards + i; 892240075Sdes break; 893240075Sdes } 894240075Sdes } 895240075Sdes break; 896240075Sdes } 897204917Sdes 898240075Sdes if (found_fwd == NULL) 899240075Sdes error_reason = "port not forwarded"; 900240075Sdes else if (ftype == MUX_FWD_REMOTE) { 901240075Sdes /* 902240075Sdes * This shouldn't fail unless we confused the host/port 903240075Sdes * between options.remote_forwards and permitted_opens. 904240075Sdes * However, for dynamic allocated listen ports we need 905295367Sdes * to use the actual listen port. 906240075Sdes */ 907295367Sdes if (channel_request_rforward_cancel(found_fwd) == -1) 908240075Sdes error_reason = "port not in permitted opens"; 909240075Sdes } else { /* local and dynamic forwards */ 910240075Sdes /* Ditto */ 911295367Sdes if (channel_cancel_lport_listener(&fwd, fwd.connect_port, 912295367Sdes &options.fwd_opts) == -1) 913240075Sdes error_reason = "port not found"; 914240075Sdes } 915240075Sdes 916240075Sdes if (error_reason == NULL) { 917240075Sdes buffer_put_int(r, MUX_S_OK); 918240075Sdes buffer_put_int(r, rid); 919240075Sdes 920255767Sdes free(found_fwd->listen_host); 921295367Sdes free(found_fwd->listen_path); 922255767Sdes free(found_fwd->connect_host); 923295367Sdes free(found_fwd->connect_path); 924240075Sdes found_fwd->listen_host = found_fwd->connect_host = NULL; 925295367Sdes found_fwd->listen_path = found_fwd->connect_path = NULL; 926240075Sdes found_fwd->listen_port = found_fwd->connect_port = 0; 927240075Sdes } else { 928240075Sdes buffer_put_int(r, MUX_S_FAILURE); 929240075Sdes buffer_put_int(r, rid); 930240075Sdes buffer_put_cstring(r, error_reason); 931240075Sdes } 932204917Sdes out: 933255767Sdes free(fwd_desc); 934295367Sdes free(listen_addr); 935295367Sdes free(connect_addr); 936204917Sdes 937204917Sdes return ret; 938204917Sdes} 939204917Sdes 940204917Sdesstatic int 941204917Sdesprocess_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 942204917Sdes{ 943204917Sdes Channel *nc; 944204917Sdes char *reserved, *chost; 945204917Sdes u_int cport, i, j; 946204917Sdes int new_fd[2]; 947295367Sdes struct mux_stdio_confirm_ctx *cctx; 948204917Sdes 949204917Sdes chost = reserved = NULL; 950204917Sdes if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || 951204917Sdes (chost = buffer_get_string_ret(m, NULL)) == NULL || 952204917Sdes buffer_get_int_ret(&cport, m) != 0) { 953255767Sdes free(reserved); 954255767Sdes free(chost); 955204917Sdes error("%s: malformed message", __func__); 956204917Sdes return -1; 957204917Sdes } 958255767Sdes free(reserved); 959204917Sdes 960204917Sdes debug2("%s: channel %d: request stdio fwd to %s:%u", 961204917Sdes __func__, c->self, chost, cport); 962204917Sdes 963204917Sdes /* Gather fds from client */ 964204917Sdes for(i = 0; i < 2; i++) { 965204917Sdes if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { 966204917Sdes error("%s: failed to receive fd %d from slave", 967204917Sdes __func__, i); 968204917Sdes for (j = 0; j < i; j++) 969204917Sdes close(new_fd[j]); 970255767Sdes free(chost); 971204917Sdes 972204917Sdes /* prepare reply */ 973204917Sdes buffer_put_int(r, MUX_S_FAILURE); 974204917Sdes buffer_put_int(r, rid); 975204917Sdes buffer_put_cstring(r, 976204917Sdes "did not receive file descriptors"); 977204917Sdes return -1; 978204917Sdes } 979204917Sdes } 980204917Sdes 981204917Sdes debug3("%s: got fds stdin %d, stdout %d", __func__, 982204917Sdes new_fd[0], new_fd[1]); 983204917Sdes 984204917Sdes /* XXX support multiple child sessions in future */ 985204917Sdes if (c->remote_id != -1) { 986204917Sdes debug2("%s: session already open", __func__); 987204917Sdes /* prepare reply */ 988204917Sdes buffer_put_int(r, MUX_S_FAILURE); 989204917Sdes buffer_put_int(r, rid); 990204917Sdes buffer_put_cstring(r, "Multiple sessions not supported"); 991204917Sdes cleanup: 992204917Sdes close(new_fd[0]); 993204917Sdes close(new_fd[1]); 994255767Sdes free(chost); 995204917Sdes return 0; 996204917Sdes } 997204917Sdes 998204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 999204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 1000221420Sdes if (!ask_permission("Allow forward to %s:%u? ", 1001204917Sdes chost, cport)) { 1002204917Sdes debug2("%s: stdio fwd refused by user", __func__); 1003204917Sdes /* prepare reply */ 1004204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 1005204917Sdes buffer_put_int(r, rid); 1006204917Sdes buffer_put_cstring(r, "Permission denied"); 1007204917Sdes goto cleanup; 1008204917Sdes } 1009204917Sdes } 1010204917Sdes 1011204917Sdes /* enable nonblocking unless tty */ 1012204917Sdes if (!isatty(new_fd[0])) 1013204917Sdes set_nonblock(new_fd[0]); 1014204917Sdes if (!isatty(new_fd[1])) 1015204917Sdes set_nonblock(new_fd[1]); 1016204917Sdes 1017204917Sdes nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]); 1018204917Sdes 1019204917Sdes nc->ctl_chan = c->self; /* link session -> control channel */ 1020204917Sdes c->remote_id = nc->self; /* link control -> session channel */ 1021204917Sdes 1022204917Sdes debug2("%s: channel_new: %d linked to control channel %d", 1023204917Sdes __func__, nc->self, nc->ctl_chan); 1024204917Sdes 1025215116Sdes channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); 1026204917Sdes 1027295367Sdes cctx = xcalloc(1, sizeof(*cctx)); 1028295367Sdes cctx->rid = rid; 1029295367Sdes channel_register_open_confirm(nc->self, mux_stdio_confirm, cctx); 1030295367Sdes c->mux_pause = 1; /* stop handling messages until open_confirm done */ 1031204917Sdes 1032295367Sdes /* reply is deferred, sent by mux_session_confirm */ 1033204917Sdes return 0; 1034204917Sdes} 1035204917Sdes 1036295367Sdes/* Callback on open confirmation in mux master for a mux stdio fwd session. */ 1037295367Sdesstatic void 1038295367Sdesmux_stdio_confirm(int id, int success, void *arg) 1039295367Sdes{ 1040295367Sdes struct mux_stdio_confirm_ctx *cctx = arg; 1041295367Sdes Channel *c, *cc; 1042295367Sdes Buffer reply; 1043295367Sdes 1044295367Sdes if (cctx == NULL) 1045295367Sdes fatal("%s: cctx == NULL", __func__); 1046295367Sdes if ((c = channel_by_id(id)) == NULL) 1047295367Sdes fatal("%s: no channel for id %d", __func__, id); 1048295367Sdes if ((cc = channel_by_id(c->ctl_chan)) == NULL) 1049295367Sdes fatal("%s: channel %d lacks control channel %d", __func__, 1050295367Sdes id, c->ctl_chan); 1051295367Sdes 1052295367Sdes if (!success) { 1053295367Sdes debug3("%s: sending failure reply", __func__); 1054295367Sdes /* prepare reply */ 1055295367Sdes buffer_init(&reply); 1056295367Sdes buffer_put_int(&reply, MUX_S_FAILURE); 1057295367Sdes buffer_put_int(&reply, cctx->rid); 1058295367Sdes buffer_put_cstring(&reply, "Session open refused by peer"); 1059295367Sdes goto done; 1060295367Sdes } 1061295367Sdes 1062295367Sdes debug3("%s: sending success reply", __func__); 1063295367Sdes /* prepare reply */ 1064295367Sdes buffer_init(&reply); 1065295367Sdes buffer_put_int(&reply, MUX_S_SESSION_OPENED); 1066295367Sdes buffer_put_int(&reply, cctx->rid); 1067295367Sdes buffer_put_int(&reply, c->self); 1068295367Sdes 1069295367Sdes done: 1070295367Sdes /* Send reply */ 1071295367Sdes buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); 1072295367Sdes buffer_free(&reply); 1073295367Sdes 1074295367Sdes if (cc->mux_pause <= 0) 1075295367Sdes fatal("%s: mux_pause %d", __func__, cc->mux_pause); 1076295367Sdes cc->mux_pause = 0; /* start processing messages again */ 1077295367Sdes c->open_confirm_ctx = NULL; 1078295367Sdes free(cctx); 1079295367Sdes} 1080295367Sdes 1081226046Sdesstatic int 1082226046Sdesprocess_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r) 1083226046Sdes{ 1084226046Sdes debug("%s: channel %d: stop listening", __func__, c->self); 1085226046Sdes 1086226046Sdes if (options.control_master == SSHCTL_MASTER_ASK || 1087226046Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 1088226046Sdes if (!ask_permission("Disable further multiplexing on shared " 1089226046Sdes "connection to %s? ", host)) { 1090226046Sdes debug2("%s: stop listen refused by user", __func__); 1091226046Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 1092226046Sdes buffer_put_int(r, rid); 1093226046Sdes buffer_put_cstring(r, "Permission denied"); 1094226046Sdes return 0; 1095226046Sdes } 1096226046Sdes } 1097226046Sdes 1098226046Sdes if (mux_listener_channel != NULL) { 1099226046Sdes channel_free(mux_listener_channel); 1100226046Sdes client_stop_mux(); 1101255767Sdes free(options.control_path); 1102226046Sdes options.control_path = NULL; 1103226046Sdes mux_listener_channel = NULL; 1104226046Sdes muxserver_sock = -1; 1105226046Sdes } 1106226046Sdes 1107226046Sdes /* prepare reply */ 1108226046Sdes buffer_put_int(r, MUX_S_OK); 1109226046Sdes buffer_put_int(r, rid); 1110226046Sdes 1111226046Sdes return 0; 1112226046Sdes} 1113226046Sdes 1114204917Sdes/* Channel callbacks fired on read/write from mux slave fd */ 1115204917Sdesstatic int 1116204917Sdesmux_master_read_cb(Channel *c) 1117204917Sdes{ 1118204917Sdes struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; 1119204917Sdes Buffer in, out; 1120295367Sdes const u_char *ptr; 1121204917Sdes u_int type, rid, have, i; 1122204917Sdes int ret = -1; 1123204917Sdes 1124204917Sdes /* Setup ctx and */ 1125204917Sdes if (c->mux_ctx == NULL) { 1126215116Sdes state = xcalloc(1, sizeof(*state)); 1127204917Sdes c->mux_ctx = state; 1128204917Sdes channel_register_cleanup(c->self, 1129204917Sdes mux_master_control_cleanup_cb, 0); 1130204917Sdes 1131204917Sdes /* Send hello */ 1132204917Sdes buffer_init(&out); 1133204917Sdes buffer_put_int(&out, MUX_MSG_HELLO); 1134204917Sdes buffer_put_int(&out, SSHMUX_VER); 1135204917Sdes /* no extensions */ 1136204917Sdes buffer_put_string(&c->output, buffer_ptr(&out), 1137204917Sdes buffer_len(&out)); 1138204917Sdes buffer_free(&out); 1139204917Sdes debug3("%s: channel %d: hello sent", __func__, c->self); 1140204917Sdes return 0; 1141204917Sdes } 1142204917Sdes 1143204917Sdes buffer_init(&in); 1144204917Sdes buffer_init(&out); 1145204917Sdes 1146204917Sdes /* Channel code ensures that we receive whole packets */ 1147204917Sdes if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) { 1148204917Sdes malf: 1149204917Sdes error("%s: malformed message", __func__); 1150204917Sdes goto out; 1151204917Sdes } 1152204917Sdes buffer_append(&in, ptr, have); 1153204917Sdes 1154204917Sdes if (buffer_get_int_ret(&type, &in) != 0) 1155204917Sdes goto malf; 1156204917Sdes debug3("%s: channel %d packet type 0x%08x len %u", 1157204917Sdes __func__, c->self, type, buffer_len(&in)); 1158204917Sdes 1159204917Sdes if (type == MUX_MSG_HELLO) 1160204917Sdes rid = 0; 1161204917Sdes else { 1162204917Sdes if (!state->hello_rcvd) { 1163204917Sdes error("%s: expected MUX_MSG_HELLO(0x%08x), " 1164204917Sdes "received 0x%08x", __func__, MUX_MSG_HELLO, type); 1165204917Sdes goto out; 1166204917Sdes } 1167204917Sdes if (buffer_get_int_ret(&rid, &in) != 0) 1168204917Sdes goto malf; 1169204917Sdes } 1170204917Sdes 1171204917Sdes for (i = 0; mux_master_handlers[i].handler != NULL; i++) { 1172204917Sdes if (type == mux_master_handlers[i].type) { 1173204917Sdes ret = mux_master_handlers[i].handler(rid, c, &in, &out); 1174204917Sdes break; 1175204917Sdes } 1176204917Sdes } 1177204917Sdes if (mux_master_handlers[i].handler == NULL) { 1178204917Sdes error("%s: unsupported mux message 0x%08x", __func__, type); 1179204917Sdes buffer_put_int(&out, MUX_S_FAILURE); 1180204917Sdes buffer_put_int(&out, rid); 1181204917Sdes buffer_put_cstring(&out, "unsupported request"); 1182204917Sdes ret = 0; 1183204917Sdes } 1184204917Sdes /* Enqueue reply packet */ 1185204917Sdes if (buffer_len(&out) != 0) { 1186204917Sdes buffer_put_string(&c->output, buffer_ptr(&out), 1187204917Sdes buffer_len(&out)); 1188204917Sdes } 1189204917Sdes out: 1190204917Sdes buffer_free(&in); 1191204917Sdes buffer_free(&out); 1192204917Sdes return ret; 1193204917Sdes} 1194204917Sdes 1195204917Sdesvoid 1196204917Sdesmux_exit_message(Channel *c, int exitval) 1197204917Sdes{ 1198204917Sdes Buffer m; 1199204917Sdes Channel *mux_chan; 1200204917Sdes 1201255767Sdes debug3("%s: channel %d: exit message, exitval %d", __func__, c->self, 1202204917Sdes exitval); 1203204917Sdes 1204204917Sdes if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) 1205204917Sdes fatal("%s: channel %d missing mux channel %d", 1206204917Sdes __func__, c->self, c->ctl_chan); 1207204917Sdes 1208204917Sdes /* Append exit message packet to control socket output queue */ 1209204917Sdes buffer_init(&m); 1210204917Sdes buffer_put_int(&m, MUX_S_EXIT_MESSAGE); 1211204917Sdes buffer_put_int(&m, c->self); 1212204917Sdes buffer_put_int(&m, exitval); 1213204917Sdes 1214204917Sdes buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); 1215204917Sdes buffer_free(&m); 1216204917Sdes} 1217204917Sdes 1218226046Sdesvoid 1219226046Sdesmux_tty_alloc_failed(Channel *c) 1220226046Sdes{ 1221226046Sdes Buffer m; 1222226046Sdes Channel *mux_chan; 1223226046Sdes 1224226046Sdes debug3("%s: channel %d: TTY alloc failed", __func__, c->self); 1225226046Sdes 1226226046Sdes if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) 1227226046Sdes fatal("%s: channel %d missing mux channel %d", 1228226046Sdes __func__, c->self, c->ctl_chan); 1229226046Sdes 1230226046Sdes /* Append exit message packet to control socket output queue */ 1231226046Sdes buffer_init(&m); 1232226046Sdes buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL); 1233226046Sdes buffer_put_int(&m, c->self); 1234226046Sdes 1235226046Sdes buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); 1236226046Sdes buffer_free(&m); 1237226046Sdes} 1238226046Sdes 1239180750Sdes/* Prepare a mux master to listen on a Unix domain socket. */ 1240180750Sdesvoid 1241180750Sdesmuxserver_listen(void) 1242180750Sdes{ 1243180750Sdes mode_t old_umask; 1244221420Sdes char *orig_control_path = options.control_path; 1245221420Sdes char rbuf[16+1]; 1246221420Sdes u_int i, r; 1247295367Sdes int oerrno; 1248180750Sdes 1249180750Sdes if (options.control_path == NULL || 1250180750Sdes options.control_master == SSHCTL_MASTER_NO) 1251180750Sdes return; 1252180750Sdes 1253180750Sdes debug("setting up multiplex master socket"); 1254180750Sdes 1255221420Sdes /* 1256221420Sdes * Use a temporary path before listen so we can pseudo-atomically 1257221420Sdes * establish the listening socket in its final location to avoid 1258221420Sdes * other processes racing in between bind() and listen() and hitting 1259221420Sdes * an unready socket. 1260221420Sdes */ 1261221420Sdes for (i = 0; i < sizeof(rbuf) - 1; i++) { 1262221420Sdes r = arc4random_uniform(26+26+10); 1263221420Sdes rbuf[i] = (r < 26) ? 'a' + r : 1264221420Sdes (r < 26*2) ? 'A' + r - 26 : 1265221420Sdes '0' + r - 26 - 26; 1266221420Sdes } 1267221420Sdes rbuf[sizeof(rbuf) - 1] = '\0'; 1268221420Sdes options.control_path = NULL; 1269221420Sdes xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf); 1270221420Sdes debug3("%s: temporary control path %s", __func__, options.control_path); 1271221420Sdes 1272180750Sdes old_umask = umask(0177); 1273295367Sdes muxserver_sock = unix_listener(options.control_path, 64, 0); 1274295367Sdes oerrno = errno; 1275295367Sdes umask(old_umask); 1276295367Sdes if (muxserver_sock < 0) { 1277295367Sdes if (oerrno == EINVAL || oerrno == EADDRINUSE) { 1278180750Sdes error("ControlSocket %s already exists, " 1279180750Sdes "disabling multiplexing", options.control_path); 1280221420Sdes disable_mux_master: 1281226046Sdes if (muxserver_sock != -1) { 1282226046Sdes close(muxserver_sock); 1283226046Sdes muxserver_sock = -1; 1284226046Sdes } 1285255767Sdes free(orig_control_path); 1286255767Sdes free(options.control_path); 1287180750Sdes options.control_path = NULL; 1288180750Sdes options.control_master = SSHCTL_MASTER_NO; 1289180750Sdes return; 1290295367Sdes } else { 1291295367Sdes /* unix_listener() logs the error */ 1292295367Sdes cleanup_exit(255); 1293295367Sdes } 1294180750Sdes } 1295180750Sdes 1296221420Sdes /* Now atomically "move" the mux socket into position */ 1297221420Sdes if (link(options.control_path, orig_control_path) != 0) { 1298221420Sdes if (errno != EEXIST) { 1299323124Sdes fatal("%s: link mux listener %s => %s: %s", __func__, 1300221420Sdes options.control_path, orig_control_path, 1301221420Sdes strerror(errno)); 1302221420Sdes } 1303221420Sdes error("ControlSocket %s already exists, disabling multiplexing", 1304221420Sdes orig_control_path); 1305221420Sdes unlink(options.control_path); 1306221420Sdes goto disable_mux_master; 1307221420Sdes } 1308221420Sdes unlink(options.control_path); 1309255767Sdes free(options.control_path); 1310221420Sdes options.control_path = orig_control_path; 1311221420Sdes 1312180750Sdes set_nonblock(muxserver_sock); 1313204917Sdes 1314204917Sdes mux_listener_channel = channel_new("mux listener", 1315204917Sdes SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, 1316204917Sdes CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 1317221420Sdes 0, options.control_path, 1); 1318204917Sdes mux_listener_channel->mux_rcb = mux_master_read_cb; 1319204917Sdes debug3("%s: mux listener channel %d fd %d", __func__, 1320204917Sdes mux_listener_channel->self, mux_listener_channel->sock); 1321180750Sdes} 1322180750Sdes 1323180750Sdes/* Callback on open confirmation in mux master for a mux client session. */ 1324180750Sdesstatic void 1325215116Sdesmux_session_confirm(int id, int success, void *arg) 1326180750Sdes{ 1327180750Sdes struct mux_session_confirm_ctx *cctx = arg; 1328180750Sdes const char *display; 1329215116Sdes Channel *c, *cc; 1330180750Sdes int i; 1331215116Sdes Buffer reply; 1332180750Sdes 1333180750Sdes if (cctx == NULL) 1334180750Sdes fatal("%s: cctx == NULL", __func__); 1335204917Sdes if ((c = channel_by_id(id)) == NULL) 1336180750Sdes fatal("%s: no channel for id %d", __func__, id); 1337215116Sdes if ((cc = channel_by_id(c->ctl_chan)) == NULL) 1338215116Sdes fatal("%s: channel %d lacks control channel %d", __func__, 1339215116Sdes id, c->ctl_chan); 1340180750Sdes 1341215116Sdes if (!success) { 1342215116Sdes debug3("%s: sending failure reply", __func__); 1343215116Sdes /* prepare reply */ 1344215116Sdes buffer_init(&reply); 1345215116Sdes buffer_put_int(&reply, MUX_S_FAILURE); 1346215116Sdes buffer_put_int(&reply, cctx->rid); 1347215116Sdes buffer_put_cstring(&reply, "Session open refused by peer"); 1348215116Sdes goto done; 1349215116Sdes } 1350215116Sdes 1351180750Sdes display = getenv("DISPLAY"); 1352180750Sdes if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { 1353180750Sdes char *proto, *data; 1354215116Sdes 1355180750Sdes /* Get reasonable local authentication information. */ 1356296781Sdes if (client_x11_get_proto(display, options.xauth_location, 1357215116Sdes options.forward_x11_trusted, options.forward_x11_timeout, 1358296781Sdes &proto, &data) == 0) { 1359296781Sdes /* Request forwarding with authentication spoofing. */ 1360296781Sdes debug("Requesting X11 forwarding with authentication " 1361296781Sdes "spoofing."); 1362296781Sdes x11_request_forwarding_with_spoofing(id, display, proto, 1363296781Sdes data, 1); 1364296781Sdes /* XXX exit_on_forward_failure */ 1365296781Sdes client_expect_confirm(id, "X11 forwarding", 1366296781Sdes CONFIRM_WARN); 1367296781Sdes } 1368180750Sdes } 1369180750Sdes 1370180750Sdes if (cctx->want_agent_fwd && options.forward_agent) { 1371180750Sdes debug("Requesting authentication agent forwarding."); 1372180750Sdes channel_request_start(id, "auth-agent-req@openssh.com", 0); 1373180750Sdes packet_send(); 1374180750Sdes } 1375180750Sdes 1376180750Sdes client_session2_setup(id, cctx->want_tty, cctx->want_subsys, 1377180750Sdes cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); 1378180750Sdes 1379215116Sdes debug3("%s: sending success reply", __func__); 1380215116Sdes /* prepare reply */ 1381215116Sdes buffer_init(&reply); 1382215116Sdes buffer_put_int(&reply, MUX_S_SESSION_OPENED); 1383215116Sdes buffer_put_int(&reply, cctx->rid); 1384215116Sdes buffer_put_int(&reply, c->self); 1385215116Sdes 1386215116Sdes done: 1387215116Sdes /* Send reply */ 1388215116Sdes buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); 1389215116Sdes buffer_free(&reply); 1390215116Sdes 1391215116Sdes if (cc->mux_pause <= 0) 1392215116Sdes fatal("%s: mux_pause %d", __func__, cc->mux_pause); 1393215116Sdes cc->mux_pause = 0; /* start processing messages again */ 1394180750Sdes c->open_confirm_ctx = NULL; 1395180750Sdes buffer_free(&cctx->cmd); 1396255767Sdes free(cctx->term); 1397180750Sdes if (cctx->env != NULL) { 1398180750Sdes for (i = 0; cctx->env[i] != NULL; i++) 1399255767Sdes free(cctx->env[i]); 1400255767Sdes free(cctx->env); 1401180750Sdes } 1402255767Sdes free(cctx); 1403180750Sdes} 1404180750Sdes 1405204917Sdes/* ** Multiplexing client support */ 1406204917Sdes 1407204917Sdes/* Exit signal handler */ 1408204917Sdesstatic void 1409204917Sdescontrol_client_sighandler(int signo) 1410204917Sdes{ 1411204917Sdes muxclient_terminate = signo; 1412204917Sdes} 1413204917Sdes 1414180750Sdes/* 1415204917Sdes * Relay signal handler - used to pass some signals from mux client to 1416204917Sdes * mux master. 1417180750Sdes */ 1418204917Sdesstatic void 1419204917Sdescontrol_client_sigrelay(int signo) 1420180750Sdes{ 1421204917Sdes int save_errno = errno; 1422180750Sdes 1423204917Sdes if (muxserver_pid > 1) 1424204917Sdes kill(muxserver_pid, signo); 1425204917Sdes 1426204917Sdes errno = save_errno; 1427204917Sdes} 1428204917Sdes 1429204917Sdesstatic int 1430204917Sdesmux_client_read(int fd, Buffer *b, u_int need) 1431204917Sdes{ 1432204917Sdes u_int have; 1433204917Sdes ssize_t len; 1434204917Sdes u_char *p; 1435204917Sdes struct pollfd pfd; 1436204917Sdes 1437204917Sdes pfd.fd = fd; 1438204917Sdes pfd.events = POLLIN; 1439204917Sdes p = buffer_append_space(b, need); 1440204917Sdes for (have = 0; have < need; ) { 1441204917Sdes if (muxclient_terminate) { 1442204917Sdes errno = EINTR; 1443204917Sdes return -1; 1444204917Sdes } 1445204917Sdes len = read(fd, p + have, need - have); 1446204917Sdes if (len < 0) { 1447204917Sdes switch (errno) { 1448204917Sdes#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) 1449204917Sdes case EWOULDBLOCK: 1450204917Sdes#endif 1451204917Sdes case EAGAIN: 1452204917Sdes (void)poll(&pfd, 1, -1); 1453204917Sdes /* FALLTHROUGH */ 1454204917Sdes case EINTR: 1455204917Sdes continue; 1456204917Sdes default: 1457204917Sdes return -1; 1458204917Sdes } 1459204917Sdes } 1460204917Sdes if (len == 0) { 1461204917Sdes errno = EPIPE; 1462204917Sdes return -1; 1463204917Sdes } 1464204917Sdes have += (u_int)len; 1465180750Sdes } 1466204917Sdes return 0; 1467204917Sdes} 1468180750Sdes 1469204917Sdesstatic int 1470204917Sdesmux_client_write_packet(int fd, Buffer *m) 1471204917Sdes{ 1472204917Sdes Buffer queue; 1473204917Sdes u_int have, need; 1474204917Sdes int oerrno, len; 1475204917Sdes u_char *ptr; 1476204917Sdes struct pollfd pfd; 1477204917Sdes 1478204917Sdes pfd.fd = fd; 1479204917Sdes pfd.events = POLLOUT; 1480204917Sdes buffer_init(&queue); 1481204917Sdes buffer_put_string(&queue, buffer_ptr(m), buffer_len(m)); 1482204917Sdes 1483204917Sdes need = buffer_len(&queue); 1484204917Sdes ptr = buffer_ptr(&queue); 1485204917Sdes 1486204917Sdes for (have = 0; have < need; ) { 1487204917Sdes if (muxclient_terminate) { 1488204917Sdes buffer_free(&queue); 1489204917Sdes errno = EINTR; 1490204917Sdes return -1; 1491204917Sdes } 1492204917Sdes len = write(fd, ptr + have, need - have); 1493204917Sdes if (len < 0) { 1494204917Sdes switch (errno) { 1495204917Sdes#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) 1496204917Sdes case EWOULDBLOCK: 1497204917Sdes#endif 1498204917Sdes case EAGAIN: 1499204917Sdes (void)poll(&pfd, 1, -1); 1500204917Sdes /* FALLTHROUGH */ 1501204917Sdes case EINTR: 1502204917Sdes continue; 1503204917Sdes default: 1504204917Sdes oerrno = errno; 1505204917Sdes buffer_free(&queue); 1506204917Sdes errno = oerrno; 1507204917Sdes return -1; 1508204917Sdes } 1509204917Sdes } 1510204917Sdes if (len == 0) { 1511204917Sdes buffer_free(&queue); 1512204917Sdes errno = EPIPE; 1513204917Sdes return -1; 1514204917Sdes } 1515204917Sdes have += (u_int)len; 1516180750Sdes } 1517204917Sdes buffer_free(&queue); 1518204917Sdes return 0; 1519204917Sdes} 1520204917Sdes 1521204917Sdesstatic int 1522204917Sdesmux_client_read_packet(int fd, Buffer *m) 1523204917Sdes{ 1524204917Sdes Buffer queue; 1525204917Sdes u_int need, have; 1526295367Sdes const u_char *ptr; 1527204917Sdes int oerrno; 1528204917Sdes 1529204917Sdes buffer_init(&queue); 1530204917Sdes if (mux_client_read(fd, &queue, 4) != 0) { 1531204917Sdes if ((oerrno = errno) == EPIPE) 1532255767Sdes debug3("%s: read header failed: %s", __func__, 1533255767Sdes strerror(errno)); 1534255767Sdes buffer_free(&queue); 1535204917Sdes errno = oerrno; 1536204917Sdes return -1; 1537180750Sdes } 1538204917Sdes need = get_u32(buffer_ptr(&queue)); 1539204917Sdes if (mux_client_read(fd, &queue, need) != 0) { 1540204917Sdes oerrno = errno; 1541204917Sdes debug3("%s: read body failed: %s", __func__, strerror(errno)); 1542255767Sdes buffer_free(&queue); 1543204917Sdes errno = oerrno; 1544204917Sdes return -1; 1545204917Sdes } 1546204917Sdes ptr = buffer_get_string_ptr(&queue, &have); 1547204917Sdes buffer_append(m, ptr, have); 1548204917Sdes buffer_free(&queue); 1549204917Sdes return 0; 1550204917Sdes} 1551180750Sdes 1552204917Sdesstatic int 1553204917Sdesmux_client_hello_exchange(int fd) 1554204917Sdes{ 1555204917Sdes Buffer m; 1556204917Sdes u_int type, ver; 1557180750Sdes 1558180750Sdes buffer_init(&m); 1559204917Sdes buffer_put_int(&m, MUX_MSG_HELLO); 1560204917Sdes buffer_put_int(&m, SSHMUX_VER); 1561204917Sdes /* no extensions */ 1562204917Sdes 1563204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1564204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1565204917Sdes 1566204917Sdes buffer_clear(&m); 1567204917Sdes 1568204917Sdes /* Read their HELLO */ 1569204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1570180750Sdes buffer_free(&m); 1571204917Sdes return -1; 1572180750Sdes } 1573204917Sdes 1574204917Sdes type = buffer_get_int(&m); 1575204917Sdes if (type != MUX_MSG_HELLO) 1576204917Sdes fatal("%s: expected HELLO (%u) received %u", 1577204917Sdes __func__, MUX_MSG_HELLO, type); 1578204917Sdes ver = buffer_get_int(&m); 1579204917Sdes if (ver != SSHMUX_VER) 1580204917Sdes fatal("Unsupported multiplexing protocol version %d " 1581204917Sdes "(expected %d)", ver, SSHMUX_VER); 1582204917Sdes debug2("%s: master version %u", __func__, ver); 1583204917Sdes /* No extensions are presently defined */ 1584204917Sdes while (buffer_len(&m) > 0) { 1585204917Sdes char *name = buffer_get_string(&m, NULL); 1586204917Sdes char *value = buffer_get_string(&m, NULL); 1587204917Sdes 1588204917Sdes debug2("Unrecognised master extension \"%s\"", name); 1589255767Sdes free(name); 1590255767Sdes free(value); 1591204917Sdes } 1592204917Sdes buffer_free(&m); 1593204917Sdes return 0; 1594204917Sdes} 1595204917Sdes 1596204917Sdesstatic u_int 1597204917Sdesmux_client_request_alive(int fd) 1598204917Sdes{ 1599204917Sdes Buffer m; 1600204917Sdes char *e; 1601204917Sdes u_int pid, type, rid; 1602204917Sdes 1603204917Sdes debug3("%s: entering", __func__); 1604204917Sdes 1605204917Sdes buffer_init(&m); 1606204917Sdes buffer_put_int(&m, MUX_C_ALIVE_CHECK); 1607204917Sdes buffer_put_int(&m, muxclient_request_id); 1608204917Sdes 1609204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1610204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1611204917Sdes 1612204917Sdes buffer_clear(&m); 1613204917Sdes 1614204917Sdes /* Read their reply */ 1615204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1616180750Sdes buffer_free(&m); 1617180750Sdes return 0; 1618180750Sdes } 1619180750Sdes 1620204917Sdes type = buffer_get_int(&m); 1621204917Sdes if (type != MUX_S_ALIVE) { 1622204917Sdes e = buffer_get_string(&m, NULL); 1623204917Sdes fatal("%s: master returned error: %s", __func__, e); 1624204917Sdes } 1625180750Sdes 1626204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1627204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1628204917Sdes __func__, muxclient_request_id, rid); 1629204917Sdes pid = buffer_get_int(&m); 1630204917Sdes buffer_free(&m); 1631204917Sdes 1632204917Sdes debug3("%s: done pid = %u", __func__, pid); 1633204917Sdes 1634204917Sdes muxclient_request_id++; 1635204917Sdes 1636204917Sdes return pid; 1637204917Sdes} 1638204917Sdes 1639204917Sdesstatic void 1640204917Sdesmux_client_request_terminate(int fd) 1641204917Sdes{ 1642204917Sdes Buffer m; 1643204917Sdes char *e; 1644204917Sdes u_int type, rid; 1645204917Sdes 1646204917Sdes debug3("%s: entering", __func__); 1647204917Sdes 1648204917Sdes buffer_init(&m); 1649204917Sdes buffer_put_int(&m, MUX_C_TERMINATE); 1650204917Sdes buffer_put_int(&m, muxclient_request_id); 1651204917Sdes 1652204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1653204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1654204917Sdes 1655180750Sdes buffer_clear(&m); 1656180750Sdes 1657204917Sdes /* Read their reply */ 1658204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1659204917Sdes /* Remote end exited already */ 1660204917Sdes if (errno == EPIPE) { 1661180750Sdes buffer_free(&m); 1662204917Sdes return; 1663180750Sdes } 1664204917Sdes fatal("%s: read from master failed: %s", 1665204917Sdes __func__, strerror(errno)); 1666204917Sdes } 1667204917Sdes 1668204917Sdes type = buffer_get_int(&m); 1669204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1670204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1671204917Sdes __func__, muxclient_request_id, rid); 1672204917Sdes switch (type) { 1673204917Sdes case MUX_S_OK: 1674204917Sdes break; 1675204917Sdes case MUX_S_PERMISSION_DENIED: 1676204917Sdes e = buffer_get_string(&m, NULL); 1677204917Sdes fatal("Master refused termination request: %s", e); 1678204917Sdes case MUX_S_FAILURE: 1679204917Sdes e = buffer_get_string(&m, NULL); 1680204917Sdes fatal("%s: termination request failed: %s", __func__, e); 1681180750Sdes default: 1682204917Sdes fatal("%s: unexpected response from master 0x%08x", 1683204917Sdes __func__, type); 1684180750Sdes } 1685204917Sdes buffer_free(&m); 1686204917Sdes muxclient_request_id++; 1687204917Sdes} 1688180750Sdes 1689204917Sdesstatic int 1690295367Sdesmux_client_forward(int fd, int cancel_flag, u_int ftype, struct Forward *fwd) 1691204917Sdes{ 1692204917Sdes Buffer m; 1693204917Sdes char *e, *fwd_desc; 1694204917Sdes u_int type, rid; 1695204917Sdes 1696204917Sdes fwd_desc = format_forward(ftype, fwd); 1697240075Sdes debug("Requesting %s %s", 1698240075Sdes cancel_flag ? "cancellation of" : "forwarding of", fwd_desc); 1699255767Sdes free(fwd_desc); 1700204917Sdes 1701204917Sdes buffer_init(&m); 1702240075Sdes buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD); 1703204917Sdes buffer_put_int(&m, muxclient_request_id); 1704204917Sdes buffer_put_int(&m, ftype); 1705295367Sdes if (fwd->listen_path != NULL) { 1706295367Sdes buffer_put_cstring(&m, fwd->listen_path); 1707295367Sdes } else { 1708295367Sdes buffer_put_cstring(&m, 1709295367Sdes fwd->listen_host == NULL ? "" : 1710295367Sdes (*fwd->listen_host == '\0' ? "*" : fwd->listen_host)); 1711295367Sdes } 1712204917Sdes buffer_put_int(&m, fwd->listen_port); 1713295367Sdes if (fwd->connect_path != NULL) { 1714295367Sdes buffer_put_cstring(&m, fwd->connect_path); 1715295367Sdes } else { 1716295367Sdes buffer_put_cstring(&m, 1717295367Sdes fwd->connect_host == NULL ? "" : fwd->connect_host); 1718295367Sdes } 1719204917Sdes buffer_put_int(&m, fwd->connect_port); 1720204917Sdes 1721204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1722204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1723204917Sdes 1724180750Sdes buffer_clear(&m); 1725204917Sdes 1726204917Sdes /* Read their reply */ 1727204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1728180750Sdes buffer_free(&m); 1729204917Sdes return -1; 1730180750Sdes } 1731180750Sdes 1732204917Sdes type = buffer_get_int(&m); 1733204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1734204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1735204917Sdes __func__, muxclient_request_id, rid); 1736204917Sdes switch (type) { 1737204917Sdes case MUX_S_OK: 1738204917Sdes break; 1739215116Sdes case MUX_S_REMOTE_PORT: 1740240075Sdes if (cancel_flag) 1741240075Sdes fatal("%s: got MUX_S_REMOTE_PORT for cancel", __func__); 1742215116Sdes fwd->allocated_port = buffer_get_int(&m); 1743295367Sdes verbose("Allocated port %u for remote forward to %s:%d", 1744215116Sdes fwd->allocated_port, 1745215116Sdes fwd->connect_host ? fwd->connect_host : "", 1746215116Sdes fwd->connect_port); 1747215116Sdes if (muxclient_command == SSHMUX_COMMAND_FORWARD) 1748296781Sdes fprintf(stdout, "%i\n", fwd->allocated_port); 1749215116Sdes break; 1750204917Sdes case MUX_S_PERMISSION_DENIED: 1751204917Sdes e = buffer_get_string(&m, NULL); 1752180750Sdes buffer_free(&m); 1753204917Sdes error("Master refused forwarding request: %s", e); 1754204917Sdes return -1; 1755204917Sdes case MUX_S_FAILURE: 1756204917Sdes e = buffer_get_string(&m, NULL); 1757204917Sdes buffer_free(&m); 1758221420Sdes error("%s: forwarding request failed: %s", __func__, e); 1759204917Sdes return -1; 1760204917Sdes default: 1761204917Sdes fatal("%s: unexpected response from master 0x%08x", 1762204917Sdes __func__, type); 1763180750Sdes } 1764204917Sdes buffer_free(&m); 1765180750Sdes 1766204917Sdes muxclient_request_id++; 1767204917Sdes return 0; 1768204917Sdes} 1769204917Sdes 1770204917Sdesstatic int 1771240075Sdesmux_client_forwards(int fd, int cancel_flag) 1772204917Sdes{ 1773240075Sdes int i, ret = 0; 1774204917Sdes 1775240075Sdes debug3("%s: %s forwardings: %d local, %d remote", __func__, 1776240075Sdes cancel_flag ? "cancel" : "request", 1777204917Sdes options.num_local_forwards, options.num_remote_forwards); 1778204917Sdes 1779204917Sdes /* XXX ExitOnForwardingFailure */ 1780204917Sdes for (i = 0; i < options.num_local_forwards; i++) { 1781240075Sdes if (mux_client_forward(fd, cancel_flag, 1782204917Sdes options.local_forwards[i].connect_port == 0 ? 1783204917Sdes MUX_FWD_DYNAMIC : MUX_FWD_LOCAL, 1784204917Sdes options.local_forwards + i) != 0) 1785240075Sdes ret = -1; 1786180750Sdes } 1787204917Sdes for (i = 0; i < options.num_remote_forwards; i++) { 1788240075Sdes if (mux_client_forward(fd, cancel_flag, MUX_FWD_REMOTE, 1789204917Sdes options.remote_forwards + i) != 0) 1790240075Sdes ret = -1; 1791180750Sdes } 1792240075Sdes return ret; 1793204917Sdes} 1794180750Sdes 1795204917Sdesstatic int 1796204917Sdesmux_client_request_session(int fd) 1797204917Sdes{ 1798204917Sdes Buffer m; 1799204917Sdes char *e, *term; 1800204917Sdes u_int i, rid, sid, esid, exitval, type, exitval_seen; 1801204917Sdes extern char **environ; 1802226046Sdes int devnull, rawmode; 1803180750Sdes 1804204917Sdes debug3("%s: entering", __func__); 1805180750Sdes 1806204917Sdes if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { 1807204917Sdes error("%s: master alive request failed", __func__); 1808204917Sdes return -1; 1809180750Sdes } 1810180750Sdes 1811204917Sdes signal(SIGPIPE, SIG_IGN); 1812180750Sdes 1813204917Sdes if (stdin_null_flag) { 1814204917Sdes if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) 1815204917Sdes fatal("open(/dev/null): %s", strerror(errno)); 1816204917Sdes if (dup2(devnull, STDIN_FILENO) == -1) 1817204917Sdes fatal("dup2: %s", strerror(errno)); 1818204917Sdes if (devnull > STDERR_FILENO) 1819204917Sdes close(devnull); 1820180750Sdes } 1821180750Sdes 1822204917Sdes term = getenv("TERM"); 1823180750Sdes 1824204917Sdes buffer_init(&m); 1825204917Sdes buffer_put_int(&m, MUX_C_NEW_SESSION); 1826204917Sdes buffer_put_int(&m, muxclient_request_id); 1827204917Sdes buffer_put_cstring(&m, ""); /* reserved */ 1828204917Sdes buffer_put_int(&m, tty_flag); 1829204917Sdes buffer_put_int(&m, options.forward_x11); 1830204917Sdes buffer_put_int(&m, options.forward_agent); 1831204917Sdes buffer_put_int(&m, subsystem_flag); 1832204917Sdes buffer_put_int(&m, options.escape_char == SSH_ESCAPECHAR_NONE ? 1833204917Sdes 0xffffffff : (u_int)options.escape_char); 1834204917Sdes buffer_put_cstring(&m, term == NULL ? "" : term); 1835204917Sdes buffer_put_string(&m, buffer_ptr(&command), buffer_len(&command)); 1836180750Sdes 1837204917Sdes if (options.num_send_env > 0 && environ != NULL) { 1838204917Sdes /* Pass environment */ 1839204917Sdes for (i = 0; environ[i] != NULL; i++) { 1840204917Sdes if (env_permitted(environ[i])) { 1841204917Sdes buffer_put_cstring(&m, environ[i]); 1842204917Sdes } 1843180750Sdes } 1844180750Sdes } 1845180750Sdes 1846204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1847204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1848180750Sdes 1849204917Sdes /* Send the stdio file descriptors */ 1850204917Sdes if (mm_send_fd(fd, STDIN_FILENO) == -1 || 1851204917Sdes mm_send_fd(fd, STDOUT_FILENO) == -1 || 1852204917Sdes mm_send_fd(fd, STDERR_FILENO) == -1) 1853204917Sdes fatal("%s: send fds failed", __func__); 1854180750Sdes 1855204917Sdes debug3("%s: session request sent", __func__); 1856204917Sdes 1857204917Sdes /* Read their reply */ 1858204917Sdes buffer_clear(&m); 1859204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1860204917Sdes error("%s: read from master failed: %s", 1861204917Sdes __func__, strerror(errno)); 1862204917Sdes buffer_free(&m); 1863204917Sdes return -1; 1864180750Sdes } 1865180750Sdes 1866204917Sdes type = buffer_get_int(&m); 1867204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1868204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1869204917Sdes __func__, muxclient_request_id, rid); 1870204917Sdes switch (type) { 1871204917Sdes case MUX_S_SESSION_OPENED: 1872204917Sdes sid = buffer_get_int(&m); 1873204917Sdes debug("%s: master session id: %u", __func__, sid); 1874204917Sdes break; 1875204917Sdes case MUX_S_PERMISSION_DENIED: 1876204917Sdes e = buffer_get_string(&m, NULL); 1877204917Sdes buffer_free(&m); 1878221420Sdes error("Master refused session request: %s", e); 1879204917Sdes return -1; 1880204917Sdes case MUX_S_FAILURE: 1881204917Sdes e = buffer_get_string(&m, NULL); 1882204917Sdes buffer_free(&m); 1883221420Sdes error("%s: session request failed: %s", __func__, e); 1884204917Sdes return -1; 1885204917Sdes default: 1886204917Sdes buffer_free(&m); 1887204917Sdes error("%s: unexpected response from master 0x%08x", 1888204917Sdes __func__, type); 1889204917Sdes return -1; 1890180750Sdes } 1891204917Sdes muxclient_request_id++; 1892180750Sdes 1893296781Sdes if (pledge("stdio proc tty", NULL) == -1) 1894296781Sdes fatal("%s pledge(): %s", __func__, strerror(errno)); 1895296781Sdes platform_pledge_mux(); 1896296781Sdes 1897204917Sdes signal(SIGHUP, control_client_sighandler); 1898204917Sdes signal(SIGINT, control_client_sighandler); 1899204917Sdes signal(SIGTERM, control_client_sighandler); 1900204917Sdes signal(SIGWINCH, control_client_sigrelay); 1901180750Sdes 1902226046Sdes rawmode = tty_flag; 1903204917Sdes if (tty_flag) 1904226046Sdes enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); 1905180750Sdes 1906204917Sdes /* 1907204917Sdes * Stick around until the controlee closes the client_fd. 1908204917Sdes * Before it does, it is expected to write an exit message. 1909204917Sdes * This process must read the value and wait for the closure of 1910204917Sdes * the client_fd; if this one closes early, the multiplex master will 1911204917Sdes * terminate early too (possibly losing data). 1912204917Sdes */ 1913204917Sdes for (exitval = 255, exitval_seen = 0;;) { 1914204917Sdes buffer_clear(&m); 1915204917Sdes if (mux_client_read_packet(fd, &m) != 0) 1916204917Sdes break; 1917204917Sdes type = buffer_get_int(&m); 1918226046Sdes switch (type) { 1919226046Sdes case MUX_S_TTY_ALLOC_FAIL: 1920226046Sdes if ((esid = buffer_get_int(&m)) != sid) 1921226046Sdes fatal("%s: tty alloc fail on unknown session: " 1922226046Sdes "my id %u theirs %u", 1923226046Sdes __func__, sid, esid); 1924226046Sdes leave_raw_mode(options.request_tty == 1925226046Sdes REQUEST_TTY_FORCE); 1926226046Sdes rawmode = 0; 1927226046Sdes continue; 1928226046Sdes case MUX_S_EXIT_MESSAGE: 1929226046Sdes if ((esid = buffer_get_int(&m)) != sid) 1930226046Sdes fatal("%s: exit on unknown session: " 1931226046Sdes "my id %u theirs %u", 1932226046Sdes __func__, sid, esid); 1933226046Sdes if (exitval_seen) 1934226046Sdes fatal("%s: exitval sent twice", __func__); 1935226046Sdes exitval = buffer_get_int(&m); 1936226046Sdes exitval_seen = 1; 1937226046Sdes continue; 1938226046Sdes default: 1939204917Sdes e = buffer_get_string(&m, NULL); 1940204917Sdes fatal("%s: master returned error: %s", __func__, e); 1941204917Sdes } 1942204917Sdes } 1943180750Sdes 1944204917Sdes close(fd); 1945226046Sdes if (rawmode) 1946226046Sdes leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); 1947180750Sdes 1948204917Sdes if (muxclient_terminate) { 1949255767Sdes debug2("Exiting on signal %ld", (long)muxclient_terminate); 1950204917Sdes exitval = 255; 1951204917Sdes } else if (!exitval_seen) { 1952204917Sdes debug2("Control master terminated unexpectedly"); 1953204917Sdes exitval = 255; 1954204917Sdes } else 1955204917Sdes debug2("Received exit status from master %d", exitval); 1956180750Sdes 1957204917Sdes if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) 1958204917Sdes fprintf(stderr, "Shared connection to %s closed.\r\n", host); 1959180750Sdes 1960204917Sdes exit(exitval); 1961180750Sdes} 1962180750Sdes 1963180750Sdesstatic int 1964204917Sdesmux_client_request_stdio_fwd(int fd) 1965180750Sdes{ 1966204917Sdes Buffer m; 1967204917Sdes char *e; 1968204917Sdes u_int type, rid, sid; 1969204917Sdes int devnull; 1970180750Sdes 1971204917Sdes debug3("%s: entering", __func__); 1972180750Sdes 1973204917Sdes if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { 1974204917Sdes error("%s: master alive request failed", __func__); 1975204917Sdes return -1; 1976204917Sdes } 1977180750Sdes 1978204917Sdes signal(SIGPIPE, SIG_IGN); 1979204917Sdes 1980204917Sdes if (stdin_null_flag) { 1981204917Sdes if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) 1982204917Sdes fatal("open(/dev/null): %s", strerror(errno)); 1983204917Sdes if (dup2(devnull, STDIN_FILENO) == -1) 1984204917Sdes fatal("dup2: %s", strerror(errno)); 1985204917Sdes if (devnull > STDERR_FILENO) 1986204917Sdes close(devnull); 1987204917Sdes } 1988204917Sdes 1989204917Sdes buffer_init(&m); 1990204917Sdes buffer_put_int(&m, MUX_C_NEW_STDIO_FWD); 1991204917Sdes buffer_put_int(&m, muxclient_request_id); 1992204917Sdes buffer_put_cstring(&m, ""); /* reserved */ 1993323124Sdes buffer_put_cstring(&m, options.stdio_forward_host); 1994323124Sdes buffer_put_int(&m, options.stdio_forward_port); 1995204917Sdes 1996204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1997204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1998204917Sdes 1999204917Sdes /* Send the stdio file descriptors */ 2000204917Sdes if (mm_send_fd(fd, STDIN_FILENO) == -1 || 2001204917Sdes mm_send_fd(fd, STDOUT_FILENO) == -1) 2002204917Sdes fatal("%s: send fds failed", __func__); 2003204917Sdes 2004296781Sdes if (pledge("stdio proc tty", NULL) == -1) 2005296781Sdes fatal("%s pledge(): %s", __func__, strerror(errno)); 2006296781Sdes platform_pledge_mux(); 2007296781Sdes 2008204917Sdes debug3("%s: stdio forward request sent", __func__); 2009204917Sdes 2010204917Sdes /* Read their reply */ 2011204917Sdes buffer_clear(&m); 2012204917Sdes 2013204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 2014204917Sdes error("%s: read from master failed: %s", 2015204917Sdes __func__, strerror(errno)); 2016204917Sdes buffer_free(&m); 2017204917Sdes return -1; 2018204917Sdes } 2019204917Sdes 2020204917Sdes type = buffer_get_int(&m); 2021204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 2022204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 2023204917Sdes __func__, muxclient_request_id, rid); 2024204917Sdes switch (type) { 2025204917Sdes case MUX_S_SESSION_OPENED: 2026204917Sdes sid = buffer_get_int(&m); 2027204917Sdes debug("%s: master session id: %u", __func__, sid); 2028204917Sdes break; 2029204917Sdes case MUX_S_PERMISSION_DENIED: 2030204917Sdes e = buffer_get_string(&m, NULL); 2031204917Sdes buffer_free(&m); 2032221420Sdes fatal("Master refused stdio forwarding request: %s", e); 2033204917Sdes case MUX_S_FAILURE: 2034204917Sdes e = buffer_get_string(&m, NULL); 2035204917Sdes buffer_free(&m); 2036295367Sdes fatal("Stdio forwarding request failed: %s", e); 2037204917Sdes default: 2038204917Sdes buffer_free(&m); 2039204917Sdes error("%s: unexpected response from master 0x%08x", 2040204917Sdes __func__, type); 2041204917Sdes return -1; 2042204917Sdes } 2043204917Sdes muxclient_request_id++; 2044204917Sdes 2045204917Sdes signal(SIGHUP, control_client_sighandler); 2046204917Sdes signal(SIGINT, control_client_sighandler); 2047204917Sdes signal(SIGTERM, control_client_sighandler); 2048204917Sdes signal(SIGWINCH, control_client_sigrelay); 2049204917Sdes 2050204917Sdes /* 2051204917Sdes * Stick around until the controlee closes the client_fd. 2052204917Sdes */ 2053204917Sdes buffer_clear(&m); 2054204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 2055204917Sdes if (errno == EPIPE || 2056204917Sdes (errno == EINTR && muxclient_terminate != 0)) 2057204917Sdes return 0; 2058204917Sdes fatal("%s: mux_client_read_packet: %s", 2059204917Sdes __func__, strerror(errno)); 2060204917Sdes } 2061204917Sdes fatal("%s: master returned unexpected message %u", __func__, type); 2062180750Sdes} 2063180750Sdes 2064226046Sdesstatic void 2065226046Sdesmux_client_request_stop_listening(int fd) 2066226046Sdes{ 2067226046Sdes Buffer m; 2068226046Sdes char *e; 2069226046Sdes u_int type, rid; 2070226046Sdes 2071226046Sdes debug3("%s: entering", __func__); 2072226046Sdes 2073226046Sdes buffer_init(&m); 2074226046Sdes buffer_put_int(&m, MUX_C_STOP_LISTENING); 2075226046Sdes buffer_put_int(&m, muxclient_request_id); 2076226046Sdes 2077226046Sdes if (mux_client_write_packet(fd, &m) != 0) 2078226046Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 2079226046Sdes 2080226046Sdes buffer_clear(&m); 2081226046Sdes 2082226046Sdes /* Read their reply */ 2083226046Sdes if (mux_client_read_packet(fd, &m) != 0) 2084226046Sdes fatal("%s: read from master failed: %s", 2085226046Sdes __func__, strerror(errno)); 2086226046Sdes 2087226046Sdes type = buffer_get_int(&m); 2088226046Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 2089226046Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 2090226046Sdes __func__, muxclient_request_id, rid); 2091226046Sdes switch (type) { 2092226046Sdes case MUX_S_OK: 2093226046Sdes break; 2094226046Sdes case MUX_S_PERMISSION_DENIED: 2095226046Sdes e = buffer_get_string(&m, NULL); 2096226046Sdes fatal("Master refused stop listening request: %s", e); 2097226046Sdes case MUX_S_FAILURE: 2098226046Sdes e = buffer_get_string(&m, NULL); 2099226046Sdes fatal("%s: stop listening request failed: %s", __func__, e); 2100226046Sdes default: 2101226046Sdes fatal("%s: unexpected response from master 0x%08x", 2102226046Sdes __func__, type); 2103226046Sdes } 2104226046Sdes buffer_free(&m); 2105226046Sdes muxclient_request_id++; 2106226046Sdes} 2107226046Sdes 2108180750Sdes/* Multiplex client main loop. */ 2109180750Sdesvoid 2110180750Sdesmuxclient(const char *path) 2111180750Sdes{ 2112180750Sdes struct sockaddr_un addr; 2113204917Sdes socklen_t sun_len; 2114204917Sdes int sock; 2115204917Sdes u_int pid; 2116180750Sdes 2117204917Sdes if (muxclient_command == 0) { 2118323124Sdes if (options.stdio_forward_host != NULL) 2119204917Sdes muxclient_command = SSHMUX_COMMAND_STDIO_FWD; 2120204917Sdes else 2121204917Sdes muxclient_command = SSHMUX_COMMAND_OPEN; 2122204917Sdes } 2123180750Sdes 2124180750Sdes switch (options.control_master) { 2125180750Sdes case SSHCTL_MASTER_AUTO: 2126180750Sdes case SSHCTL_MASTER_AUTO_ASK: 2127180750Sdes debug("auto-mux: Trying existing master"); 2128180750Sdes /* FALLTHROUGH */ 2129180750Sdes case SSHCTL_MASTER_NO: 2130180750Sdes break; 2131180750Sdes default: 2132180750Sdes return; 2133180750Sdes } 2134180750Sdes 2135180750Sdes memset(&addr, '\0', sizeof(addr)); 2136180750Sdes addr.sun_family = AF_UNIX; 2137204917Sdes sun_len = offsetof(struct sockaddr_un, sun_path) + 2138180750Sdes strlen(path) + 1; 2139180750Sdes 2140180750Sdes if (strlcpy(addr.sun_path, path, 2141180750Sdes sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) 2142180750Sdes fatal("ControlPath too long"); 2143180750Sdes 2144180750Sdes if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) 2145180750Sdes fatal("%s socket(): %s", __func__, strerror(errno)); 2146180750Sdes 2147204917Sdes if (connect(sock, (struct sockaddr *)&addr, sun_len) == -1) { 2148204917Sdes switch (muxclient_command) { 2149204917Sdes case SSHMUX_COMMAND_OPEN: 2150204917Sdes case SSHMUX_COMMAND_STDIO_FWD: 2151204917Sdes break; 2152204917Sdes default: 2153180750Sdes fatal("Control socket connect(%.100s): %s", path, 2154180750Sdes strerror(errno)); 2155180750Sdes } 2156221420Sdes if (errno == ECONNREFUSED && 2157221420Sdes options.control_master != SSHCTL_MASTER_NO) { 2158221420Sdes debug("Stale control socket %.100s, unlinking", path); 2159221420Sdes unlink(path); 2160221420Sdes } else if (errno == ENOENT) { 2161180750Sdes debug("Control socket \"%.100s\" does not exist", path); 2162221420Sdes } else { 2163180750Sdes error("Control socket connect(%.100s): %s", path, 2164180750Sdes strerror(errno)); 2165180750Sdes } 2166180750Sdes close(sock); 2167180750Sdes return; 2168180750Sdes } 2169204917Sdes set_nonblock(sock); 2170180750Sdes 2171204917Sdes if (mux_client_hello_exchange(sock) != 0) { 2172204917Sdes error("%s: master hello exchange failed", __func__); 2173180750Sdes close(sock); 2174180750Sdes return; 2175180750Sdes } 2176180750Sdes 2177180750Sdes switch (muxclient_command) { 2178180750Sdes case SSHMUX_COMMAND_ALIVE_CHECK: 2179204917Sdes if ((pid = mux_client_request_alive(sock)) == 0) 2180204917Sdes fatal("%s: master alive check failed", __func__); 2181296781Sdes fprintf(stderr, "Master running (pid=%u)\r\n", pid); 2182180750Sdes exit(0); 2183180750Sdes case SSHMUX_COMMAND_TERMINATE: 2184204917Sdes mux_client_request_terminate(sock); 2185180750Sdes fprintf(stderr, "Exit request sent.\r\n"); 2186180750Sdes exit(0); 2187215116Sdes case SSHMUX_COMMAND_FORWARD: 2188240075Sdes if (mux_client_forwards(sock, 0) != 0) 2189215116Sdes fatal("%s: master forward request failed", __func__); 2190215116Sdes exit(0); 2191180750Sdes case SSHMUX_COMMAND_OPEN: 2192240075Sdes if (mux_client_forwards(sock, 0) != 0) { 2193204917Sdes error("%s: master forward request failed", __func__); 2194204917Sdes return; 2195180750Sdes } 2196204917Sdes mux_client_request_session(sock); 2197204917Sdes return; 2198204917Sdes case SSHMUX_COMMAND_STDIO_FWD: 2199204917Sdes mux_client_request_stdio_fwd(sock); 2200204917Sdes exit(0); 2201226046Sdes case SSHMUX_COMMAND_STOP: 2202226046Sdes mux_client_request_stop_listening(sock); 2203226046Sdes fprintf(stderr, "Stop listening request sent.\r\n"); 2204226046Sdes exit(0); 2205240075Sdes case SSHMUX_COMMAND_CANCEL_FWD: 2206240075Sdes if (mux_client_forwards(sock, 1) != 0) 2207240075Sdes error("%s: master cancel forward request failed", 2208240075Sdes __func__); 2209240075Sdes exit(0); 2210180750Sdes default: 2211180750Sdes fatal("unrecognised muxclient_command %d", muxclient_command); 2212180750Sdes } 2213180750Sdes} 2214