1*99e85e0dSPeter Avalos /* $OpenBSD: mux.c,v 1.36 2012/07/06 01:37:21 djm Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> 418de8d7fSPeter Avalos * 518de8d7fSPeter Avalos * Permission to use, copy, modify, and distribute this software for any 618de8d7fSPeter Avalos * purpose with or without fee is hereby granted, provided that the above 718de8d7fSPeter Avalos * copyright notice and this permission notice appear in all copies. 818de8d7fSPeter Avalos * 918de8d7fSPeter Avalos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1018de8d7fSPeter Avalos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1118de8d7fSPeter Avalos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1218de8d7fSPeter Avalos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1318de8d7fSPeter Avalos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1418de8d7fSPeter Avalos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1518de8d7fSPeter Avalos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1618de8d7fSPeter Avalos */ 1718de8d7fSPeter Avalos 1818de8d7fSPeter Avalos /* ssh session multiplexing support */ 1918de8d7fSPeter Avalos 2018de8d7fSPeter Avalos /* 2118de8d7fSPeter Avalos * TODO: 22856ea928SPeter Avalos * - Better signalling from master to slave, especially passing of 2318de8d7fSPeter Avalos * error messages 24856ea928SPeter Avalos * - Better fall-back from mux slave error to new connection. 25856ea928SPeter Avalos * - ExitOnForwardingFailure 26856ea928SPeter Avalos * - Maybe extension mechanisms for multi-X11/multi-agent forwarding 27856ea928SPeter Avalos * - Support ~^Z in mux slaves. 28856ea928SPeter Avalos * - Inspect or control sessions in master. 29856ea928SPeter Avalos * - If we ever support the "signal" channel request, send signals on 3018de8d7fSPeter Avalos * sessions in master. 3118de8d7fSPeter Avalos */ 3218de8d7fSPeter Avalos 33856ea928SPeter Avalos #include "includes.h" 34856ea928SPeter Avalos 3518de8d7fSPeter Avalos #include <sys/types.h> 3618de8d7fSPeter Avalos #include <sys/param.h> 3718de8d7fSPeter Avalos #include <sys/stat.h> 3818de8d7fSPeter Avalos #include <sys/socket.h> 3918de8d7fSPeter Avalos #include <sys/un.h> 4018de8d7fSPeter Avalos 4118de8d7fSPeter Avalos #include <errno.h> 4218de8d7fSPeter Avalos #include <fcntl.h> 4318de8d7fSPeter Avalos #include <signal.h> 4418de8d7fSPeter Avalos #include <stdarg.h> 4518de8d7fSPeter Avalos #include <stddef.h> 4618de8d7fSPeter Avalos #include <stdlib.h> 4718de8d7fSPeter Avalos #include <stdio.h> 4818de8d7fSPeter Avalos #include <string.h> 4918de8d7fSPeter Avalos #include <unistd.h> 5018de8d7fSPeter Avalos #ifdef HAVE_PATHS_H 5118de8d7fSPeter Avalos #include <paths.h> 5218de8d7fSPeter Avalos #endif 5318de8d7fSPeter Avalos 54856ea928SPeter Avalos #ifdef HAVE_POLL_H 55856ea928SPeter Avalos #include <poll.h> 56856ea928SPeter Avalos #else 57856ea928SPeter Avalos # ifdef HAVE_SYS_POLL_H 58856ea928SPeter Avalos # include <sys/poll.h> 59856ea928SPeter Avalos # endif 60856ea928SPeter Avalos #endif 61856ea928SPeter Avalos 6218de8d7fSPeter Avalos #ifdef HAVE_UTIL_H 6318de8d7fSPeter Avalos # include <util.h> 6418de8d7fSPeter Avalos #endif 6518de8d7fSPeter Avalos 6618de8d7fSPeter Avalos #ifdef HAVE_LIBUTIL_H 6718de8d7fSPeter Avalos # include <libutil.h> 6818de8d7fSPeter Avalos #endif 6918de8d7fSPeter Avalos 7018de8d7fSPeter Avalos #include "openbsd-compat/sys-queue.h" 7118de8d7fSPeter Avalos #include "xmalloc.h" 7218de8d7fSPeter Avalos #include "log.h" 7318de8d7fSPeter Avalos #include "ssh.h" 74856ea928SPeter Avalos #include "ssh2.h" 7518de8d7fSPeter Avalos #include "pathnames.h" 7618de8d7fSPeter Avalos #include "misc.h" 7718de8d7fSPeter Avalos #include "match.h" 7818de8d7fSPeter Avalos #include "buffer.h" 7918de8d7fSPeter Avalos #include "channels.h" 8018de8d7fSPeter Avalos #include "msg.h" 8118de8d7fSPeter Avalos #include "packet.h" 8218de8d7fSPeter Avalos #include "monitor_fdpass.h" 8318de8d7fSPeter Avalos #include "sshpty.h" 8418de8d7fSPeter Avalos #include "key.h" 8518de8d7fSPeter Avalos #include "readconf.h" 8618de8d7fSPeter Avalos #include "clientloop.h" 8718de8d7fSPeter Avalos 8818de8d7fSPeter Avalos /* from ssh.c */ 8918de8d7fSPeter Avalos extern int tty_flag; 9018de8d7fSPeter Avalos extern Options options; 9118de8d7fSPeter Avalos extern int stdin_null_flag; 9218de8d7fSPeter Avalos extern char *host; 93856ea928SPeter Avalos extern int subsystem_flag; 9418de8d7fSPeter Avalos extern Buffer command; 95856ea928SPeter Avalos extern volatile sig_atomic_t quit_pending; 96856ea928SPeter Avalos extern char *stdio_forward_host; 97856ea928SPeter Avalos extern int stdio_forward_port; 9818de8d7fSPeter Avalos 9918de8d7fSPeter Avalos /* Context for session open confirmation callback */ 10018de8d7fSPeter Avalos struct mux_session_confirm_ctx { 101856ea928SPeter Avalos u_int want_tty; 102856ea928SPeter Avalos u_int want_subsys; 103856ea928SPeter Avalos u_int want_x_fwd; 104856ea928SPeter Avalos u_int want_agent_fwd; 10518de8d7fSPeter Avalos Buffer cmd; 10618de8d7fSPeter Avalos char *term; 10718de8d7fSPeter Avalos struct termios tio; 10818de8d7fSPeter Avalos char **env; 109856ea928SPeter Avalos u_int rid; 110856ea928SPeter Avalos }; 111856ea928SPeter Avalos 112856ea928SPeter Avalos /* Context for global channel callback */ 113856ea928SPeter Avalos struct mux_channel_confirm_ctx { 114856ea928SPeter Avalos u_int cid; /* channel id */ 115856ea928SPeter Avalos u_int rid; /* request id */ 116856ea928SPeter Avalos int fid; /* forward id */ 11718de8d7fSPeter Avalos }; 11818de8d7fSPeter Avalos 11918de8d7fSPeter Avalos /* fd to control socket */ 12018de8d7fSPeter Avalos int muxserver_sock = -1; 12118de8d7fSPeter Avalos 122856ea928SPeter Avalos /* client request id */ 123856ea928SPeter Avalos u_int muxclient_request_id = 0; 124856ea928SPeter Avalos 12518de8d7fSPeter Avalos /* Multiplexing control command */ 12618de8d7fSPeter Avalos u_int muxclient_command = 0; 12718de8d7fSPeter Avalos 12818de8d7fSPeter Avalos /* Set when signalled. */ 12918de8d7fSPeter Avalos static volatile sig_atomic_t muxclient_terminate = 0; 13018de8d7fSPeter Avalos 13118de8d7fSPeter Avalos /* PID of multiplex server */ 13218de8d7fSPeter Avalos static u_int muxserver_pid = 0; 13318de8d7fSPeter Avalos 134856ea928SPeter Avalos static Channel *mux_listener_channel = NULL; 13518de8d7fSPeter Avalos 136856ea928SPeter Avalos struct mux_master_state { 137856ea928SPeter Avalos int hello_rcvd; 138856ea928SPeter Avalos }; 139856ea928SPeter Avalos 140856ea928SPeter Avalos /* mux protocol messages */ 141856ea928SPeter Avalos #define MUX_MSG_HELLO 0x00000001 142856ea928SPeter Avalos #define MUX_C_NEW_SESSION 0x10000002 143856ea928SPeter Avalos #define MUX_C_ALIVE_CHECK 0x10000004 144856ea928SPeter Avalos #define MUX_C_TERMINATE 0x10000005 145856ea928SPeter Avalos #define MUX_C_OPEN_FWD 0x10000006 146856ea928SPeter Avalos #define MUX_C_CLOSE_FWD 0x10000007 147856ea928SPeter Avalos #define MUX_C_NEW_STDIO_FWD 0x10000008 1481c188a7fSPeter Avalos #define MUX_C_STOP_LISTENING 0x10000009 149856ea928SPeter Avalos #define MUX_S_OK 0x80000001 150856ea928SPeter Avalos #define MUX_S_PERMISSION_DENIED 0x80000002 151856ea928SPeter Avalos #define MUX_S_FAILURE 0x80000003 152856ea928SPeter Avalos #define MUX_S_EXIT_MESSAGE 0x80000004 153856ea928SPeter Avalos #define MUX_S_ALIVE 0x80000005 154856ea928SPeter Avalos #define MUX_S_SESSION_OPENED 0x80000006 155856ea928SPeter Avalos #define MUX_S_REMOTE_PORT 0x80000007 1561c188a7fSPeter Avalos #define MUX_S_TTY_ALLOC_FAIL 0x80000008 157856ea928SPeter Avalos 158856ea928SPeter Avalos /* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ 159856ea928SPeter Avalos #define MUX_FWD_LOCAL 1 160856ea928SPeter Avalos #define MUX_FWD_REMOTE 2 161856ea928SPeter Avalos #define MUX_FWD_DYNAMIC 3 162856ea928SPeter Avalos 163856ea928SPeter Avalos static void mux_session_confirm(int, int, void *); 164856ea928SPeter Avalos 165856ea928SPeter Avalos static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); 166856ea928SPeter Avalos static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); 167856ea928SPeter Avalos static int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *); 168856ea928SPeter Avalos static int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *); 169856ea928SPeter Avalos static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); 170856ea928SPeter Avalos static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); 171856ea928SPeter Avalos static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); 1721c188a7fSPeter Avalos static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *); 173856ea928SPeter Avalos 174856ea928SPeter Avalos static const struct { 175856ea928SPeter Avalos u_int type; 176856ea928SPeter Avalos int (*handler)(u_int, Channel *, Buffer *, Buffer *); 177856ea928SPeter Avalos } mux_master_handlers[] = { 178856ea928SPeter Avalos { MUX_MSG_HELLO, process_mux_master_hello }, 179856ea928SPeter Avalos { MUX_C_NEW_SESSION, process_mux_new_session }, 180856ea928SPeter Avalos { MUX_C_ALIVE_CHECK, process_mux_alive_check }, 181856ea928SPeter Avalos { MUX_C_TERMINATE, process_mux_terminate }, 182856ea928SPeter Avalos { MUX_C_OPEN_FWD, process_mux_open_fwd }, 183856ea928SPeter Avalos { MUX_C_CLOSE_FWD, process_mux_close_fwd }, 184856ea928SPeter Avalos { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, 1851c188a7fSPeter Avalos { MUX_C_STOP_LISTENING, process_mux_stop_listening }, 186856ea928SPeter Avalos { 0, NULL } 187856ea928SPeter Avalos }; 188856ea928SPeter Avalos 189856ea928SPeter Avalos /* Cleanup callback fired on closure of mux slave _session_ channel */ 190856ea928SPeter Avalos /* ARGSUSED */ 191856ea928SPeter Avalos static void 192856ea928SPeter Avalos mux_master_session_cleanup_cb(int cid, void *unused) 193856ea928SPeter Avalos { 194856ea928SPeter Avalos Channel *cc, *c = channel_by_id(cid); 195856ea928SPeter Avalos 196856ea928SPeter Avalos debug3("%s: entering for channel %d", __func__, cid); 197856ea928SPeter Avalos if (c == NULL) 198856ea928SPeter Avalos fatal("%s: channel_by_id(%i) == NULL", __func__, cid); 199856ea928SPeter Avalos if (c->ctl_chan != -1) { 200856ea928SPeter Avalos if ((cc = channel_by_id(c->ctl_chan)) == NULL) 201856ea928SPeter Avalos fatal("%s: channel %d missing control channel %d", 202856ea928SPeter Avalos __func__, c->self, c->ctl_chan); 203856ea928SPeter Avalos c->ctl_chan = -1; 204856ea928SPeter Avalos cc->remote_id = -1; 205856ea928SPeter Avalos chan_rcvd_oclose(cc); 206856ea928SPeter Avalos } 207856ea928SPeter Avalos channel_cancel_cleanup(c->self); 208856ea928SPeter Avalos } 209856ea928SPeter Avalos 210856ea928SPeter Avalos /* Cleanup callback fired on closure of mux slave _control_ channel */ 211856ea928SPeter Avalos /* ARGSUSED */ 212856ea928SPeter Avalos static void 213856ea928SPeter Avalos mux_master_control_cleanup_cb(int cid, void *unused) 214856ea928SPeter Avalos { 215856ea928SPeter Avalos Channel *sc, *c = channel_by_id(cid); 216856ea928SPeter Avalos 217856ea928SPeter Avalos debug3("%s: entering for channel %d", __func__, cid); 218856ea928SPeter Avalos if (c == NULL) 219856ea928SPeter Avalos fatal("%s: channel_by_id(%i) == NULL", __func__, cid); 220856ea928SPeter Avalos if (c->remote_id != -1) { 221856ea928SPeter Avalos if ((sc = channel_by_id(c->remote_id)) == NULL) 222856ea928SPeter Avalos fatal("%s: channel %d missing session channel %d", 223856ea928SPeter Avalos __func__, c->self, c->remote_id); 224856ea928SPeter Avalos c->remote_id = -1; 225856ea928SPeter Avalos sc->ctl_chan = -1; 226856ea928SPeter Avalos if (sc->type != SSH_CHANNEL_OPEN) { 227856ea928SPeter Avalos debug2("%s: channel %d: not open", __func__, sc->self); 228856ea928SPeter Avalos chan_mark_dead(sc); 229856ea928SPeter Avalos } else { 230856ea928SPeter Avalos if (sc->istate == CHAN_INPUT_OPEN) 231856ea928SPeter Avalos chan_read_failed(sc); 232856ea928SPeter Avalos if (sc->ostate == CHAN_OUTPUT_OPEN) 233856ea928SPeter Avalos chan_write_failed(sc); 234856ea928SPeter Avalos } 235856ea928SPeter Avalos } 236856ea928SPeter Avalos channel_cancel_cleanup(c->self); 237856ea928SPeter Avalos } 238856ea928SPeter Avalos 239856ea928SPeter Avalos /* Check mux client environment variables before passing them to mux master. */ 240856ea928SPeter Avalos static int 241856ea928SPeter Avalos env_permitted(char *env) 242856ea928SPeter Avalos { 243856ea928SPeter Avalos int i, ret; 244856ea928SPeter Avalos char name[1024], *cp; 245856ea928SPeter Avalos 246856ea928SPeter Avalos if ((cp = strchr(env, '=')) == NULL || cp == env) 247856ea928SPeter Avalos return 0; 248856ea928SPeter Avalos ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env); 249856ea928SPeter Avalos if (ret <= 0 || (size_t)ret >= sizeof(name)) { 250856ea928SPeter Avalos error("env_permitted: name '%.100s...' too long", env); 251856ea928SPeter Avalos return 0; 252856ea928SPeter Avalos } 253856ea928SPeter Avalos 254856ea928SPeter Avalos for (i = 0; i < options.num_send_env; i++) 255856ea928SPeter Avalos if (match_pattern(name, options.send_env[i])) 256856ea928SPeter Avalos return 1; 257856ea928SPeter Avalos 258856ea928SPeter Avalos return 0; 259856ea928SPeter Avalos } 260856ea928SPeter Avalos 261856ea928SPeter Avalos /* Mux master protocol message handlers */ 262856ea928SPeter Avalos 263856ea928SPeter Avalos static int 264856ea928SPeter Avalos process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r) 265856ea928SPeter Avalos { 266856ea928SPeter Avalos u_int ver; 267856ea928SPeter Avalos struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; 268856ea928SPeter Avalos 269856ea928SPeter Avalos if (state == NULL) 270856ea928SPeter Avalos fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self); 271856ea928SPeter Avalos if (state->hello_rcvd) { 272856ea928SPeter Avalos error("%s: HELLO received twice", __func__); 273856ea928SPeter Avalos return -1; 274856ea928SPeter Avalos } 275856ea928SPeter Avalos if (buffer_get_int_ret(&ver, m) != 0) { 276856ea928SPeter Avalos malf: 277856ea928SPeter Avalos error("%s: malformed message", __func__); 278856ea928SPeter Avalos return -1; 279856ea928SPeter Avalos } 280856ea928SPeter Avalos if (ver != SSHMUX_VER) { 281856ea928SPeter Avalos error("Unsupported multiplexing protocol version %d " 282856ea928SPeter Avalos "(expected %d)", ver, SSHMUX_VER); 283856ea928SPeter Avalos return -1; 284856ea928SPeter Avalos } 285856ea928SPeter Avalos debug2("%s: channel %d slave version %u", __func__, c->self, ver); 286856ea928SPeter Avalos 287856ea928SPeter Avalos /* No extensions are presently defined */ 288856ea928SPeter Avalos while (buffer_len(m) > 0) { 289856ea928SPeter Avalos char *name = buffer_get_string_ret(m, NULL); 290856ea928SPeter Avalos char *value = buffer_get_string_ret(m, NULL); 291856ea928SPeter Avalos 292856ea928SPeter Avalos if (name == NULL || value == NULL) { 293856ea928SPeter Avalos if (name != NULL) 294856ea928SPeter Avalos xfree(name); 295856ea928SPeter Avalos goto malf; 296856ea928SPeter Avalos } 297856ea928SPeter Avalos debug2("Unrecognised slave extension \"%s\"", name); 298856ea928SPeter Avalos xfree(name); 299856ea928SPeter Avalos xfree(value); 300856ea928SPeter Avalos } 301856ea928SPeter Avalos state->hello_rcvd = 1; 302856ea928SPeter Avalos return 0; 303856ea928SPeter Avalos } 304856ea928SPeter Avalos 305856ea928SPeter Avalos static int 306856ea928SPeter Avalos process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) 307856ea928SPeter Avalos { 308856ea928SPeter Avalos Channel *nc; 309856ea928SPeter Avalos struct mux_session_confirm_ctx *cctx; 310856ea928SPeter Avalos char *reserved, *cmd, *cp; 311856ea928SPeter Avalos u_int i, j, len, env_len, escape_char, window, packetmax; 312856ea928SPeter Avalos int new_fd[3]; 313856ea928SPeter Avalos 314856ea928SPeter Avalos /* Reply for SSHMUX_COMMAND_OPEN */ 315856ea928SPeter Avalos cctx = xcalloc(1, sizeof(*cctx)); 316856ea928SPeter Avalos cctx->term = NULL; 317856ea928SPeter Avalos cctx->rid = rid; 318856ea928SPeter Avalos cmd = reserved = NULL; 319*99e85e0dSPeter Avalos cctx->env = NULL; 320*99e85e0dSPeter Avalos env_len = 0; 321856ea928SPeter Avalos if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || 322856ea928SPeter Avalos buffer_get_int_ret(&cctx->want_tty, m) != 0 || 323856ea928SPeter Avalos buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 || 324856ea928SPeter Avalos buffer_get_int_ret(&cctx->want_agent_fwd, m) != 0 || 325856ea928SPeter Avalos buffer_get_int_ret(&cctx->want_subsys, m) != 0 || 326856ea928SPeter Avalos buffer_get_int_ret(&escape_char, m) != 0 || 327856ea928SPeter Avalos (cctx->term = buffer_get_string_ret(m, &len)) == NULL || 328856ea928SPeter Avalos (cmd = buffer_get_string_ret(m, &len)) == NULL) { 329856ea928SPeter Avalos malf: 330856ea928SPeter Avalos if (cmd != NULL) 331856ea928SPeter Avalos xfree(cmd); 332856ea928SPeter Avalos if (reserved != NULL) 333856ea928SPeter Avalos xfree(reserved); 334*99e85e0dSPeter Avalos for (j = 0; j < env_len; j++) 335*99e85e0dSPeter Avalos xfree(cctx->env[j]); 336*99e85e0dSPeter Avalos if (env_len > 0) 337*99e85e0dSPeter Avalos xfree(cctx->env); 338856ea928SPeter Avalos if (cctx->term != NULL) 339856ea928SPeter Avalos xfree(cctx->term); 340*99e85e0dSPeter Avalos xfree(cctx); 341856ea928SPeter Avalos error("%s: malformed message", __func__); 342856ea928SPeter Avalos return -1; 343856ea928SPeter Avalos } 344856ea928SPeter Avalos xfree(reserved); 345856ea928SPeter Avalos reserved = NULL; 346856ea928SPeter Avalos 347856ea928SPeter Avalos while (buffer_len(m) > 0) { 348856ea928SPeter Avalos #define MUX_MAX_ENV_VARS 4096 349*99e85e0dSPeter Avalos if ((cp = buffer_get_string_ret(m, &len)) == NULL) 350856ea928SPeter Avalos goto malf; 351856ea928SPeter Avalos if (!env_permitted(cp)) { 352856ea928SPeter Avalos xfree(cp); 353856ea928SPeter Avalos continue; 354856ea928SPeter Avalos } 355856ea928SPeter Avalos cctx->env = xrealloc(cctx->env, env_len + 2, 356856ea928SPeter Avalos sizeof(*cctx->env)); 357856ea928SPeter Avalos cctx->env[env_len++] = cp; 358856ea928SPeter Avalos cctx->env[env_len] = NULL; 359856ea928SPeter Avalos if (env_len > MUX_MAX_ENV_VARS) { 360856ea928SPeter Avalos error(">%d environment variables received, ignoring " 361856ea928SPeter Avalos "additional", MUX_MAX_ENV_VARS); 362856ea928SPeter Avalos break; 363856ea928SPeter Avalos } 364856ea928SPeter Avalos } 365856ea928SPeter Avalos 366856ea928SPeter Avalos debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, " 367856ea928SPeter Avalos "term \"%s\", cmd \"%s\", env %u", __func__, c->self, 368856ea928SPeter Avalos cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd, 369856ea928SPeter Avalos cctx->want_subsys, cctx->term, cmd, env_len); 370856ea928SPeter Avalos 371856ea928SPeter Avalos buffer_init(&cctx->cmd); 372856ea928SPeter Avalos buffer_append(&cctx->cmd, cmd, strlen(cmd)); 373856ea928SPeter Avalos xfree(cmd); 374856ea928SPeter Avalos cmd = NULL; 375856ea928SPeter Avalos 376856ea928SPeter Avalos /* Gather fds from client */ 377856ea928SPeter Avalos for(i = 0; i < 3; i++) { 378856ea928SPeter Avalos if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { 379856ea928SPeter Avalos error("%s: failed to receive fd %d from slave", 380856ea928SPeter Avalos __func__, i); 381856ea928SPeter Avalos for (j = 0; j < i; j++) 382856ea928SPeter Avalos close(new_fd[j]); 383856ea928SPeter Avalos for (j = 0; j < env_len; j++) 384856ea928SPeter Avalos xfree(cctx->env[j]); 385856ea928SPeter Avalos if (env_len > 0) 386856ea928SPeter Avalos xfree(cctx->env); 387856ea928SPeter Avalos xfree(cctx->term); 388856ea928SPeter Avalos buffer_free(&cctx->cmd); 389856ea928SPeter Avalos xfree(cctx); 390856ea928SPeter Avalos 391856ea928SPeter Avalos /* prepare reply */ 392856ea928SPeter Avalos buffer_put_int(r, MUX_S_FAILURE); 393856ea928SPeter Avalos buffer_put_int(r, rid); 394856ea928SPeter Avalos buffer_put_cstring(r, 395856ea928SPeter Avalos "did not receive file descriptors"); 396856ea928SPeter Avalos return -1; 397856ea928SPeter Avalos } 398856ea928SPeter Avalos } 399856ea928SPeter Avalos 400856ea928SPeter Avalos debug3("%s: got fds stdin %d, stdout %d, stderr %d", __func__, 401856ea928SPeter Avalos new_fd[0], new_fd[1], new_fd[2]); 402856ea928SPeter Avalos 403856ea928SPeter Avalos /* XXX support multiple child sessions in future */ 404856ea928SPeter Avalos if (c->remote_id != -1) { 405856ea928SPeter Avalos debug2("%s: session already open", __func__); 406856ea928SPeter Avalos /* prepare reply */ 407856ea928SPeter Avalos buffer_put_int(r, MUX_S_FAILURE); 408856ea928SPeter Avalos buffer_put_int(r, rid); 409856ea928SPeter Avalos buffer_put_cstring(r, "Multiple sessions not supported"); 410856ea928SPeter Avalos cleanup: 411856ea928SPeter Avalos close(new_fd[0]); 412856ea928SPeter Avalos close(new_fd[1]); 413856ea928SPeter Avalos close(new_fd[2]); 414856ea928SPeter Avalos xfree(cctx->term); 415856ea928SPeter Avalos if (env_len != 0) { 416856ea928SPeter Avalos for (i = 0; i < env_len; i++) 417856ea928SPeter Avalos xfree(cctx->env[i]); 418856ea928SPeter Avalos xfree(cctx->env); 419856ea928SPeter Avalos } 420856ea928SPeter Avalos buffer_free(&cctx->cmd); 421*99e85e0dSPeter Avalos xfree(cctx); 422856ea928SPeter Avalos return 0; 423856ea928SPeter Avalos } 424856ea928SPeter Avalos 425856ea928SPeter Avalos if (options.control_master == SSHCTL_MASTER_ASK || 426856ea928SPeter Avalos options.control_master == SSHCTL_MASTER_AUTO_ASK) { 427856ea928SPeter Avalos if (!ask_permission("Allow shared connection to %s? ", host)) { 428856ea928SPeter Avalos debug2("%s: session refused by user", __func__); 429856ea928SPeter Avalos /* prepare reply */ 430856ea928SPeter Avalos buffer_put_int(r, MUX_S_PERMISSION_DENIED); 431856ea928SPeter Avalos buffer_put_int(r, rid); 432856ea928SPeter Avalos buffer_put_cstring(r, "Permission denied"); 433856ea928SPeter Avalos goto cleanup; 434856ea928SPeter Avalos } 435856ea928SPeter Avalos } 436856ea928SPeter Avalos 437856ea928SPeter Avalos /* Try to pick up ttymodes from client before it goes raw */ 438856ea928SPeter Avalos if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) 439856ea928SPeter Avalos error("%s: tcgetattr: %s", __func__, strerror(errno)); 440856ea928SPeter Avalos 441856ea928SPeter Avalos /* enable nonblocking unless tty */ 442856ea928SPeter Avalos if (!isatty(new_fd[0])) 443856ea928SPeter Avalos set_nonblock(new_fd[0]); 444856ea928SPeter Avalos if (!isatty(new_fd[1])) 445856ea928SPeter Avalos set_nonblock(new_fd[1]); 446856ea928SPeter Avalos if (!isatty(new_fd[2])) 447856ea928SPeter Avalos set_nonblock(new_fd[2]); 448856ea928SPeter Avalos 449856ea928SPeter Avalos window = CHAN_SES_WINDOW_DEFAULT; 450856ea928SPeter Avalos packetmax = CHAN_SES_PACKET_DEFAULT; 451856ea928SPeter Avalos if (cctx->want_tty) { 452856ea928SPeter Avalos window >>= 1; 453856ea928SPeter Avalos packetmax >>= 1; 454856ea928SPeter Avalos } 455856ea928SPeter Avalos 456856ea928SPeter Avalos nc = channel_new("session", SSH_CHANNEL_OPENING, 457856ea928SPeter Avalos new_fd[0], new_fd[1], new_fd[2], window, packetmax, 458856ea928SPeter Avalos CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); 459856ea928SPeter Avalos 460856ea928SPeter Avalos nc->ctl_chan = c->self; /* link session -> control channel */ 461856ea928SPeter Avalos c->remote_id = nc->self; /* link control -> session channel */ 462856ea928SPeter Avalos 463856ea928SPeter Avalos if (cctx->want_tty && escape_char != 0xffffffff) { 464856ea928SPeter Avalos channel_register_filter(nc->self, 465856ea928SPeter Avalos client_simple_escape_filter, NULL, 466856ea928SPeter Avalos client_filter_cleanup, 467856ea928SPeter Avalos client_new_escape_filter_ctx((int)escape_char)); 468856ea928SPeter Avalos } 469856ea928SPeter Avalos 470856ea928SPeter Avalos debug2("%s: channel_new: %d linked to control channel %d", 471856ea928SPeter Avalos __func__, nc->self, nc->ctl_chan); 472856ea928SPeter Avalos 473856ea928SPeter Avalos channel_send_open(nc->self); 474856ea928SPeter Avalos channel_register_open_confirm(nc->self, mux_session_confirm, cctx); 475856ea928SPeter Avalos c->mux_pause = 1; /* stop handling messages until open_confirm done */ 476856ea928SPeter Avalos channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); 477856ea928SPeter Avalos 478856ea928SPeter Avalos /* reply is deferred, sent by mux_session_confirm */ 479856ea928SPeter Avalos return 0; 480856ea928SPeter Avalos } 481856ea928SPeter Avalos 482856ea928SPeter Avalos static int 483856ea928SPeter Avalos process_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r) 484856ea928SPeter Avalos { 485856ea928SPeter Avalos debug2("%s: channel %d: alive check", __func__, c->self); 486856ea928SPeter Avalos 487856ea928SPeter Avalos /* prepare reply */ 488856ea928SPeter Avalos buffer_put_int(r, MUX_S_ALIVE); 489856ea928SPeter Avalos buffer_put_int(r, rid); 490856ea928SPeter Avalos buffer_put_int(r, (u_int)getpid()); 491856ea928SPeter Avalos 492856ea928SPeter Avalos return 0; 493856ea928SPeter Avalos } 494856ea928SPeter Avalos 495856ea928SPeter Avalos static int 496856ea928SPeter Avalos process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r) 497856ea928SPeter Avalos { 498856ea928SPeter Avalos debug2("%s: channel %d: terminate request", __func__, c->self); 499856ea928SPeter Avalos 500856ea928SPeter Avalos if (options.control_master == SSHCTL_MASTER_ASK || 501856ea928SPeter Avalos options.control_master == SSHCTL_MASTER_AUTO_ASK) { 502856ea928SPeter Avalos if (!ask_permission("Terminate shared connection to %s? ", 503856ea928SPeter Avalos host)) { 504856ea928SPeter Avalos debug2("%s: termination refused by user", __func__); 505856ea928SPeter Avalos buffer_put_int(r, MUX_S_PERMISSION_DENIED); 506856ea928SPeter Avalos buffer_put_int(r, rid); 507856ea928SPeter Avalos buffer_put_cstring(r, "Permission denied"); 508856ea928SPeter Avalos return 0; 509856ea928SPeter Avalos } 510856ea928SPeter Avalos } 511856ea928SPeter Avalos 512856ea928SPeter Avalos quit_pending = 1; 513856ea928SPeter Avalos buffer_put_int(r, MUX_S_OK); 514856ea928SPeter Avalos buffer_put_int(r, rid); 515856ea928SPeter Avalos /* XXX exit happens too soon - message never makes it to client */ 516856ea928SPeter Avalos return 0; 517856ea928SPeter Avalos } 518856ea928SPeter Avalos 519856ea928SPeter Avalos static char * 520856ea928SPeter Avalos format_forward(u_int ftype, Forward *fwd) 521856ea928SPeter Avalos { 522856ea928SPeter Avalos char *ret; 523856ea928SPeter Avalos 524856ea928SPeter Avalos switch (ftype) { 525856ea928SPeter Avalos case MUX_FWD_LOCAL: 526856ea928SPeter Avalos xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d", 527856ea928SPeter Avalos (fwd->listen_host == NULL) ? 528856ea928SPeter Avalos (options.gateway_ports ? "*" : "LOCALHOST") : 529856ea928SPeter Avalos fwd->listen_host, fwd->listen_port, 530856ea928SPeter Avalos fwd->connect_host, fwd->connect_port); 531856ea928SPeter Avalos break; 532856ea928SPeter Avalos case MUX_FWD_DYNAMIC: 533856ea928SPeter Avalos xasprintf(&ret, "dynamic forward %.200s:%d -> *", 534856ea928SPeter Avalos (fwd->listen_host == NULL) ? 535856ea928SPeter Avalos (options.gateway_ports ? "*" : "LOCALHOST") : 536856ea928SPeter Avalos fwd->listen_host, fwd->listen_port); 537856ea928SPeter Avalos break; 538856ea928SPeter Avalos case MUX_FWD_REMOTE: 539856ea928SPeter Avalos xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d", 540856ea928SPeter Avalos (fwd->listen_host == NULL) ? 541856ea928SPeter Avalos "LOCALHOST" : fwd->listen_host, 542856ea928SPeter Avalos fwd->listen_port, 543856ea928SPeter Avalos fwd->connect_host, fwd->connect_port); 544856ea928SPeter Avalos break; 545856ea928SPeter Avalos default: 546856ea928SPeter Avalos fatal("%s: unknown forward type %u", __func__, ftype); 547856ea928SPeter Avalos } 548856ea928SPeter Avalos return ret; 549856ea928SPeter Avalos } 550856ea928SPeter Avalos 551856ea928SPeter Avalos static int 552856ea928SPeter Avalos compare_host(const char *a, const char *b) 553856ea928SPeter Avalos { 554856ea928SPeter Avalos if (a == NULL && b == NULL) 555856ea928SPeter Avalos return 1; 556856ea928SPeter Avalos if (a == NULL || b == NULL) 557856ea928SPeter Avalos return 0; 558856ea928SPeter Avalos return strcmp(a, b) == 0; 559856ea928SPeter Avalos } 560856ea928SPeter Avalos 561856ea928SPeter Avalos static int 562856ea928SPeter Avalos compare_forward(Forward *a, Forward *b) 563856ea928SPeter Avalos { 564856ea928SPeter Avalos if (!compare_host(a->listen_host, b->listen_host)) 565856ea928SPeter Avalos return 0; 566856ea928SPeter Avalos if (a->listen_port != b->listen_port) 567856ea928SPeter Avalos return 0; 568856ea928SPeter Avalos if (!compare_host(a->connect_host, b->connect_host)) 569856ea928SPeter Avalos return 0; 570856ea928SPeter Avalos if (a->connect_port != b->connect_port) 571856ea928SPeter Avalos return 0; 572856ea928SPeter Avalos 573856ea928SPeter Avalos return 1; 574856ea928SPeter Avalos } 575856ea928SPeter Avalos 576856ea928SPeter Avalos static void 577856ea928SPeter Avalos mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) 578856ea928SPeter Avalos { 579856ea928SPeter Avalos struct mux_channel_confirm_ctx *fctx = ctxt; 580856ea928SPeter Avalos char *failmsg = NULL; 581856ea928SPeter Avalos Forward *rfwd; 582856ea928SPeter Avalos Channel *c; 583856ea928SPeter Avalos Buffer out; 584856ea928SPeter Avalos 585856ea928SPeter Avalos if ((c = channel_by_id(fctx->cid)) == NULL) { 586856ea928SPeter Avalos /* no channel for reply */ 587856ea928SPeter Avalos error("%s: unknown channel", __func__); 588856ea928SPeter Avalos return; 589856ea928SPeter Avalos } 590856ea928SPeter Avalos buffer_init(&out); 591856ea928SPeter Avalos if (fctx->fid >= options.num_remote_forwards) { 592856ea928SPeter Avalos xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid); 593856ea928SPeter Avalos goto fail; 594856ea928SPeter Avalos } 595856ea928SPeter Avalos rfwd = &options.remote_forwards[fctx->fid]; 596856ea928SPeter Avalos debug("%s: %s for: listen %d, connect %s:%d", __func__, 597856ea928SPeter Avalos type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", 598856ea928SPeter Avalos rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); 599856ea928SPeter Avalos if (type == SSH2_MSG_REQUEST_SUCCESS) { 600856ea928SPeter Avalos if (rfwd->listen_port == 0) { 601856ea928SPeter Avalos rfwd->allocated_port = packet_get_int(); 602856ea928SPeter Avalos logit("Allocated port %u for mux remote forward" 603856ea928SPeter Avalos " to %s:%d", rfwd->allocated_port, 604856ea928SPeter Avalos rfwd->connect_host, rfwd->connect_port); 605856ea928SPeter Avalos buffer_put_int(&out, MUX_S_REMOTE_PORT); 606856ea928SPeter Avalos buffer_put_int(&out, fctx->rid); 607856ea928SPeter Avalos buffer_put_int(&out, rfwd->allocated_port); 608*99e85e0dSPeter Avalos channel_update_permitted_opens(rfwd->handle, 609*99e85e0dSPeter Avalos rfwd->allocated_port); 610856ea928SPeter Avalos } else { 611856ea928SPeter Avalos buffer_put_int(&out, MUX_S_OK); 612856ea928SPeter Avalos buffer_put_int(&out, fctx->rid); 613856ea928SPeter Avalos } 614856ea928SPeter Avalos goto out; 615856ea928SPeter Avalos } else { 616*99e85e0dSPeter Avalos if (rfwd->listen_port == 0) 617*99e85e0dSPeter Avalos channel_update_permitted_opens(rfwd->handle, -1); 618856ea928SPeter Avalos xasprintf(&failmsg, "remote port forwarding failed for " 619856ea928SPeter Avalos "listen port %d", rfwd->listen_port); 620856ea928SPeter Avalos } 621856ea928SPeter Avalos fail: 622856ea928SPeter Avalos error("%s: %s", __func__, failmsg); 623856ea928SPeter Avalos buffer_put_int(&out, MUX_S_FAILURE); 624856ea928SPeter Avalos buffer_put_int(&out, fctx->rid); 625856ea928SPeter Avalos buffer_put_cstring(&out, failmsg); 626856ea928SPeter Avalos xfree(failmsg); 627856ea928SPeter Avalos out: 628856ea928SPeter Avalos buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out)); 629856ea928SPeter Avalos buffer_free(&out); 630856ea928SPeter Avalos if (c->mux_pause <= 0) 631856ea928SPeter Avalos fatal("%s: mux_pause %d", __func__, c->mux_pause); 632856ea928SPeter Avalos c->mux_pause = 0; /* start processing messages again */ 633856ea928SPeter Avalos } 634856ea928SPeter Avalos 635856ea928SPeter Avalos static int 636856ea928SPeter Avalos process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 637856ea928SPeter Avalos { 638856ea928SPeter Avalos Forward fwd; 639856ea928SPeter Avalos char *fwd_desc = NULL; 640856ea928SPeter Avalos u_int ftype; 641856ea928SPeter Avalos int i, ret = 0, freefwd = 1; 642856ea928SPeter Avalos 643856ea928SPeter Avalos fwd.listen_host = fwd.connect_host = NULL; 644856ea928SPeter Avalos if (buffer_get_int_ret(&ftype, m) != 0 || 645856ea928SPeter Avalos (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL || 646856ea928SPeter Avalos buffer_get_int_ret(&fwd.listen_port, m) != 0 || 647856ea928SPeter Avalos (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL || 648856ea928SPeter Avalos buffer_get_int_ret(&fwd.connect_port, m) != 0) { 649856ea928SPeter Avalos error("%s: malformed message", __func__); 650856ea928SPeter Avalos ret = -1; 651856ea928SPeter Avalos goto out; 652856ea928SPeter Avalos } 653856ea928SPeter Avalos 654856ea928SPeter Avalos if (*fwd.listen_host == '\0') { 655856ea928SPeter Avalos xfree(fwd.listen_host); 656856ea928SPeter Avalos fwd.listen_host = NULL; 657856ea928SPeter Avalos } 658856ea928SPeter Avalos if (*fwd.connect_host == '\0') { 659856ea928SPeter Avalos xfree(fwd.connect_host); 660856ea928SPeter Avalos fwd.connect_host = NULL; 661856ea928SPeter Avalos } 662856ea928SPeter Avalos 663856ea928SPeter Avalos debug2("%s: channel %d: request %s", __func__, c->self, 664856ea928SPeter Avalos (fwd_desc = format_forward(ftype, &fwd))); 665856ea928SPeter Avalos 666856ea928SPeter Avalos if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE && 667856ea928SPeter Avalos ftype != MUX_FWD_DYNAMIC) { 668856ea928SPeter Avalos logit("%s: invalid forwarding type %u", __func__, ftype); 669856ea928SPeter Avalos invalid: 670856ea928SPeter Avalos if (fwd.listen_host) 671856ea928SPeter Avalos xfree(fwd.listen_host); 672856ea928SPeter Avalos if (fwd.connect_host) 673856ea928SPeter Avalos xfree(fwd.connect_host); 674856ea928SPeter Avalos buffer_put_int(r, MUX_S_FAILURE); 675856ea928SPeter Avalos buffer_put_int(r, rid); 676856ea928SPeter Avalos buffer_put_cstring(r, "Invalid forwarding request"); 677856ea928SPeter Avalos return 0; 678856ea928SPeter Avalos } 679856ea928SPeter Avalos if (fwd.listen_port >= 65536) { 680856ea928SPeter Avalos logit("%s: invalid listen port %u", __func__, 681856ea928SPeter Avalos fwd.listen_port); 682856ea928SPeter Avalos goto invalid; 683856ea928SPeter Avalos } 684856ea928SPeter Avalos if (fwd.connect_port >= 65536 || (ftype != MUX_FWD_DYNAMIC && 685856ea928SPeter Avalos ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) { 686856ea928SPeter Avalos logit("%s: invalid connect port %u", __func__, 687856ea928SPeter Avalos fwd.connect_port); 688856ea928SPeter Avalos goto invalid; 689856ea928SPeter Avalos } 690856ea928SPeter Avalos if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL) { 691856ea928SPeter Avalos logit("%s: missing connect host", __func__); 692856ea928SPeter Avalos goto invalid; 693856ea928SPeter Avalos } 694856ea928SPeter Avalos 695856ea928SPeter Avalos /* Skip forwards that have already been requested */ 696856ea928SPeter Avalos switch (ftype) { 697856ea928SPeter Avalos case MUX_FWD_LOCAL: 698856ea928SPeter Avalos case MUX_FWD_DYNAMIC: 699856ea928SPeter Avalos for (i = 0; i < options.num_local_forwards; i++) { 700856ea928SPeter Avalos if (compare_forward(&fwd, 701856ea928SPeter Avalos options.local_forwards + i)) { 702856ea928SPeter Avalos exists: 703856ea928SPeter Avalos debug2("%s: found existing forwarding", 704856ea928SPeter Avalos __func__); 705856ea928SPeter Avalos buffer_put_int(r, MUX_S_OK); 706856ea928SPeter Avalos buffer_put_int(r, rid); 707856ea928SPeter Avalos goto out; 708856ea928SPeter Avalos } 709856ea928SPeter Avalos } 710856ea928SPeter Avalos break; 711856ea928SPeter Avalos case MUX_FWD_REMOTE: 712856ea928SPeter Avalos for (i = 0; i < options.num_remote_forwards; i++) { 713856ea928SPeter Avalos if (compare_forward(&fwd, 714856ea928SPeter Avalos options.remote_forwards + i)) { 715856ea928SPeter Avalos if (fwd.listen_port != 0) 716856ea928SPeter Avalos goto exists; 717856ea928SPeter Avalos debug2("%s: found allocated port", 718856ea928SPeter Avalos __func__); 719856ea928SPeter Avalos buffer_put_int(r, MUX_S_REMOTE_PORT); 720856ea928SPeter Avalos buffer_put_int(r, rid); 721856ea928SPeter Avalos buffer_put_int(r, 722856ea928SPeter Avalos options.remote_forwards[i].allocated_port); 723856ea928SPeter Avalos goto out; 724856ea928SPeter Avalos } 725856ea928SPeter Avalos } 726856ea928SPeter Avalos break; 727856ea928SPeter Avalos } 728856ea928SPeter Avalos 729856ea928SPeter Avalos if (options.control_master == SSHCTL_MASTER_ASK || 730856ea928SPeter Avalos options.control_master == SSHCTL_MASTER_AUTO_ASK) { 731856ea928SPeter Avalos if (!ask_permission("Open %s on %s?", fwd_desc, host)) { 732856ea928SPeter Avalos debug2("%s: forwarding refused by user", __func__); 733856ea928SPeter Avalos buffer_put_int(r, MUX_S_PERMISSION_DENIED); 734856ea928SPeter Avalos buffer_put_int(r, rid); 735856ea928SPeter Avalos buffer_put_cstring(r, "Permission denied"); 736856ea928SPeter Avalos goto out; 737856ea928SPeter Avalos } 738856ea928SPeter Avalos } 739856ea928SPeter Avalos 740856ea928SPeter Avalos if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { 741856ea928SPeter Avalos if (channel_setup_local_fwd_listener(fwd.listen_host, 742856ea928SPeter Avalos fwd.listen_port, fwd.connect_host, fwd.connect_port, 743856ea928SPeter Avalos options.gateway_ports) < 0) { 744856ea928SPeter Avalos fail: 745856ea928SPeter Avalos logit("slave-requested %s failed", fwd_desc); 746856ea928SPeter Avalos buffer_put_int(r, MUX_S_FAILURE); 747856ea928SPeter Avalos buffer_put_int(r, rid); 748856ea928SPeter Avalos buffer_put_cstring(r, "Port forwarding failed"); 749856ea928SPeter Avalos goto out; 750856ea928SPeter Avalos } 751856ea928SPeter Avalos add_local_forward(&options, &fwd); 752856ea928SPeter Avalos freefwd = 0; 753856ea928SPeter Avalos } else { 754856ea928SPeter Avalos struct mux_channel_confirm_ctx *fctx; 755856ea928SPeter Avalos 756*99e85e0dSPeter Avalos fwd.handle = channel_request_remote_forwarding(fwd.listen_host, 757*99e85e0dSPeter Avalos fwd.listen_port, fwd.connect_host, fwd.connect_port); 758*99e85e0dSPeter Avalos if (fwd.handle < 0) 759856ea928SPeter Avalos goto fail; 760856ea928SPeter Avalos add_remote_forward(&options, &fwd); 761856ea928SPeter Avalos fctx = xcalloc(1, sizeof(*fctx)); 762856ea928SPeter Avalos fctx->cid = c->self; 763856ea928SPeter Avalos fctx->rid = rid; 764856ea928SPeter Avalos fctx->fid = options.num_remote_forwards - 1; 765856ea928SPeter Avalos client_register_global_confirm(mux_confirm_remote_forward, 766856ea928SPeter Avalos fctx); 767856ea928SPeter Avalos freefwd = 0; 768856ea928SPeter Avalos c->mux_pause = 1; /* wait for mux_confirm_remote_forward */ 769856ea928SPeter Avalos /* delayed reply in mux_confirm_remote_forward */ 770856ea928SPeter Avalos goto out; 771856ea928SPeter Avalos } 772856ea928SPeter Avalos buffer_put_int(r, MUX_S_OK); 773856ea928SPeter Avalos buffer_put_int(r, rid); 774856ea928SPeter Avalos out: 775856ea928SPeter Avalos if (fwd_desc != NULL) 776856ea928SPeter Avalos xfree(fwd_desc); 777856ea928SPeter Avalos if (freefwd) { 778856ea928SPeter Avalos if (fwd.listen_host != NULL) 779856ea928SPeter Avalos xfree(fwd.listen_host); 780856ea928SPeter Avalos if (fwd.connect_host != NULL) 781856ea928SPeter Avalos xfree(fwd.connect_host); 782856ea928SPeter Avalos } 783856ea928SPeter Avalos return ret; 784856ea928SPeter Avalos } 785856ea928SPeter Avalos 786856ea928SPeter Avalos static int 787856ea928SPeter Avalos process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 788856ea928SPeter Avalos { 789*99e85e0dSPeter Avalos Forward fwd, *found_fwd; 790856ea928SPeter Avalos char *fwd_desc = NULL; 791*99e85e0dSPeter Avalos const char *error_reason = NULL; 792856ea928SPeter Avalos u_int ftype; 793*99e85e0dSPeter Avalos int i, listen_port, ret = 0; 794856ea928SPeter Avalos 795856ea928SPeter Avalos fwd.listen_host = fwd.connect_host = NULL; 796856ea928SPeter Avalos if (buffer_get_int_ret(&ftype, m) != 0 || 797856ea928SPeter Avalos (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL || 798856ea928SPeter Avalos buffer_get_int_ret(&fwd.listen_port, m) != 0 || 799856ea928SPeter Avalos (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL || 800856ea928SPeter Avalos buffer_get_int_ret(&fwd.connect_port, m) != 0) { 801856ea928SPeter Avalos error("%s: malformed message", __func__); 802856ea928SPeter Avalos ret = -1; 803856ea928SPeter Avalos goto out; 804856ea928SPeter Avalos } 805856ea928SPeter Avalos 806856ea928SPeter Avalos if (*fwd.listen_host == '\0') { 807856ea928SPeter Avalos xfree(fwd.listen_host); 808856ea928SPeter Avalos fwd.listen_host = NULL; 809856ea928SPeter Avalos } 810856ea928SPeter Avalos if (*fwd.connect_host == '\0') { 811856ea928SPeter Avalos xfree(fwd.connect_host); 812856ea928SPeter Avalos fwd.connect_host = NULL; 813856ea928SPeter Avalos } 814856ea928SPeter Avalos 815*99e85e0dSPeter Avalos debug2("%s: channel %d: request cancel %s", __func__, c->self, 816856ea928SPeter Avalos (fwd_desc = format_forward(ftype, &fwd))); 817856ea928SPeter Avalos 818*99e85e0dSPeter Avalos /* make sure this has been requested */ 819*99e85e0dSPeter Avalos found_fwd = NULL; 820*99e85e0dSPeter Avalos switch (ftype) { 821*99e85e0dSPeter Avalos case MUX_FWD_LOCAL: 822*99e85e0dSPeter Avalos case MUX_FWD_DYNAMIC: 823*99e85e0dSPeter Avalos for (i = 0; i < options.num_local_forwards; i++) { 824*99e85e0dSPeter Avalos if (compare_forward(&fwd, 825*99e85e0dSPeter Avalos options.local_forwards + i)) { 826*99e85e0dSPeter Avalos found_fwd = options.local_forwards + i; 827*99e85e0dSPeter Avalos break; 828*99e85e0dSPeter Avalos } 829*99e85e0dSPeter Avalos } 830*99e85e0dSPeter Avalos break; 831*99e85e0dSPeter Avalos case MUX_FWD_REMOTE: 832*99e85e0dSPeter Avalos for (i = 0; i < options.num_remote_forwards; i++) { 833*99e85e0dSPeter Avalos if (compare_forward(&fwd, 834*99e85e0dSPeter Avalos options.remote_forwards + i)) { 835*99e85e0dSPeter Avalos found_fwd = options.remote_forwards + i; 836*99e85e0dSPeter Avalos break; 837*99e85e0dSPeter Avalos } 838*99e85e0dSPeter Avalos } 839*99e85e0dSPeter Avalos break; 840*99e85e0dSPeter Avalos } 841*99e85e0dSPeter Avalos 842*99e85e0dSPeter Avalos if (found_fwd == NULL) 843*99e85e0dSPeter Avalos error_reason = "port not forwarded"; 844*99e85e0dSPeter Avalos else if (ftype == MUX_FWD_REMOTE) { 845*99e85e0dSPeter Avalos /* 846*99e85e0dSPeter Avalos * This shouldn't fail unless we confused the host/port 847*99e85e0dSPeter Avalos * between options.remote_forwards and permitted_opens. 848*99e85e0dSPeter Avalos * However, for dynamic allocated listen ports we need 849*99e85e0dSPeter Avalos * to lookup the actual listen port. 850*99e85e0dSPeter Avalos */ 851*99e85e0dSPeter Avalos listen_port = (fwd.listen_port == 0) ? 852*99e85e0dSPeter Avalos found_fwd->allocated_port : fwd.listen_port; 853*99e85e0dSPeter Avalos if (channel_request_rforward_cancel(fwd.listen_host, 854*99e85e0dSPeter Avalos listen_port) == -1) 855*99e85e0dSPeter Avalos error_reason = "port not in permitted opens"; 856*99e85e0dSPeter Avalos } else { /* local and dynamic forwards */ 857*99e85e0dSPeter Avalos /* Ditto */ 858*99e85e0dSPeter Avalos if (channel_cancel_lport_listener(fwd.listen_host, 859*99e85e0dSPeter Avalos fwd.listen_port, fwd.connect_port, 860*99e85e0dSPeter Avalos options.gateway_ports) == -1) 861*99e85e0dSPeter Avalos error_reason = "port not found"; 862*99e85e0dSPeter Avalos } 863*99e85e0dSPeter Avalos 864*99e85e0dSPeter Avalos if (error_reason == NULL) { 865*99e85e0dSPeter Avalos buffer_put_int(r, MUX_S_OK); 866*99e85e0dSPeter Avalos buffer_put_int(r, rid); 867*99e85e0dSPeter Avalos 868*99e85e0dSPeter Avalos if (found_fwd->listen_host != NULL) 869*99e85e0dSPeter Avalos xfree(found_fwd->listen_host); 870*99e85e0dSPeter Avalos if (found_fwd->connect_host != NULL) 871*99e85e0dSPeter Avalos xfree(found_fwd->connect_host); 872*99e85e0dSPeter Avalos found_fwd->listen_host = found_fwd->connect_host = NULL; 873*99e85e0dSPeter Avalos found_fwd->listen_port = found_fwd->connect_port = 0; 874*99e85e0dSPeter Avalos } else { 875856ea928SPeter Avalos buffer_put_int(r, MUX_S_FAILURE); 876856ea928SPeter Avalos buffer_put_int(r, rid); 877*99e85e0dSPeter Avalos buffer_put_cstring(r, error_reason); 878*99e85e0dSPeter Avalos } 879856ea928SPeter Avalos out: 880856ea928SPeter Avalos if (fwd_desc != NULL) 881856ea928SPeter Avalos xfree(fwd_desc); 882856ea928SPeter Avalos if (fwd.listen_host != NULL) 883856ea928SPeter Avalos xfree(fwd.listen_host); 884856ea928SPeter Avalos if (fwd.connect_host != NULL) 885856ea928SPeter Avalos xfree(fwd.connect_host); 886856ea928SPeter Avalos 887856ea928SPeter Avalos return ret; 888856ea928SPeter Avalos } 889856ea928SPeter Avalos 890856ea928SPeter Avalos static int 891856ea928SPeter Avalos process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 892856ea928SPeter Avalos { 893856ea928SPeter Avalos Channel *nc; 894856ea928SPeter Avalos char *reserved, *chost; 895856ea928SPeter Avalos u_int cport, i, j; 896856ea928SPeter Avalos int new_fd[2]; 897856ea928SPeter Avalos 898856ea928SPeter Avalos chost = reserved = NULL; 899856ea928SPeter Avalos if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || 900856ea928SPeter Avalos (chost = buffer_get_string_ret(m, NULL)) == NULL || 901856ea928SPeter Avalos buffer_get_int_ret(&cport, m) != 0) { 902856ea928SPeter Avalos if (reserved != NULL) 903856ea928SPeter Avalos xfree(reserved); 904856ea928SPeter Avalos if (chost != NULL) 905856ea928SPeter Avalos xfree(chost); 906856ea928SPeter Avalos error("%s: malformed message", __func__); 907856ea928SPeter Avalos return -1; 908856ea928SPeter Avalos } 909856ea928SPeter Avalos xfree(reserved); 910856ea928SPeter Avalos 911856ea928SPeter Avalos debug2("%s: channel %d: request stdio fwd to %s:%u", 912856ea928SPeter Avalos __func__, c->self, chost, cport); 913856ea928SPeter Avalos 914856ea928SPeter Avalos /* Gather fds from client */ 915856ea928SPeter Avalos for(i = 0; i < 2; i++) { 916856ea928SPeter Avalos if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { 917856ea928SPeter Avalos error("%s: failed to receive fd %d from slave", 918856ea928SPeter Avalos __func__, i); 919856ea928SPeter Avalos for (j = 0; j < i; j++) 920856ea928SPeter Avalos close(new_fd[j]); 921856ea928SPeter Avalos xfree(chost); 922856ea928SPeter Avalos 923856ea928SPeter Avalos /* prepare reply */ 924856ea928SPeter Avalos buffer_put_int(r, MUX_S_FAILURE); 925856ea928SPeter Avalos buffer_put_int(r, rid); 926856ea928SPeter Avalos buffer_put_cstring(r, 927856ea928SPeter Avalos "did not receive file descriptors"); 928856ea928SPeter Avalos return -1; 929856ea928SPeter Avalos } 930856ea928SPeter Avalos } 931856ea928SPeter Avalos 932856ea928SPeter Avalos debug3("%s: got fds stdin %d, stdout %d", __func__, 933856ea928SPeter Avalos new_fd[0], new_fd[1]); 934856ea928SPeter Avalos 935856ea928SPeter Avalos /* XXX support multiple child sessions in future */ 936856ea928SPeter Avalos if (c->remote_id != -1) { 937856ea928SPeter Avalos debug2("%s: session already open", __func__); 938856ea928SPeter Avalos /* prepare reply */ 939856ea928SPeter Avalos buffer_put_int(r, MUX_S_FAILURE); 940856ea928SPeter Avalos buffer_put_int(r, rid); 941856ea928SPeter Avalos buffer_put_cstring(r, "Multiple sessions not supported"); 942856ea928SPeter Avalos cleanup: 943856ea928SPeter Avalos close(new_fd[0]); 944856ea928SPeter Avalos close(new_fd[1]); 945856ea928SPeter Avalos xfree(chost); 946856ea928SPeter Avalos return 0; 947856ea928SPeter Avalos } 948856ea928SPeter Avalos 949856ea928SPeter Avalos if (options.control_master == SSHCTL_MASTER_ASK || 950856ea928SPeter Avalos options.control_master == SSHCTL_MASTER_AUTO_ASK) { 9519f304aafSPeter Avalos if (!ask_permission("Allow forward to %s:%u? ", 952856ea928SPeter Avalos chost, cport)) { 953856ea928SPeter Avalos debug2("%s: stdio fwd refused by user", __func__); 954856ea928SPeter Avalos /* prepare reply */ 955856ea928SPeter Avalos buffer_put_int(r, MUX_S_PERMISSION_DENIED); 956856ea928SPeter Avalos buffer_put_int(r, rid); 957856ea928SPeter Avalos buffer_put_cstring(r, "Permission denied"); 958856ea928SPeter Avalos goto cleanup; 959856ea928SPeter Avalos } 960856ea928SPeter Avalos } 961856ea928SPeter Avalos 962856ea928SPeter Avalos /* enable nonblocking unless tty */ 963856ea928SPeter Avalos if (!isatty(new_fd[0])) 964856ea928SPeter Avalos set_nonblock(new_fd[0]); 965856ea928SPeter Avalos if (!isatty(new_fd[1])) 966856ea928SPeter Avalos set_nonblock(new_fd[1]); 967856ea928SPeter Avalos 968856ea928SPeter Avalos nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]); 969856ea928SPeter Avalos 970856ea928SPeter Avalos nc->ctl_chan = c->self; /* link session -> control channel */ 971856ea928SPeter Avalos c->remote_id = nc->self; /* link control -> session channel */ 972856ea928SPeter Avalos 973856ea928SPeter Avalos debug2("%s: channel_new: %d linked to control channel %d", 974856ea928SPeter Avalos __func__, nc->self, nc->ctl_chan); 975856ea928SPeter Avalos 976856ea928SPeter Avalos channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); 977856ea928SPeter Avalos 978856ea928SPeter Avalos /* prepare reply */ 979856ea928SPeter Avalos /* XXX defer until channel confirmed */ 980856ea928SPeter Avalos buffer_put_int(r, MUX_S_SESSION_OPENED); 981856ea928SPeter Avalos buffer_put_int(r, rid); 982856ea928SPeter Avalos buffer_put_int(r, nc->self); 983856ea928SPeter Avalos 984856ea928SPeter Avalos return 0; 985856ea928SPeter Avalos } 986856ea928SPeter Avalos 9871c188a7fSPeter Avalos static int 9881c188a7fSPeter Avalos process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r) 9891c188a7fSPeter Avalos { 9901c188a7fSPeter Avalos debug("%s: channel %d: stop listening", __func__, c->self); 9911c188a7fSPeter Avalos 9921c188a7fSPeter Avalos if (options.control_master == SSHCTL_MASTER_ASK || 9931c188a7fSPeter Avalos options.control_master == SSHCTL_MASTER_AUTO_ASK) { 9941c188a7fSPeter Avalos if (!ask_permission("Disable further multiplexing on shared " 9951c188a7fSPeter Avalos "connection to %s? ", host)) { 9961c188a7fSPeter Avalos debug2("%s: stop listen refused by user", __func__); 9971c188a7fSPeter Avalos buffer_put_int(r, MUX_S_PERMISSION_DENIED); 9981c188a7fSPeter Avalos buffer_put_int(r, rid); 9991c188a7fSPeter Avalos buffer_put_cstring(r, "Permission denied"); 10001c188a7fSPeter Avalos return 0; 10011c188a7fSPeter Avalos } 10021c188a7fSPeter Avalos } 10031c188a7fSPeter Avalos 10041c188a7fSPeter Avalos if (mux_listener_channel != NULL) { 10051c188a7fSPeter Avalos channel_free(mux_listener_channel); 10061c188a7fSPeter Avalos client_stop_mux(); 10071c188a7fSPeter Avalos xfree(options.control_path); 10081c188a7fSPeter Avalos options.control_path = NULL; 10091c188a7fSPeter Avalos mux_listener_channel = NULL; 10101c188a7fSPeter Avalos muxserver_sock = -1; 10111c188a7fSPeter Avalos } 10121c188a7fSPeter Avalos 10131c188a7fSPeter Avalos /* prepare reply */ 10141c188a7fSPeter Avalos buffer_put_int(r, MUX_S_OK); 10151c188a7fSPeter Avalos buffer_put_int(r, rid); 10161c188a7fSPeter Avalos 10171c188a7fSPeter Avalos return 0; 10181c188a7fSPeter Avalos } 10191c188a7fSPeter Avalos 1020856ea928SPeter Avalos /* Channel callbacks fired on read/write from mux slave fd */ 1021856ea928SPeter Avalos static int 1022856ea928SPeter Avalos mux_master_read_cb(Channel *c) 1023856ea928SPeter Avalos { 1024856ea928SPeter Avalos struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; 1025856ea928SPeter Avalos Buffer in, out; 1026856ea928SPeter Avalos void *ptr; 1027856ea928SPeter Avalos u_int type, rid, have, i; 1028856ea928SPeter Avalos int ret = -1; 1029856ea928SPeter Avalos 1030856ea928SPeter Avalos /* Setup ctx and */ 1031856ea928SPeter Avalos if (c->mux_ctx == NULL) { 1032856ea928SPeter Avalos state = xcalloc(1, sizeof(*state)); 1033856ea928SPeter Avalos c->mux_ctx = state; 1034856ea928SPeter Avalos channel_register_cleanup(c->self, 1035856ea928SPeter Avalos mux_master_control_cleanup_cb, 0); 1036856ea928SPeter Avalos 1037856ea928SPeter Avalos /* Send hello */ 1038856ea928SPeter Avalos buffer_init(&out); 1039856ea928SPeter Avalos buffer_put_int(&out, MUX_MSG_HELLO); 1040856ea928SPeter Avalos buffer_put_int(&out, SSHMUX_VER); 1041856ea928SPeter Avalos /* no extensions */ 1042856ea928SPeter Avalos buffer_put_string(&c->output, buffer_ptr(&out), 1043856ea928SPeter Avalos buffer_len(&out)); 1044856ea928SPeter Avalos buffer_free(&out); 1045856ea928SPeter Avalos debug3("%s: channel %d: hello sent", __func__, c->self); 1046856ea928SPeter Avalos return 0; 1047856ea928SPeter Avalos } 1048856ea928SPeter Avalos 1049856ea928SPeter Avalos buffer_init(&in); 1050856ea928SPeter Avalos buffer_init(&out); 1051856ea928SPeter Avalos 1052856ea928SPeter Avalos /* Channel code ensures that we receive whole packets */ 1053856ea928SPeter Avalos if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) { 1054856ea928SPeter Avalos malf: 1055856ea928SPeter Avalos error("%s: malformed message", __func__); 1056856ea928SPeter Avalos goto out; 1057856ea928SPeter Avalos } 1058856ea928SPeter Avalos buffer_append(&in, ptr, have); 1059856ea928SPeter Avalos 1060856ea928SPeter Avalos if (buffer_get_int_ret(&type, &in) != 0) 1061856ea928SPeter Avalos goto malf; 1062856ea928SPeter Avalos debug3("%s: channel %d packet type 0x%08x len %u", 1063856ea928SPeter Avalos __func__, c->self, type, buffer_len(&in)); 1064856ea928SPeter Avalos 1065856ea928SPeter Avalos if (type == MUX_MSG_HELLO) 1066856ea928SPeter Avalos rid = 0; 1067856ea928SPeter Avalos else { 1068856ea928SPeter Avalos if (!state->hello_rcvd) { 1069856ea928SPeter Avalos error("%s: expected MUX_MSG_HELLO(0x%08x), " 1070856ea928SPeter Avalos "received 0x%08x", __func__, MUX_MSG_HELLO, type); 1071856ea928SPeter Avalos goto out; 1072856ea928SPeter Avalos } 1073856ea928SPeter Avalos if (buffer_get_int_ret(&rid, &in) != 0) 1074856ea928SPeter Avalos goto malf; 1075856ea928SPeter Avalos } 1076856ea928SPeter Avalos 1077856ea928SPeter Avalos for (i = 0; mux_master_handlers[i].handler != NULL; i++) { 1078856ea928SPeter Avalos if (type == mux_master_handlers[i].type) { 1079856ea928SPeter Avalos ret = mux_master_handlers[i].handler(rid, c, &in, &out); 1080856ea928SPeter Avalos break; 1081856ea928SPeter Avalos } 1082856ea928SPeter Avalos } 1083856ea928SPeter Avalos if (mux_master_handlers[i].handler == NULL) { 1084856ea928SPeter Avalos error("%s: unsupported mux message 0x%08x", __func__, type); 1085856ea928SPeter Avalos buffer_put_int(&out, MUX_S_FAILURE); 1086856ea928SPeter Avalos buffer_put_int(&out, rid); 1087856ea928SPeter Avalos buffer_put_cstring(&out, "unsupported request"); 1088856ea928SPeter Avalos ret = 0; 1089856ea928SPeter Avalos } 1090856ea928SPeter Avalos /* Enqueue reply packet */ 1091856ea928SPeter Avalos if (buffer_len(&out) != 0) { 1092856ea928SPeter Avalos buffer_put_string(&c->output, buffer_ptr(&out), 1093856ea928SPeter Avalos buffer_len(&out)); 1094856ea928SPeter Avalos } 1095856ea928SPeter Avalos out: 1096856ea928SPeter Avalos buffer_free(&in); 1097856ea928SPeter Avalos buffer_free(&out); 1098856ea928SPeter Avalos return ret; 1099856ea928SPeter Avalos } 1100856ea928SPeter Avalos 1101856ea928SPeter Avalos void 1102856ea928SPeter Avalos mux_exit_message(Channel *c, int exitval) 1103856ea928SPeter Avalos { 1104856ea928SPeter Avalos Buffer m; 1105856ea928SPeter Avalos Channel *mux_chan; 1106856ea928SPeter Avalos 1107856ea928SPeter Avalos debug3("%s: channel %d: exit message, evitval %d", __func__, c->self, 1108856ea928SPeter Avalos exitval); 1109856ea928SPeter Avalos 1110856ea928SPeter Avalos if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) 1111856ea928SPeter Avalos fatal("%s: channel %d missing mux channel %d", 1112856ea928SPeter Avalos __func__, c->self, c->ctl_chan); 1113856ea928SPeter Avalos 1114856ea928SPeter Avalos /* Append exit message packet to control socket output queue */ 1115856ea928SPeter Avalos buffer_init(&m); 1116856ea928SPeter Avalos buffer_put_int(&m, MUX_S_EXIT_MESSAGE); 1117856ea928SPeter Avalos buffer_put_int(&m, c->self); 1118856ea928SPeter Avalos buffer_put_int(&m, exitval); 1119856ea928SPeter Avalos 1120856ea928SPeter Avalos buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); 1121856ea928SPeter Avalos buffer_free(&m); 1122856ea928SPeter Avalos } 112318de8d7fSPeter Avalos 11241c188a7fSPeter Avalos void 11251c188a7fSPeter Avalos mux_tty_alloc_failed(Channel *c) 11261c188a7fSPeter Avalos { 11271c188a7fSPeter Avalos Buffer m; 11281c188a7fSPeter Avalos Channel *mux_chan; 11291c188a7fSPeter Avalos 11301c188a7fSPeter Avalos debug3("%s: channel %d: TTY alloc failed", __func__, c->self); 11311c188a7fSPeter Avalos 11321c188a7fSPeter Avalos if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) 11331c188a7fSPeter Avalos fatal("%s: channel %d missing mux channel %d", 11341c188a7fSPeter Avalos __func__, c->self, c->ctl_chan); 11351c188a7fSPeter Avalos 11361c188a7fSPeter Avalos /* Append exit message packet to control socket output queue */ 11371c188a7fSPeter Avalos buffer_init(&m); 11381c188a7fSPeter Avalos buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL); 11391c188a7fSPeter Avalos buffer_put_int(&m, c->self); 11401c188a7fSPeter Avalos 11411c188a7fSPeter Avalos buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); 11421c188a7fSPeter Avalos buffer_free(&m); 11431c188a7fSPeter Avalos } 11441c188a7fSPeter Avalos 114518de8d7fSPeter Avalos /* Prepare a mux master to listen on a Unix domain socket. */ 114618de8d7fSPeter Avalos void 114718de8d7fSPeter Avalos muxserver_listen(void) 114818de8d7fSPeter Avalos { 114918de8d7fSPeter Avalos struct sockaddr_un addr; 1150856ea928SPeter Avalos socklen_t sun_len; 115118de8d7fSPeter Avalos mode_t old_umask; 11529f304aafSPeter Avalos char *orig_control_path = options.control_path; 11539f304aafSPeter Avalos char rbuf[16+1]; 11549f304aafSPeter Avalos u_int i, r; 115518de8d7fSPeter Avalos 115618de8d7fSPeter Avalos if (options.control_path == NULL || 115718de8d7fSPeter Avalos options.control_master == SSHCTL_MASTER_NO) 115818de8d7fSPeter Avalos return; 115918de8d7fSPeter Avalos 116018de8d7fSPeter Avalos debug("setting up multiplex master socket"); 116118de8d7fSPeter Avalos 11629f304aafSPeter Avalos /* 11639f304aafSPeter Avalos * Use a temporary path before listen so we can pseudo-atomically 11649f304aafSPeter Avalos * establish the listening socket in its final location to avoid 11659f304aafSPeter Avalos * other processes racing in between bind() and listen() and hitting 11669f304aafSPeter Avalos * an unready socket. 11679f304aafSPeter Avalos */ 11689f304aafSPeter Avalos for (i = 0; i < sizeof(rbuf) - 1; i++) { 11699f304aafSPeter Avalos r = arc4random_uniform(26+26+10); 11709f304aafSPeter Avalos rbuf[i] = (r < 26) ? 'a' + r : 11719f304aafSPeter Avalos (r < 26*2) ? 'A' + r - 26 : 11729f304aafSPeter Avalos '0' + r - 26 - 26; 11739f304aafSPeter Avalos } 11749f304aafSPeter Avalos rbuf[sizeof(rbuf) - 1] = '\0'; 11759f304aafSPeter Avalos options.control_path = NULL; 11769f304aafSPeter Avalos xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf); 11779f304aafSPeter Avalos debug3("%s: temporary control path %s", __func__, options.control_path); 11789f304aafSPeter Avalos 117918de8d7fSPeter Avalos memset(&addr, '\0', sizeof(addr)); 118018de8d7fSPeter Avalos addr.sun_family = AF_UNIX; 1181856ea928SPeter Avalos sun_len = offsetof(struct sockaddr_un, sun_path) + 118218de8d7fSPeter Avalos strlen(options.control_path) + 1; 118318de8d7fSPeter Avalos 118418de8d7fSPeter Avalos if (strlcpy(addr.sun_path, options.control_path, 11851c188a7fSPeter Avalos sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) { 11861c188a7fSPeter Avalos error("ControlPath \"%s\" too long for Unix domain socket", 11871c188a7fSPeter Avalos options.control_path); 11881c188a7fSPeter Avalos goto disable_mux_master; 11891c188a7fSPeter Avalos } 119018de8d7fSPeter Avalos 119118de8d7fSPeter Avalos if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) 119218de8d7fSPeter Avalos fatal("%s socket(): %s", __func__, strerror(errno)); 119318de8d7fSPeter Avalos 119418de8d7fSPeter Avalos old_umask = umask(0177); 1195856ea928SPeter Avalos if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) { 119618de8d7fSPeter Avalos if (errno == EINVAL || errno == EADDRINUSE) { 119718de8d7fSPeter Avalos error("ControlSocket %s already exists, " 119818de8d7fSPeter Avalos "disabling multiplexing", options.control_path); 11999f304aafSPeter Avalos disable_mux_master: 12001c188a7fSPeter Avalos if (muxserver_sock != -1) { 120118de8d7fSPeter Avalos close(muxserver_sock); 120218de8d7fSPeter Avalos muxserver_sock = -1; 12031c188a7fSPeter Avalos } 1204*99e85e0dSPeter Avalos xfree(orig_control_path); 120518de8d7fSPeter Avalos xfree(options.control_path); 120618de8d7fSPeter Avalos options.control_path = NULL; 120718de8d7fSPeter Avalos options.control_master = SSHCTL_MASTER_NO; 120818de8d7fSPeter Avalos return; 120918de8d7fSPeter Avalos } else 121018de8d7fSPeter Avalos fatal("%s bind(): %s", __func__, strerror(errno)); 121118de8d7fSPeter Avalos } 121218de8d7fSPeter Avalos umask(old_umask); 121318de8d7fSPeter Avalos 121418de8d7fSPeter Avalos if (listen(muxserver_sock, 64) == -1) 121518de8d7fSPeter Avalos fatal("%s listen(): %s", __func__, strerror(errno)); 121618de8d7fSPeter Avalos 12179f304aafSPeter Avalos /* Now atomically "move" the mux socket into position */ 12189f304aafSPeter Avalos if (link(options.control_path, orig_control_path) != 0) { 12199f304aafSPeter Avalos if (errno != EEXIST) { 12209f304aafSPeter Avalos fatal("%s: link mux listener %s => %s: %s", __func__, 12219f304aafSPeter Avalos options.control_path, orig_control_path, 12229f304aafSPeter Avalos strerror(errno)); 12239f304aafSPeter Avalos } 12249f304aafSPeter Avalos error("ControlSocket %s already exists, disabling multiplexing", 12259f304aafSPeter Avalos orig_control_path); 12269f304aafSPeter Avalos unlink(options.control_path); 12279f304aafSPeter Avalos goto disable_mux_master; 12289f304aafSPeter Avalos } 12299f304aafSPeter Avalos unlink(options.control_path); 12309f304aafSPeter Avalos xfree(options.control_path); 12319f304aafSPeter Avalos options.control_path = orig_control_path; 12329f304aafSPeter Avalos 123318de8d7fSPeter Avalos set_nonblock(muxserver_sock); 1234856ea928SPeter Avalos 1235856ea928SPeter Avalos mux_listener_channel = channel_new("mux listener", 1236856ea928SPeter Avalos SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, 1237856ea928SPeter Avalos CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 12389f304aafSPeter Avalos 0, options.control_path, 1); 1239856ea928SPeter Avalos mux_listener_channel->mux_rcb = mux_master_read_cb; 1240856ea928SPeter Avalos debug3("%s: mux listener channel %d fd %d", __func__, 1241856ea928SPeter Avalos mux_listener_channel->self, mux_listener_channel->sock); 124218de8d7fSPeter Avalos } 124318de8d7fSPeter Avalos 124418de8d7fSPeter Avalos /* Callback on open confirmation in mux master for a mux client session. */ 124518de8d7fSPeter Avalos static void 1246856ea928SPeter Avalos mux_session_confirm(int id, int success, void *arg) 124718de8d7fSPeter Avalos { 124818de8d7fSPeter Avalos struct mux_session_confirm_ctx *cctx = arg; 124918de8d7fSPeter Avalos const char *display; 1250856ea928SPeter Avalos Channel *c, *cc; 125118de8d7fSPeter Avalos int i; 1252856ea928SPeter Avalos Buffer reply; 125318de8d7fSPeter Avalos 125418de8d7fSPeter Avalos if (cctx == NULL) 125518de8d7fSPeter Avalos fatal("%s: cctx == NULL", __func__); 1256856ea928SPeter Avalos if ((c = channel_by_id(id)) == NULL) 125718de8d7fSPeter Avalos fatal("%s: no channel for id %d", __func__, id); 1258856ea928SPeter Avalos if ((cc = channel_by_id(c->ctl_chan)) == NULL) 1259856ea928SPeter Avalos fatal("%s: channel %d lacks control channel %d", __func__, 1260856ea928SPeter Avalos id, c->ctl_chan); 1261856ea928SPeter Avalos 1262856ea928SPeter Avalos if (!success) { 1263856ea928SPeter Avalos debug3("%s: sending failure reply", __func__); 1264856ea928SPeter Avalos /* prepare reply */ 1265856ea928SPeter Avalos buffer_init(&reply); 1266856ea928SPeter Avalos buffer_put_int(&reply, MUX_S_FAILURE); 1267856ea928SPeter Avalos buffer_put_int(&reply, cctx->rid); 1268856ea928SPeter Avalos buffer_put_cstring(&reply, "Session open refused by peer"); 1269856ea928SPeter Avalos goto done; 1270856ea928SPeter Avalos } 127118de8d7fSPeter Avalos 127218de8d7fSPeter Avalos display = getenv("DISPLAY"); 127318de8d7fSPeter Avalos if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { 127418de8d7fSPeter Avalos char *proto, *data; 1275856ea928SPeter Avalos 127618de8d7fSPeter Avalos /* Get reasonable local authentication information. */ 127718de8d7fSPeter Avalos client_x11_get_proto(display, options.xauth_location, 1278856ea928SPeter Avalos options.forward_x11_trusted, options.forward_x11_timeout, 1279856ea928SPeter Avalos &proto, &data); 128018de8d7fSPeter Avalos /* Request forwarding with authentication spoofing. */ 1281856ea928SPeter Avalos debug("Requesting X11 forwarding with authentication " 1282856ea928SPeter Avalos "spoofing."); 12831c188a7fSPeter Avalos x11_request_forwarding_with_spoofing(id, display, proto, 12841c188a7fSPeter Avalos data, 1); 12851c188a7fSPeter Avalos client_expect_confirm(id, "X11 forwarding", CONFIRM_WARN); 12861c188a7fSPeter Avalos /* XXX exit_on_forward_failure */ 128718de8d7fSPeter Avalos } 128818de8d7fSPeter Avalos 128918de8d7fSPeter Avalos if (cctx->want_agent_fwd && options.forward_agent) { 129018de8d7fSPeter Avalos debug("Requesting authentication agent forwarding."); 129118de8d7fSPeter Avalos channel_request_start(id, "auth-agent-req@openssh.com", 0); 129218de8d7fSPeter Avalos packet_send(); 129318de8d7fSPeter Avalos } 129418de8d7fSPeter Avalos 129518de8d7fSPeter Avalos client_session2_setup(id, cctx->want_tty, cctx->want_subsys, 129618de8d7fSPeter Avalos cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); 129718de8d7fSPeter Avalos 1298856ea928SPeter Avalos debug3("%s: sending success reply", __func__); 1299856ea928SPeter Avalos /* prepare reply */ 1300856ea928SPeter Avalos buffer_init(&reply); 1301856ea928SPeter Avalos buffer_put_int(&reply, MUX_S_SESSION_OPENED); 1302856ea928SPeter Avalos buffer_put_int(&reply, cctx->rid); 1303856ea928SPeter Avalos buffer_put_int(&reply, c->self); 1304856ea928SPeter Avalos 1305856ea928SPeter Avalos done: 1306856ea928SPeter Avalos /* Send reply */ 1307856ea928SPeter Avalos buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); 1308856ea928SPeter Avalos buffer_free(&reply); 1309856ea928SPeter Avalos 1310856ea928SPeter Avalos if (cc->mux_pause <= 0) 1311856ea928SPeter Avalos fatal("%s: mux_pause %d", __func__, cc->mux_pause); 1312856ea928SPeter Avalos cc->mux_pause = 0; /* start processing messages again */ 131318de8d7fSPeter Avalos c->open_confirm_ctx = NULL; 131418de8d7fSPeter Avalos buffer_free(&cctx->cmd); 131518de8d7fSPeter Avalos xfree(cctx->term); 131618de8d7fSPeter Avalos if (cctx->env != NULL) { 131718de8d7fSPeter Avalos for (i = 0; cctx->env[i] != NULL; i++) 131818de8d7fSPeter Avalos xfree(cctx->env[i]); 131918de8d7fSPeter Avalos xfree(cctx->env); 132018de8d7fSPeter Avalos } 132118de8d7fSPeter Avalos xfree(cctx); 132218de8d7fSPeter Avalos } 132318de8d7fSPeter Avalos 132418de8d7fSPeter Avalos /* ** Multiplexing client support */ 132518de8d7fSPeter Avalos 132618de8d7fSPeter Avalos /* Exit signal handler */ 132718de8d7fSPeter Avalos static void 132818de8d7fSPeter Avalos control_client_sighandler(int signo) 132918de8d7fSPeter Avalos { 133018de8d7fSPeter Avalos muxclient_terminate = signo; 133118de8d7fSPeter Avalos } 133218de8d7fSPeter Avalos 133318de8d7fSPeter Avalos /* 133418de8d7fSPeter Avalos * Relay signal handler - used to pass some signals from mux client to 133518de8d7fSPeter Avalos * mux master. 133618de8d7fSPeter Avalos */ 133718de8d7fSPeter Avalos static void 133818de8d7fSPeter Avalos control_client_sigrelay(int signo) 133918de8d7fSPeter Avalos { 134018de8d7fSPeter Avalos int save_errno = errno; 134118de8d7fSPeter Avalos 134218de8d7fSPeter Avalos if (muxserver_pid > 1) 134318de8d7fSPeter Avalos kill(muxserver_pid, signo); 134418de8d7fSPeter Avalos 134518de8d7fSPeter Avalos errno = save_errno; 134618de8d7fSPeter Avalos } 134718de8d7fSPeter Avalos 134818de8d7fSPeter Avalos static int 1349856ea928SPeter Avalos mux_client_read(int fd, Buffer *b, u_int need) 135018de8d7fSPeter Avalos { 1351856ea928SPeter Avalos u_int have; 1352856ea928SPeter Avalos ssize_t len; 1353856ea928SPeter Avalos u_char *p; 1354856ea928SPeter Avalos struct pollfd pfd; 135518de8d7fSPeter Avalos 1356856ea928SPeter Avalos pfd.fd = fd; 1357856ea928SPeter Avalos pfd.events = POLLIN; 1358856ea928SPeter Avalos p = buffer_append_space(b, need); 1359856ea928SPeter Avalos for (have = 0; have < need; ) { 1360856ea928SPeter Avalos if (muxclient_terminate) { 1361856ea928SPeter Avalos errno = EINTR; 1362856ea928SPeter Avalos return -1; 1363856ea928SPeter Avalos } 1364856ea928SPeter Avalos len = read(fd, p + have, need - have); 1365856ea928SPeter Avalos if (len < 0) { 1366856ea928SPeter Avalos switch (errno) { 1367856ea928SPeter Avalos #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) 1368856ea928SPeter Avalos case EWOULDBLOCK: 1369856ea928SPeter Avalos #endif 1370856ea928SPeter Avalos case EAGAIN: 1371856ea928SPeter Avalos (void)poll(&pfd, 1, -1); 1372856ea928SPeter Avalos /* FALLTHROUGH */ 1373856ea928SPeter Avalos case EINTR: 1374856ea928SPeter Avalos continue; 1375856ea928SPeter Avalos default: 1376856ea928SPeter Avalos return -1; 1377856ea928SPeter Avalos } 1378856ea928SPeter Avalos } 1379856ea928SPeter Avalos if (len == 0) { 1380856ea928SPeter Avalos errno = EPIPE; 1381856ea928SPeter Avalos return -1; 1382856ea928SPeter Avalos } 1383856ea928SPeter Avalos have += (u_int)len; 1384856ea928SPeter Avalos } 1385856ea928SPeter Avalos return 0; 1386856ea928SPeter Avalos } 138718de8d7fSPeter Avalos 1388856ea928SPeter Avalos static int 1389856ea928SPeter Avalos mux_client_write_packet(int fd, Buffer *m) 1390856ea928SPeter Avalos { 1391856ea928SPeter Avalos Buffer queue; 1392856ea928SPeter Avalos u_int have, need; 1393856ea928SPeter Avalos int oerrno, len; 1394856ea928SPeter Avalos u_char *ptr; 1395856ea928SPeter Avalos struct pollfd pfd; 139618de8d7fSPeter Avalos 1397856ea928SPeter Avalos pfd.fd = fd; 1398856ea928SPeter Avalos pfd.events = POLLOUT; 1399856ea928SPeter Avalos buffer_init(&queue); 1400856ea928SPeter Avalos buffer_put_string(&queue, buffer_ptr(m), buffer_len(m)); 1401856ea928SPeter Avalos 1402856ea928SPeter Avalos need = buffer_len(&queue); 1403856ea928SPeter Avalos ptr = buffer_ptr(&queue); 1404856ea928SPeter Avalos 1405856ea928SPeter Avalos for (have = 0; have < need; ) { 1406856ea928SPeter Avalos if (muxclient_terminate) { 1407856ea928SPeter Avalos buffer_free(&queue); 1408856ea928SPeter Avalos errno = EINTR; 1409856ea928SPeter Avalos return -1; 1410856ea928SPeter Avalos } 1411856ea928SPeter Avalos len = write(fd, ptr + have, need - have); 1412856ea928SPeter Avalos if (len < 0) { 1413856ea928SPeter Avalos switch (errno) { 1414856ea928SPeter Avalos #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) 1415856ea928SPeter Avalos case EWOULDBLOCK: 1416856ea928SPeter Avalos #endif 1417856ea928SPeter Avalos case EAGAIN: 1418856ea928SPeter Avalos (void)poll(&pfd, 1, -1); 1419856ea928SPeter Avalos /* FALLTHROUGH */ 1420856ea928SPeter Avalos case EINTR: 1421856ea928SPeter Avalos continue; 1422856ea928SPeter Avalos default: 1423856ea928SPeter Avalos oerrno = errno; 1424856ea928SPeter Avalos buffer_free(&queue); 1425856ea928SPeter Avalos errno = oerrno; 1426856ea928SPeter Avalos return -1; 1427856ea928SPeter Avalos } 1428856ea928SPeter Avalos } 1429856ea928SPeter Avalos if (len == 0) { 1430856ea928SPeter Avalos buffer_free(&queue); 1431856ea928SPeter Avalos errno = EPIPE; 1432856ea928SPeter Avalos return -1; 1433856ea928SPeter Avalos } 1434856ea928SPeter Avalos have += (u_int)len; 1435856ea928SPeter Avalos } 1436856ea928SPeter Avalos buffer_free(&queue); 1437856ea928SPeter Avalos return 0; 1438856ea928SPeter Avalos } 1439856ea928SPeter Avalos 1440856ea928SPeter Avalos static int 1441856ea928SPeter Avalos mux_client_read_packet(int fd, Buffer *m) 1442856ea928SPeter Avalos { 1443856ea928SPeter Avalos Buffer queue; 1444856ea928SPeter Avalos u_int need, have; 1445856ea928SPeter Avalos void *ptr; 1446856ea928SPeter Avalos int oerrno; 1447856ea928SPeter Avalos 1448856ea928SPeter Avalos buffer_init(&queue); 1449856ea928SPeter Avalos if (mux_client_read(fd, &queue, 4) != 0) { 1450856ea928SPeter Avalos if ((oerrno = errno) == EPIPE) 1451856ea928SPeter Avalos debug3("%s: read header failed: %s", __func__, strerror(errno)); 1452856ea928SPeter Avalos errno = oerrno; 1453856ea928SPeter Avalos return -1; 1454856ea928SPeter Avalos } 1455856ea928SPeter Avalos need = get_u32(buffer_ptr(&queue)); 1456856ea928SPeter Avalos if (mux_client_read(fd, &queue, need) != 0) { 1457856ea928SPeter Avalos oerrno = errno; 1458856ea928SPeter Avalos debug3("%s: read body failed: %s", __func__, strerror(errno)); 1459856ea928SPeter Avalos errno = oerrno; 1460856ea928SPeter Avalos return -1; 1461856ea928SPeter Avalos } 1462856ea928SPeter Avalos ptr = buffer_get_string_ptr(&queue, &have); 1463856ea928SPeter Avalos buffer_append(m, ptr, have); 1464856ea928SPeter Avalos buffer_free(&queue); 1465856ea928SPeter Avalos return 0; 1466856ea928SPeter Avalos } 1467856ea928SPeter Avalos 1468856ea928SPeter Avalos static int 1469856ea928SPeter Avalos mux_client_hello_exchange(int fd) 1470856ea928SPeter Avalos { 1471856ea928SPeter Avalos Buffer m; 1472856ea928SPeter Avalos u_int type, ver; 1473856ea928SPeter Avalos 1474856ea928SPeter Avalos buffer_init(&m); 1475856ea928SPeter Avalos buffer_put_int(&m, MUX_MSG_HELLO); 1476856ea928SPeter Avalos buffer_put_int(&m, SSHMUX_VER); 1477856ea928SPeter Avalos /* no extensions */ 1478856ea928SPeter Avalos 1479856ea928SPeter Avalos if (mux_client_write_packet(fd, &m) != 0) 1480856ea928SPeter Avalos fatal("%s: write packet: %s", __func__, strerror(errno)); 1481856ea928SPeter Avalos 1482856ea928SPeter Avalos buffer_clear(&m); 1483856ea928SPeter Avalos 1484856ea928SPeter Avalos /* Read their HELLO */ 1485856ea928SPeter Avalos if (mux_client_read_packet(fd, &m) != 0) { 1486856ea928SPeter Avalos buffer_free(&m); 1487856ea928SPeter Avalos return -1; 1488856ea928SPeter Avalos } 1489856ea928SPeter Avalos 1490856ea928SPeter Avalos type = buffer_get_int(&m); 1491856ea928SPeter Avalos if (type != MUX_MSG_HELLO) 1492856ea928SPeter Avalos fatal("%s: expected HELLO (%u) received %u", 1493856ea928SPeter Avalos __func__, MUX_MSG_HELLO, type); 1494856ea928SPeter Avalos ver = buffer_get_int(&m); 1495856ea928SPeter Avalos if (ver != SSHMUX_VER) 1496856ea928SPeter Avalos fatal("Unsupported multiplexing protocol version %d " 1497856ea928SPeter Avalos "(expected %d)", ver, SSHMUX_VER); 1498856ea928SPeter Avalos debug2("%s: master version %u", __func__, ver); 1499856ea928SPeter Avalos /* No extensions are presently defined */ 1500856ea928SPeter Avalos while (buffer_len(&m) > 0) { 1501856ea928SPeter Avalos char *name = buffer_get_string(&m, NULL); 1502856ea928SPeter Avalos char *value = buffer_get_string(&m, NULL); 1503856ea928SPeter Avalos 1504856ea928SPeter Avalos debug2("Unrecognised master extension \"%s\"", name); 1505856ea928SPeter Avalos xfree(name); 1506856ea928SPeter Avalos xfree(value); 1507856ea928SPeter Avalos } 1508856ea928SPeter Avalos buffer_free(&m); 1509856ea928SPeter Avalos return 0; 1510856ea928SPeter Avalos } 1511856ea928SPeter Avalos 1512856ea928SPeter Avalos static u_int 1513856ea928SPeter Avalos mux_client_request_alive(int fd) 1514856ea928SPeter Avalos { 1515856ea928SPeter Avalos Buffer m; 1516856ea928SPeter Avalos char *e; 1517856ea928SPeter Avalos u_int pid, type, rid; 1518856ea928SPeter Avalos 1519856ea928SPeter Avalos debug3("%s: entering", __func__); 1520856ea928SPeter Avalos 1521856ea928SPeter Avalos buffer_init(&m); 1522856ea928SPeter Avalos buffer_put_int(&m, MUX_C_ALIVE_CHECK); 1523856ea928SPeter Avalos buffer_put_int(&m, muxclient_request_id); 1524856ea928SPeter Avalos 1525856ea928SPeter Avalos if (mux_client_write_packet(fd, &m) != 0) 1526856ea928SPeter Avalos fatal("%s: write packet: %s", __func__, strerror(errno)); 1527856ea928SPeter Avalos 1528856ea928SPeter Avalos buffer_clear(&m); 1529856ea928SPeter Avalos 1530856ea928SPeter Avalos /* Read their reply */ 1531856ea928SPeter Avalos if (mux_client_read_packet(fd, &m) != 0) { 1532856ea928SPeter Avalos buffer_free(&m); 1533856ea928SPeter Avalos return 0; 1534856ea928SPeter Avalos } 1535856ea928SPeter Avalos 1536856ea928SPeter Avalos type = buffer_get_int(&m); 1537856ea928SPeter Avalos if (type != MUX_S_ALIVE) { 1538856ea928SPeter Avalos e = buffer_get_string(&m, NULL); 1539856ea928SPeter Avalos fatal("%s: master returned error: %s", __func__, e); 1540856ea928SPeter Avalos } 1541856ea928SPeter Avalos 1542856ea928SPeter Avalos if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1543856ea928SPeter Avalos fatal("%s: out of sequence reply: my id %u theirs %u", 1544856ea928SPeter Avalos __func__, muxclient_request_id, rid); 1545856ea928SPeter Avalos pid = buffer_get_int(&m); 1546856ea928SPeter Avalos buffer_free(&m); 1547856ea928SPeter Avalos 1548856ea928SPeter Avalos debug3("%s: done pid = %u", __func__, pid); 1549856ea928SPeter Avalos 1550856ea928SPeter Avalos muxclient_request_id++; 1551856ea928SPeter Avalos 1552856ea928SPeter Avalos return pid; 1553856ea928SPeter Avalos } 1554856ea928SPeter Avalos 1555856ea928SPeter Avalos static void 1556856ea928SPeter Avalos mux_client_request_terminate(int fd) 1557856ea928SPeter Avalos { 1558856ea928SPeter Avalos Buffer m; 1559856ea928SPeter Avalos char *e; 1560856ea928SPeter Avalos u_int type, rid; 1561856ea928SPeter Avalos 1562856ea928SPeter Avalos debug3("%s: entering", __func__); 1563856ea928SPeter Avalos 1564856ea928SPeter Avalos buffer_init(&m); 1565856ea928SPeter Avalos buffer_put_int(&m, MUX_C_TERMINATE); 1566856ea928SPeter Avalos buffer_put_int(&m, muxclient_request_id); 1567856ea928SPeter Avalos 1568856ea928SPeter Avalos if (mux_client_write_packet(fd, &m) != 0) 1569856ea928SPeter Avalos fatal("%s: write packet: %s", __func__, strerror(errno)); 1570856ea928SPeter Avalos 1571856ea928SPeter Avalos buffer_clear(&m); 1572856ea928SPeter Avalos 1573856ea928SPeter Avalos /* Read their reply */ 1574856ea928SPeter Avalos if (mux_client_read_packet(fd, &m) != 0) { 1575856ea928SPeter Avalos /* Remote end exited already */ 1576856ea928SPeter Avalos if (errno == EPIPE) { 1577856ea928SPeter Avalos buffer_free(&m); 1578856ea928SPeter Avalos return; 1579856ea928SPeter Avalos } 1580856ea928SPeter Avalos fatal("%s: read from master failed: %s", 1581856ea928SPeter Avalos __func__, strerror(errno)); 1582856ea928SPeter Avalos } 1583856ea928SPeter Avalos 1584856ea928SPeter Avalos type = buffer_get_int(&m); 1585856ea928SPeter Avalos if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1586856ea928SPeter Avalos fatal("%s: out of sequence reply: my id %u theirs %u", 1587856ea928SPeter Avalos __func__, muxclient_request_id, rid); 1588856ea928SPeter Avalos switch (type) { 1589856ea928SPeter Avalos case MUX_S_OK: 1590856ea928SPeter Avalos break; 1591856ea928SPeter Avalos case MUX_S_PERMISSION_DENIED: 1592856ea928SPeter Avalos e = buffer_get_string(&m, NULL); 1593856ea928SPeter Avalos fatal("Master refused termination request: %s", e); 1594856ea928SPeter Avalos case MUX_S_FAILURE: 1595856ea928SPeter Avalos e = buffer_get_string(&m, NULL); 1596856ea928SPeter Avalos fatal("%s: termination request failed: %s", __func__, e); 1597856ea928SPeter Avalos default: 1598856ea928SPeter Avalos fatal("%s: unexpected response from master 0x%08x", 1599856ea928SPeter Avalos __func__, type); 1600856ea928SPeter Avalos } 1601856ea928SPeter Avalos buffer_free(&m); 1602856ea928SPeter Avalos muxclient_request_id++; 1603856ea928SPeter Avalos } 1604856ea928SPeter Avalos 1605856ea928SPeter Avalos static int 1606*99e85e0dSPeter Avalos mux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *fwd) 1607856ea928SPeter Avalos { 1608856ea928SPeter Avalos Buffer m; 1609856ea928SPeter Avalos char *e, *fwd_desc; 1610856ea928SPeter Avalos u_int type, rid; 1611856ea928SPeter Avalos 1612856ea928SPeter Avalos fwd_desc = format_forward(ftype, fwd); 1613*99e85e0dSPeter Avalos debug("Requesting %s %s", 1614*99e85e0dSPeter Avalos cancel_flag ? "cancellation of" : "forwarding of", fwd_desc); 1615856ea928SPeter Avalos xfree(fwd_desc); 1616856ea928SPeter Avalos 1617856ea928SPeter Avalos buffer_init(&m); 1618*99e85e0dSPeter Avalos buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD); 1619856ea928SPeter Avalos buffer_put_int(&m, muxclient_request_id); 1620856ea928SPeter Avalos buffer_put_int(&m, ftype); 1621856ea928SPeter Avalos buffer_put_cstring(&m, 1622856ea928SPeter Avalos fwd->listen_host == NULL ? "" : fwd->listen_host); 1623856ea928SPeter Avalos buffer_put_int(&m, fwd->listen_port); 1624856ea928SPeter Avalos buffer_put_cstring(&m, 1625856ea928SPeter Avalos fwd->connect_host == NULL ? "" : fwd->connect_host); 1626856ea928SPeter Avalos buffer_put_int(&m, fwd->connect_port); 1627856ea928SPeter Avalos 1628856ea928SPeter Avalos if (mux_client_write_packet(fd, &m) != 0) 1629856ea928SPeter Avalos fatal("%s: write packet: %s", __func__, strerror(errno)); 1630856ea928SPeter Avalos 1631856ea928SPeter Avalos buffer_clear(&m); 1632856ea928SPeter Avalos 1633856ea928SPeter Avalos /* Read their reply */ 1634856ea928SPeter Avalos if (mux_client_read_packet(fd, &m) != 0) { 1635856ea928SPeter Avalos buffer_free(&m); 1636856ea928SPeter Avalos return -1; 1637856ea928SPeter Avalos } 1638856ea928SPeter Avalos 1639856ea928SPeter Avalos type = buffer_get_int(&m); 1640856ea928SPeter Avalos if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1641856ea928SPeter Avalos fatal("%s: out of sequence reply: my id %u theirs %u", 1642856ea928SPeter Avalos __func__, muxclient_request_id, rid); 1643856ea928SPeter Avalos switch (type) { 1644856ea928SPeter Avalos case MUX_S_OK: 1645856ea928SPeter Avalos break; 1646856ea928SPeter Avalos case MUX_S_REMOTE_PORT: 1647*99e85e0dSPeter Avalos if (cancel_flag) 1648*99e85e0dSPeter Avalos fatal("%s: got MUX_S_REMOTE_PORT for cancel", __func__); 1649856ea928SPeter Avalos fwd->allocated_port = buffer_get_int(&m); 1650856ea928SPeter Avalos logit("Allocated port %u for remote forward to %s:%d", 1651856ea928SPeter Avalos fwd->allocated_port, 1652856ea928SPeter Avalos fwd->connect_host ? fwd->connect_host : "", 1653856ea928SPeter Avalos fwd->connect_port); 1654856ea928SPeter Avalos if (muxclient_command == SSHMUX_COMMAND_FORWARD) 1655856ea928SPeter Avalos fprintf(stdout, "%u\n", fwd->allocated_port); 1656856ea928SPeter Avalos break; 1657856ea928SPeter Avalos case MUX_S_PERMISSION_DENIED: 1658856ea928SPeter Avalos e = buffer_get_string(&m, NULL); 1659856ea928SPeter Avalos buffer_free(&m); 1660856ea928SPeter Avalos error("Master refused forwarding request: %s", e); 1661856ea928SPeter Avalos return -1; 1662856ea928SPeter Avalos case MUX_S_FAILURE: 1663856ea928SPeter Avalos e = buffer_get_string(&m, NULL); 1664856ea928SPeter Avalos buffer_free(&m); 16659f304aafSPeter Avalos error("%s: forwarding request failed: %s", __func__, e); 1666856ea928SPeter Avalos return -1; 1667856ea928SPeter Avalos default: 1668856ea928SPeter Avalos fatal("%s: unexpected response from master 0x%08x", 1669856ea928SPeter Avalos __func__, type); 1670856ea928SPeter Avalos } 1671856ea928SPeter Avalos buffer_free(&m); 1672856ea928SPeter Avalos 1673856ea928SPeter Avalos muxclient_request_id++; 1674856ea928SPeter Avalos return 0; 1675856ea928SPeter Avalos } 1676856ea928SPeter Avalos 1677856ea928SPeter Avalos static int 1678*99e85e0dSPeter Avalos mux_client_forwards(int fd, int cancel_flag) 1679856ea928SPeter Avalos { 1680*99e85e0dSPeter Avalos int i, ret = 0; 1681856ea928SPeter Avalos 1682*99e85e0dSPeter Avalos debug3("%s: %s forwardings: %d local, %d remote", __func__, 1683*99e85e0dSPeter Avalos cancel_flag ? "cancel" : "request", 1684856ea928SPeter Avalos options.num_local_forwards, options.num_remote_forwards); 1685856ea928SPeter Avalos 1686856ea928SPeter Avalos /* XXX ExitOnForwardingFailure */ 1687856ea928SPeter Avalos for (i = 0; i < options.num_local_forwards; i++) { 1688*99e85e0dSPeter Avalos if (mux_client_forward(fd, cancel_flag, 1689856ea928SPeter Avalos options.local_forwards[i].connect_port == 0 ? 1690856ea928SPeter Avalos MUX_FWD_DYNAMIC : MUX_FWD_LOCAL, 1691856ea928SPeter Avalos options.local_forwards + i) != 0) 1692*99e85e0dSPeter Avalos ret = -1; 1693856ea928SPeter Avalos } 1694856ea928SPeter Avalos for (i = 0; i < options.num_remote_forwards; i++) { 1695*99e85e0dSPeter Avalos if (mux_client_forward(fd, cancel_flag, MUX_FWD_REMOTE, 1696856ea928SPeter Avalos options.remote_forwards + i) != 0) 1697*99e85e0dSPeter Avalos ret = -1; 1698856ea928SPeter Avalos } 1699*99e85e0dSPeter Avalos return ret; 1700856ea928SPeter Avalos } 1701856ea928SPeter Avalos 1702856ea928SPeter Avalos static int 1703856ea928SPeter Avalos mux_client_request_session(int fd) 1704856ea928SPeter Avalos { 1705856ea928SPeter Avalos Buffer m; 1706856ea928SPeter Avalos char *e, *term; 1707856ea928SPeter Avalos u_int i, rid, sid, esid, exitval, type, exitval_seen; 1708856ea928SPeter Avalos extern char **environ; 17091c188a7fSPeter Avalos int devnull, rawmode; 1710856ea928SPeter Avalos 1711856ea928SPeter Avalos debug3("%s: entering", __func__); 1712856ea928SPeter Avalos 1713856ea928SPeter Avalos if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { 1714856ea928SPeter Avalos error("%s: master alive request failed", __func__); 1715856ea928SPeter Avalos return -1; 1716856ea928SPeter Avalos } 1717856ea928SPeter Avalos 1718856ea928SPeter Avalos signal(SIGPIPE, SIG_IGN); 1719856ea928SPeter Avalos 1720856ea928SPeter Avalos if (stdin_null_flag) { 1721856ea928SPeter Avalos if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) 1722856ea928SPeter Avalos fatal("open(/dev/null): %s", strerror(errno)); 1723856ea928SPeter Avalos if (dup2(devnull, STDIN_FILENO) == -1) 1724856ea928SPeter Avalos fatal("dup2: %s", strerror(errno)); 1725856ea928SPeter Avalos if (devnull > STDERR_FILENO) 1726856ea928SPeter Avalos close(devnull); 1727856ea928SPeter Avalos } 1728856ea928SPeter Avalos 1729856ea928SPeter Avalos term = getenv("TERM"); 1730856ea928SPeter Avalos 1731856ea928SPeter Avalos buffer_init(&m); 1732856ea928SPeter Avalos buffer_put_int(&m, MUX_C_NEW_SESSION); 1733856ea928SPeter Avalos buffer_put_int(&m, muxclient_request_id); 1734856ea928SPeter Avalos buffer_put_cstring(&m, ""); /* reserved */ 1735856ea928SPeter Avalos buffer_put_int(&m, tty_flag); 1736856ea928SPeter Avalos buffer_put_int(&m, options.forward_x11); 1737856ea928SPeter Avalos buffer_put_int(&m, options.forward_agent); 1738856ea928SPeter Avalos buffer_put_int(&m, subsystem_flag); 1739856ea928SPeter Avalos buffer_put_int(&m, options.escape_char == SSH_ESCAPECHAR_NONE ? 1740856ea928SPeter Avalos 0xffffffff : (u_int)options.escape_char); 1741856ea928SPeter Avalos buffer_put_cstring(&m, term == NULL ? "" : term); 1742856ea928SPeter Avalos buffer_put_string(&m, buffer_ptr(&command), buffer_len(&command)); 1743856ea928SPeter Avalos 1744856ea928SPeter Avalos if (options.num_send_env > 0 && environ != NULL) { 1745856ea928SPeter Avalos /* Pass environment */ 1746856ea928SPeter Avalos for (i = 0; environ[i] != NULL; i++) { 1747856ea928SPeter Avalos if (env_permitted(environ[i])) { 1748856ea928SPeter Avalos buffer_put_cstring(&m, environ[i]); 1749856ea928SPeter Avalos } 1750856ea928SPeter Avalos } 1751856ea928SPeter Avalos } 1752856ea928SPeter Avalos 1753856ea928SPeter Avalos if (mux_client_write_packet(fd, &m) != 0) 1754856ea928SPeter Avalos fatal("%s: write packet: %s", __func__, strerror(errno)); 1755856ea928SPeter Avalos 1756856ea928SPeter Avalos /* Send the stdio file descriptors */ 1757856ea928SPeter Avalos if (mm_send_fd(fd, STDIN_FILENO) == -1 || 1758856ea928SPeter Avalos mm_send_fd(fd, STDOUT_FILENO) == -1 || 1759856ea928SPeter Avalos mm_send_fd(fd, STDERR_FILENO) == -1) 1760856ea928SPeter Avalos fatal("%s: send fds failed", __func__); 1761856ea928SPeter Avalos 1762856ea928SPeter Avalos debug3("%s: session request sent", __func__); 1763856ea928SPeter Avalos 1764856ea928SPeter Avalos /* Read their reply */ 1765856ea928SPeter Avalos buffer_clear(&m); 1766856ea928SPeter Avalos if (mux_client_read_packet(fd, &m) != 0) { 1767856ea928SPeter Avalos error("%s: read from master failed: %s", 1768856ea928SPeter Avalos __func__, strerror(errno)); 1769856ea928SPeter Avalos buffer_free(&m); 1770856ea928SPeter Avalos return -1; 1771856ea928SPeter Avalos } 1772856ea928SPeter Avalos 1773856ea928SPeter Avalos type = buffer_get_int(&m); 1774856ea928SPeter Avalos if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1775856ea928SPeter Avalos fatal("%s: out of sequence reply: my id %u theirs %u", 1776856ea928SPeter Avalos __func__, muxclient_request_id, rid); 1777856ea928SPeter Avalos switch (type) { 1778856ea928SPeter Avalos case MUX_S_SESSION_OPENED: 1779856ea928SPeter Avalos sid = buffer_get_int(&m); 1780856ea928SPeter Avalos debug("%s: master session id: %u", __func__, sid); 1781856ea928SPeter Avalos break; 1782856ea928SPeter Avalos case MUX_S_PERMISSION_DENIED: 1783856ea928SPeter Avalos e = buffer_get_string(&m, NULL); 1784856ea928SPeter Avalos buffer_free(&m); 17859f304aafSPeter Avalos error("Master refused session request: %s", e); 1786856ea928SPeter Avalos return -1; 1787856ea928SPeter Avalos case MUX_S_FAILURE: 1788856ea928SPeter Avalos e = buffer_get_string(&m, NULL); 1789856ea928SPeter Avalos buffer_free(&m); 17909f304aafSPeter Avalos error("%s: session request failed: %s", __func__, e); 1791856ea928SPeter Avalos return -1; 1792856ea928SPeter Avalos default: 1793856ea928SPeter Avalos buffer_free(&m); 1794856ea928SPeter Avalos error("%s: unexpected response from master 0x%08x", 1795856ea928SPeter Avalos __func__, type); 1796856ea928SPeter Avalos return -1; 1797856ea928SPeter Avalos } 1798856ea928SPeter Avalos muxclient_request_id++; 1799856ea928SPeter Avalos 1800856ea928SPeter Avalos signal(SIGHUP, control_client_sighandler); 1801856ea928SPeter Avalos signal(SIGINT, control_client_sighandler); 1802856ea928SPeter Avalos signal(SIGTERM, control_client_sighandler); 1803856ea928SPeter Avalos signal(SIGWINCH, control_client_sigrelay); 1804856ea928SPeter Avalos 18051c188a7fSPeter Avalos rawmode = tty_flag; 1806856ea928SPeter Avalos if (tty_flag) 18071c188a7fSPeter Avalos enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); 1808856ea928SPeter Avalos 1809856ea928SPeter Avalos /* 1810856ea928SPeter Avalos * Stick around until the controlee closes the client_fd. 1811856ea928SPeter Avalos * Before it does, it is expected to write an exit message. 1812856ea928SPeter Avalos * This process must read the value and wait for the closure of 1813856ea928SPeter Avalos * the client_fd; if this one closes early, the multiplex master will 1814856ea928SPeter Avalos * terminate early too (possibly losing data). 1815856ea928SPeter Avalos */ 1816856ea928SPeter Avalos for (exitval = 255, exitval_seen = 0;;) { 1817856ea928SPeter Avalos buffer_clear(&m); 1818856ea928SPeter Avalos if (mux_client_read_packet(fd, &m) != 0) 1819856ea928SPeter Avalos break; 1820856ea928SPeter Avalos type = buffer_get_int(&m); 18211c188a7fSPeter Avalos switch (type) { 18221c188a7fSPeter Avalos case MUX_S_TTY_ALLOC_FAIL: 1823856ea928SPeter Avalos if ((esid = buffer_get_int(&m)) != sid) 18241c188a7fSPeter Avalos fatal("%s: tty alloc fail on unknown session: " 18251c188a7fSPeter Avalos "my id %u theirs %u", 1826856ea928SPeter Avalos __func__, sid, esid); 18271c188a7fSPeter Avalos leave_raw_mode(options.request_tty == 18281c188a7fSPeter Avalos REQUEST_TTY_FORCE); 18291c188a7fSPeter Avalos rawmode = 0; 18301c188a7fSPeter Avalos continue; 18311c188a7fSPeter Avalos case MUX_S_EXIT_MESSAGE: 18321c188a7fSPeter Avalos if ((esid = buffer_get_int(&m)) != sid) 18331c188a7fSPeter Avalos fatal("%s: exit on unknown session: " 18341c188a7fSPeter Avalos "my id %u theirs %u", 18351c188a7fSPeter Avalos __func__, sid, esid); 1836856ea928SPeter Avalos if (exitval_seen) 1837856ea928SPeter Avalos fatal("%s: exitval sent twice", __func__); 1838856ea928SPeter Avalos exitval = buffer_get_int(&m); 1839856ea928SPeter Avalos exitval_seen = 1; 18401c188a7fSPeter Avalos continue; 18411c188a7fSPeter Avalos default: 18421c188a7fSPeter Avalos e = buffer_get_string(&m, NULL); 18431c188a7fSPeter Avalos fatal("%s: master returned error: %s", __func__, e); 18441c188a7fSPeter Avalos } 1845856ea928SPeter Avalos } 1846856ea928SPeter Avalos 1847856ea928SPeter Avalos close(fd); 18481c188a7fSPeter Avalos if (rawmode) 18491c188a7fSPeter Avalos leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); 1850856ea928SPeter Avalos 1851856ea928SPeter Avalos if (muxclient_terminate) { 1852856ea928SPeter Avalos debug2("Exiting on signal %d", muxclient_terminate); 1853856ea928SPeter Avalos exitval = 255; 1854856ea928SPeter Avalos } else if (!exitval_seen) { 1855856ea928SPeter Avalos debug2("Control master terminated unexpectedly"); 1856856ea928SPeter Avalos exitval = 255; 1857856ea928SPeter Avalos } else 1858856ea928SPeter Avalos debug2("Received exit status from master %d", exitval); 1859856ea928SPeter Avalos 1860856ea928SPeter Avalos if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) 1861856ea928SPeter Avalos fprintf(stderr, "Shared connection to %s closed.\r\n", host); 1862856ea928SPeter Avalos 1863856ea928SPeter Avalos exit(exitval); 1864856ea928SPeter Avalos } 1865856ea928SPeter Avalos 1866856ea928SPeter Avalos static int 1867856ea928SPeter Avalos mux_client_request_stdio_fwd(int fd) 1868856ea928SPeter Avalos { 1869856ea928SPeter Avalos Buffer m; 1870856ea928SPeter Avalos char *e; 1871856ea928SPeter Avalos u_int type, rid, sid; 1872856ea928SPeter Avalos int devnull; 1873856ea928SPeter Avalos 1874856ea928SPeter Avalos debug3("%s: entering", __func__); 1875856ea928SPeter Avalos 1876856ea928SPeter Avalos if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { 1877856ea928SPeter Avalos error("%s: master alive request failed", __func__); 1878856ea928SPeter Avalos return -1; 1879856ea928SPeter Avalos } 1880856ea928SPeter Avalos 1881856ea928SPeter Avalos signal(SIGPIPE, SIG_IGN); 1882856ea928SPeter Avalos 1883856ea928SPeter Avalos if (stdin_null_flag) { 1884856ea928SPeter Avalos if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) 1885856ea928SPeter Avalos fatal("open(/dev/null): %s", strerror(errno)); 1886856ea928SPeter Avalos if (dup2(devnull, STDIN_FILENO) == -1) 1887856ea928SPeter Avalos fatal("dup2: %s", strerror(errno)); 1888856ea928SPeter Avalos if (devnull > STDERR_FILENO) 1889856ea928SPeter Avalos close(devnull); 1890856ea928SPeter Avalos } 1891856ea928SPeter Avalos 1892856ea928SPeter Avalos buffer_init(&m); 1893856ea928SPeter Avalos buffer_put_int(&m, MUX_C_NEW_STDIO_FWD); 1894856ea928SPeter Avalos buffer_put_int(&m, muxclient_request_id); 1895856ea928SPeter Avalos buffer_put_cstring(&m, ""); /* reserved */ 1896856ea928SPeter Avalos buffer_put_cstring(&m, stdio_forward_host); 1897856ea928SPeter Avalos buffer_put_int(&m, stdio_forward_port); 1898856ea928SPeter Avalos 1899856ea928SPeter Avalos if (mux_client_write_packet(fd, &m) != 0) 1900856ea928SPeter Avalos fatal("%s: write packet: %s", __func__, strerror(errno)); 1901856ea928SPeter Avalos 1902856ea928SPeter Avalos /* Send the stdio file descriptors */ 1903856ea928SPeter Avalos if (mm_send_fd(fd, STDIN_FILENO) == -1 || 1904856ea928SPeter Avalos mm_send_fd(fd, STDOUT_FILENO) == -1) 1905856ea928SPeter Avalos fatal("%s: send fds failed", __func__); 1906856ea928SPeter Avalos 1907856ea928SPeter Avalos debug3("%s: stdio forward request sent", __func__); 1908856ea928SPeter Avalos 1909856ea928SPeter Avalos /* Read their reply */ 1910856ea928SPeter Avalos buffer_clear(&m); 1911856ea928SPeter Avalos 1912856ea928SPeter Avalos if (mux_client_read_packet(fd, &m) != 0) { 1913856ea928SPeter Avalos error("%s: read from master failed: %s", 1914856ea928SPeter Avalos __func__, strerror(errno)); 1915856ea928SPeter Avalos buffer_free(&m); 1916856ea928SPeter Avalos return -1; 1917856ea928SPeter Avalos } 1918856ea928SPeter Avalos 1919856ea928SPeter Avalos type = buffer_get_int(&m); 1920856ea928SPeter Avalos if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1921856ea928SPeter Avalos fatal("%s: out of sequence reply: my id %u theirs %u", 1922856ea928SPeter Avalos __func__, muxclient_request_id, rid); 1923856ea928SPeter Avalos switch (type) { 1924856ea928SPeter Avalos case MUX_S_SESSION_OPENED: 1925856ea928SPeter Avalos sid = buffer_get_int(&m); 1926856ea928SPeter Avalos debug("%s: master session id: %u", __func__, sid); 1927856ea928SPeter Avalos break; 1928856ea928SPeter Avalos case MUX_S_PERMISSION_DENIED: 1929856ea928SPeter Avalos e = buffer_get_string(&m, NULL); 1930856ea928SPeter Avalos buffer_free(&m); 19319f304aafSPeter Avalos fatal("Master refused stdio forwarding request: %s", e); 1932856ea928SPeter Avalos case MUX_S_FAILURE: 1933856ea928SPeter Avalos e = buffer_get_string(&m, NULL); 1934856ea928SPeter Avalos buffer_free(&m); 1935856ea928SPeter Avalos fatal("%s: stdio forwarding request failed: %s", __func__, e); 1936856ea928SPeter Avalos default: 1937856ea928SPeter Avalos buffer_free(&m); 1938856ea928SPeter Avalos error("%s: unexpected response from master 0x%08x", 1939856ea928SPeter Avalos __func__, type); 1940856ea928SPeter Avalos return -1; 1941856ea928SPeter Avalos } 1942856ea928SPeter Avalos muxclient_request_id++; 1943856ea928SPeter Avalos 1944856ea928SPeter Avalos signal(SIGHUP, control_client_sighandler); 1945856ea928SPeter Avalos signal(SIGINT, control_client_sighandler); 1946856ea928SPeter Avalos signal(SIGTERM, control_client_sighandler); 1947856ea928SPeter Avalos signal(SIGWINCH, control_client_sigrelay); 1948856ea928SPeter Avalos 1949856ea928SPeter Avalos /* 1950856ea928SPeter Avalos * Stick around until the controlee closes the client_fd. 1951856ea928SPeter Avalos */ 1952856ea928SPeter Avalos buffer_clear(&m); 1953856ea928SPeter Avalos if (mux_client_read_packet(fd, &m) != 0) { 1954856ea928SPeter Avalos if (errno == EPIPE || 1955856ea928SPeter Avalos (errno == EINTR && muxclient_terminate != 0)) 1956856ea928SPeter Avalos return 0; 1957856ea928SPeter Avalos fatal("%s: mux_client_read_packet: %s", 1958856ea928SPeter Avalos __func__, strerror(errno)); 1959856ea928SPeter Avalos } 1960856ea928SPeter Avalos fatal("%s: master returned unexpected message %u", __func__, type); 196118de8d7fSPeter Avalos } 196218de8d7fSPeter Avalos 19631c188a7fSPeter Avalos static void 19641c188a7fSPeter Avalos mux_client_request_stop_listening(int fd) 19651c188a7fSPeter Avalos { 19661c188a7fSPeter Avalos Buffer m; 19671c188a7fSPeter Avalos char *e; 19681c188a7fSPeter Avalos u_int type, rid; 19691c188a7fSPeter Avalos 19701c188a7fSPeter Avalos debug3("%s: entering", __func__); 19711c188a7fSPeter Avalos 19721c188a7fSPeter Avalos buffer_init(&m); 19731c188a7fSPeter Avalos buffer_put_int(&m, MUX_C_STOP_LISTENING); 19741c188a7fSPeter Avalos buffer_put_int(&m, muxclient_request_id); 19751c188a7fSPeter Avalos 19761c188a7fSPeter Avalos if (mux_client_write_packet(fd, &m) != 0) 19771c188a7fSPeter Avalos fatal("%s: write packet: %s", __func__, strerror(errno)); 19781c188a7fSPeter Avalos 19791c188a7fSPeter Avalos buffer_clear(&m); 19801c188a7fSPeter Avalos 19811c188a7fSPeter Avalos /* Read their reply */ 19821c188a7fSPeter Avalos if (mux_client_read_packet(fd, &m) != 0) 19831c188a7fSPeter Avalos fatal("%s: read from master failed: %s", 19841c188a7fSPeter Avalos __func__, strerror(errno)); 19851c188a7fSPeter Avalos 19861c188a7fSPeter Avalos type = buffer_get_int(&m); 19871c188a7fSPeter Avalos if ((rid = buffer_get_int(&m)) != muxclient_request_id) 19881c188a7fSPeter Avalos fatal("%s: out of sequence reply: my id %u theirs %u", 19891c188a7fSPeter Avalos __func__, muxclient_request_id, rid); 19901c188a7fSPeter Avalos switch (type) { 19911c188a7fSPeter Avalos case MUX_S_OK: 19921c188a7fSPeter Avalos break; 19931c188a7fSPeter Avalos case MUX_S_PERMISSION_DENIED: 19941c188a7fSPeter Avalos e = buffer_get_string(&m, NULL); 19951c188a7fSPeter Avalos fatal("Master refused stop listening request: %s", e); 19961c188a7fSPeter Avalos case MUX_S_FAILURE: 19971c188a7fSPeter Avalos e = buffer_get_string(&m, NULL); 19981c188a7fSPeter Avalos fatal("%s: stop listening request failed: %s", __func__, e); 19991c188a7fSPeter Avalos default: 20001c188a7fSPeter Avalos fatal("%s: unexpected response from master 0x%08x", 20011c188a7fSPeter Avalos __func__, type); 20021c188a7fSPeter Avalos } 20031c188a7fSPeter Avalos buffer_free(&m); 20041c188a7fSPeter Avalos muxclient_request_id++; 20051c188a7fSPeter Avalos } 20061c188a7fSPeter Avalos 200718de8d7fSPeter Avalos /* Multiplex client main loop. */ 200818de8d7fSPeter Avalos void 200918de8d7fSPeter Avalos muxclient(const char *path) 201018de8d7fSPeter Avalos { 201118de8d7fSPeter Avalos struct sockaddr_un addr; 2012856ea928SPeter Avalos socklen_t sun_len; 2013856ea928SPeter Avalos int sock; 2014856ea928SPeter Avalos u_int pid; 201518de8d7fSPeter Avalos 2016856ea928SPeter Avalos if (muxclient_command == 0) { 2017856ea928SPeter Avalos if (stdio_forward_host != NULL) 2018856ea928SPeter Avalos muxclient_command = SSHMUX_COMMAND_STDIO_FWD; 2019856ea928SPeter Avalos else 202018de8d7fSPeter Avalos muxclient_command = SSHMUX_COMMAND_OPEN; 2021856ea928SPeter Avalos } 202218de8d7fSPeter Avalos 202318de8d7fSPeter Avalos switch (options.control_master) { 202418de8d7fSPeter Avalos case SSHCTL_MASTER_AUTO: 202518de8d7fSPeter Avalos case SSHCTL_MASTER_AUTO_ASK: 202618de8d7fSPeter Avalos debug("auto-mux: Trying existing master"); 202718de8d7fSPeter Avalos /* FALLTHROUGH */ 202818de8d7fSPeter Avalos case SSHCTL_MASTER_NO: 202918de8d7fSPeter Avalos break; 203018de8d7fSPeter Avalos default: 203118de8d7fSPeter Avalos return; 203218de8d7fSPeter Avalos } 203318de8d7fSPeter Avalos 203418de8d7fSPeter Avalos memset(&addr, '\0', sizeof(addr)); 203518de8d7fSPeter Avalos addr.sun_family = AF_UNIX; 2036856ea928SPeter Avalos sun_len = offsetof(struct sockaddr_un, sun_path) + 203718de8d7fSPeter Avalos strlen(path) + 1; 203818de8d7fSPeter Avalos 203918de8d7fSPeter Avalos if (strlcpy(addr.sun_path, path, 204018de8d7fSPeter Avalos sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) 204118de8d7fSPeter Avalos fatal("ControlPath too long"); 204218de8d7fSPeter Avalos 204318de8d7fSPeter Avalos if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) 204418de8d7fSPeter Avalos fatal("%s socket(): %s", __func__, strerror(errno)); 204518de8d7fSPeter Avalos 2046856ea928SPeter Avalos if (connect(sock, (struct sockaddr *)&addr, sun_len) == -1) { 2047856ea928SPeter Avalos switch (muxclient_command) { 2048856ea928SPeter Avalos case SSHMUX_COMMAND_OPEN: 2049856ea928SPeter Avalos case SSHMUX_COMMAND_STDIO_FWD: 2050856ea928SPeter Avalos break; 2051856ea928SPeter Avalos default: 205218de8d7fSPeter Avalos fatal("Control socket connect(%.100s): %s", path, 205318de8d7fSPeter Avalos strerror(errno)); 205418de8d7fSPeter Avalos } 20559f304aafSPeter Avalos if (errno == ECONNREFUSED && 20569f304aafSPeter Avalos options.control_master != SSHCTL_MASTER_NO) { 20579f304aafSPeter Avalos debug("Stale control socket %.100s, unlinking", path); 20589f304aafSPeter Avalos unlink(path); 20599f304aafSPeter Avalos } else if (errno == ENOENT) { 206018de8d7fSPeter Avalos debug("Control socket \"%.100s\" does not exist", path); 20619f304aafSPeter Avalos } else { 206218de8d7fSPeter Avalos error("Control socket connect(%.100s): %s", path, 206318de8d7fSPeter Avalos strerror(errno)); 206418de8d7fSPeter Avalos } 206518de8d7fSPeter Avalos close(sock); 206618de8d7fSPeter Avalos return; 206718de8d7fSPeter Avalos } 2068856ea928SPeter Avalos set_nonblock(sock); 206918de8d7fSPeter Avalos 2070856ea928SPeter Avalos if (mux_client_hello_exchange(sock) != 0) { 2071856ea928SPeter Avalos error("%s: master hello exchange failed", __func__); 207218de8d7fSPeter Avalos close(sock); 207318de8d7fSPeter Avalos return; 207418de8d7fSPeter Avalos } 207518de8d7fSPeter Avalos 207618de8d7fSPeter Avalos switch (muxclient_command) { 207718de8d7fSPeter Avalos case SSHMUX_COMMAND_ALIVE_CHECK: 2078856ea928SPeter Avalos if ((pid = mux_client_request_alive(sock)) == 0) 2079856ea928SPeter Avalos fatal("%s: master alive check failed", __func__); 2080856ea928SPeter Avalos fprintf(stderr, "Master running (pid=%d)\r\n", pid); 208118de8d7fSPeter Avalos exit(0); 208218de8d7fSPeter Avalos case SSHMUX_COMMAND_TERMINATE: 2083856ea928SPeter Avalos mux_client_request_terminate(sock); 208418de8d7fSPeter Avalos fprintf(stderr, "Exit request sent.\r\n"); 208518de8d7fSPeter Avalos exit(0); 2086856ea928SPeter Avalos case SSHMUX_COMMAND_FORWARD: 2087*99e85e0dSPeter Avalos if (mux_client_forwards(sock, 0) != 0) 2088856ea928SPeter Avalos fatal("%s: master forward request failed", __func__); 2089856ea928SPeter Avalos exit(0); 209018de8d7fSPeter Avalos case SSHMUX_COMMAND_OPEN: 2091*99e85e0dSPeter Avalos if (mux_client_forwards(sock, 0) != 0) { 2092856ea928SPeter Avalos error("%s: master forward request failed", __func__); 2093856ea928SPeter Avalos return; 209418de8d7fSPeter Avalos } 2095856ea928SPeter Avalos mux_client_request_session(sock); 2096856ea928SPeter Avalos return; 2097856ea928SPeter Avalos case SSHMUX_COMMAND_STDIO_FWD: 2098856ea928SPeter Avalos mux_client_request_stdio_fwd(sock); 2099856ea928SPeter Avalos exit(0); 21001c188a7fSPeter Avalos case SSHMUX_COMMAND_STOP: 21011c188a7fSPeter Avalos mux_client_request_stop_listening(sock); 21021c188a7fSPeter Avalos fprintf(stderr, "Stop listening request sent.\r\n"); 21031c188a7fSPeter Avalos exit(0); 2104*99e85e0dSPeter Avalos case SSHMUX_COMMAND_CANCEL_FWD: 2105*99e85e0dSPeter Avalos if (mux_client_forwards(sock, 1) != 0) 2106*99e85e0dSPeter Avalos error("%s: master cancel forward request failed", 2107*99e85e0dSPeter Avalos __func__); 2108*99e85e0dSPeter Avalos exit(0); 210918de8d7fSPeter Avalos default: 211018de8d7fSPeter Avalos fatal("unrecognised muxclient_command %d", muxclient_command); 211118de8d7fSPeter Avalos } 211218de8d7fSPeter Avalos } 2113