1255767Sdes/* $OpenBSD: mux.c,v 1.44 2013/07/12 00:19:58 djm Exp $ */ 2180750Sdes/* 3180750Sdes * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> 4180750Sdes * 5180750Sdes * Permission to use, copy, modify, and distribute this software for any 6180750Sdes * purpose with or without fee is hereby granted, provided that the above 7180750Sdes * copyright notice and this permission notice appear in all copies. 8180750Sdes * 9180750Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10180750Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11180750Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12180750Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13180750Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14180750Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15180750Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16180750Sdes */ 17180750Sdes 18180750Sdes/* ssh session multiplexing support */ 19180750Sdes 20180750Sdes/* 21180750Sdes * TODO: 22204917Sdes * - Better signalling from master to slave, especially passing of 23180750Sdes * error messages 24204917Sdes * - Better fall-back from mux slave error to new connection. 25204917Sdes * - ExitOnForwardingFailure 26204917Sdes * - Maybe extension mechanisms for multi-X11/multi-agent forwarding 27204917Sdes * - Support ~^Z in mux slaves. 28204917Sdes * - Inspect or control sessions in master. 29204917Sdes * - If we ever support the "signal" channel request, send signals on 30204917Sdes * sessions in master. 31180750Sdes */ 32180750Sdes 33204917Sdes#include "includes.h" 34204917Sdes 35180750Sdes#include <sys/types.h> 36180750Sdes#include <sys/param.h> 37180750Sdes#include <sys/stat.h> 38180750Sdes#include <sys/socket.h> 39180750Sdes#include <sys/un.h> 40180750Sdes 41180750Sdes#include <errno.h> 42180750Sdes#include <fcntl.h> 43180750Sdes#include <signal.h> 44180750Sdes#include <stdarg.h> 45180750Sdes#include <stddef.h> 46180750Sdes#include <stdlib.h> 47180750Sdes#include <stdio.h> 48180750Sdes#include <string.h> 49180750Sdes#include <unistd.h> 50180750Sdes#ifdef HAVE_PATHS_H 51180750Sdes#include <paths.h> 52180750Sdes#endif 53180750Sdes 54204917Sdes#ifdef HAVE_POLL_H 55204917Sdes#include <poll.h> 56204917Sdes#else 57204917Sdes# ifdef HAVE_SYS_POLL_H 58204917Sdes# include <sys/poll.h> 59204917Sdes# endif 60204917Sdes#endif 61204917Sdes 62180750Sdes#ifdef HAVE_UTIL_H 63180750Sdes# include <util.h> 64180750Sdes#endif 65180750Sdes 66180750Sdes#include "openbsd-compat/sys-queue.h" 67180750Sdes#include "xmalloc.h" 68180750Sdes#include "log.h" 69180750Sdes#include "ssh.h" 70215116Sdes#include "ssh2.h" 71180750Sdes#include "pathnames.h" 72180750Sdes#include "misc.h" 73180750Sdes#include "match.h" 74180750Sdes#include "buffer.h" 75180750Sdes#include "channels.h" 76180750Sdes#include "msg.h" 77180750Sdes#include "packet.h" 78180750Sdes#include "monitor_fdpass.h" 79180750Sdes#include "sshpty.h" 80180750Sdes#include "key.h" 81180750Sdes#include "readconf.h" 82180750Sdes#include "clientloop.h" 83180750Sdes 84180750Sdes/* from ssh.c */ 85180750Sdesextern int tty_flag; 86180750Sdesextern Options options; 87180750Sdesextern int stdin_null_flag; 88180750Sdesextern char *host; 89204917Sdesextern int subsystem_flag; 90180750Sdesextern Buffer command; 91204917Sdesextern volatile sig_atomic_t quit_pending; 92204917Sdesextern char *stdio_forward_host; 93204917Sdesextern int stdio_forward_port; 94180750Sdes 95180750Sdes/* Context for session open confirmation callback */ 96180750Sdesstruct mux_session_confirm_ctx { 97204917Sdes u_int want_tty; 98204917Sdes u_int want_subsys; 99204917Sdes u_int want_x_fwd; 100204917Sdes u_int want_agent_fwd; 101180750Sdes Buffer cmd; 102180750Sdes char *term; 103180750Sdes struct termios tio; 104180750Sdes char **env; 105215116Sdes u_int rid; 106180750Sdes}; 107180750Sdes 108215116Sdes/* Context for global channel callback */ 109215116Sdesstruct mux_channel_confirm_ctx { 110215116Sdes u_int cid; /* channel id */ 111215116Sdes u_int rid; /* request id */ 112215116Sdes int fid; /* forward id */ 113215116Sdes}; 114215116Sdes 115180750Sdes/* fd to control socket */ 116180750Sdesint muxserver_sock = -1; 117180750Sdes 118204917Sdes/* client request id */ 119204917Sdesu_int muxclient_request_id = 0; 120204917Sdes 121180750Sdes/* Multiplexing control command */ 122180750Sdesu_int muxclient_command = 0; 123180750Sdes 124180750Sdes/* Set when signalled. */ 125180750Sdesstatic volatile sig_atomic_t muxclient_terminate = 0; 126180750Sdes 127180750Sdes/* PID of multiplex server */ 128180750Sdesstatic u_int muxserver_pid = 0; 129180750Sdes 130204917Sdesstatic Channel *mux_listener_channel = NULL; 131180750Sdes 132204917Sdesstruct mux_master_state { 133204917Sdes int hello_rcvd; 134204917Sdes}; 135180750Sdes 136204917Sdes/* mux protocol messages */ 137204917Sdes#define MUX_MSG_HELLO 0x00000001 138204917Sdes#define MUX_C_NEW_SESSION 0x10000002 139204917Sdes#define MUX_C_ALIVE_CHECK 0x10000004 140204917Sdes#define MUX_C_TERMINATE 0x10000005 141204917Sdes#define MUX_C_OPEN_FWD 0x10000006 142204917Sdes#define MUX_C_CLOSE_FWD 0x10000007 143204917Sdes#define MUX_C_NEW_STDIO_FWD 0x10000008 144226046Sdes#define MUX_C_STOP_LISTENING 0x10000009 145204917Sdes#define MUX_S_OK 0x80000001 146204917Sdes#define MUX_S_PERMISSION_DENIED 0x80000002 147204917Sdes#define MUX_S_FAILURE 0x80000003 148204917Sdes#define MUX_S_EXIT_MESSAGE 0x80000004 149204917Sdes#define MUX_S_ALIVE 0x80000005 150204917Sdes#define MUX_S_SESSION_OPENED 0x80000006 151215116Sdes#define MUX_S_REMOTE_PORT 0x80000007 152226046Sdes#define MUX_S_TTY_ALLOC_FAIL 0x80000008 153204917Sdes 154204917Sdes/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ 155204917Sdes#define MUX_FWD_LOCAL 1 156204917Sdes#define MUX_FWD_REMOTE 2 157204917Sdes#define MUX_FWD_DYNAMIC 3 158204917Sdes 159215116Sdesstatic void mux_session_confirm(int, int, void *); 160204917Sdes 161204917Sdesstatic int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); 162204917Sdesstatic int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); 163204917Sdesstatic int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *); 164204917Sdesstatic int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *); 165204917Sdesstatic int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); 166204917Sdesstatic int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); 167204917Sdesstatic int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); 168226046Sdesstatic int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *); 169204917Sdes 170204917Sdesstatic const struct { 171204917Sdes u_int type; 172204917Sdes int (*handler)(u_int, Channel *, Buffer *, Buffer *); 173204917Sdes} mux_master_handlers[] = { 174204917Sdes { MUX_MSG_HELLO, process_mux_master_hello }, 175204917Sdes { MUX_C_NEW_SESSION, process_mux_new_session }, 176204917Sdes { MUX_C_ALIVE_CHECK, process_mux_alive_check }, 177204917Sdes { MUX_C_TERMINATE, process_mux_terminate }, 178204917Sdes { MUX_C_OPEN_FWD, process_mux_open_fwd }, 179204917Sdes { MUX_C_CLOSE_FWD, process_mux_close_fwd }, 180204917Sdes { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, 181226046Sdes { MUX_C_STOP_LISTENING, process_mux_stop_listening }, 182204917Sdes { 0, NULL } 183204917Sdes}; 184204917Sdes 185204917Sdes/* Cleanup callback fired on closure of mux slave _session_ channel */ 186204917Sdes/* ARGSUSED */ 187255767Sdesstatic void 188204917Sdesmux_master_session_cleanup_cb(int cid, void *unused) 189204917Sdes{ 190204917Sdes Channel *cc, *c = channel_by_id(cid); 191204917Sdes 192204917Sdes debug3("%s: entering for channel %d", __func__, cid); 193204917Sdes if (c == NULL) 194204917Sdes fatal("%s: channel_by_id(%i) == NULL", __func__, cid); 195204917Sdes if (c->ctl_chan != -1) { 196204917Sdes if ((cc = channel_by_id(c->ctl_chan)) == NULL) 197204917Sdes fatal("%s: channel %d missing control channel %d", 198204917Sdes __func__, c->self, c->ctl_chan); 199204917Sdes c->ctl_chan = -1; 200204917Sdes cc->remote_id = -1; 201204917Sdes chan_rcvd_oclose(cc); 202204917Sdes } 203204917Sdes channel_cancel_cleanup(c->self); 204204917Sdes} 205204917Sdes 206204917Sdes/* Cleanup callback fired on closure of mux slave _control_ channel */ 207204917Sdes/* ARGSUSED */ 208204917Sdesstatic void 209204917Sdesmux_master_control_cleanup_cb(int cid, void *unused) 210204917Sdes{ 211204917Sdes Channel *sc, *c = channel_by_id(cid); 212204917Sdes 213204917Sdes debug3("%s: entering for channel %d", __func__, cid); 214204917Sdes if (c == NULL) 215204917Sdes fatal("%s: channel_by_id(%i) == NULL", __func__, cid); 216204917Sdes if (c->remote_id != -1) { 217204917Sdes if ((sc = channel_by_id(c->remote_id)) == NULL) 218215116Sdes fatal("%s: channel %d missing session channel %d", 219204917Sdes __func__, c->self, c->remote_id); 220204917Sdes c->remote_id = -1; 221204917Sdes sc->ctl_chan = -1; 222255767Sdes if (sc->type != SSH_CHANNEL_OPEN && 223255767Sdes sc->type != SSH_CHANNEL_OPENING) { 224204917Sdes debug2("%s: channel %d: not open", __func__, sc->self); 225204917Sdes chan_mark_dead(sc); 226204917Sdes } else { 227204917Sdes if (sc->istate == CHAN_INPUT_OPEN) 228204917Sdes chan_read_failed(sc); 229204917Sdes if (sc->ostate == CHAN_OUTPUT_OPEN) 230204917Sdes chan_write_failed(sc); 231204917Sdes } 232204917Sdes } 233204917Sdes channel_cancel_cleanup(c->self); 234204917Sdes} 235204917Sdes 236204917Sdes/* Check mux client environment variables before passing them to mux master. */ 237204917Sdesstatic int 238204917Sdesenv_permitted(char *env) 239204917Sdes{ 240204917Sdes int i, ret; 241204917Sdes char name[1024], *cp; 242204917Sdes 243204917Sdes if ((cp = strchr(env, '=')) == NULL || cp == env) 244204917Sdes return 0; 245204917Sdes ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env); 246204917Sdes if (ret <= 0 || (size_t)ret >= sizeof(name)) { 247204917Sdes error("env_permitted: name '%.100s...' too long", env); 248204917Sdes return 0; 249204917Sdes } 250204917Sdes 251204917Sdes for (i = 0; i < options.num_send_env; i++) 252204917Sdes if (match_pattern(name, options.send_env[i])) 253204917Sdes return 1; 254204917Sdes 255204917Sdes return 0; 256204917Sdes} 257204917Sdes 258204917Sdes/* Mux master protocol message handlers */ 259204917Sdes 260204917Sdesstatic int 261204917Sdesprocess_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r) 262204917Sdes{ 263204917Sdes u_int ver; 264204917Sdes struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; 265204917Sdes 266204917Sdes if (state == NULL) 267204917Sdes fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self); 268204917Sdes if (state->hello_rcvd) { 269204917Sdes error("%s: HELLO received twice", __func__); 270204917Sdes return -1; 271204917Sdes } 272204917Sdes if (buffer_get_int_ret(&ver, m) != 0) { 273204917Sdes malf: 274204917Sdes error("%s: malformed message", __func__); 275204917Sdes return -1; 276204917Sdes } 277204917Sdes if (ver != SSHMUX_VER) { 278204917Sdes error("Unsupported multiplexing protocol version %d " 279204917Sdes "(expected %d)", ver, SSHMUX_VER); 280204917Sdes return -1; 281204917Sdes } 282204917Sdes debug2("%s: channel %d slave version %u", __func__, c->self, ver); 283204917Sdes 284204917Sdes /* No extensions are presently defined */ 285204917Sdes while (buffer_len(m) > 0) { 286204917Sdes char *name = buffer_get_string_ret(m, NULL); 287204917Sdes char *value = buffer_get_string_ret(m, NULL); 288204917Sdes 289204917Sdes if (name == NULL || value == NULL) { 290255767Sdes free(name); 291255767Sdes free(value); 292204917Sdes goto malf; 293204917Sdes } 294204917Sdes debug2("Unrecognised slave extension \"%s\"", name); 295255767Sdes free(name); 296255767Sdes free(value); 297204917Sdes } 298204917Sdes state->hello_rcvd = 1; 299204917Sdes return 0; 300204917Sdes} 301204917Sdes 302204917Sdesstatic int 303204917Sdesprocess_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) 304204917Sdes{ 305204917Sdes Channel *nc; 306204917Sdes struct mux_session_confirm_ctx *cctx; 307204917Sdes char *reserved, *cmd, *cp; 308204917Sdes u_int i, j, len, env_len, escape_char, window, packetmax; 309204917Sdes int new_fd[3]; 310204917Sdes 311204917Sdes /* Reply for SSHMUX_COMMAND_OPEN */ 312204917Sdes cctx = xcalloc(1, sizeof(*cctx)); 313204917Sdes cctx->term = NULL; 314215116Sdes cctx->rid = rid; 315204917Sdes cmd = reserved = NULL; 316240075Sdes cctx->env = NULL; 317240075Sdes env_len = 0; 318204917Sdes if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || 319204917Sdes buffer_get_int_ret(&cctx->want_tty, m) != 0 || 320204917Sdes buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 || 321204917Sdes buffer_get_int_ret(&cctx->want_agent_fwd, m) != 0 || 322204917Sdes buffer_get_int_ret(&cctx->want_subsys, m) != 0 || 323204917Sdes buffer_get_int_ret(&escape_char, m) != 0 || 324204917Sdes (cctx->term = buffer_get_string_ret(m, &len)) == NULL || 325204917Sdes (cmd = buffer_get_string_ret(m, &len)) == NULL) { 326204917Sdes malf: 327255767Sdes free(cmd); 328255767Sdes free(reserved); 329240075Sdes for (j = 0; j < env_len; j++) 330255767Sdes free(cctx->env[j]); 331255767Sdes free(cctx->env); 332255767Sdes free(cctx->term); 333255767Sdes free(cctx); 334204917Sdes error("%s: malformed message", __func__); 335204917Sdes return -1; 336204917Sdes } 337255767Sdes free(reserved); 338204917Sdes reserved = NULL; 339204917Sdes 340204917Sdes while (buffer_len(m) > 0) { 341204917Sdes#define MUX_MAX_ENV_VARS 4096 342240075Sdes if ((cp = buffer_get_string_ret(m, &len)) == NULL) 343204917Sdes goto malf; 344204917Sdes if (!env_permitted(cp)) { 345255767Sdes free(cp); 346204917Sdes continue; 347204917Sdes } 348204917Sdes cctx->env = xrealloc(cctx->env, env_len + 2, 349204917Sdes sizeof(*cctx->env)); 350204917Sdes cctx->env[env_len++] = cp; 351204917Sdes cctx->env[env_len] = NULL; 352204917Sdes if (env_len > MUX_MAX_ENV_VARS) { 353204917Sdes error(">%d environment variables received, ignoring " 354204917Sdes "additional", MUX_MAX_ENV_VARS); 355204917Sdes break; 356204917Sdes } 357204917Sdes } 358204917Sdes 359204917Sdes debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, " 360204917Sdes "term \"%s\", cmd \"%s\", env %u", __func__, c->self, 361204917Sdes cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd, 362204917Sdes cctx->want_subsys, cctx->term, cmd, env_len); 363204917Sdes 364204917Sdes buffer_init(&cctx->cmd); 365204917Sdes buffer_append(&cctx->cmd, cmd, strlen(cmd)); 366255767Sdes free(cmd); 367204917Sdes cmd = NULL; 368204917Sdes 369204917Sdes /* Gather fds from client */ 370204917Sdes for(i = 0; i < 3; i++) { 371204917Sdes if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { 372204917Sdes error("%s: failed to receive fd %d from slave", 373204917Sdes __func__, i); 374204917Sdes for (j = 0; j < i; j++) 375204917Sdes close(new_fd[j]); 376204917Sdes for (j = 0; j < env_len; j++) 377255767Sdes free(cctx->env[j]); 378255767Sdes free(cctx->env); 379255767Sdes free(cctx->term); 380204917Sdes buffer_free(&cctx->cmd); 381255767Sdes free(cctx); 382204917Sdes 383204917Sdes /* prepare reply */ 384204917Sdes buffer_put_int(r, MUX_S_FAILURE); 385204917Sdes buffer_put_int(r, rid); 386204917Sdes buffer_put_cstring(r, 387204917Sdes "did not receive file descriptors"); 388204917Sdes return -1; 389204917Sdes } 390204917Sdes } 391204917Sdes 392204917Sdes debug3("%s: got fds stdin %d, stdout %d, stderr %d", __func__, 393204917Sdes new_fd[0], new_fd[1], new_fd[2]); 394204917Sdes 395204917Sdes /* XXX support multiple child sessions in future */ 396204917Sdes if (c->remote_id != -1) { 397204917Sdes debug2("%s: session already open", __func__); 398204917Sdes /* prepare reply */ 399204917Sdes buffer_put_int(r, MUX_S_FAILURE); 400204917Sdes buffer_put_int(r, rid); 401204917Sdes buffer_put_cstring(r, "Multiple sessions not supported"); 402204917Sdes cleanup: 403204917Sdes close(new_fd[0]); 404204917Sdes close(new_fd[1]); 405204917Sdes close(new_fd[2]); 406255767Sdes free(cctx->term); 407204917Sdes if (env_len != 0) { 408204917Sdes for (i = 0; i < env_len; i++) 409255767Sdes free(cctx->env[i]); 410255767Sdes free(cctx->env); 411204917Sdes } 412204917Sdes buffer_free(&cctx->cmd); 413255767Sdes free(cctx); 414204917Sdes return 0; 415204917Sdes } 416204917Sdes 417204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 418204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 419204917Sdes if (!ask_permission("Allow shared connection to %s? ", host)) { 420204917Sdes debug2("%s: session refused by user", __func__); 421204917Sdes /* prepare reply */ 422204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 423204917Sdes buffer_put_int(r, rid); 424204917Sdes buffer_put_cstring(r, "Permission denied"); 425204917Sdes goto cleanup; 426204917Sdes } 427204917Sdes } 428204917Sdes 429204917Sdes /* Try to pick up ttymodes from client before it goes raw */ 430204917Sdes if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) 431204917Sdes error("%s: tcgetattr: %s", __func__, strerror(errno)); 432204917Sdes 433204917Sdes /* enable nonblocking unless tty */ 434204917Sdes if (!isatty(new_fd[0])) 435204917Sdes set_nonblock(new_fd[0]); 436204917Sdes if (!isatty(new_fd[1])) 437204917Sdes set_nonblock(new_fd[1]); 438204917Sdes if (!isatty(new_fd[2])) 439204917Sdes set_nonblock(new_fd[2]); 440204917Sdes 441204917Sdes window = CHAN_SES_WINDOW_DEFAULT; 442204917Sdes packetmax = CHAN_SES_PACKET_DEFAULT; 443204917Sdes if (cctx->want_tty) { 444204917Sdes window >>= 1; 445204917Sdes packetmax >>= 1; 446204917Sdes } 447204917Sdes 448204917Sdes nc = channel_new("session", SSH_CHANNEL_OPENING, 449204917Sdes new_fd[0], new_fd[1], new_fd[2], window, packetmax, 450204917Sdes CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); 451204917Sdes 452204917Sdes nc->ctl_chan = c->self; /* link session -> control channel */ 453204917Sdes c->remote_id = nc->self; /* link control -> session channel */ 454204917Sdes 455204917Sdes if (cctx->want_tty && escape_char != 0xffffffff) { 456204917Sdes channel_register_filter(nc->self, 457204917Sdes client_simple_escape_filter, NULL, 458204917Sdes client_filter_cleanup, 459204917Sdes client_new_escape_filter_ctx((int)escape_char)); 460204917Sdes } 461204917Sdes 462204917Sdes debug2("%s: channel_new: %d linked to control channel %d", 463204917Sdes __func__, nc->self, nc->ctl_chan); 464204917Sdes 465204917Sdes channel_send_open(nc->self); 466204917Sdes channel_register_open_confirm(nc->self, mux_session_confirm, cctx); 467215116Sdes c->mux_pause = 1; /* stop handling messages until open_confirm done */ 468215116Sdes channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); 469204917Sdes 470215116Sdes /* reply is deferred, sent by mux_session_confirm */ 471204917Sdes return 0; 472204917Sdes} 473204917Sdes 474204917Sdesstatic int 475204917Sdesprocess_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r) 476204917Sdes{ 477204917Sdes debug2("%s: channel %d: alive check", __func__, c->self); 478204917Sdes 479204917Sdes /* prepare reply */ 480204917Sdes buffer_put_int(r, MUX_S_ALIVE); 481204917Sdes buffer_put_int(r, rid); 482204917Sdes buffer_put_int(r, (u_int)getpid()); 483204917Sdes 484204917Sdes return 0; 485204917Sdes} 486204917Sdes 487204917Sdesstatic int 488204917Sdesprocess_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r) 489204917Sdes{ 490204917Sdes debug2("%s: channel %d: terminate request", __func__, c->self); 491204917Sdes 492204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 493204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 494204917Sdes if (!ask_permission("Terminate shared connection to %s? ", 495204917Sdes host)) { 496204917Sdes debug2("%s: termination refused by user", __func__); 497204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 498204917Sdes buffer_put_int(r, rid); 499204917Sdes buffer_put_cstring(r, "Permission denied"); 500204917Sdes return 0; 501204917Sdes } 502204917Sdes } 503204917Sdes 504204917Sdes quit_pending = 1; 505204917Sdes buffer_put_int(r, MUX_S_OK); 506204917Sdes buffer_put_int(r, rid); 507204917Sdes /* XXX exit happens too soon - message never makes it to client */ 508204917Sdes return 0; 509204917Sdes} 510204917Sdes 511204917Sdesstatic char * 512204917Sdesformat_forward(u_int ftype, Forward *fwd) 513204917Sdes{ 514204917Sdes char *ret; 515204917Sdes 516204917Sdes switch (ftype) { 517204917Sdes case MUX_FWD_LOCAL: 518204917Sdes xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d", 519204917Sdes (fwd->listen_host == NULL) ? 520204917Sdes (options.gateway_ports ? "*" : "LOCALHOST") : 521204917Sdes fwd->listen_host, fwd->listen_port, 522204917Sdes fwd->connect_host, fwd->connect_port); 523204917Sdes break; 524204917Sdes case MUX_FWD_DYNAMIC: 525204917Sdes xasprintf(&ret, "dynamic forward %.200s:%d -> *", 526204917Sdes (fwd->listen_host == NULL) ? 527204917Sdes (options.gateway_ports ? "*" : "LOCALHOST") : 528204917Sdes fwd->listen_host, fwd->listen_port); 529204917Sdes break; 530204917Sdes case MUX_FWD_REMOTE: 531204917Sdes xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d", 532204917Sdes (fwd->listen_host == NULL) ? 533204917Sdes "LOCALHOST" : fwd->listen_host, 534204917Sdes fwd->listen_port, 535204917Sdes fwd->connect_host, fwd->connect_port); 536204917Sdes break; 537204917Sdes default: 538204917Sdes fatal("%s: unknown forward type %u", __func__, ftype); 539204917Sdes } 540204917Sdes return ret; 541204917Sdes} 542204917Sdes 543204917Sdesstatic int 544204917Sdescompare_host(const char *a, const char *b) 545204917Sdes{ 546204917Sdes if (a == NULL && b == NULL) 547204917Sdes return 1; 548204917Sdes if (a == NULL || b == NULL) 549204917Sdes return 0; 550204917Sdes return strcmp(a, b) == 0; 551204917Sdes} 552204917Sdes 553204917Sdesstatic int 554204917Sdescompare_forward(Forward *a, Forward *b) 555204917Sdes{ 556204917Sdes if (!compare_host(a->listen_host, b->listen_host)) 557204917Sdes return 0; 558204917Sdes if (a->listen_port != b->listen_port) 559204917Sdes return 0; 560204917Sdes if (!compare_host(a->connect_host, b->connect_host)) 561204917Sdes return 0; 562204917Sdes if (a->connect_port != b->connect_port) 563204917Sdes return 0; 564204917Sdes 565204917Sdes return 1; 566204917Sdes} 567204917Sdes 568215116Sdesstatic void 569215116Sdesmux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) 570215116Sdes{ 571215116Sdes struct mux_channel_confirm_ctx *fctx = ctxt; 572215116Sdes char *failmsg = NULL; 573215116Sdes Forward *rfwd; 574215116Sdes Channel *c; 575215116Sdes Buffer out; 576215116Sdes 577215116Sdes if ((c = channel_by_id(fctx->cid)) == NULL) { 578215116Sdes /* no channel for reply */ 579215116Sdes error("%s: unknown channel", __func__); 580215116Sdes return; 581215116Sdes } 582215116Sdes buffer_init(&out); 583215116Sdes if (fctx->fid >= options.num_remote_forwards) { 584215116Sdes xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid); 585215116Sdes goto fail; 586215116Sdes } 587215116Sdes rfwd = &options.remote_forwards[fctx->fid]; 588215116Sdes debug("%s: %s for: listen %d, connect %s:%d", __func__, 589215116Sdes type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", 590215116Sdes rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); 591215116Sdes if (type == SSH2_MSG_REQUEST_SUCCESS) { 592215116Sdes if (rfwd->listen_port == 0) { 593215116Sdes rfwd->allocated_port = packet_get_int(); 594215116Sdes logit("Allocated port %u for mux remote forward" 595215116Sdes " to %s:%d", rfwd->allocated_port, 596215116Sdes rfwd->connect_host, rfwd->connect_port); 597215116Sdes buffer_put_int(&out, MUX_S_REMOTE_PORT); 598215116Sdes buffer_put_int(&out, fctx->rid); 599215116Sdes buffer_put_int(&out, rfwd->allocated_port); 600240075Sdes channel_update_permitted_opens(rfwd->handle, 601240075Sdes rfwd->allocated_port); 602215116Sdes } else { 603215116Sdes buffer_put_int(&out, MUX_S_OK); 604215116Sdes buffer_put_int(&out, fctx->rid); 605215116Sdes } 606215116Sdes goto out; 607215116Sdes } else { 608240075Sdes if (rfwd->listen_port == 0) 609240075Sdes channel_update_permitted_opens(rfwd->handle, -1); 610215116Sdes xasprintf(&failmsg, "remote port forwarding failed for " 611215116Sdes "listen port %d", rfwd->listen_port); 612215116Sdes } 613215116Sdes fail: 614215116Sdes error("%s: %s", __func__, failmsg); 615215116Sdes buffer_put_int(&out, MUX_S_FAILURE); 616215116Sdes buffer_put_int(&out, fctx->rid); 617215116Sdes buffer_put_cstring(&out, failmsg); 618255767Sdes free(failmsg); 619215116Sdes out: 620215116Sdes buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out)); 621215116Sdes buffer_free(&out); 622215116Sdes if (c->mux_pause <= 0) 623215116Sdes fatal("%s: mux_pause %d", __func__, c->mux_pause); 624215116Sdes c->mux_pause = 0; /* start processing messages again */ 625215116Sdes} 626215116Sdes 627204917Sdesstatic int 628204917Sdesprocess_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 629204917Sdes{ 630204917Sdes Forward fwd; 631204917Sdes char *fwd_desc = NULL; 632204917Sdes u_int ftype; 633255767Sdes u_int lport, cport; 634204917Sdes int i, ret = 0, freefwd = 1; 635204917Sdes 636287146Sdelphij memset(&fwd, 0, sizeof(fwd)); 637287146Sdelphij 638204917Sdes if (buffer_get_int_ret(&ftype, m) != 0 || 639204917Sdes (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL || 640255767Sdes buffer_get_int_ret(&lport, m) != 0 || 641204917Sdes (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL || 642255767Sdes buffer_get_int_ret(&cport, m) != 0 || 643255767Sdes lport > 65535 || cport > 65535) { 644204917Sdes error("%s: malformed message", __func__); 645204917Sdes ret = -1; 646204917Sdes goto out; 647204917Sdes } 648255767Sdes fwd.listen_port = lport; 649255767Sdes fwd.connect_port = cport; 650204917Sdes if (*fwd.listen_host == '\0') { 651255767Sdes free(fwd.listen_host); 652204917Sdes fwd.listen_host = NULL; 653204917Sdes } 654204917Sdes if (*fwd.connect_host == '\0') { 655255767Sdes free(fwd.connect_host); 656204917Sdes fwd.connect_host = NULL; 657204917Sdes } 658204917Sdes 659204917Sdes debug2("%s: channel %d: request %s", __func__, c->self, 660204917Sdes (fwd_desc = format_forward(ftype, &fwd))); 661204917Sdes 662204917Sdes if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE && 663204917Sdes ftype != MUX_FWD_DYNAMIC) { 664204917Sdes logit("%s: invalid forwarding type %u", __func__, ftype); 665204917Sdes invalid: 666255767Sdes free(fwd.listen_host); 667255767Sdes free(fwd.connect_host); 668204917Sdes buffer_put_int(r, MUX_S_FAILURE); 669204917Sdes buffer_put_int(r, rid); 670204917Sdes buffer_put_cstring(r, "Invalid forwarding request"); 671204917Sdes return 0; 672204917Sdes } 673215116Sdes if (fwd.listen_port >= 65536) { 674204917Sdes logit("%s: invalid listen port %u", __func__, 675204917Sdes fwd.listen_port); 676204917Sdes goto invalid; 677204917Sdes } 678204917Sdes if (fwd.connect_port >= 65536 || (ftype != MUX_FWD_DYNAMIC && 679204917Sdes ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) { 680204917Sdes logit("%s: invalid connect port %u", __func__, 681204917Sdes fwd.connect_port); 682204917Sdes goto invalid; 683204917Sdes } 684204917Sdes if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL) { 685204917Sdes logit("%s: missing connect host", __func__); 686204917Sdes goto invalid; 687204917Sdes } 688204917Sdes 689204917Sdes /* Skip forwards that have already been requested */ 690204917Sdes switch (ftype) { 691204917Sdes case MUX_FWD_LOCAL: 692204917Sdes case MUX_FWD_DYNAMIC: 693204917Sdes for (i = 0; i < options.num_local_forwards; i++) { 694204917Sdes if (compare_forward(&fwd, 695204917Sdes options.local_forwards + i)) { 696204917Sdes exists: 697204917Sdes debug2("%s: found existing forwarding", 698204917Sdes __func__); 699204917Sdes buffer_put_int(r, MUX_S_OK); 700204917Sdes buffer_put_int(r, rid); 701204917Sdes goto out; 702204917Sdes } 703204917Sdes } 704204917Sdes break; 705204917Sdes case MUX_FWD_REMOTE: 706204917Sdes for (i = 0; i < options.num_remote_forwards; i++) { 707204917Sdes if (compare_forward(&fwd, 708215116Sdes options.remote_forwards + i)) { 709215116Sdes if (fwd.listen_port != 0) 710215116Sdes goto exists; 711215116Sdes debug2("%s: found allocated port", 712215116Sdes __func__); 713215116Sdes buffer_put_int(r, MUX_S_REMOTE_PORT); 714215116Sdes buffer_put_int(r, rid); 715215116Sdes buffer_put_int(r, 716215116Sdes options.remote_forwards[i].allocated_port); 717215116Sdes goto out; 718215116Sdes } 719204917Sdes } 720204917Sdes break; 721204917Sdes } 722204917Sdes 723204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 724204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 725204917Sdes if (!ask_permission("Open %s on %s?", fwd_desc, host)) { 726204917Sdes debug2("%s: forwarding refused by user", __func__); 727204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 728204917Sdes buffer_put_int(r, rid); 729204917Sdes buffer_put_cstring(r, "Permission denied"); 730204917Sdes goto out; 731204917Sdes } 732204917Sdes } 733204917Sdes 734204917Sdes if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { 735248619Sdes if (!channel_setup_local_fwd_listener(fwd.listen_host, 736204917Sdes fwd.listen_port, fwd.connect_host, fwd.connect_port, 737248619Sdes options.gateway_ports)) { 738204917Sdes fail: 739204917Sdes logit("slave-requested %s failed", fwd_desc); 740204917Sdes buffer_put_int(r, MUX_S_FAILURE); 741204917Sdes buffer_put_int(r, rid); 742204917Sdes buffer_put_cstring(r, "Port forwarding failed"); 743204917Sdes goto out; 744204917Sdes } 745204917Sdes add_local_forward(&options, &fwd); 746204917Sdes freefwd = 0; 747204917Sdes } else { 748215116Sdes struct mux_channel_confirm_ctx *fctx; 749215116Sdes 750240075Sdes fwd.handle = channel_request_remote_forwarding(fwd.listen_host, 751240075Sdes fwd.listen_port, fwd.connect_host, fwd.connect_port); 752240075Sdes if (fwd.handle < 0) 753204917Sdes goto fail; 754204917Sdes add_remote_forward(&options, &fwd); 755215116Sdes fctx = xcalloc(1, sizeof(*fctx)); 756215116Sdes fctx->cid = c->self; 757215116Sdes fctx->rid = rid; 758215116Sdes fctx->fid = options.num_remote_forwards - 1; 759215116Sdes client_register_global_confirm(mux_confirm_remote_forward, 760215116Sdes fctx); 761204917Sdes freefwd = 0; 762215116Sdes c->mux_pause = 1; /* wait for mux_confirm_remote_forward */ 763215116Sdes /* delayed reply in mux_confirm_remote_forward */ 764215116Sdes goto out; 765204917Sdes } 766204917Sdes buffer_put_int(r, MUX_S_OK); 767204917Sdes buffer_put_int(r, rid); 768204917Sdes out: 769255767Sdes free(fwd_desc); 770204917Sdes if (freefwd) { 771255767Sdes free(fwd.listen_host); 772255767Sdes free(fwd.connect_host); 773204917Sdes } 774204917Sdes return ret; 775204917Sdes} 776204917Sdes 777204917Sdesstatic int 778204917Sdesprocess_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 779204917Sdes{ 780240075Sdes Forward fwd, *found_fwd; 781204917Sdes char *fwd_desc = NULL; 782240075Sdes const char *error_reason = NULL; 783204917Sdes u_int ftype; 784240075Sdes int i, listen_port, ret = 0; 785255767Sdes u_int lport, cport; 786204917Sdes 787287146Sdelphij memset(&fwd, 0, sizeof(fwd)); 788287146Sdelphij 789204917Sdes if (buffer_get_int_ret(&ftype, m) != 0 || 790204917Sdes (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL || 791255767Sdes buffer_get_int_ret(&lport, m) != 0 || 792204917Sdes (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL || 793255767Sdes buffer_get_int_ret(&cport, m) != 0 || 794255767Sdes lport > 65535 || cport > 65535) { 795204917Sdes error("%s: malformed message", __func__); 796204917Sdes ret = -1; 797204917Sdes goto out; 798204917Sdes } 799255767Sdes fwd.listen_port = lport; 800255767Sdes fwd.connect_port = cport; 801204917Sdes 802204917Sdes if (*fwd.listen_host == '\0') { 803255767Sdes free(fwd.listen_host); 804204917Sdes fwd.listen_host = NULL; 805204917Sdes } 806204917Sdes if (*fwd.connect_host == '\0') { 807255767Sdes free(fwd.connect_host); 808204917Sdes fwd.connect_host = NULL; 809204917Sdes } 810204917Sdes 811240075Sdes debug2("%s: channel %d: request cancel %s", __func__, c->self, 812204917Sdes (fwd_desc = format_forward(ftype, &fwd))); 813204917Sdes 814240075Sdes /* make sure this has been requested */ 815240075Sdes found_fwd = NULL; 816240075Sdes switch (ftype) { 817240075Sdes case MUX_FWD_LOCAL: 818240075Sdes case MUX_FWD_DYNAMIC: 819240075Sdes for (i = 0; i < options.num_local_forwards; i++) { 820240075Sdes if (compare_forward(&fwd, 821240075Sdes options.local_forwards + i)) { 822240075Sdes found_fwd = options.local_forwards + i; 823240075Sdes break; 824240075Sdes } 825240075Sdes } 826240075Sdes break; 827240075Sdes case MUX_FWD_REMOTE: 828240075Sdes for (i = 0; i < options.num_remote_forwards; i++) { 829240075Sdes if (compare_forward(&fwd, 830240075Sdes options.remote_forwards + i)) { 831240075Sdes found_fwd = options.remote_forwards + i; 832240075Sdes break; 833240075Sdes } 834240075Sdes } 835240075Sdes break; 836240075Sdes } 837204917Sdes 838240075Sdes if (found_fwd == NULL) 839240075Sdes error_reason = "port not forwarded"; 840240075Sdes else if (ftype == MUX_FWD_REMOTE) { 841240075Sdes /* 842240075Sdes * This shouldn't fail unless we confused the host/port 843240075Sdes * between options.remote_forwards and permitted_opens. 844240075Sdes * However, for dynamic allocated listen ports we need 845240075Sdes * to lookup the actual listen port. 846240075Sdes */ 847240075Sdes listen_port = (fwd.listen_port == 0) ? 848240075Sdes found_fwd->allocated_port : fwd.listen_port; 849240075Sdes if (channel_request_rforward_cancel(fwd.listen_host, 850240075Sdes listen_port) == -1) 851240075Sdes error_reason = "port not in permitted opens"; 852240075Sdes } else { /* local and dynamic forwards */ 853240075Sdes /* Ditto */ 854240075Sdes if (channel_cancel_lport_listener(fwd.listen_host, 855240075Sdes fwd.listen_port, fwd.connect_port, 856240075Sdes options.gateway_ports) == -1) 857240075Sdes error_reason = "port not found"; 858240075Sdes } 859240075Sdes 860240075Sdes if (error_reason == NULL) { 861240075Sdes buffer_put_int(r, MUX_S_OK); 862240075Sdes buffer_put_int(r, rid); 863240075Sdes 864255767Sdes free(found_fwd->listen_host); 865255767Sdes free(found_fwd->connect_host); 866240075Sdes found_fwd->listen_host = found_fwd->connect_host = NULL; 867240075Sdes found_fwd->listen_port = found_fwd->connect_port = 0; 868240075Sdes } else { 869240075Sdes buffer_put_int(r, MUX_S_FAILURE); 870240075Sdes buffer_put_int(r, rid); 871240075Sdes buffer_put_cstring(r, error_reason); 872240075Sdes } 873204917Sdes out: 874255767Sdes free(fwd_desc); 875255767Sdes free(fwd.listen_host); 876255767Sdes free(fwd.connect_host); 877204917Sdes 878204917Sdes return ret; 879204917Sdes} 880204917Sdes 881204917Sdesstatic int 882204917Sdesprocess_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 883204917Sdes{ 884204917Sdes Channel *nc; 885204917Sdes char *reserved, *chost; 886204917Sdes u_int cport, i, j; 887204917Sdes int new_fd[2]; 888204917Sdes 889204917Sdes chost = reserved = NULL; 890204917Sdes if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || 891204917Sdes (chost = buffer_get_string_ret(m, NULL)) == NULL || 892204917Sdes buffer_get_int_ret(&cport, m) != 0) { 893255767Sdes free(reserved); 894255767Sdes free(chost); 895204917Sdes error("%s: malformed message", __func__); 896204917Sdes return -1; 897204917Sdes } 898255767Sdes free(reserved); 899204917Sdes 900204917Sdes debug2("%s: channel %d: request stdio fwd to %s:%u", 901204917Sdes __func__, c->self, chost, cport); 902204917Sdes 903204917Sdes /* Gather fds from client */ 904204917Sdes for(i = 0; i < 2; i++) { 905204917Sdes if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { 906204917Sdes error("%s: failed to receive fd %d from slave", 907204917Sdes __func__, i); 908204917Sdes for (j = 0; j < i; j++) 909204917Sdes close(new_fd[j]); 910255767Sdes free(chost); 911204917Sdes 912204917Sdes /* prepare reply */ 913204917Sdes buffer_put_int(r, MUX_S_FAILURE); 914204917Sdes buffer_put_int(r, rid); 915204917Sdes buffer_put_cstring(r, 916204917Sdes "did not receive file descriptors"); 917204917Sdes return -1; 918204917Sdes } 919204917Sdes } 920204917Sdes 921204917Sdes debug3("%s: got fds stdin %d, stdout %d", __func__, 922204917Sdes new_fd[0], new_fd[1]); 923204917Sdes 924204917Sdes /* XXX support multiple child sessions in future */ 925204917Sdes if (c->remote_id != -1) { 926204917Sdes debug2("%s: session already open", __func__); 927204917Sdes /* prepare reply */ 928204917Sdes buffer_put_int(r, MUX_S_FAILURE); 929204917Sdes buffer_put_int(r, rid); 930204917Sdes buffer_put_cstring(r, "Multiple sessions not supported"); 931204917Sdes cleanup: 932204917Sdes close(new_fd[0]); 933204917Sdes close(new_fd[1]); 934255767Sdes free(chost); 935204917Sdes return 0; 936204917Sdes } 937204917Sdes 938204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 939204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 940221420Sdes if (!ask_permission("Allow forward to %s:%u? ", 941204917Sdes chost, cport)) { 942204917Sdes debug2("%s: stdio fwd refused by user", __func__); 943204917Sdes /* prepare reply */ 944204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 945204917Sdes buffer_put_int(r, rid); 946204917Sdes buffer_put_cstring(r, "Permission denied"); 947204917Sdes goto cleanup; 948204917Sdes } 949204917Sdes } 950204917Sdes 951204917Sdes /* enable nonblocking unless tty */ 952204917Sdes if (!isatty(new_fd[0])) 953204917Sdes set_nonblock(new_fd[0]); 954204917Sdes if (!isatty(new_fd[1])) 955204917Sdes set_nonblock(new_fd[1]); 956204917Sdes 957204917Sdes nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]); 958204917Sdes 959204917Sdes nc->ctl_chan = c->self; /* link session -> control channel */ 960204917Sdes c->remote_id = nc->self; /* link control -> session channel */ 961204917Sdes 962204917Sdes debug2("%s: channel_new: %d linked to control channel %d", 963204917Sdes __func__, nc->self, nc->ctl_chan); 964204917Sdes 965215116Sdes channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); 966204917Sdes 967204917Sdes /* prepare reply */ 968204917Sdes /* XXX defer until channel confirmed */ 969204917Sdes buffer_put_int(r, MUX_S_SESSION_OPENED); 970204917Sdes buffer_put_int(r, rid); 971204917Sdes buffer_put_int(r, nc->self); 972204917Sdes 973204917Sdes return 0; 974204917Sdes} 975204917Sdes 976226046Sdesstatic int 977226046Sdesprocess_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r) 978226046Sdes{ 979226046Sdes debug("%s: channel %d: stop listening", __func__, c->self); 980226046Sdes 981226046Sdes if (options.control_master == SSHCTL_MASTER_ASK || 982226046Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 983226046Sdes if (!ask_permission("Disable further multiplexing on shared " 984226046Sdes "connection to %s? ", host)) { 985226046Sdes debug2("%s: stop listen refused by user", __func__); 986226046Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 987226046Sdes buffer_put_int(r, rid); 988226046Sdes buffer_put_cstring(r, "Permission denied"); 989226046Sdes return 0; 990226046Sdes } 991226046Sdes } 992226046Sdes 993226046Sdes if (mux_listener_channel != NULL) { 994226046Sdes channel_free(mux_listener_channel); 995226046Sdes client_stop_mux(); 996255767Sdes free(options.control_path); 997226046Sdes options.control_path = NULL; 998226046Sdes mux_listener_channel = NULL; 999226046Sdes muxserver_sock = -1; 1000226046Sdes } 1001226046Sdes 1002226046Sdes /* prepare reply */ 1003226046Sdes buffer_put_int(r, MUX_S_OK); 1004226046Sdes buffer_put_int(r, rid); 1005226046Sdes 1006226046Sdes return 0; 1007226046Sdes} 1008226046Sdes 1009204917Sdes/* Channel callbacks fired on read/write from mux slave fd */ 1010204917Sdesstatic int 1011204917Sdesmux_master_read_cb(Channel *c) 1012204917Sdes{ 1013204917Sdes struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; 1014204917Sdes Buffer in, out; 1015204917Sdes void *ptr; 1016204917Sdes u_int type, rid, have, i; 1017204917Sdes int ret = -1; 1018204917Sdes 1019204917Sdes /* Setup ctx and */ 1020204917Sdes if (c->mux_ctx == NULL) { 1021215116Sdes state = xcalloc(1, sizeof(*state)); 1022204917Sdes c->mux_ctx = state; 1023204917Sdes channel_register_cleanup(c->self, 1024204917Sdes mux_master_control_cleanup_cb, 0); 1025204917Sdes 1026204917Sdes /* Send hello */ 1027204917Sdes buffer_init(&out); 1028204917Sdes buffer_put_int(&out, MUX_MSG_HELLO); 1029204917Sdes buffer_put_int(&out, SSHMUX_VER); 1030204917Sdes /* no extensions */ 1031204917Sdes buffer_put_string(&c->output, buffer_ptr(&out), 1032204917Sdes buffer_len(&out)); 1033204917Sdes buffer_free(&out); 1034204917Sdes debug3("%s: channel %d: hello sent", __func__, c->self); 1035204917Sdes return 0; 1036204917Sdes } 1037204917Sdes 1038204917Sdes buffer_init(&in); 1039204917Sdes buffer_init(&out); 1040204917Sdes 1041204917Sdes /* Channel code ensures that we receive whole packets */ 1042204917Sdes if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) { 1043204917Sdes malf: 1044204917Sdes error("%s: malformed message", __func__); 1045204917Sdes goto out; 1046204917Sdes } 1047204917Sdes buffer_append(&in, ptr, have); 1048204917Sdes 1049204917Sdes if (buffer_get_int_ret(&type, &in) != 0) 1050204917Sdes goto malf; 1051204917Sdes debug3("%s: channel %d packet type 0x%08x len %u", 1052204917Sdes __func__, c->self, type, buffer_len(&in)); 1053204917Sdes 1054204917Sdes if (type == MUX_MSG_HELLO) 1055204917Sdes rid = 0; 1056204917Sdes else { 1057204917Sdes if (!state->hello_rcvd) { 1058204917Sdes error("%s: expected MUX_MSG_HELLO(0x%08x), " 1059204917Sdes "received 0x%08x", __func__, MUX_MSG_HELLO, type); 1060204917Sdes goto out; 1061204917Sdes } 1062204917Sdes if (buffer_get_int_ret(&rid, &in) != 0) 1063204917Sdes goto malf; 1064204917Sdes } 1065204917Sdes 1066204917Sdes for (i = 0; mux_master_handlers[i].handler != NULL; i++) { 1067204917Sdes if (type == mux_master_handlers[i].type) { 1068204917Sdes ret = mux_master_handlers[i].handler(rid, c, &in, &out); 1069204917Sdes break; 1070204917Sdes } 1071204917Sdes } 1072204917Sdes if (mux_master_handlers[i].handler == NULL) { 1073204917Sdes error("%s: unsupported mux message 0x%08x", __func__, type); 1074204917Sdes buffer_put_int(&out, MUX_S_FAILURE); 1075204917Sdes buffer_put_int(&out, rid); 1076204917Sdes buffer_put_cstring(&out, "unsupported request"); 1077204917Sdes ret = 0; 1078204917Sdes } 1079204917Sdes /* Enqueue reply packet */ 1080204917Sdes if (buffer_len(&out) != 0) { 1081204917Sdes buffer_put_string(&c->output, buffer_ptr(&out), 1082204917Sdes buffer_len(&out)); 1083204917Sdes } 1084204917Sdes out: 1085204917Sdes buffer_free(&in); 1086204917Sdes buffer_free(&out); 1087204917Sdes return ret; 1088204917Sdes} 1089204917Sdes 1090204917Sdesvoid 1091204917Sdesmux_exit_message(Channel *c, int exitval) 1092204917Sdes{ 1093204917Sdes Buffer m; 1094204917Sdes Channel *mux_chan; 1095204917Sdes 1096255767Sdes debug3("%s: channel %d: exit message, exitval %d", __func__, c->self, 1097204917Sdes exitval); 1098204917Sdes 1099204917Sdes if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) 1100204917Sdes fatal("%s: channel %d missing mux channel %d", 1101204917Sdes __func__, c->self, c->ctl_chan); 1102204917Sdes 1103204917Sdes /* Append exit message packet to control socket output queue */ 1104204917Sdes buffer_init(&m); 1105204917Sdes buffer_put_int(&m, MUX_S_EXIT_MESSAGE); 1106204917Sdes buffer_put_int(&m, c->self); 1107204917Sdes buffer_put_int(&m, exitval); 1108204917Sdes 1109204917Sdes buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); 1110204917Sdes buffer_free(&m); 1111204917Sdes} 1112204917Sdes 1113226046Sdesvoid 1114226046Sdesmux_tty_alloc_failed(Channel *c) 1115226046Sdes{ 1116226046Sdes Buffer m; 1117226046Sdes Channel *mux_chan; 1118226046Sdes 1119226046Sdes debug3("%s: channel %d: TTY alloc failed", __func__, c->self); 1120226046Sdes 1121226046Sdes if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) 1122226046Sdes fatal("%s: channel %d missing mux channel %d", 1123226046Sdes __func__, c->self, c->ctl_chan); 1124226046Sdes 1125226046Sdes /* Append exit message packet to control socket output queue */ 1126226046Sdes buffer_init(&m); 1127226046Sdes buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL); 1128226046Sdes buffer_put_int(&m, c->self); 1129226046Sdes 1130226046Sdes buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); 1131226046Sdes buffer_free(&m); 1132226046Sdes} 1133226046Sdes 1134180750Sdes/* Prepare a mux master to listen on a Unix domain socket. */ 1135180750Sdesvoid 1136180750Sdesmuxserver_listen(void) 1137180750Sdes{ 1138180750Sdes struct sockaddr_un addr; 1139204917Sdes socklen_t sun_len; 1140180750Sdes mode_t old_umask; 1141221420Sdes char *orig_control_path = options.control_path; 1142221420Sdes char rbuf[16+1]; 1143221420Sdes u_int i, r; 1144180750Sdes 1145180750Sdes if (options.control_path == NULL || 1146180750Sdes options.control_master == SSHCTL_MASTER_NO) 1147180750Sdes return; 1148180750Sdes 1149180750Sdes debug("setting up multiplex master socket"); 1150180750Sdes 1151221420Sdes /* 1152221420Sdes * Use a temporary path before listen so we can pseudo-atomically 1153221420Sdes * establish the listening socket in its final location to avoid 1154221420Sdes * other processes racing in between bind() and listen() and hitting 1155221420Sdes * an unready socket. 1156221420Sdes */ 1157221420Sdes for (i = 0; i < sizeof(rbuf) - 1; i++) { 1158221420Sdes r = arc4random_uniform(26+26+10); 1159221420Sdes rbuf[i] = (r < 26) ? 'a' + r : 1160221420Sdes (r < 26*2) ? 'A' + r - 26 : 1161221420Sdes '0' + r - 26 - 26; 1162221420Sdes } 1163221420Sdes rbuf[sizeof(rbuf) - 1] = '\0'; 1164221420Sdes options.control_path = NULL; 1165221420Sdes xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf); 1166221420Sdes debug3("%s: temporary control path %s", __func__, options.control_path); 1167221420Sdes 1168180750Sdes memset(&addr, '\0', sizeof(addr)); 1169180750Sdes addr.sun_family = AF_UNIX; 1170204917Sdes sun_len = offsetof(struct sockaddr_un, sun_path) + 1171180750Sdes strlen(options.control_path) + 1; 1172180750Sdes 1173180750Sdes if (strlcpy(addr.sun_path, options.control_path, 1174226046Sdes sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) { 1175226046Sdes error("ControlPath \"%s\" too long for Unix domain socket", 1176226046Sdes options.control_path); 1177226046Sdes goto disable_mux_master; 1178226046Sdes } 1179180750Sdes 1180180750Sdes if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) 1181180750Sdes fatal("%s socket(): %s", __func__, strerror(errno)); 1182180750Sdes 1183180750Sdes old_umask = umask(0177); 1184204917Sdes if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) { 1185180750Sdes if (errno == EINVAL || errno == EADDRINUSE) { 1186180750Sdes error("ControlSocket %s already exists, " 1187180750Sdes "disabling multiplexing", options.control_path); 1188221420Sdes disable_mux_master: 1189226046Sdes if (muxserver_sock != -1) { 1190226046Sdes close(muxserver_sock); 1191226046Sdes muxserver_sock = -1; 1192226046Sdes } 1193255767Sdes free(orig_control_path); 1194255767Sdes free(options.control_path); 1195180750Sdes options.control_path = NULL; 1196180750Sdes options.control_master = SSHCTL_MASTER_NO; 1197180750Sdes return; 1198180750Sdes } else 1199180750Sdes fatal("%s bind(): %s", __func__, strerror(errno)); 1200180750Sdes } 1201180750Sdes umask(old_umask); 1202180750Sdes 1203180750Sdes if (listen(muxserver_sock, 64) == -1) 1204180750Sdes fatal("%s listen(): %s", __func__, strerror(errno)); 1205180750Sdes 1206221420Sdes /* Now atomically "move" the mux socket into position */ 1207221420Sdes if (link(options.control_path, orig_control_path) != 0) { 1208221420Sdes if (errno != EEXIST) { 1209221420Sdes fatal("%s: link mux listener %s => %s: %s", __func__, 1210221420Sdes options.control_path, orig_control_path, 1211221420Sdes strerror(errno)); 1212221420Sdes } 1213221420Sdes error("ControlSocket %s already exists, disabling multiplexing", 1214221420Sdes orig_control_path); 1215221420Sdes unlink(options.control_path); 1216221420Sdes goto disable_mux_master; 1217221420Sdes } 1218221420Sdes unlink(options.control_path); 1219255767Sdes free(options.control_path); 1220221420Sdes options.control_path = orig_control_path; 1221221420Sdes 1222180750Sdes set_nonblock(muxserver_sock); 1223204917Sdes 1224204917Sdes mux_listener_channel = channel_new("mux listener", 1225204917Sdes SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, 1226204917Sdes CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 1227221420Sdes 0, options.control_path, 1); 1228204917Sdes mux_listener_channel->mux_rcb = mux_master_read_cb; 1229204917Sdes debug3("%s: mux listener channel %d fd %d", __func__, 1230204917Sdes mux_listener_channel->self, mux_listener_channel->sock); 1231180750Sdes} 1232180750Sdes 1233180750Sdes/* Callback on open confirmation in mux master for a mux client session. */ 1234180750Sdesstatic void 1235215116Sdesmux_session_confirm(int id, int success, void *arg) 1236180750Sdes{ 1237180750Sdes struct mux_session_confirm_ctx *cctx = arg; 1238180750Sdes const char *display; 1239215116Sdes Channel *c, *cc; 1240180750Sdes int i; 1241215116Sdes Buffer reply; 1242180750Sdes 1243180750Sdes if (cctx == NULL) 1244180750Sdes fatal("%s: cctx == NULL", __func__); 1245204917Sdes if ((c = channel_by_id(id)) == NULL) 1246180750Sdes fatal("%s: no channel for id %d", __func__, id); 1247215116Sdes if ((cc = channel_by_id(c->ctl_chan)) == NULL) 1248215116Sdes fatal("%s: channel %d lacks control channel %d", __func__, 1249215116Sdes id, c->ctl_chan); 1250180750Sdes 1251215116Sdes if (!success) { 1252215116Sdes debug3("%s: sending failure reply", __func__); 1253215116Sdes /* prepare reply */ 1254215116Sdes buffer_init(&reply); 1255215116Sdes buffer_put_int(&reply, MUX_S_FAILURE); 1256215116Sdes buffer_put_int(&reply, cctx->rid); 1257215116Sdes buffer_put_cstring(&reply, "Session open refused by peer"); 1258215116Sdes goto done; 1259215116Sdes } 1260215116Sdes 1261180750Sdes display = getenv("DISPLAY"); 1262180750Sdes if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { 1263180750Sdes char *proto, *data; 1264215116Sdes 1265180750Sdes /* Get reasonable local authentication information. */ 1266180750Sdes client_x11_get_proto(display, options.xauth_location, 1267215116Sdes options.forward_x11_trusted, options.forward_x11_timeout, 1268215116Sdes &proto, &data); 1269180750Sdes /* Request forwarding with authentication spoofing. */ 1270215116Sdes debug("Requesting X11 forwarding with authentication " 1271215116Sdes "spoofing."); 1272226046Sdes x11_request_forwarding_with_spoofing(id, display, proto, 1273226046Sdes data, 1); 1274226046Sdes client_expect_confirm(id, "X11 forwarding", CONFIRM_WARN); 1275226046Sdes /* XXX exit_on_forward_failure */ 1276180750Sdes } 1277180750Sdes 1278180750Sdes if (cctx->want_agent_fwd && options.forward_agent) { 1279180750Sdes debug("Requesting authentication agent forwarding."); 1280180750Sdes channel_request_start(id, "auth-agent-req@openssh.com", 0); 1281180750Sdes packet_send(); 1282180750Sdes } 1283180750Sdes 1284180750Sdes client_session2_setup(id, cctx->want_tty, cctx->want_subsys, 1285180750Sdes cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); 1286180750Sdes 1287215116Sdes debug3("%s: sending success reply", __func__); 1288215116Sdes /* prepare reply */ 1289215116Sdes buffer_init(&reply); 1290215116Sdes buffer_put_int(&reply, MUX_S_SESSION_OPENED); 1291215116Sdes buffer_put_int(&reply, cctx->rid); 1292215116Sdes buffer_put_int(&reply, c->self); 1293215116Sdes 1294215116Sdes done: 1295215116Sdes /* Send reply */ 1296215116Sdes buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); 1297215116Sdes buffer_free(&reply); 1298215116Sdes 1299215116Sdes if (cc->mux_pause <= 0) 1300215116Sdes fatal("%s: mux_pause %d", __func__, cc->mux_pause); 1301215116Sdes cc->mux_pause = 0; /* start processing messages again */ 1302180750Sdes c->open_confirm_ctx = NULL; 1303180750Sdes buffer_free(&cctx->cmd); 1304255767Sdes free(cctx->term); 1305180750Sdes if (cctx->env != NULL) { 1306180750Sdes for (i = 0; cctx->env[i] != NULL; i++) 1307255767Sdes free(cctx->env[i]); 1308255767Sdes free(cctx->env); 1309180750Sdes } 1310255767Sdes free(cctx); 1311180750Sdes} 1312180750Sdes 1313204917Sdes/* ** Multiplexing client support */ 1314204917Sdes 1315204917Sdes/* Exit signal handler */ 1316204917Sdesstatic void 1317204917Sdescontrol_client_sighandler(int signo) 1318204917Sdes{ 1319204917Sdes muxclient_terminate = signo; 1320204917Sdes} 1321204917Sdes 1322180750Sdes/* 1323204917Sdes * Relay signal handler - used to pass some signals from mux client to 1324204917Sdes * mux master. 1325180750Sdes */ 1326204917Sdesstatic void 1327204917Sdescontrol_client_sigrelay(int signo) 1328180750Sdes{ 1329204917Sdes int save_errno = errno; 1330180750Sdes 1331204917Sdes if (muxserver_pid > 1) 1332204917Sdes kill(muxserver_pid, signo); 1333204917Sdes 1334204917Sdes errno = save_errno; 1335204917Sdes} 1336204917Sdes 1337204917Sdesstatic int 1338204917Sdesmux_client_read(int fd, Buffer *b, u_int need) 1339204917Sdes{ 1340204917Sdes u_int have; 1341204917Sdes ssize_t len; 1342204917Sdes u_char *p; 1343204917Sdes struct pollfd pfd; 1344204917Sdes 1345204917Sdes pfd.fd = fd; 1346204917Sdes pfd.events = POLLIN; 1347204917Sdes p = buffer_append_space(b, need); 1348204917Sdes for (have = 0; have < need; ) { 1349204917Sdes if (muxclient_terminate) { 1350204917Sdes errno = EINTR; 1351204917Sdes return -1; 1352204917Sdes } 1353204917Sdes len = read(fd, p + have, need - have); 1354204917Sdes if (len < 0) { 1355204917Sdes switch (errno) { 1356204917Sdes#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) 1357204917Sdes case EWOULDBLOCK: 1358204917Sdes#endif 1359204917Sdes case EAGAIN: 1360204917Sdes (void)poll(&pfd, 1, -1); 1361204917Sdes /* FALLTHROUGH */ 1362204917Sdes case EINTR: 1363204917Sdes continue; 1364204917Sdes default: 1365204917Sdes return -1; 1366204917Sdes } 1367204917Sdes } 1368204917Sdes if (len == 0) { 1369204917Sdes errno = EPIPE; 1370204917Sdes return -1; 1371204917Sdes } 1372204917Sdes have += (u_int)len; 1373180750Sdes } 1374204917Sdes return 0; 1375204917Sdes} 1376180750Sdes 1377204917Sdesstatic int 1378204917Sdesmux_client_write_packet(int fd, Buffer *m) 1379204917Sdes{ 1380204917Sdes Buffer queue; 1381204917Sdes u_int have, need; 1382204917Sdes int oerrno, len; 1383204917Sdes u_char *ptr; 1384204917Sdes struct pollfd pfd; 1385204917Sdes 1386204917Sdes pfd.fd = fd; 1387204917Sdes pfd.events = POLLOUT; 1388204917Sdes buffer_init(&queue); 1389204917Sdes buffer_put_string(&queue, buffer_ptr(m), buffer_len(m)); 1390204917Sdes 1391204917Sdes need = buffer_len(&queue); 1392204917Sdes ptr = buffer_ptr(&queue); 1393204917Sdes 1394204917Sdes for (have = 0; have < need; ) { 1395204917Sdes if (muxclient_terminate) { 1396204917Sdes buffer_free(&queue); 1397204917Sdes errno = EINTR; 1398204917Sdes return -1; 1399204917Sdes } 1400204917Sdes len = write(fd, ptr + have, need - have); 1401204917Sdes if (len < 0) { 1402204917Sdes switch (errno) { 1403204917Sdes#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) 1404204917Sdes case EWOULDBLOCK: 1405204917Sdes#endif 1406204917Sdes case EAGAIN: 1407204917Sdes (void)poll(&pfd, 1, -1); 1408204917Sdes /* FALLTHROUGH */ 1409204917Sdes case EINTR: 1410204917Sdes continue; 1411204917Sdes default: 1412204917Sdes oerrno = errno; 1413204917Sdes buffer_free(&queue); 1414204917Sdes errno = oerrno; 1415204917Sdes return -1; 1416204917Sdes } 1417204917Sdes } 1418204917Sdes if (len == 0) { 1419204917Sdes buffer_free(&queue); 1420204917Sdes errno = EPIPE; 1421204917Sdes return -1; 1422204917Sdes } 1423204917Sdes have += (u_int)len; 1424180750Sdes } 1425204917Sdes buffer_free(&queue); 1426204917Sdes return 0; 1427204917Sdes} 1428204917Sdes 1429204917Sdesstatic int 1430204917Sdesmux_client_read_packet(int fd, Buffer *m) 1431204917Sdes{ 1432204917Sdes Buffer queue; 1433204917Sdes u_int need, have; 1434204917Sdes void *ptr; 1435204917Sdes int oerrno; 1436204917Sdes 1437204917Sdes buffer_init(&queue); 1438204917Sdes if (mux_client_read(fd, &queue, 4) != 0) { 1439204917Sdes if ((oerrno = errno) == EPIPE) 1440255767Sdes debug3("%s: read header failed: %s", __func__, 1441255767Sdes strerror(errno)); 1442255767Sdes buffer_free(&queue); 1443204917Sdes errno = oerrno; 1444204917Sdes return -1; 1445180750Sdes } 1446204917Sdes need = get_u32(buffer_ptr(&queue)); 1447204917Sdes if (mux_client_read(fd, &queue, need) != 0) { 1448204917Sdes oerrno = errno; 1449204917Sdes debug3("%s: read body failed: %s", __func__, strerror(errno)); 1450255767Sdes buffer_free(&queue); 1451204917Sdes errno = oerrno; 1452204917Sdes return -1; 1453204917Sdes } 1454204917Sdes ptr = buffer_get_string_ptr(&queue, &have); 1455204917Sdes buffer_append(m, ptr, have); 1456204917Sdes buffer_free(&queue); 1457204917Sdes return 0; 1458204917Sdes} 1459180750Sdes 1460204917Sdesstatic int 1461204917Sdesmux_client_hello_exchange(int fd) 1462204917Sdes{ 1463204917Sdes Buffer m; 1464204917Sdes u_int type, ver; 1465180750Sdes 1466180750Sdes buffer_init(&m); 1467204917Sdes buffer_put_int(&m, MUX_MSG_HELLO); 1468204917Sdes buffer_put_int(&m, SSHMUX_VER); 1469204917Sdes /* no extensions */ 1470204917Sdes 1471204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1472204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1473204917Sdes 1474204917Sdes buffer_clear(&m); 1475204917Sdes 1476204917Sdes /* Read their HELLO */ 1477204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1478180750Sdes buffer_free(&m); 1479204917Sdes return -1; 1480180750Sdes } 1481204917Sdes 1482204917Sdes type = buffer_get_int(&m); 1483204917Sdes if (type != MUX_MSG_HELLO) 1484204917Sdes fatal("%s: expected HELLO (%u) received %u", 1485204917Sdes __func__, MUX_MSG_HELLO, type); 1486204917Sdes ver = buffer_get_int(&m); 1487204917Sdes if (ver != SSHMUX_VER) 1488204917Sdes fatal("Unsupported multiplexing protocol version %d " 1489204917Sdes "(expected %d)", ver, SSHMUX_VER); 1490204917Sdes debug2("%s: master version %u", __func__, ver); 1491204917Sdes /* No extensions are presently defined */ 1492204917Sdes while (buffer_len(&m) > 0) { 1493204917Sdes char *name = buffer_get_string(&m, NULL); 1494204917Sdes char *value = buffer_get_string(&m, NULL); 1495204917Sdes 1496204917Sdes debug2("Unrecognised master extension \"%s\"", name); 1497255767Sdes free(name); 1498255767Sdes free(value); 1499204917Sdes } 1500204917Sdes buffer_free(&m); 1501204917Sdes return 0; 1502204917Sdes} 1503204917Sdes 1504204917Sdesstatic u_int 1505204917Sdesmux_client_request_alive(int fd) 1506204917Sdes{ 1507204917Sdes Buffer m; 1508204917Sdes char *e; 1509204917Sdes u_int pid, type, rid; 1510204917Sdes 1511204917Sdes debug3("%s: entering", __func__); 1512204917Sdes 1513204917Sdes buffer_init(&m); 1514204917Sdes buffer_put_int(&m, MUX_C_ALIVE_CHECK); 1515204917Sdes buffer_put_int(&m, muxclient_request_id); 1516204917Sdes 1517204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1518204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1519204917Sdes 1520204917Sdes buffer_clear(&m); 1521204917Sdes 1522204917Sdes /* Read their reply */ 1523204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1524180750Sdes buffer_free(&m); 1525180750Sdes return 0; 1526180750Sdes } 1527180750Sdes 1528204917Sdes type = buffer_get_int(&m); 1529204917Sdes if (type != MUX_S_ALIVE) { 1530204917Sdes e = buffer_get_string(&m, NULL); 1531204917Sdes fatal("%s: master returned error: %s", __func__, e); 1532204917Sdes } 1533180750Sdes 1534204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1535204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1536204917Sdes __func__, muxclient_request_id, rid); 1537204917Sdes pid = buffer_get_int(&m); 1538204917Sdes buffer_free(&m); 1539204917Sdes 1540204917Sdes debug3("%s: done pid = %u", __func__, pid); 1541204917Sdes 1542204917Sdes muxclient_request_id++; 1543204917Sdes 1544204917Sdes return pid; 1545204917Sdes} 1546204917Sdes 1547204917Sdesstatic void 1548204917Sdesmux_client_request_terminate(int fd) 1549204917Sdes{ 1550204917Sdes Buffer m; 1551204917Sdes char *e; 1552204917Sdes u_int type, rid; 1553204917Sdes 1554204917Sdes debug3("%s: entering", __func__); 1555204917Sdes 1556204917Sdes buffer_init(&m); 1557204917Sdes buffer_put_int(&m, MUX_C_TERMINATE); 1558204917Sdes buffer_put_int(&m, muxclient_request_id); 1559204917Sdes 1560204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1561204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1562204917Sdes 1563180750Sdes buffer_clear(&m); 1564180750Sdes 1565204917Sdes /* Read their reply */ 1566204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1567204917Sdes /* Remote end exited already */ 1568204917Sdes if (errno == EPIPE) { 1569180750Sdes buffer_free(&m); 1570204917Sdes return; 1571180750Sdes } 1572204917Sdes fatal("%s: read from master failed: %s", 1573204917Sdes __func__, strerror(errno)); 1574204917Sdes } 1575204917Sdes 1576204917Sdes type = buffer_get_int(&m); 1577204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1578204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1579204917Sdes __func__, muxclient_request_id, rid); 1580204917Sdes switch (type) { 1581204917Sdes case MUX_S_OK: 1582204917Sdes break; 1583204917Sdes case MUX_S_PERMISSION_DENIED: 1584204917Sdes e = buffer_get_string(&m, NULL); 1585204917Sdes fatal("Master refused termination request: %s", e); 1586204917Sdes case MUX_S_FAILURE: 1587204917Sdes e = buffer_get_string(&m, NULL); 1588204917Sdes fatal("%s: termination request failed: %s", __func__, e); 1589180750Sdes default: 1590204917Sdes fatal("%s: unexpected response from master 0x%08x", 1591204917Sdes __func__, type); 1592180750Sdes } 1593204917Sdes buffer_free(&m); 1594204917Sdes muxclient_request_id++; 1595204917Sdes} 1596180750Sdes 1597204917Sdesstatic int 1598240075Sdesmux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *fwd) 1599204917Sdes{ 1600204917Sdes Buffer m; 1601204917Sdes char *e, *fwd_desc; 1602204917Sdes u_int type, rid; 1603204917Sdes 1604204917Sdes fwd_desc = format_forward(ftype, fwd); 1605240075Sdes debug("Requesting %s %s", 1606240075Sdes cancel_flag ? "cancellation of" : "forwarding of", fwd_desc); 1607255767Sdes free(fwd_desc); 1608204917Sdes 1609204917Sdes buffer_init(&m); 1610240075Sdes buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD); 1611204917Sdes buffer_put_int(&m, muxclient_request_id); 1612204917Sdes buffer_put_int(&m, ftype); 1613204917Sdes buffer_put_cstring(&m, 1614204917Sdes fwd->listen_host == NULL ? "" : fwd->listen_host); 1615204917Sdes buffer_put_int(&m, fwd->listen_port); 1616204917Sdes buffer_put_cstring(&m, 1617204917Sdes fwd->connect_host == NULL ? "" : fwd->connect_host); 1618204917Sdes buffer_put_int(&m, fwd->connect_port); 1619204917Sdes 1620204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1621204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1622204917Sdes 1623180750Sdes buffer_clear(&m); 1624204917Sdes 1625204917Sdes /* Read their reply */ 1626204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1627180750Sdes buffer_free(&m); 1628204917Sdes return -1; 1629180750Sdes } 1630180750Sdes 1631204917Sdes type = buffer_get_int(&m); 1632204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1633204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1634204917Sdes __func__, muxclient_request_id, rid); 1635204917Sdes switch (type) { 1636204917Sdes case MUX_S_OK: 1637204917Sdes break; 1638215116Sdes case MUX_S_REMOTE_PORT: 1639240075Sdes if (cancel_flag) 1640240075Sdes fatal("%s: got MUX_S_REMOTE_PORT for cancel", __func__); 1641215116Sdes fwd->allocated_port = buffer_get_int(&m); 1642215116Sdes logit("Allocated port %u for remote forward to %s:%d", 1643215116Sdes fwd->allocated_port, 1644215116Sdes fwd->connect_host ? fwd->connect_host : "", 1645215116Sdes fwd->connect_port); 1646215116Sdes if (muxclient_command == SSHMUX_COMMAND_FORWARD) 1647215116Sdes fprintf(stdout, "%u\n", fwd->allocated_port); 1648215116Sdes break; 1649204917Sdes case MUX_S_PERMISSION_DENIED: 1650204917Sdes e = buffer_get_string(&m, NULL); 1651180750Sdes buffer_free(&m); 1652204917Sdes error("Master refused forwarding request: %s", e); 1653204917Sdes return -1; 1654204917Sdes case MUX_S_FAILURE: 1655204917Sdes e = buffer_get_string(&m, NULL); 1656204917Sdes buffer_free(&m); 1657221420Sdes error("%s: forwarding request failed: %s", __func__, e); 1658204917Sdes return -1; 1659204917Sdes default: 1660204917Sdes fatal("%s: unexpected response from master 0x%08x", 1661204917Sdes __func__, type); 1662180750Sdes } 1663204917Sdes buffer_free(&m); 1664180750Sdes 1665204917Sdes muxclient_request_id++; 1666204917Sdes return 0; 1667204917Sdes} 1668204917Sdes 1669204917Sdesstatic int 1670240075Sdesmux_client_forwards(int fd, int cancel_flag) 1671204917Sdes{ 1672240075Sdes int i, ret = 0; 1673204917Sdes 1674240075Sdes debug3("%s: %s forwardings: %d local, %d remote", __func__, 1675240075Sdes cancel_flag ? "cancel" : "request", 1676204917Sdes options.num_local_forwards, options.num_remote_forwards); 1677204917Sdes 1678204917Sdes /* XXX ExitOnForwardingFailure */ 1679204917Sdes for (i = 0; i < options.num_local_forwards; i++) { 1680240075Sdes if (mux_client_forward(fd, cancel_flag, 1681204917Sdes options.local_forwards[i].connect_port == 0 ? 1682204917Sdes MUX_FWD_DYNAMIC : MUX_FWD_LOCAL, 1683204917Sdes options.local_forwards + i) != 0) 1684240075Sdes ret = -1; 1685180750Sdes } 1686204917Sdes for (i = 0; i < options.num_remote_forwards; i++) { 1687240075Sdes if (mux_client_forward(fd, cancel_flag, MUX_FWD_REMOTE, 1688204917Sdes options.remote_forwards + i) != 0) 1689240075Sdes ret = -1; 1690180750Sdes } 1691240075Sdes return ret; 1692204917Sdes} 1693180750Sdes 1694204917Sdesstatic int 1695204917Sdesmux_client_request_session(int fd) 1696204917Sdes{ 1697204917Sdes Buffer m; 1698204917Sdes char *e, *term; 1699204917Sdes u_int i, rid, sid, esid, exitval, type, exitval_seen; 1700204917Sdes extern char **environ; 1701226046Sdes int devnull, rawmode; 1702180750Sdes 1703204917Sdes debug3("%s: entering", __func__); 1704180750Sdes 1705204917Sdes if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { 1706204917Sdes error("%s: master alive request failed", __func__); 1707204917Sdes return -1; 1708180750Sdes } 1709180750Sdes 1710204917Sdes signal(SIGPIPE, SIG_IGN); 1711180750Sdes 1712204917Sdes if (stdin_null_flag) { 1713204917Sdes if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) 1714204917Sdes fatal("open(/dev/null): %s", strerror(errno)); 1715204917Sdes if (dup2(devnull, STDIN_FILENO) == -1) 1716204917Sdes fatal("dup2: %s", strerror(errno)); 1717204917Sdes if (devnull > STDERR_FILENO) 1718204917Sdes close(devnull); 1719180750Sdes } 1720180750Sdes 1721204917Sdes term = getenv("TERM"); 1722180750Sdes 1723204917Sdes buffer_init(&m); 1724204917Sdes buffer_put_int(&m, MUX_C_NEW_SESSION); 1725204917Sdes buffer_put_int(&m, muxclient_request_id); 1726204917Sdes buffer_put_cstring(&m, ""); /* reserved */ 1727204917Sdes buffer_put_int(&m, tty_flag); 1728204917Sdes buffer_put_int(&m, options.forward_x11); 1729204917Sdes buffer_put_int(&m, options.forward_agent); 1730204917Sdes buffer_put_int(&m, subsystem_flag); 1731204917Sdes buffer_put_int(&m, options.escape_char == SSH_ESCAPECHAR_NONE ? 1732204917Sdes 0xffffffff : (u_int)options.escape_char); 1733204917Sdes buffer_put_cstring(&m, term == NULL ? "" : term); 1734204917Sdes buffer_put_string(&m, buffer_ptr(&command), buffer_len(&command)); 1735180750Sdes 1736204917Sdes if (options.num_send_env > 0 && environ != NULL) { 1737204917Sdes /* Pass environment */ 1738204917Sdes for (i = 0; environ[i] != NULL; i++) { 1739204917Sdes if (env_permitted(environ[i])) { 1740204917Sdes buffer_put_cstring(&m, environ[i]); 1741204917Sdes } 1742180750Sdes } 1743180750Sdes } 1744180750Sdes 1745204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1746204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1747180750Sdes 1748204917Sdes /* Send the stdio file descriptors */ 1749204917Sdes if (mm_send_fd(fd, STDIN_FILENO) == -1 || 1750204917Sdes mm_send_fd(fd, STDOUT_FILENO) == -1 || 1751204917Sdes mm_send_fd(fd, STDERR_FILENO) == -1) 1752204917Sdes fatal("%s: send fds failed", __func__); 1753180750Sdes 1754204917Sdes debug3("%s: session request sent", __func__); 1755204917Sdes 1756204917Sdes /* Read their reply */ 1757204917Sdes buffer_clear(&m); 1758204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1759204917Sdes error("%s: read from master failed: %s", 1760204917Sdes __func__, strerror(errno)); 1761204917Sdes buffer_free(&m); 1762204917Sdes return -1; 1763180750Sdes } 1764180750Sdes 1765204917Sdes type = buffer_get_int(&m); 1766204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1767204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1768204917Sdes __func__, muxclient_request_id, rid); 1769204917Sdes switch (type) { 1770204917Sdes case MUX_S_SESSION_OPENED: 1771204917Sdes sid = buffer_get_int(&m); 1772204917Sdes debug("%s: master session id: %u", __func__, sid); 1773204917Sdes break; 1774204917Sdes case MUX_S_PERMISSION_DENIED: 1775204917Sdes e = buffer_get_string(&m, NULL); 1776204917Sdes buffer_free(&m); 1777221420Sdes error("Master refused session request: %s", e); 1778204917Sdes return -1; 1779204917Sdes case MUX_S_FAILURE: 1780204917Sdes e = buffer_get_string(&m, NULL); 1781204917Sdes buffer_free(&m); 1782221420Sdes error("%s: session request failed: %s", __func__, e); 1783204917Sdes return -1; 1784204917Sdes default: 1785204917Sdes buffer_free(&m); 1786204917Sdes error("%s: unexpected response from master 0x%08x", 1787204917Sdes __func__, type); 1788204917Sdes return -1; 1789180750Sdes } 1790204917Sdes muxclient_request_id++; 1791180750Sdes 1792204917Sdes signal(SIGHUP, control_client_sighandler); 1793204917Sdes signal(SIGINT, control_client_sighandler); 1794204917Sdes signal(SIGTERM, control_client_sighandler); 1795204917Sdes signal(SIGWINCH, control_client_sigrelay); 1796180750Sdes 1797226046Sdes rawmode = tty_flag; 1798204917Sdes if (tty_flag) 1799226046Sdes enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); 1800180750Sdes 1801204917Sdes /* 1802204917Sdes * Stick around until the controlee closes the client_fd. 1803204917Sdes * Before it does, it is expected to write an exit message. 1804204917Sdes * This process must read the value and wait for the closure of 1805204917Sdes * the client_fd; if this one closes early, the multiplex master will 1806204917Sdes * terminate early too (possibly losing data). 1807204917Sdes */ 1808204917Sdes for (exitval = 255, exitval_seen = 0;;) { 1809204917Sdes buffer_clear(&m); 1810204917Sdes if (mux_client_read_packet(fd, &m) != 0) 1811204917Sdes break; 1812204917Sdes type = buffer_get_int(&m); 1813226046Sdes switch (type) { 1814226046Sdes case MUX_S_TTY_ALLOC_FAIL: 1815226046Sdes if ((esid = buffer_get_int(&m)) != sid) 1816226046Sdes fatal("%s: tty alloc fail on unknown session: " 1817226046Sdes "my id %u theirs %u", 1818226046Sdes __func__, sid, esid); 1819226046Sdes leave_raw_mode(options.request_tty == 1820226046Sdes REQUEST_TTY_FORCE); 1821226046Sdes rawmode = 0; 1822226046Sdes continue; 1823226046Sdes case MUX_S_EXIT_MESSAGE: 1824226046Sdes if ((esid = buffer_get_int(&m)) != sid) 1825226046Sdes fatal("%s: exit on unknown session: " 1826226046Sdes "my id %u theirs %u", 1827226046Sdes __func__, sid, esid); 1828226046Sdes if (exitval_seen) 1829226046Sdes fatal("%s: exitval sent twice", __func__); 1830226046Sdes exitval = buffer_get_int(&m); 1831226046Sdes exitval_seen = 1; 1832226046Sdes continue; 1833226046Sdes default: 1834204917Sdes e = buffer_get_string(&m, NULL); 1835204917Sdes fatal("%s: master returned error: %s", __func__, e); 1836204917Sdes } 1837204917Sdes } 1838180750Sdes 1839204917Sdes close(fd); 1840226046Sdes if (rawmode) 1841226046Sdes leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); 1842180750Sdes 1843204917Sdes if (muxclient_terminate) { 1844255767Sdes debug2("Exiting on signal %ld", (long)muxclient_terminate); 1845204917Sdes exitval = 255; 1846204917Sdes } else if (!exitval_seen) { 1847204917Sdes debug2("Control master terminated unexpectedly"); 1848204917Sdes exitval = 255; 1849204917Sdes } else 1850204917Sdes debug2("Received exit status from master %d", exitval); 1851180750Sdes 1852204917Sdes if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) 1853204917Sdes fprintf(stderr, "Shared connection to %s closed.\r\n", host); 1854180750Sdes 1855204917Sdes exit(exitval); 1856180750Sdes} 1857180750Sdes 1858180750Sdesstatic int 1859204917Sdesmux_client_request_stdio_fwd(int fd) 1860180750Sdes{ 1861204917Sdes Buffer m; 1862204917Sdes char *e; 1863204917Sdes u_int type, rid, sid; 1864204917Sdes int devnull; 1865180750Sdes 1866204917Sdes debug3("%s: entering", __func__); 1867180750Sdes 1868204917Sdes if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { 1869204917Sdes error("%s: master alive request failed", __func__); 1870204917Sdes return -1; 1871204917Sdes } 1872180750Sdes 1873204917Sdes signal(SIGPIPE, SIG_IGN); 1874204917Sdes 1875204917Sdes if (stdin_null_flag) { 1876204917Sdes if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) 1877204917Sdes fatal("open(/dev/null): %s", strerror(errno)); 1878204917Sdes if (dup2(devnull, STDIN_FILENO) == -1) 1879204917Sdes fatal("dup2: %s", strerror(errno)); 1880204917Sdes if (devnull > STDERR_FILENO) 1881204917Sdes close(devnull); 1882204917Sdes } 1883204917Sdes 1884204917Sdes buffer_init(&m); 1885204917Sdes buffer_put_int(&m, MUX_C_NEW_STDIO_FWD); 1886204917Sdes buffer_put_int(&m, muxclient_request_id); 1887204917Sdes buffer_put_cstring(&m, ""); /* reserved */ 1888204917Sdes buffer_put_cstring(&m, stdio_forward_host); 1889204917Sdes buffer_put_int(&m, stdio_forward_port); 1890204917Sdes 1891204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1892204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1893204917Sdes 1894204917Sdes /* Send the stdio file descriptors */ 1895204917Sdes if (mm_send_fd(fd, STDIN_FILENO) == -1 || 1896204917Sdes mm_send_fd(fd, STDOUT_FILENO) == -1) 1897204917Sdes fatal("%s: send fds failed", __func__); 1898204917Sdes 1899204917Sdes debug3("%s: stdio forward request sent", __func__); 1900204917Sdes 1901204917Sdes /* Read their reply */ 1902204917Sdes buffer_clear(&m); 1903204917Sdes 1904204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1905204917Sdes error("%s: read from master failed: %s", 1906204917Sdes __func__, strerror(errno)); 1907204917Sdes buffer_free(&m); 1908204917Sdes return -1; 1909204917Sdes } 1910204917Sdes 1911204917Sdes type = buffer_get_int(&m); 1912204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1913204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1914204917Sdes __func__, muxclient_request_id, rid); 1915204917Sdes switch (type) { 1916204917Sdes case MUX_S_SESSION_OPENED: 1917204917Sdes sid = buffer_get_int(&m); 1918204917Sdes debug("%s: master session id: %u", __func__, sid); 1919204917Sdes break; 1920204917Sdes case MUX_S_PERMISSION_DENIED: 1921204917Sdes e = buffer_get_string(&m, NULL); 1922204917Sdes buffer_free(&m); 1923221420Sdes fatal("Master refused stdio forwarding request: %s", e); 1924204917Sdes case MUX_S_FAILURE: 1925204917Sdes e = buffer_get_string(&m, NULL); 1926204917Sdes buffer_free(&m); 1927204917Sdes fatal("%s: stdio forwarding request failed: %s", __func__, e); 1928204917Sdes default: 1929204917Sdes buffer_free(&m); 1930204917Sdes error("%s: unexpected response from master 0x%08x", 1931204917Sdes __func__, type); 1932204917Sdes return -1; 1933204917Sdes } 1934204917Sdes muxclient_request_id++; 1935204917Sdes 1936204917Sdes signal(SIGHUP, control_client_sighandler); 1937204917Sdes signal(SIGINT, control_client_sighandler); 1938204917Sdes signal(SIGTERM, control_client_sighandler); 1939204917Sdes signal(SIGWINCH, control_client_sigrelay); 1940204917Sdes 1941204917Sdes /* 1942204917Sdes * Stick around until the controlee closes the client_fd. 1943204917Sdes */ 1944204917Sdes buffer_clear(&m); 1945204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1946204917Sdes if (errno == EPIPE || 1947204917Sdes (errno == EINTR && muxclient_terminate != 0)) 1948204917Sdes return 0; 1949204917Sdes fatal("%s: mux_client_read_packet: %s", 1950204917Sdes __func__, strerror(errno)); 1951204917Sdes } 1952204917Sdes fatal("%s: master returned unexpected message %u", __func__, type); 1953180750Sdes} 1954180750Sdes 1955226046Sdesstatic void 1956226046Sdesmux_client_request_stop_listening(int fd) 1957226046Sdes{ 1958226046Sdes Buffer m; 1959226046Sdes char *e; 1960226046Sdes u_int type, rid; 1961226046Sdes 1962226046Sdes debug3("%s: entering", __func__); 1963226046Sdes 1964226046Sdes buffer_init(&m); 1965226046Sdes buffer_put_int(&m, MUX_C_STOP_LISTENING); 1966226046Sdes buffer_put_int(&m, muxclient_request_id); 1967226046Sdes 1968226046Sdes if (mux_client_write_packet(fd, &m) != 0) 1969226046Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1970226046Sdes 1971226046Sdes buffer_clear(&m); 1972226046Sdes 1973226046Sdes /* Read their reply */ 1974226046Sdes if (mux_client_read_packet(fd, &m) != 0) 1975226046Sdes fatal("%s: read from master failed: %s", 1976226046Sdes __func__, strerror(errno)); 1977226046Sdes 1978226046Sdes type = buffer_get_int(&m); 1979226046Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1980226046Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1981226046Sdes __func__, muxclient_request_id, rid); 1982226046Sdes switch (type) { 1983226046Sdes case MUX_S_OK: 1984226046Sdes break; 1985226046Sdes case MUX_S_PERMISSION_DENIED: 1986226046Sdes e = buffer_get_string(&m, NULL); 1987226046Sdes fatal("Master refused stop listening request: %s", e); 1988226046Sdes case MUX_S_FAILURE: 1989226046Sdes e = buffer_get_string(&m, NULL); 1990226046Sdes fatal("%s: stop listening request failed: %s", __func__, e); 1991226046Sdes default: 1992226046Sdes fatal("%s: unexpected response from master 0x%08x", 1993226046Sdes __func__, type); 1994226046Sdes } 1995226046Sdes buffer_free(&m); 1996226046Sdes muxclient_request_id++; 1997226046Sdes} 1998226046Sdes 1999180750Sdes/* Multiplex client main loop. */ 2000180750Sdesvoid 2001180750Sdesmuxclient(const char *path) 2002180750Sdes{ 2003180750Sdes struct sockaddr_un addr; 2004204917Sdes socklen_t sun_len; 2005204917Sdes int sock; 2006204917Sdes u_int pid; 2007180750Sdes 2008204917Sdes if (muxclient_command == 0) { 2009204917Sdes if (stdio_forward_host != NULL) 2010204917Sdes muxclient_command = SSHMUX_COMMAND_STDIO_FWD; 2011204917Sdes else 2012204917Sdes muxclient_command = SSHMUX_COMMAND_OPEN; 2013204917Sdes } 2014180750Sdes 2015180750Sdes switch (options.control_master) { 2016180750Sdes case SSHCTL_MASTER_AUTO: 2017180750Sdes case SSHCTL_MASTER_AUTO_ASK: 2018180750Sdes debug("auto-mux: Trying existing master"); 2019180750Sdes /* FALLTHROUGH */ 2020180750Sdes case SSHCTL_MASTER_NO: 2021180750Sdes break; 2022180750Sdes default: 2023180750Sdes return; 2024180750Sdes } 2025180750Sdes 2026180750Sdes memset(&addr, '\0', sizeof(addr)); 2027180750Sdes addr.sun_family = AF_UNIX; 2028204917Sdes sun_len = offsetof(struct sockaddr_un, sun_path) + 2029180750Sdes strlen(path) + 1; 2030180750Sdes 2031180750Sdes if (strlcpy(addr.sun_path, path, 2032180750Sdes sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) 2033180750Sdes fatal("ControlPath too long"); 2034180750Sdes 2035180750Sdes if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) 2036180750Sdes fatal("%s socket(): %s", __func__, strerror(errno)); 2037180750Sdes 2038204917Sdes if (connect(sock, (struct sockaddr *)&addr, sun_len) == -1) { 2039204917Sdes switch (muxclient_command) { 2040204917Sdes case SSHMUX_COMMAND_OPEN: 2041204917Sdes case SSHMUX_COMMAND_STDIO_FWD: 2042204917Sdes break; 2043204917Sdes default: 2044180750Sdes fatal("Control socket connect(%.100s): %s", path, 2045180750Sdes strerror(errno)); 2046180750Sdes } 2047221420Sdes if (errno == ECONNREFUSED && 2048221420Sdes options.control_master != SSHCTL_MASTER_NO) { 2049221420Sdes debug("Stale control socket %.100s, unlinking", path); 2050221420Sdes unlink(path); 2051221420Sdes } else if (errno == ENOENT) { 2052180750Sdes debug("Control socket \"%.100s\" does not exist", path); 2053221420Sdes } else { 2054180750Sdes error("Control socket connect(%.100s): %s", path, 2055180750Sdes strerror(errno)); 2056180750Sdes } 2057180750Sdes close(sock); 2058180750Sdes return; 2059180750Sdes } 2060204917Sdes set_nonblock(sock); 2061180750Sdes 2062204917Sdes if (mux_client_hello_exchange(sock) != 0) { 2063204917Sdes error("%s: master hello exchange failed", __func__); 2064180750Sdes close(sock); 2065180750Sdes return; 2066180750Sdes } 2067180750Sdes 2068180750Sdes switch (muxclient_command) { 2069180750Sdes case SSHMUX_COMMAND_ALIVE_CHECK: 2070204917Sdes if ((pid = mux_client_request_alive(sock)) == 0) 2071204917Sdes fatal("%s: master alive check failed", __func__); 2072204917Sdes fprintf(stderr, "Master running (pid=%d)\r\n", pid); 2073180750Sdes exit(0); 2074180750Sdes case SSHMUX_COMMAND_TERMINATE: 2075204917Sdes mux_client_request_terminate(sock); 2076180750Sdes fprintf(stderr, "Exit request sent.\r\n"); 2077180750Sdes exit(0); 2078215116Sdes case SSHMUX_COMMAND_FORWARD: 2079240075Sdes if (mux_client_forwards(sock, 0) != 0) 2080215116Sdes fatal("%s: master forward request failed", __func__); 2081215116Sdes exit(0); 2082180750Sdes case SSHMUX_COMMAND_OPEN: 2083240075Sdes if (mux_client_forwards(sock, 0) != 0) { 2084204917Sdes error("%s: master forward request failed", __func__); 2085204917Sdes return; 2086180750Sdes } 2087204917Sdes mux_client_request_session(sock); 2088204917Sdes return; 2089204917Sdes case SSHMUX_COMMAND_STDIO_FWD: 2090204917Sdes mux_client_request_stdio_fwd(sock); 2091204917Sdes exit(0); 2092226046Sdes case SSHMUX_COMMAND_STOP: 2093226046Sdes mux_client_request_stop_listening(sock); 2094226046Sdes fprintf(stderr, "Stop listening request sent.\r\n"); 2095226046Sdes exit(0); 2096240075Sdes case SSHMUX_COMMAND_CANCEL_FWD: 2097240075Sdes if (mux_client_forwards(sock, 1) != 0) 2098240075Sdes error("%s: master cancel forward request failed", 2099240075Sdes __func__); 2100240075Sdes exit(0); 2101180750Sdes default: 2102180750Sdes fatal("unrecognised muxclient_command %d", muxclient_command); 2103180750Sdes } 2104180750Sdes} 2105