mux.c revision 204917
1204917Sdes/* $OpenBSD: mux.c,v 1.14 2010/01/30 02:54:53 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#ifdef HAVE_LIBUTIL_H 67180750Sdes# include <libutil.h> 68180750Sdes#endif 69180750Sdes 70180750Sdes#include "openbsd-compat/sys-queue.h" 71180750Sdes#include "xmalloc.h" 72180750Sdes#include "log.h" 73180750Sdes#include "ssh.h" 74180750Sdes#include "pathnames.h" 75180750Sdes#include "misc.h" 76180750Sdes#include "match.h" 77180750Sdes#include "buffer.h" 78180750Sdes#include "channels.h" 79180750Sdes#include "msg.h" 80180750Sdes#include "packet.h" 81180750Sdes#include "monitor_fdpass.h" 82180750Sdes#include "sshpty.h" 83180750Sdes#include "key.h" 84180750Sdes#include "readconf.h" 85180750Sdes#include "clientloop.h" 86180750Sdes 87180750Sdes/* from ssh.c */ 88180750Sdesextern int tty_flag; 89204917Sdesextern int force_tty_flag; 90180750Sdesextern Options options; 91180750Sdesextern int stdin_null_flag; 92180750Sdesextern char *host; 93204917Sdesextern int subsystem_flag; 94180750Sdesextern Buffer command; 95204917Sdesextern volatile sig_atomic_t quit_pending; 96204917Sdesextern char *stdio_forward_host; 97204917Sdesextern int stdio_forward_port; 98180750Sdes 99180750Sdes/* Context for session open confirmation callback */ 100180750Sdesstruct mux_session_confirm_ctx { 101204917Sdes u_int want_tty; 102204917Sdes u_int want_subsys; 103204917Sdes u_int want_x_fwd; 104204917Sdes u_int want_agent_fwd; 105180750Sdes Buffer cmd; 106180750Sdes char *term; 107180750Sdes struct termios tio; 108180750Sdes char **env; 109180750Sdes}; 110180750Sdes 111180750Sdes/* fd to control socket */ 112180750Sdesint muxserver_sock = -1; 113180750Sdes 114204917Sdes/* client request id */ 115204917Sdesu_int muxclient_request_id = 0; 116204917Sdes 117180750Sdes/* Multiplexing control command */ 118180750Sdesu_int muxclient_command = 0; 119180750Sdes 120180750Sdes/* Set when signalled. */ 121180750Sdesstatic volatile sig_atomic_t muxclient_terminate = 0; 122180750Sdes 123180750Sdes/* PID of multiplex server */ 124180750Sdesstatic u_int muxserver_pid = 0; 125180750Sdes 126204917Sdesstatic Channel *mux_listener_channel = NULL; 127180750Sdes 128204917Sdesstruct mux_master_state { 129204917Sdes int hello_rcvd; 130204917Sdes}; 131180750Sdes 132204917Sdes/* mux protocol messages */ 133204917Sdes#define MUX_MSG_HELLO 0x00000001 134204917Sdes#define MUX_C_NEW_SESSION 0x10000002 135204917Sdes#define MUX_C_ALIVE_CHECK 0x10000004 136204917Sdes#define MUX_C_TERMINATE 0x10000005 137204917Sdes#define MUX_C_OPEN_FWD 0x10000006 138204917Sdes#define MUX_C_CLOSE_FWD 0x10000007 139204917Sdes#define MUX_C_NEW_STDIO_FWD 0x10000008 140204917Sdes#define MUX_S_OK 0x80000001 141204917Sdes#define MUX_S_PERMISSION_DENIED 0x80000002 142204917Sdes#define MUX_S_FAILURE 0x80000003 143204917Sdes#define MUX_S_EXIT_MESSAGE 0x80000004 144204917Sdes#define MUX_S_ALIVE 0x80000005 145204917Sdes#define MUX_S_SESSION_OPENED 0x80000006 146204917Sdes 147204917Sdes/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ 148204917Sdes#define MUX_FWD_LOCAL 1 149204917Sdes#define MUX_FWD_REMOTE 2 150204917Sdes#define MUX_FWD_DYNAMIC 3 151204917Sdes 152204917Sdesstatic void mux_session_confirm(int, void *); 153204917Sdes 154204917Sdesstatic int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); 155204917Sdesstatic int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); 156204917Sdesstatic int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *); 157204917Sdesstatic int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *); 158204917Sdesstatic int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); 159204917Sdesstatic int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); 160204917Sdesstatic int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); 161204917Sdes 162204917Sdesstatic const struct { 163204917Sdes u_int type; 164204917Sdes int (*handler)(u_int, Channel *, Buffer *, Buffer *); 165204917Sdes} mux_master_handlers[] = { 166204917Sdes { MUX_MSG_HELLO, process_mux_master_hello }, 167204917Sdes { MUX_C_NEW_SESSION, process_mux_new_session }, 168204917Sdes { MUX_C_ALIVE_CHECK, process_mux_alive_check }, 169204917Sdes { MUX_C_TERMINATE, process_mux_terminate }, 170204917Sdes { MUX_C_OPEN_FWD, process_mux_open_fwd }, 171204917Sdes { MUX_C_CLOSE_FWD, process_mux_close_fwd }, 172204917Sdes { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, 173204917Sdes { 0, NULL } 174204917Sdes}; 175204917Sdes 176204917Sdes/* Cleanup callback fired on closure of mux slave _session_ channel */ 177204917Sdes/* ARGSUSED */ 178204917Sdesstatic void 179204917Sdesmux_master_session_cleanup_cb(int cid, void *unused) 180204917Sdes{ 181204917Sdes Channel *cc, *c = channel_by_id(cid); 182204917Sdes 183204917Sdes debug3("%s: entering for channel %d", __func__, cid); 184204917Sdes if (c == NULL) 185204917Sdes fatal("%s: channel_by_id(%i) == NULL", __func__, cid); 186204917Sdes if (c->ctl_chan != -1) { 187204917Sdes if ((cc = channel_by_id(c->ctl_chan)) == NULL) 188204917Sdes fatal("%s: channel %d missing control channel %d", 189204917Sdes __func__, c->self, c->ctl_chan); 190204917Sdes c->ctl_chan = -1; 191204917Sdes cc->remote_id = -1; 192204917Sdes chan_rcvd_oclose(cc); 193204917Sdes } 194204917Sdes channel_cancel_cleanup(c->self); 195204917Sdes} 196204917Sdes 197204917Sdes/* Cleanup callback fired on closure of mux slave _control_ channel */ 198204917Sdes/* ARGSUSED */ 199204917Sdesstatic void 200204917Sdesmux_master_control_cleanup_cb(int cid, void *unused) 201204917Sdes{ 202204917Sdes Channel *sc, *c = channel_by_id(cid); 203204917Sdes 204204917Sdes debug3("%s: entering for channel %d", __func__, cid); 205204917Sdes if (c == NULL) 206204917Sdes fatal("%s: channel_by_id(%i) == NULL", __func__, cid); 207204917Sdes if (c->remote_id != -1) { 208204917Sdes if ((sc = channel_by_id(c->remote_id)) == NULL) 209204917Sdes debug2("%s: channel %d n session channel %d", 210204917Sdes __func__, c->self, c->remote_id); 211204917Sdes c->remote_id = -1; 212204917Sdes sc->ctl_chan = -1; 213204917Sdes if (sc->type != SSH_CHANNEL_OPEN) { 214204917Sdes debug2("%s: channel %d: not open", __func__, sc->self); 215204917Sdes chan_mark_dead(sc); 216204917Sdes } else { 217204917Sdes if (sc->istate == CHAN_INPUT_OPEN) 218204917Sdes chan_read_failed(sc); 219204917Sdes if (sc->ostate == CHAN_OUTPUT_OPEN) 220204917Sdes chan_write_failed(sc); 221204917Sdes } 222204917Sdes } 223204917Sdes channel_cancel_cleanup(c->self); 224204917Sdes} 225204917Sdes 226204917Sdes/* Check mux client environment variables before passing them to mux master. */ 227204917Sdesstatic int 228204917Sdesenv_permitted(char *env) 229204917Sdes{ 230204917Sdes int i, ret; 231204917Sdes char name[1024], *cp; 232204917Sdes 233204917Sdes if ((cp = strchr(env, '=')) == NULL || cp == env) 234204917Sdes return 0; 235204917Sdes ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env); 236204917Sdes if (ret <= 0 || (size_t)ret >= sizeof(name)) { 237204917Sdes error("env_permitted: name '%.100s...' too long", env); 238204917Sdes return 0; 239204917Sdes } 240204917Sdes 241204917Sdes for (i = 0; i < options.num_send_env; i++) 242204917Sdes if (match_pattern(name, options.send_env[i])) 243204917Sdes return 1; 244204917Sdes 245204917Sdes return 0; 246204917Sdes} 247204917Sdes 248204917Sdes/* Mux master protocol message handlers */ 249204917Sdes 250204917Sdesstatic int 251204917Sdesprocess_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r) 252204917Sdes{ 253204917Sdes u_int ver; 254204917Sdes struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; 255204917Sdes 256204917Sdes if (state == NULL) 257204917Sdes fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self); 258204917Sdes if (state->hello_rcvd) { 259204917Sdes error("%s: HELLO received twice", __func__); 260204917Sdes return -1; 261204917Sdes } 262204917Sdes if (buffer_get_int_ret(&ver, m) != 0) { 263204917Sdes malf: 264204917Sdes error("%s: malformed message", __func__); 265204917Sdes return -1; 266204917Sdes } 267204917Sdes if (ver != SSHMUX_VER) { 268204917Sdes error("Unsupported multiplexing protocol version %d " 269204917Sdes "(expected %d)", ver, SSHMUX_VER); 270204917Sdes return -1; 271204917Sdes } 272204917Sdes debug2("%s: channel %d slave version %u", __func__, c->self, ver); 273204917Sdes 274204917Sdes /* No extensions are presently defined */ 275204917Sdes while (buffer_len(m) > 0) { 276204917Sdes char *name = buffer_get_string_ret(m, NULL); 277204917Sdes char *value = buffer_get_string_ret(m, NULL); 278204917Sdes 279204917Sdes if (name == NULL || value == NULL) { 280204917Sdes if (name != NULL) 281204917Sdes xfree(name); 282204917Sdes goto malf; 283204917Sdes } 284204917Sdes debug2("Unrecognised slave extension \"%s\"", name); 285204917Sdes xfree(name); 286204917Sdes xfree(value); 287204917Sdes } 288204917Sdes state->hello_rcvd = 1; 289204917Sdes return 0; 290204917Sdes} 291204917Sdes 292204917Sdesstatic int 293204917Sdesprocess_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) 294204917Sdes{ 295204917Sdes Channel *nc; 296204917Sdes struct mux_session_confirm_ctx *cctx; 297204917Sdes char *reserved, *cmd, *cp; 298204917Sdes u_int i, j, len, env_len, escape_char, window, packetmax; 299204917Sdes int new_fd[3]; 300204917Sdes 301204917Sdes /* Reply for SSHMUX_COMMAND_OPEN */ 302204917Sdes cctx = xcalloc(1, sizeof(*cctx)); 303204917Sdes cctx->term = NULL; 304204917Sdes cmd = reserved = NULL; 305204917Sdes if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || 306204917Sdes buffer_get_int_ret(&cctx->want_tty, m) != 0 || 307204917Sdes buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 || 308204917Sdes buffer_get_int_ret(&cctx->want_agent_fwd, m) != 0 || 309204917Sdes buffer_get_int_ret(&cctx->want_subsys, m) != 0 || 310204917Sdes buffer_get_int_ret(&escape_char, m) != 0 || 311204917Sdes (cctx->term = buffer_get_string_ret(m, &len)) == NULL || 312204917Sdes (cmd = buffer_get_string_ret(m, &len)) == NULL) { 313204917Sdes malf: 314204917Sdes if (cmd != NULL) 315204917Sdes xfree(cmd); 316204917Sdes if (reserved != NULL) 317204917Sdes xfree(reserved); 318204917Sdes if (cctx->term != NULL) 319204917Sdes xfree(cctx->term); 320204917Sdes error("%s: malformed message", __func__); 321204917Sdes return -1; 322204917Sdes } 323204917Sdes xfree(reserved); 324204917Sdes reserved = NULL; 325204917Sdes 326204917Sdes cctx->env = NULL; 327204917Sdes env_len = 0; 328204917Sdes while (buffer_len(m) > 0) { 329204917Sdes#define MUX_MAX_ENV_VARS 4096 330204917Sdes if ((cp = buffer_get_string_ret(m, &len)) == NULL) { 331204917Sdes xfree(cmd); 332204917Sdes goto malf; 333204917Sdes } 334204917Sdes if (!env_permitted(cp)) { 335204917Sdes xfree(cp); 336204917Sdes continue; 337204917Sdes } 338204917Sdes cctx->env = xrealloc(cctx->env, env_len + 2, 339204917Sdes sizeof(*cctx->env)); 340204917Sdes cctx->env[env_len++] = cp; 341204917Sdes cctx->env[env_len] = NULL; 342204917Sdes if (env_len > MUX_MAX_ENV_VARS) { 343204917Sdes error(">%d environment variables received, ignoring " 344204917Sdes "additional", MUX_MAX_ENV_VARS); 345204917Sdes break; 346204917Sdes } 347204917Sdes } 348204917Sdes 349204917Sdes debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, " 350204917Sdes "term \"%s\", cmd \"%s\", env %u", __func__, c->self, 351204917Sdes cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd, 352204917Sdes cctx->want_subsys, cctx->term, cmd, env_len); 353204917Sdes 354204917Sdes buffer_init(&cctx->cmd); 355204917Sdes buffer_append(&cctx->cmd, cmd, strlen(cmd)); 356204917Sdes xfree(cmd); 357204917Sdes cmd = NULL; 358204917Sdes 359204917Sdes /* Gather fds from client */ 360204917Sdes for(i = 0; i < 3; i++) { 361204917Sdes if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { 362204917Sdes error("%s: failed to receive fd %d from slave", 363204917Sdes __func__, i); 364204917Sdes for (j = 0; j < i; j++) 365204917Sdes close(new_fd[j]); 366204917Sdes for (j = 0; j < env_len; j++) 367204917Sdes xfree(cctx->env[j]); 368204917Sdes if (env_len > 0) 369204917Sdes xfree(cctx->env); 370204917Sdes xfree(cctx->term); 371204917Sdes buffer_free(&cctx->cmd); 372204917Sdes xfree(cctx); 373204917Sdes 374204917Sdes /* prepare reply */ 375204917Sdes buffer_put_int(r, MUX_S_FAILURE); 376204917Sdes buffer_put_int(r, rid); 377204917Sdes buffer_put_cstring(r, 378204917Sdes "did not receive file descriptors"); 379204917Sdes return -1; 380204917Sdes } 381204917Sdes } 382204917Sdes 383204917Sdes debug3("%s: got fds stdin %d, stdout %d, stderr %d", __func__, 384204917Sdes new_fd[0], new_fd[1], new_fd[2]); 385204917Sdes 386204917Sdes /* XXX support multiple child sessions in future */ 387204917Sdes if (c->remote_id != -1) { 388204917Sdes debug2("%s: session already open", __func__); 389204917Sdes /* prepare reply */ 390204917Sdes buffer_put_int(r, MUX_S_FAILURE); 391204917Sdes buffer_put_int(r, rid); 392204917Sdes buffer_put_cstring(r, "Multiple sessions not supported"); 393204917Sdes cleanup: 394204917Sdes close(new_fd[0]); 395204917Sdes close(new_fd[1]); 396204917Sdes close(new_fd[2]); 397204917Sdes xfree(cctx->term); 398204917Sdes if (env_len != 0) { 399204917Sdes for (i = 0; i < env_len; i++) 400204917Sdes xfree(cctx->env[i]); 401204917Sdes xfree(cctx->env); 402204917Sdes } 403204917Sdes buffer_free(&cctx->cmd); 404204917Sdes return 0; 405204917Sdes } 406204917Sdes 407204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 408204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 409204917Sdes if (!ask_permission("Allow shared connection to %s? ", host)) { 410204917Sdes debug2("%s: session refused by user", __func__); 411204917Sdes /* prepare reply */ 412204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 413204917Sdes buffer_put_int(r, rid); 414204917Sdes buffer_put_cstring(r, "Permission denied"); 415204917Sdes goto cleanup; 416204917Sdes } 417204917Sdes } 418204917Sdes 419204917Sdes /* Try to pick up ttymodes from client before it goes raw */ 420204917Sdes if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) 421204917Sdes error("%s: tcgetattr: %s", __func__, strerror(errno)); 422204917Sdes 423204917Sdes /* enable nonblocking unless tty */ 424204917Sdes if (!isatty(new_fd[0])) 425204917Sdes set_nonblock(new_fd[0]); 426204917Sdes if (!isatty(new_fd[1])) 427204917Sdes set_nonblock(new_fd[1]); 428204917Sdes if (!isatty(new_fd[2])) 429204917Sdes set_nonblock(new_fd[2]); 430204917Sdes 431204917Sdes window = CHAN_SES_WINDOW_DEFAULT; 432204917Sdes packetmax = CHAN_SES_PACKET_DEFAULT; 433204917Sdes if (cctx->want_tty) { 434204917Sdes window >>= 1; 435204917Sdes packetmax >>= 1; 436204917Sdes } 437204917Sdes 438204917Sdes nc = channel_new("session", SSH_CHANNEL_OPENING, 439204917Sdes new_fd[0], new_fd[1], new_fd[2], window, packetmax, 440204917Sdes CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); 441204917Sdes 442204917Sdes nc->ctl_chan = c->self; /* link session -> control channel */ 443204917Sdes c->remote_id = nc->self; /* link control -> session channel */ 444204917Sdes 445204917Sdes if (cctx->want_tty && escape_char != 0xffffffff) { 446204917Sdes channel_register_filter(nc->self, 447204917Sdes client_simple_escape_filter, NULL, 448204917Sdes client_filter_cleanup, 449204917Sdes client_new_escape_filter_ctx((int)escape_char)); 450204917Sdes } 451204917Sdes 452204917Sdes debug2("%s: channel_new: %d linked to control channel %d", 453204917Sdes __func__, nc->self, nc->ctl_chan); 454204917Sdes 455204917Sdes channel_send_open(nc->self); 456204917Sdes channel_register_open_confirm(nc->self, mux_session_confirm, cctx); 457204917Sdes channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 0); 458204917Sdes 459204917Sdes /* prepare reply */ 460204917Sdes /* XXX defer until mux_session_confirm() fires */ 461204917Sdes buffer_put_int(r, MUX_S_SESSION_OPENED); 462204917Sdes buffer_put_int(r, rid); 463204917Sdes buffer_put_int(r, nc->self); 464204917Sdes 465204917Sdes return 0; 466204917Sdes} 467204917Sdes 468204917Sdesstatic int 469204917Sdesprocess_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r) 470204917Sdes{ 471204917Sdes debug2("%s: channel %d: alive check", __func__, c->self); 472204917Sdes 473204917Sdes /* prepare reply */ 474204917Sdes buffer_put_int(r, MUX_S_ALIVE); 475204917Sdes buffer_put_int(r, rid); 476204917Sdes buffer_put_int(r, (u_int)getpid()); 477204917Sdes 478204917Sdes return 0; 479204917Sdes} 480204917Sdes 481204917Sdesstatic int 482204917Sdesprocess_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r) 483204917Sdes{ 484204917Sdes debug2("%s: channel %d: terminate request", __func__, c->self); 485204917Sdes 486204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 487204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 488204917Sdes if (!ask_permission("Terminate shared connection to %s? ", 489204917Sdes host)) { 490204917Sdes debug2("%s: termination refused by user", __func__); 491204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 492204917Sdes buffer_put_int(r, rid); 493204917Sdes buffer_put_cstring(r, "Permission denied"); 494204917Sdes return 0; 495204917Sdes } 496204917Sdes } 497204917Sdes 498204917Sdes quit_pending = 1; 499204917Sdes buffer_put_int(r, MUX_S_OK); 500204917Sdes buffer_put_int(r, rid); 501204917Sdes /* XXX exit happens too soon - message never makes it to client */ 502204917Sdes return 0; 503204917Sdes} 504204917Sdes 505204917Sdesstatic char * 506204917Sdesformat_forward(u_int ftype, Forward *fwd) 507204917Sdes{ 508204917Sdes char *ret; 509204917Sdes 510204917Sdes switch (ftype) { 511204917Sdes case MUX_FWD_LOCAL: 512204917Sdes xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d", 513204917Sdes (fwd->listen_host == NULL) ? 514204917Sdes (options.gateway_ports ? "*" : "LOCALHOST") : 515204917Sdes fwd->listen_host, fwd->listen_port, 516204917Sdes fwd->connect_host, fwd->connect_port); 517204917Sdes break; 518204917Sdes case MUX_FWD_DYNAMIC: 519204917Sdes xasprintf(&ret, "dynamic forward %.200s:%d -> *", 520204917Sdes (fwd->listen_host == NULL) ? 521204917Sdes (options.gateway_ports ? "*" : "LOCALHOST") : 522204917Sdes fwd->listen_host, fwd->listen_port); 523204917Sdes break; 524204917Sdes case MUX_FWD_REMOTE: 525204917Sdes xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d", 526204917Sdes (fwd->listen_host == NULL) ? 527204917Sdes "LOCALHOST" : fwd->listen_host, 528204917Sdes fwd->listen_port, 529204917Sdes fwd->connect_host, fwd->connect_port); 530204917Sdes break; 531204917Sdes default: 532204917Sdes fatal("%s: unknown forward type %u", __func__, ftype); 533204917Sdes } 534204917Sdes return ret; 535204917Sdes} 536204917Sdes 537204917Sdesstatic int 538204917Sdescompare_host(const char *a, const char *b) 539204917Sdes{ 540204917Sdes if (a == NULL && b == NULL) 541204917Sdes return 1; 542204917Sdes if (a == NULL || b == NULL) 543204917Sdes return 0; 544204917Sdes return strcmp(a, b) == 0; 545204917Sdes} 546204917Sdes 547204917Sdesstatic int 548204917Sdescompare_forward(Forward *a, Forward *b) 549204917Sdes{ 550204917Sdes if (!compare_host(a->listen_host, b->listen_host)) 551204917Sdes return 0; 552204917Sdes if (a->listen_port != b->listen_port) 553204917Sdes return 0; 554204917Sdes if (!compare_host(a->connect_host, b->connect_host)) 555204917Sdes return 0; 556204917Sdes if (a->connect_port != b->connect_port) 557204917Sdes return 0; 558204917Sdes 559204917Sdes return 1; 560204917Sdes} 561204917Sdes 562204917Sdesstatic int 563204917Sdesprocess_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 564204917Sdes{ 565204917Sdes Forward fwd; 566204917Sdes char *fwd_desc = NULL; 567204917Sdes u_int ftype; 568204917Sdes int i, ret = 0, freefwd = 1; 569204917Sdes 570204917Sdes fwd.listen_host = fwd.connect_host = NULL; 571204917Sdes if (buffer_get_int_ret(&ftype, m) != 0 || 572204917Sdes (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL || 573204917Sdes buffer_get_int_ret(&fwd.listen_port, m) != 0 || 574204917Sdes (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL || 575204917Sdes buffer_get_int_ret(&fwd.connect_port, m) != 0) { 576204917Sdes error("%s: malformed message", __func__); 577204917Sdes ret = -1; 578204917Sdes goto out; 579204917Sdes } 580204917Sdes 581204917Sdes if (*fwd.listen_host == '\0') { 582204917Sdes xfree(fwd.listen_host); 583204917Sdes fwd.listen_host = NULL; 584204917Sdes } 585204917Sdes if (*fwd.connect_host == '\0') { 586204917Sdes xfree(fwd.connect_host); 587204917Sdes fwd.connect_host = NULL; 588204917Sdes } 589204917Sdes 590204917Sdes debug2("%s: channel %d: request %s", __func__, c->self, 591204917Sdes (fwd_desc = format_forward(ftype, &fwd))); 592204917Sdes 593204917Sdes if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE && 594204917Sdes ftype != MUX_FWD_DYNAMIC) { 595204917Sdes logit("%s: invalid forwarding type %u", __func__, ftype); 596204917Sdes invalid: 597204917Sdes xfree(fwd.listen_host); 598204917Sdes xfree(fwd.connect_host); 599204917Sdes buffer_put_int(r, MUX_S_FAILURE); 600204917Sdes buffer_put_int(r, rid); 601204917Sdes buffer_put_cstring(r, "Invalid forwarding request"); 602204917Sdes return 0; 603204917Sdes } 604204917Sdes /* XXX support rport0 forwarding with reply of port assigned */ 605204917Sdes if (fwd.listen_port == 0 || fwd.listen_port >= 65536) { 606204917Sdes logit("%s: invalid listen port %u", __func__, 607204917Sdes fwd.listen_port); 608204917Sdes goto invalid; 609204917Sdes } 610204917Sdes if (fwd.connect_port >= 65536 || (ftype != MUX_FWD_DYNAMIC && 611204917Sdes ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) { 612204917Sdes logit("%s: invalid connect port %u", __func__, 613204917Sdes fwd.connect_port); 614204917Sdes goto invalid; 615204917Sdes } 616204917Sdes if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL) { 617204917Sdes logit("%s: missing connect host", __func__); 618204917Sdes goto invalid; 619204917Sdes } 620204917Sdes 621204917Sdes /* Skip forwards that have already been requested */ 622204917Sdes switch (ftype) { 623204917Sdes case MUX_FWD_LOCAL: 624204917Sdes case MUX_FWD_DYNAMIC: 625204917Sdes for (i = 0; i < options.num_local_forwards; i++) { 626204917Sdes if (compare_forward(&fwd, 627204917Sdes options.local_forwards + i)) { 628204917Sdes exists: 629204917Sdes debug2("%s: found existing forwarding", 630204917Sdes __func__); 631204917Sdes buffer_put_int(r, MUX_S_OK); 632204917Sdes buffer_put_int(r, rid); 633204917Sdes goto out; 634204917Sdes } 635204917Sdes } 636204917Sdes break; 637204917Sdes case MUX_FWD_REMOTE: 638204917Sdes for (i = 0; i < options.num_remote_forwards; i++) { 639204917Sdes if (compare_forward(&fwd, 640204917Sdes options.remote_forwards + i)) 641204917Sdes goto exists; 642204917Sdes } 643204917Sdes break; 644204917Sdes } 645204917Sdes 646204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 647204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 648204917Sdes if (!ask_permission("Open %s on %s?", fwd_desc, host)) { 649204917Sdes debug2("%s: forwarding refused by user", __func__); 650204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 651204917Sdes buffer_put_int(r, rid); 652204917Sdes buffer_put_cstring(r, "Permission denied"); 653204917Sdes goto out; 654204917Sdes } 655204917Sdes } 656204917Sdes 657204917Sdes if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { 658204917Sdes if (options.num_local_forwards + 1 >= 659204917Sdes SSH_MAX_FORWARDS_PER_DIRECTION || 660204917Sdes channel_setup_local_fwd_listener(fwd.listen_host, 661204917Sdes fwd.listen_port, fwd.connect_host, fwd.connect_port, 662204917Sdes options.gateway_ports) < 0) { 663204917Sdes fail: 664204917Sdes logit("slave-requested %s failed", fwd_desc); 665204917Sdes buffer_put_int(r, MUX_S_FAILURE); 666204917Sdes buffer_put_int(r, rid); 667204917Sdes buffer_put_cstring(r, "Port forwarding failed"); 668204917Sdes goto out; 669204917Sdes } 670204917Sdes add_local_forward(&options, &fwd); 671204917Sdes freefwd = 0; 672204917Sdes } else { 673204917Sdes /* XXX wait for remote to confirm */ 674204917Sdes if (options.num_remote_forwards + 1 >= 675204917Sdes SSH_MAX_FORWARDS_PER_DIRECTION || 676204917Sdes channel_request_remote_forwarding(fwd.listen_host, 677204917Sdes fwd.listen_port, fwd.connect_host, fwd.connect_port) < 0) 678204917Sdes goto fail; 679204917Sdes add_remote_forward(&options, &fwd); 680204917Sdes freefwd = 0; 681204917Sdes } 682204917Sdes buffer_put_int(r, MUX_S_OK); 683204917Sdes buffer_put_int(r, rid); 684204917Sdes out: 685204917Sdes if (fwd_desc != NULL) 686204917Sdes xfree(fwd_desc); 687204917Sdes if (freefwd) { 688204917Sdes if (fwd.listen_host != NULL) 689204917Sdes xfree(fwd.listen_host); 690204917Sdes if (fwd.connect_host != NULL) 691204917Sdes xfree(fwd.connect_host); 692204917Sdes } 693204917Sdes return ret; 694204917Sdes} 695204917Sdes 696204917Sdesstatic int 697204917Sdesprocess_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 698204917Sdes{ 699204917Sdes Forward fwd; 700204917Sdes char *fwd_desc = NULL; 701204917Sdes u_int ftype; 702204917Sdes int ret = 0; 703204917Sdes 704204917Sdes fwd.listen_host = fwd.connect_host = NULL; 705204917Sdes if (buffer_get_int_ret(&ftype, m) != 0 || 706204917Sdes (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL || 707204917Sdes buffer_get_int_ret(&fwd.listen_port, m) != 0 || 708204917Sdes (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL || 709204917Sdes buffer_get_int_ret(&fwd.connect_port, m) != 0) { 710204917Sdes error("%s: malformed message", __func__); 711204917Sdes ret = -1; 712204917Sdes goto out; 713204917Sdes } 714204917Sdes 715204917Sdes if (*fwd.listen_host == '\0') { 716204917Sdes xfree(fwd.listen_host); 717204917Sdes fwd.listen_host = NULL; 718204917Sdes } 719204917Sdes if (*fwd.connect_host == '\0') { 720204917Sdes xfree(fwd.connect_host); 721204917Sdes fwd.connect_host = NULL; 722204917Sdes } 723204917Sdes 724204917Sdes debug2("%s: channel %d: request %s", __func__, c->self, 725204917Sdes (fwd_desc = format_forward(ftype, &fwd))); 726204917Sdes 727204917Sdes /* XXX implement this */ 728204917Sdes buffer_put_int(r, MUX_S_FAILURE); 729204917Sdes buffer_put_int(r, rid); 730204917Sdes buffer_put_cstring(r, "unimplemented"); 731204917Sdes 732204917Sdes out: 733204917Sdes if (fwd_desc != NULL) 734204917Sdes xfree(fwd_desc); 735204917Sdes if (fwd.listen_host != NULL) 736204917Sdes xfree(fwd.listen_host); 737204917Sdes if (fwd.connect_host != NULL) 738204917Sdes xfree(fwd.connect_host); 739204917Sdes 740204917Sdes return ret; 741204917Sdes} 742204917Sdes 743204917Sdesstatic int 744204917Sdesprocess_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 745204917Sdes{ 746204917Sdes Channel *nc; 747204917Sdes char *reserved, *chost; 748204917Sdes u_int cport, i, j; 749204917Sdes int new_fd[2]; 750204917Sdes 751204917Sdes chost = reserved = NULL; 752204917Sdes if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || 753204917Sdes (chost = buffer_get_string_ret(m, NULL)) == NULL || 754204917Sdes buffer_get_int_ret(&cport, m) != 0) { 755204917Sdes if (reserved != NULL) 756204917Sdes xfree(reserved); 757204917Sdes if (chost != NULL) 758204917Sdes xfree(chost); 759204917Sdes error("%s: malformed message", __func__); 760204917Sdes return -1; 761204917Sdes } 762204917Sdes xfree(reserved); 763204917Sdes 764204917Sdes debug2("%s: channel %d: request stdio fwd to %s:%u", 765204917Sdes __func__, c->self, chost, cport); 766204917Sdes 767204917Sdes /* Gather fds from client */ 768204917Sdes for(i = 0; i < 2; i++) { 769204917Sdes if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { 770204917Sdes error("%s: failed to receive fd %d from slave", 771204917Sdes __func__, i); 772204917Sdes for (j = 0; j < i; j++) 773204917Sdes close(new_fd[j]); 774204917Sdes xfree(chost); 775204917Sdes 776204917Sdes /* prepare reply */ 777204917Sdes buffer_put_int(r, MUX_S_FAILURE); 778204917Sdes buffer_put_int(r, rid); 779204917Sdes buffer_put_cstring(r, 780204917Sdes "did not receive file descriptors"); 781204917Sdes return -1; 782204917Sdes } 783204917Sdes } 784204917Sdes 785204917Sdes debug3("%s: got fds stdin %d, stdout %d", __func__, 786204917Sdes new_fd[0], new_fd[1]); 787204917Sdes 788204917Sdes /* XXX support multiple child sessions in future */ 789204917Sdes if (c->remote_id != -1) { 790204917Sdes debug2("%s: session already open", __func__); 791204917Sdes /* prepare reply */ 792204917Sdes buffer_put_int(r, MUX_S_FAILURE); 793204917Sdes buffer_put_int(r, rid); 794204917Sdes buffer_put_cstring(r, "Multiple sessions not supported"); 795204917Sdes cleanup: 796204917Sdes close(new_fd[0]); 797204917Sdes close(new_fd[1]); 798204917Sdes xfree(chost); 799204917Sdes return 0; 800204917Sdes } 801204917Sdes 802204917Sdes if (options.control_master == SSHCTL_MASTER_ASK || 803204917Sdes options.control_master == SSHCTL_MASTER_AUTO_ASK) { 804204917Sdes if (!ask_permission("Allow forward to to %s:%u? ", 805204917Sdes chost, cport)) { 806204917Sdes debug2("%s: stdio fwd refused by user", __func__); 807204917Sdes /* prepare reply */ 808204917Sdes buffer_put_int(r, MUX_S_PERMISSION_DENIED); 809204917Sdes buffer_put_int(r, rid); 810204917Sdes buffer_put_cstring(r, "Permission denied"); 811204917Sdes goto cleanup; 812204917Sdes } 813204917Sdes } 814204917Sdes 815204917Sdes /* enable nonblocking unless tty */ 816204917Sdes if (!isatty(new_fd[0])) 817204917Sdes set_nonblock(new_fd[0]); 818204917Sdes if (!isatty(new_fd[1])) 819204917Sdes set_nonblock(new_fd[1]); 820204917Sdes 821204917Sdes nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]); 822204917Sdes 823204917Sdes nc->ctl_chan = c->self; /* link session -> control channel */ 824204917Sdes c->remote_id = nc->self; /* link control -> session channel */ 825204917Sdes 826204917Sdes debug2("%s: channel_new: %d linked to control channel %d", 827204917Sdes __func__, nc->self, nc->ctl_chan); 828204917Sdes 829204917Sdes channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 0); 830204917Sdes 831204917Sdes /* prepare reply */ 832204917Sdes /* XXX defer until channel confirmed */ 833204917Sdes buffer_put_int(r, MUX_S_SESSION_OPENED); 834204917Sdes buffer_put_int(r, rid); 835204917Sdes buffer_put_int(r, nc->self); 836204917Sdes 837204917Sdes return 0; 838204917Sdes} 839204917Sdes 840204917Sdes/* Channel callbacks fired on read/write from mux slave fd */ 841204917Sdesstatic int 842204917Sdesmux_master_read_cb(Channel *c) 843204917Sdes{ 844204917Sdes struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; 845204917Sdes Buffer in, out; 846204917Sdes void *ptr; 847204917Sdes u_int type, rid, have, i; 848204917Sdes int ret = -1; 849204917Sdes 850204917Sdes /* Setup ctx and */ 851204917Sdes if (c->mux_ctx == NULL) { 852204917Sdes state = xcalloc(1, sizeof(state)); 853204917Sdes c->mux_ctx = state; 854204917Sdes channel_register_cleanup(c->self, 855204917Sdes mux_master_control_cleanup_cb, 0); 856204917Sdes 857204917Sdes /* Send hello */ 858204917Sdes buffer_init(&out); 859204917Sdes buffer_put_int(&out, MUX_MSG_HELLO); 860204917Sdes buffer_put_int(&out, SSHMUX_VER); 861204917Sdes /* no extensions */ 862204917Sdes buffer_put_string(&c->output, buffer_ptr(&out), 863204917Sdes buffer_len(&out)); 864204917Sdes buffer_free(&out); 865204917Sdes debug3("%s: channel %d: hello sent", __func__, c->self); 866204917Sdes return 0; 867204917Sdes } 868204917Sdes 869204917Sdes buffer_init(&in); 870204917Sdes buffer_init(&out); 871204917Sdes 872204917Sdes /* Channel code ensures that we receive whole packets */ 873204917Sdes if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) { 874204917Sdes malf: 875204917Sdes error("%s: malformed message", __func__); 876204917Sdes goto out; 877204917Sdes } 878204917Sdes buffer_append(&in, ptr, have); 879204917Sdes 880204917Sdes if (buffer_get_int_ret(&type, &in) != 0) 881204917Sdes goto malf; 882204917Sdes debug3("%s: channel %d packet type 0x%08x len %u", 883204917Sdes __func__, c->self, type, buffer_len(&in)); 884204917Sdes 885204917Sdes if (type == MUX_MSG_HELLO) 886204917Sdes rid = 0; 887204917Sdes else { 888204917Sdes if (!state->hello_rcvd) { 889204917Sdes error("%s: expected MUX_MSG_HELLO(0x%08x), " 890204917Sdes "received 0x%08x", __func__, MUX_MSG_HELLO, type); 891204917Sdes goto out; 892204917Sdes } 893204917Sdes if (buffer_get_int_ret(&rid, &in) != 0) 894204917Sdes goto malf; 895204917Sdes } 896204917Sdes 897204917Sdes for (i = 0; mux_master_handlers[i].handler != NULL; i++) { 898204917Sdes if (type == mux_master_handlers[i].type) { 899204917Sdes ret = mux_master_handlers[i].handler(rid, c, &in, &out); 900204917Sdes break; 901204917Sdes } 902204917Sdes } 903204917Sdes if (mux_master_handlers[i].handler == NULL) { 904204917Sdes error("%s: unsupported mux message 0x%08x", __func__, type); 905204917Sdes buffer_put_int(&out, MUX_S_FAILURE); 906204917Sdes buffer_put_int(&out, rid); 907204917Sdes buffer_put_cstring(&out, "unsupported request"); 908204917Sdes ret = 0; 909204917Sdes } 910204917Sdes /* Enqueue reply packet */ 911204917Sdes if (buffer_len(&out) != 0) { 912204917Sdes buffer_put_string(&c->output, buffer_ptr(&out), 913204917Sdes buffer_len(&out)); 914204917Sdes } 915204917Sdes out: 916204917Sdes buffer_free(&in); 917204917Sdes buffer_free(&out); 918204917Sdes return ret; 919204917Sdes} 920204917Sdes 921204917Sdesvoid 922204917Sdesmux_exit_message(Channel *c, int exitval) 923204917Sdes{ 924204917Sdes Buffer m; 925204917Sdes Channel *mux_chan; 926204917Sdes 927204917Sdes debug3("%s: channel %d: exit message, evitval %d", __func__, c->self, 928204917Sdes exitval); 929204917Sdes 930204917Sdes if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) 931204917Sdes fatal("%s: channel %d missing mux channel %d", 932204917Sdes __func__, c->self, c->ctl_chan); 933204917Sdes 934204917Sdes /* Append exit message packet to control socket output queue */ 935204917Sdes buffer_init(&m); 936204917Sdes buffer_put_int(&m, MUX_S_EXIT_MESSAGE); 937204917Sdes buffer_put_int(&m, c->self); 938204917Sdes buffer_put_int(&m, exitval); 939204917Sdes 940204917Sdes buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); 941204917Sdes buffer_free(&m); 942204917Sdes} 943204917Sdes 944180750Sdes/* Prepare a mux master to listen on a Unix domain socket. */ 945180750Sdesvoid 946180750Sdesmuxserver_listen(void) 947180750Sdes{ 948180750Sdes struct sockaddr_un addr; 949204917Sdes socklen_t sun_len; 950180750Sdes mode_t old_umask; 951180750Sdes 952180750Sdes if (options.control_path == NULL || 953180750Sdes options.control_master == SSHCTL_MASTER_NO) 954180750Sdes return; 955180750Sdes 956180750Sdes debug("setting up multiplex master socket"); 957180750Sdes 958180750Sdes memset(&addr, '\0', sizeof(addr)); 959180750Sdes addr.sun_family = AF_UNIX; 960204917Sdes sun_len = offsetof(struct sockaddr_un, sun_path) + 961180750Sdes strlen(options.control_path) + 1; 962180750Sdes 963180750Sdes if (strlcpy(addr.sun_path, options.control_path, 964180750Sdes sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) 965180750Sdes fatal("ControlPath too long"); 966180750Sdes 967180750Sdes if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) 968180750Sdes fatal("%s socket(): %s", __func__, strerror(errno)); 969180750Sdes 970180750Sdes old_umask = umask(0177); 971204917Sdes if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) { 972180750Sdes muxserver_sock = -1; 973180750Sdes if (errno == EINVAL || errno == EADDRINUSE) { 974180750Sdes error("ControlSocket %s already exists, " 975180750Sdes "disabling multiplexing", options.control_path); 976180750Sdes close(muxserver_sock); 977180750Sdes muxserver_sock = -1; 978180750Sdes xfree(options.control_path); 979180750Sdes options.control_path = NULL; 980180750Sdes options.control_master = SSHCTL_MASTER_NO; 981180750Sdes return; 982180750Sdes } else 983180750Sdes fatal("%s bind(): %s", __func__, strerror(errno)); 984180750Sdes } 985180750Sdes umask(old_umask); 986180750Sdes 987180750Sdes if (listen(muxserver_sock, 64) == -1) 988180750Sdes fatal("%s listen(): %s", __func__, strerror(errno)); 989180750Sdes 990180750Sdes set_nonblock(muxserver_sock); 991204917Sdes 992204917Sdes mux_listener_channel = channel_new("mux listener", 993204917Sdes SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, 994204917Sdes CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 995204917Sdes 0, addr.sun_path, 1); 996204917Sdes mux_listener_channel->mux_rcb = mux_master_read_cb; 997204917Sdes debug3("%s: mux listener channel %d fd %d", __func__, 998204917Sdes mux_listener_channel->self, mux_listener_channel->sock); 999180750Sdes} 1000180750Sdes 1001180750Sdes/* Callback on open confirmation in mux master for a mux client session. */ 1002180750Sdesstatic void 1003180750Sdesmux_session_confirm(int id, void *arg) 1004180750Sdes{ 1005180750Sdes struct mux_session_confirm_ctx *cctx = arg; 1006180750Sdes const char *display; 1007180750Sdes Channel *c; 1008180750Sdes int i; 1009180750Sdes 1010180750Sdes if (cctx == NULL) 1011180750Sdes fatal("%s: cctx == NULL", __func__); 1012204917Sdes if ((c = channel_by_id(id)) == NULL) 1013180750Sdes fatal("%s: no channel for id %d", __func__, id); 1014180750Sdes 1015180750Sdes display = getenv("DISPLAY"); 1016180750Sdes if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { 1017180750Sdes char *proto, *data; 1018180750Sdes /* Get reasonable local authentication information. */ 1019180750Sdes client_x11_get_proto(display, options.xauth_location, 1020180750Sdes options.forward_x11_trusted, &proto, &data); 1021180750Sdes /* Request forwarding with authentication spoofing. */ 1022180750Sdes debug("Requesting X11 forwarding with authentication spoofing."); 1023180750Sdes x11_request_forwarding_with_spoofing(id, display, proto, data); 1024180750Sdes /* XXX wait for reply */ 1025180750Sdes } 1026180750Sdes 1027180750Sdes if (cctx->want_agent_fwd && options.forward_agent) { 1028180750Sdes debug("Requesting authentication agent forwarding."); 1029180750Sdes channel_request_start(id, "auth-agent-req@openssh.com", 0); 1030180750Sdes packet_send(); 1031180750Sdes } 1032180750Sdes 1033180750Sdes client_session2_setup(id, cctx->want_tty, cctx->want_subsys, 1034180750Sdes cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); 1035180750Sdes 1036180750Sdes c->open_confirm_ctx = NULL; 1037180750Sdes buffer_free(&cctx->cmd); 1038180750Sdes xfree(cctx->term); 1039180750Sdes if (cctx->env != NULL) { 1040180750Sdes for (i = 0; cctx->env[i] != NULL; i++) 1041180750Sdes xfree(cctx->env[i]); 1042180750Sdes xfree(cctx->env); 1043180750Sdes } 1044180750Sdes xfree(cctx); 1045180750Sdes} 1046180750Sdes 1047204917Sdes/* ** Multiplexing client support */ 1048204917Sdes 1049204917Sdes/* Exit signal handler */ 1050204917Sdesstatic void 1051204917Sdescontrol_client_sighandler(int signo) 1052204917Sdes{ 1053204917Sdes muxclient_terminate = signo; 1054204917Sdes} 1055204917Sdes 1056180750Sdes/* 1057204917Sdes * Relay signal handler - used to pass some signals from mux client to 1058204917Sdes * mux master. 1059180750Sdes */ 1060204917Sdesstatic void 1061204917Sdescontrol_client_sigrelay(int signo) 1062180750Sdes{ 1063204917Sdes int save_errno = errno; 1064180750Sdes 1065204917Sdes if (muxserver_pid > 1) 1066204917Sdes kill(muxserver_pid, signo); 1067204917Sdes 1068204917Sdes errno = save_errno; 1069204917Sdes} 1070204917Sdes 1071204917Sdesstatic int 1072204917Sdesmux_client_read(int fd, Buffer *b, u_int need) 1073204917Sdes{ 1074204917Sdes u_int have; 1075204917Sdes ssize_t len; 1076204917Sdes u_char *p; 1077204917Sdes struct pollfd pfd; 1078204917Sdes 1079204917Sdes pfd.fd = fd; 1080204917Sdes pfd.events = POLLIN; 1081204917Sdes p = buffer_append_space(b, need); 1082204917Sdes for (have = 0; have < need; ) { 1083204917Sdes if (muxclient_terminate) { 1084204917Sdes errno = EINTR; 1085204917Sdes return -1; 1086204917Sdes } 1087204917Sdes len = read(fd, p + have, need - have); 1088204917Sdes if (len < 0) { 1089204917Sdes switch (errno) { 1090204917Sdes#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) 1091204917Sdes case EWOULDBLOCK: 1092204917Sdes#endif 1093204917Sdes case EAGAIN: 1094204917Sdes (void)poll(&pfd, 1, -1); 1095204917Sdes /* FALLTHROUGH */ 1096204917Sdes case EINTR: 1097204917Sdes continue; 1098204917Sdes default: 1099204917Sdes return -1; 1100204917Sdes } 1101204917Sdes } 1102204917Sdes if (len == 0) { 1103204917Sdes errno = EPIPE; 1104204917Sdes return -1; 1105204917Sdes } 1106204917Sdes have += (u_int)len; 1107180750Sdes } 1108204917Sdes return 0; 1109204917Sdes} 1110180750Sdes 1111204917Sdesstatic int 1112204917Sdesmux_client_write_packet(int fd, Buffer *m) 1113204917Sdes{ 1114204917Sdes Buffer queue; 1115204917Sdes u_int have, need; 1116204917Sdes int oerrno, len; 1117204917Sdes u_char *ptr; 1118204917Sdes struct pollfd pfd; 1119204917Sdes 1120204917Sdes pfd.fd = fd; 1121204917Sdes pfd.events = POLLOUT; 1122204917Sdes buffer_init(&queue); 1123204917Sdes buffer_put_string(&queue, buffer_ptr(m), buffer_len(m)); 1124204917Sdes 1125204917Sdes need = buffer_len(&queue); 1126204917Sdes ptr = buffer_ptr(&queue); 1127204917Sdes 1128204917Sdes for (have = 0; have < need; ) { 1129204917Sdes if (muxclient_terminate) { 1130204917Sdes buffer_free(&queue); 1131204917Sdes errno = EINTR; 1132204917Sdes return -1; 1133204917Sdes } 1134204917Sdes len = write(fd, ptr + have, need - have); 1135204917Sdes if (len < 0) { 1136204917Sdes switch (errno) { 1137204917Sdes#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) 1138204917Sdes case EWOULDBLOCK: 1139204917Sdes#endif 1140204917Sdes case EAGAIN: 1141204917Sdes (void)poll(&pfd, 1, -1); 1142204917Sdes /* FALLTHROUGH */ 1143204917Sdes case EINTR: 1144204917Sdes continue; 1145204917Sdes default: 1146204917Sdes oerrno = errno; 1147204917Sdes buffer_free(&queue); 1148204917Sdes errno = oerrno; 1149204917Sdes return -1; 1150204917Sdes } 1151204917Sdes } 1152204917Sdes if (len == 0) { 1153204917Sdes buffer_free(&queue); 1154204917Sdes errno = EPIPE; 1155204917Sdes return -1; 1156204917Sdes } 1157204917Sdes have += (u_int)len; 1158180750Sdes } 1159204917Sdes buffer_free(&queue); 1160204917Sdes return 0; 1161204917Sdes} 1162204917Sdes 1163204917Sdesstatic int 1164204917Sdesmux_client_read_packet(int fd, Buffer *m) 1165204917Sdes{ 1166204917Sdes Buffer queue; 1167204917Sdes u_int need, have; 1168204917Sdes void *ptr; 1169204917Sdes int oerrno; 1170204917Sdes 1171204917Sdes buffer_init(&queue); 1172204917Sdes if (mux_client_read(fd, &queue, 4) != 0) { 1173204917Sdes if ((oerrno = errno) == EPIPE) 1174204917Sdes debug3("%s: read header failed: %s", __func__, strerror(errno)); 1175204917Sdes errno = oerrno; 1176204917Sdes return -1; 1177180750Sdes } 1178204917Sdes need = get_u32(buffer_ptr(&queue)); 1179204917Sdes if (mux_client_read(fd, &queue, need) != 0) { 1180204917Sdes oerrno = errno; 1181204917Sdes debug3("%s: read body failed: %s", __func__, strerror(errno)); 1182204917Sdes errno = oerrno; 1183204917Sdes return -1; 1184204917Sdes } 1185204917Sdes ptr = buffer_get_string_ptr(&queue, &have); 1186204917Sdes buffer_append(m, ptr, have); 1187204917Sdes buffer_free(&queue); 1188204917Sdes return 0; 1189204917Sdes} 1190180750Sdes 1191204917Sdesstatic int 1192204917Sdesmux_client_hello_exchange(int fd) 1193204917Sdes{ 1194204917Sdes Buffer m; 1195204917Sdes u_int type, ver; 1196180750Sdes 1197180750Sdes buffer_init(&m); 1198204917Sdes buffer_put_int(&m, MUX_MSG_HELLO); 1199204917Sdes buffer_put_int(&m, SSHMUX_VER); 1200204917Sdes /* no extensions */ 1201204917Sdes 1202204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1203204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1204204917Sdes 1205204917Sdes buffer_clear(&m); 1206204917Sdes 1207204917Sdes /* Read their HELLO */ 1208204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1209180750Sdes buffer_free(&m); 1210204917Sdes return -1; 1211180750Sdes } 1212204917Sdes 1213204917Sdes type = buffer_get_int(&m); 1214204917Sdes if (type != MUX_MSG_HELLO) 1215204917Sdes fatal("%s: expected HELLO (%u) received %u", 1216204917Sdes __func__, MUX_MSG_HELLO, type); 1217204917Sdes ver = buffer_get_int(&m); 1218204917Sdes if (ver != SSHMUX_VER) 1219204917Sdes fatal("Unsupported multiplexing protocol version %d " 1220204917Sdes "(expected %d)", ver, SSHMUX_VER); 1221204917Sdes debug2("%s: master version %u", __func__, ver); 1222204917Sdes /* No extensions are presently defined */ 1223204917Sdes while (buffer_len(&m) > 0) { 1224204917Sdes char *name = buffer_get_string(&m, NULL); 1225204917Sdes char *value = buffer_get_string(&m, NULL); 1226204917Sdes 1227204917Sdes debug2("Unrecognised master extension \"%s\"", name); 1228204917Sdes xfree(name); 1229204917Sdes xfree(value); 1230204917Sdes } 1231204917Sdes buffer_free(&m); 1232204917Sdes return 0; 1233204917Sdes} 1234204917Sdes 1235204917Sdesstatic u_int 1236204917Sdesmux_client_request_alive(int fd) 1237204917Sdes{ 1238204917Sdes Buffer m; 1239204917Sdes char *e; 1240204917Sdes u_int pid, type, rid; 1241204917Sdes 1242204917Sdes debug3("%s: entering", __func__); 1243204917Sdes 1244204917Sdes buffer_init(&m); 1245204917Sdes buffer_put_int(&m, MUX_C_ALIVE_CHECK); 1246204917Sdes buffer_put_int(&m, muxclient_request_id); 1247204917Sdes 1248204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1249204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1250204917Sdes 1251204917Sdes buffer_clear(&m); 1252204917Sdes 1253204917Sdes /* Read their reply */ 1254204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1255180750Sdes buffer_free(&m); 1256180750Sdes return 0; 1257180750Sdes } 1258180750Sdes 1259204917Sdes type = buffer_get_int(&m); 1260204917Sdes if (type != MUX_S_ALIVE) { 1261204917Sdes e = buffer_get_string(&m, NULL); 1262204917Sdes fatal("%s: master returned error: %s", __func__, e); 1263204917Sdes } 1264180750Sdes 1265204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1266204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1267204917Sdes __func__, muxclient_request_id, rid); 1268204917Sdes pid = buffer_get_int(&m); 1269204917Sdes buffer_free(&m); 1270204917Sdes 1271204917Sdes debug3("%s: done pid = %u", __func__, pid); 1272204917Sdes 1273204917Sdes muxclient_request_id++; 1274204917Sdes 1275204917Sdes return pid; 1276204917Sdes} 1277204917Sdes 1278204917Sdesstatic void 1279204917Sdesmux_client_request_terminate(int fd) 1280204917Sdes{ 1281204917Sdes Buffer m; 1282204917Sdes char *e; 1283204917Sdes u_int type, rid; 1284204917Sdes 1285204917Sdes debug3("%s: entering", __func__); 1286204917Sdes 1287204917Sdes buffer_init(&m); 1288204917Sdes buffer_put_int(&m, MUX_C_TERMINATE); 1289204917Sdes buffer_put_int(&m, muxclient_request_id); 1290204917Sdes 1291204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1292204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1293204917Sdes 1294180750Sdes buffer_clear(&m); 1295180750Sdes 1296204917Sdes /* Read their reply */ 1297204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1298204917Sdes /* Remote end exited already */ 1299204917Sdes if (errno == EPIPE) { 1300180750Sdes buffer_free(&m); 1301204917Sdes return; 1302180750Sdes } 1303204917Sdes fatal("%s: read from master failed: %s", 1304204917Sdes __func__, strerror(errno)); 1305204917Sdes } 1306204917Sdes 1307204917Sdes type = buffer_get_int(&m); 1308204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1309204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1310204917Sdes __func__, muxclient_request_id, rid); 1311204917Sdes switch (type) { 1312204917Sdes case MUX_S_OK: 1313204917Sdes break; 1314204917Sdes case MUX_S_PERMISSION_DENIED: 1315204917Sdes e = buffer_get_string(&m, NULL); 1316204917Sdes fatal("Master refused termination request: %s", e); 1317204917Sdes case MUX_S_FAILURE: 1318204917Sdes e = buffer_get_string(&m, NULL); 1319204917Sdes fatal("%s: termination request failed: %s", __func__, e); 1320180750Sdes default: 1321204917Sdes fatal("%s: unexpected response from master 0x%08x", 1322204917Sdes __func__, type); 1323180750Sdes } 1324204917Sdes buffer_free(&m); 1325204917Sdes muxclient_request_id++; 1326204917Sdes} 1327180750Sdes 1328204917Sdesstatic int 1329204917Sdesmux_client_request_forward(int fd, u_int ftype, Forward *fwd) 1330204917Sdes{ 1331204917Sdes Buffer m; 1332204917Sdes char *e, *fwd_desc; 1333204917Sdes u_int type, rid; 1334204917Sdes 1335204917Sdes fwd_desc = format_forward(ftype, fwd); 1336204917Sdes debug("Requesting %s", fwd_desc); 1337204917Sdes xfree(fwd_desc); 1338204917Sdes 1339204917Sdes buffer_init(&m); 1340204917Sdes buffer_put_int(&m, MUX_C_OPEN_FWD); 1341204917Sdes buffer_put_int(&m, muxclient_request_id); 1342204917Sdes buffer_put_int(&m, ftype); 1343204917Sdes buffer_put_cstring(&m, 1344204917Sdes fwd->listen_host == NULL ? "" : fwd->listen_host); 1345204917Sdes buffer_put_int(&m, fwd->listen_port); 1346204917Sdes buffer_put_cstring(&m, 1347204917Sdes fwd->connect_host == NULL ? "" : fwd->connect_host); 1348204917Sdes buffer_put_int(&m, fwd->connect_port); 1349204917Sdes 1350204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1351204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1352204917Sdes 1353180750Sdes buffer_clear(&m); 1354204917Sdes 1355204917Sdes /* Read their reply */ 1356204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1357180750Sdes buffer_free(&m); 1358204917Sdes return -1; 1359180750Sdes } 1360180750Sdes 1361204917Sdes type = buffer_get_int(&m); 1362204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1363204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1364204917Sdes __func__, muxclient_request_id, rid); 1365204917Sdes switch (type) { 1366204917Sdes case MUX_S_OK: 1367204917Sdes break; 1368204917Sdes case MUX_S_PERMISSION_DENIED: 1369204917Sdes e = buffer_get_string(&m, NULL); 1370180750Sdes buffer_free(&m); 1371204917Sdes error("Master refused forwarding request: %s", e); 1372204917Sdes return -1; 1373204917Sdes case MUX_S_FAILURE: 1374204917Sdes e = buffer_get_string(&m, NULL); 1375204917Sdes buffer_free(&m); 1376204917Sdes error("%s: session request failed: %s", __func__, e); 1377204917Sdes return -1; 1378204917Sdes default: 1379204917Sdes fatal("%s: unexpected response from master 0x%08x", 1380204917Sdes __func__, type); 1381180750Sdes } 1382204917Sdes buffer_free(&m); 1383180750Sdes 1384204917Sdes muxclient_request_id++; 1385204917Sdes return 0; 1386204917Sdes} 1387204917Sdes 1388204917Sdesstatic int 1389204917Sdesmux_client_request_forwards(int fd) 1390204917Sdes{ 1391204917Sdes int i; 1392204917Sdes 1393204917Sdes debug3("%s: requesting forwardings: %d local, %d remote", __func__, 1394204917Sdes options.num_local_forwards, options.num_remote_forwards); 1395204917Sdes 1396204917Sdes /* XXX ExitOnForwardingFailure */ 1397204917Sdes for (i = 0; i < options.num_local_forwards; i++) { 1398204917Sdes if (mux_client_request_forward(fd, 1399204917Sdes options.local_forwards[i].connect_port == 0 ? 1400204917Sdes MUX_FWD_DYNAMIC : MUX_FWD_LOCAL, 1401204917Sdes options.local_forwards + i) != 0) 1402204917Sdes return -1; 1403180750Sdes } 1404204917Sdes for (i = 0; i < options.num_remote_forwards; i++) { 1405204917Sdes if (mux_client_request_forward(fd, MUX_FWD_REMOTE, 1406204917Sdes options.remote_forwards + i) != 0) 1407204917Sdes return -1; 1408180750Sdes } 1409204917Sdes return 0; 1410204917Sdes} 1411180750Sdes 1412204917Sdesstatic int 1413204917Sdesmux_client_request_session(int fd) 1414204917Sdes{ 1415204917Sdes Buffer m; 1416204917Sdes char *e, *term; 1417204917Sdes u_int i, rid, sid, esid, exitval, type, exitval_seen; 1418204917Sdes extern char **environ; 1419204917Sdes int devnull; 1420180750Sdes 1421204917Sdes debug3("%s: entering", __func__); 1422180750Sdes 1423204917Sdes if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { 1424204917Sdes error("%s: master alive request failed", __func__); 1425204917Sdes return -1; 1426180750Sdes } 1427180750Sdes 1428204917Sdes signal(SIGPIPE, SIG_IGN); 1429180750Sdes 1430204917Sdes if (stdin_null_flag) { 1431204917Sdes if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) 1432204917Sdes fatal("open(/dev/null): %s", strerror(errno)); 1433204917Sdes if (dup2(devnull, STDIN_FILENO) == -1) 1434204917Sdes fatal("dup2: %s", strerror(errno)); 1435204917Sdes if (devnull > STDERR_FILENO) 1436204917Sdes close(devnull); 1437180750Sdes } 1438180750Sdes 1439204917Sdes term = getenv("TERM"); 1440180750Sdes 1441204917Sdes buffer_init(&m); 1442204917Sdes buffer_put_int(&m, MUX_C_NEW_SESSION); 1443204917Sdes buffer_put_int(&m, muxclient_request_id); 1444204917Sdes buffer_put_cstring(&m, ""); /* reserved */ 1445204917Sdes buffer_put_int(&m, tty_flag); 1446204917Sdes buffer_put_int(&m, options.forward_x11); 1447204917Sdes buffer_put_int(&m, options.forward_agent); 1448204917Sdes buffer_put_int(&m, subsystem_flag); 1449204917Sdes buffer_put_int(&m, options.escape_char == SSH_ESCAPECHAR_NONE ? 1450204917Sdes 0xffffffff : (u_int)options.escape_char); 1451204917Sdes buffer_put_cstring(&m, term == NULL ? "" : term); 1452204917Sdes buffer_put_string(&m, buffer_ptr(&command), buffer_len(&command)); 1453180750Sdes 1454204917Sdes if (options.num_send_env > 0 && environ != NULL) { 1455204917Sdes /* Pass environment */ 1456204917Sdes for (i = 0; environ[i] != NULL; i++) { 1457204917Sdes if (env_permitted(environ[i])) { 1458204917Sdes buffer_put_cstring(&m, environ[i]); 1459204917Sdes } 1460180750Sdes } 1461180750Sdes } 1462180750Sdes 1463204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1464204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1465180750Sdes 1466204917Sdes /* Send the stdio file descriptors */ 1467204917Sdes if (mm_send_fd(fd, STDIN_FILENO) == -1 || 1468204917Sdes mm_send_fd(fd, STDOUT_FILENO) == -1 || 1469204917Sdes mm_send_fd(fd, STDERR_FILENO) == -1) 1470204917Sdes fatal("%s: send fds failed", __func__); 1471180750Sdes 1472204917Sdes debug3("%s: session request sent", __func__); 1473204917Sdes 1474204917Sdes /* Read their reply */ 1475204917Sdes buffer_clear(&m); 1476204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1477204917Sdes error("%s: read from master failed: %s", 1478204917Sdes __func__, strerror(errno)); 1479204917Sdes buffer_free(&m); 1480204917Sdes return -1; 1481180750Sdes } 1482180750Sdes 1483204917Sdes type = buffer_get_int(&m); 1484204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1485204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1486204917Sdes __func__, muxclient_request_id, rid); 1487204917Sdes switch (type) { 1488204917Sdes case MUX_S_SESSION_OPENED: 1489204917Sdes sid = buffer_get_int(&m); 1490204917Sdes debug("%s: master session id: %u", __func__, sid); 1491204917Sdes break; 1492204917Sdes case MUX_S_PERMISSION_DENIED: 1493204917Sdes e = buffer_get_string(&m, NULL); 1494204917Sdes buffer_free(&m); 1495204917Sdes error("Master refused forwarding request: %s", e); 1496204917Sdes return -1; 1497204917Sdes case MUX_S_FAILURE: 1498204917Sdes e = buffer_get_string(&m, NULL); 1499204917Sdes buffer_free(&m); 1500204917Sdes error("%s: forwarding request failed: %s", __func__, e); 1501204917Sdes return -1; 1502204917Sdes default: 1503204917Sdes buffer_free(&m); 1504204917Sdes error("%s: unexpected response from master 0x%08x", 1505204917Sdes __func__, type); 1506204917Sdes return -1; 1507180750Sdes } 1508204917Sdes muxclient_request_id++; 1509180750Sdes 1510204917Sdes signal(SIGHUP, control_client_sighandler); 1511204917Sdes signal(SIGINT, control_client_sighandler); 1512204917Sdes signal(SIGTERM, control_client_sighandler); 1513204917Sdes signal(SIGWINCH, control_client_sigrelay); 1514180750Sdes 1515204917Sdes if (tty_flag) 1516204917Sdes enter_raw_mode(force_tty_flag); 1517180750Sdes 1518204917Sdes /* 1519204917Sdes * Stick around until the controlee closes the client_fd. 1520204917Sdes * Before it does, it is expected to write an exit message. 1521204917Sdes * This process must read the value and wait for the closure of 1522204917Sdes * the client_fd; if this one closes early, the multiplex master will 1523204917Sdes * terminate early too (possibly losing data). 1524204917Sdes */ 1525204917Sdes for (exitval = 255, exitval_seen = 0;;) { 1526204917Sdes buffer_clear(&m); 1527204917Sdes if (mux_client_read_packet(fd, &m) != 0) 1528204917Sdes break; 1529204917Sdes type = buffer_get_int(&m); 1530204917Sdes if (type != MUX_S_EXIT_MESSAGE) { 1531204917Sdes e = buffer_get_string(&m, NULL); 1532204917Sdes fatal("%s: master returned error: %s", __func__, e); 1533204917Sdes } 1534204917Sdes if ((esid = buffer_get_int(&m)) != sid) 1535204917Sdes fatal("%s: exit on unknown session: my id %u theirs %u", 1536204917Sdes __func__, sid, esid); 1537204917Sdes debug("%s: master session id: %u", __func__, sid); 1538204917Sdes if (exitval_seen) 1539204917Sdes fatal("%s: exitval sent twice", __func__); 1540204917Sdes exitval = buffer_get_int(&m); 1541204917Sdes exitval_seen = 1; 1542204917Sdes } 1543180750Sdes 1544204917Sdes close(fd); 1545204917Sdes leave_raw_mode(force_tty_flag); 1546180750Sdes 1547204917Sdes if (muxclient_terminate) { 1548204917Sdes debug2("Exiting on signal %d", muxclient_terminate); 1549204917Sdes exitval = 255; 1550204917Sdes } else if (!exitval_seen) { 1551204917Sdes debug2("Control master terminated unexpectedly"); 1552204917Sdes exitval = 255; 1553204917Sdes } else 1554204917Sdes debug2("Received exit status from master %d", exitval); 1555180750Sdes 1556204917Sdes if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) 1557204917Sdes fprintf(stderr, "Shared connection to %s closed.\r\n", host); 1558180750Sdes 1559204917Sdes exit(exitval); 1560180750Sdes} 1561180750Sdes 1562180750Sdesstatic int 1563204917Sdesmux_client_request_stdio_fwd(int fd) 1564180750Sdes{ 1565204917Sdes Buffer m; 1566204917Sdes char *e; 1567204917Sdes u_int type, rid, sid; 1568204917Sdes int devnull; 1569180750Sdes 1570204917Sdes debug3("%s: entering", __func__); 1571180750Sdes 1572204917Sdes if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { 1573204917Sdes error("%s: master alive request failed", __func__); 1574204917Sdes return -1; 1575204917Sdes } 1576180750Sdes 1577204917Sdes signal(SIGPIPE, SIG_IGN); 1578204917Sdes 1579204917Sdes if (stdin_null_flag) { 1580204917Sdes if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) 1581204917Sdes fatal("open(/dev/null): %s", strerror(errno)); 1582204917Sdes if (dup2(devnull, STDIN_FILENO) == -1) 1583204917Sdes fatal("dup2: %s", strerror(errno)); 1584204917Sdes if (devnull > STDERR_FILENO) 1585204917Sdes close(devnull); 1586204917Sdes } 1587204917Sdes 1588204917Sdes buffer_init(&m); 1589204917Sdes buffer_put_int(&m, MUX_C_NEW_STDIO_FWD); 1590204917Sdes buffer_put_int(&m, muxclient_request_id); 1591204917Sdes buffer_put_cstring(&m, ""); /* reserved */ 1592204917Sdes buffer_put_cstring(&m, stdio_forward_host); 1593204917Sdes buffer_put_int(&m, stdio_forward_port); 1594204917Sdes 1595204917Sdes if (mux_client_write_packet(fd, &m) != 0) 1596204917Sdes fatal("%s: write packet: %s", __func__, strerror(errno)); 1597204917Sdes 1598204917Sdes /* Send the stdio file descriptors */ 1599204917Sdes if (mm_send_fd(fd, STDIN_FILENO) == -1 || 1600204917Sdes mm_send_fd(fd, STDOUT_FILENO) == -1) 1601204917Sdes fatal("%s: send fds failed", __func__); 1602204917Sdes 1603204917Sdes debug3("%s: stdio forward request sent", __func__); 1604204917Sdes 1605204917Sdes /* Read their reply */ 1606204917Sdes buffer_clear(&m); 1607204917Sdes 1608204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1609204917Sdes error("%s: read from master failed: %s", 1610204917Sdes __func__, strerror(errno)); 1611204917Sdes buffer_free(&m); 1612204917Sdes return -1; 1613204917Sdes } 1614204917Sdes 1615204917Sdes type = buffer_get_int(&m); 1616204917Sdes if ((rid = buffer_get_int(&m)) != muxclient_request_id) 1617204917Sdes fatal("%s: out of sequence reply: my id %u theirs %u", 1618204917Sdes __func__, muxclient_request_id, rid); 1619204917Sdes switch (type) { 1620204917Sdes case MUX_S_SESSION_OPENED: 1621204917Sdes sid = buffer_get_int(&m); 1622204917Sdes debug("%s: master session id: %u", __func__, sid); 1623204917Sdes break; 1624204917Sdes case MUX_S_PERMISSION_DENIED: 1625204917Sdes e = buffer_get_string(&m, NULL); 1626204917Sdes buffer_free(&m); 1627204917Sdes fatal("Master refused forwarding request: %s", e); 1628204917Sdes case MUX_S_FAILURE: 1629204917Sdes e = buffer_get_string(&m, NULL); 1630204917Sdes buffer_free(&m); 1631204917Sdes fatal("%s: stdio forwarding request failed: %s", __func__, e); 1632204917Sdes default: 1633204917Sdes buffer_free(&m); 1634204917Sdes error("%s: unexpected response from master 0x%08x", 1635204917Sdes __func__, type); 1636204917Sdes return -1; 1637204917Sdes } 1638204917Sdes muxclient_request_id++; 1639204917Sdes 1640204917Sdes signal(SIGHUP, control_client_sighandler); 1641204917Sdes signal(SIGINT, control_client_sighandler); 1642204917Sdes signal(SIGTERM, control_client_sighandler); 1643204917Sdes signal(SIGWINCH, control_client_sigrelay); 1644204917Sdes 1645204917Sdes /* 1646204917Sdes * Stick around until the controlee closes the client_fd. 1647204917Sdes */ 1648204917Sdes buffer_clear(&m); 1649204917Sdes if (mux_client_read_packet(fd, &m) != 0) { 1650204917Sdes if (errno == EPIPE || 1651204917Sdes (errno == EINTR && muxclient_terminate != 0)) 1652204917Sdes return 0; 1653204917Sdes fatal("%s: mux_client_read_packet: %s", 1654204917Sdes __func__, strerror(errno)); 1655204917Sdes } 1656204917Sdes fatal("%s: master returned unexpected message %u", __func__, type); 1657180750Sdes} 1658180750Sdes 1659180750Sdes/* Multiplex client main loop. */ 1660180750Sdesvoid 1661180750Sdesmuxclient(const char *path) 1662180750Sdes{ 1663180750Sdes struct sockaddr_un addr; 1664204917Sdes socklen_t sun_len; 1665204917Sdes int sock; 1666204917Sdes u_int pid; 1667180750Sdes 1668204917Sdes if (muxclient_command == 0) { 1669204917Sdes if (stdio_forward_host != NULL) 1670204917Sdes muxclient_command = SSHMUX_COMMAND_STDIO_FWD; 1671204917Sdes else 1672204917Sdes muxclient_command = SSHMUX_COMMAND_OPEN; 1673204917Sdes } 1674180750Sdes 1675180750Sdes switch (options.control_master) { 1676180750Sdes case SSHCTL_MASTER_AUTO: 1677180750Sdes case SSHCTL_MASTER_AUTO_ASK: 1678180750Sdes debug("auto-mux: Trying existing master"); 1679180750Sdes /* FALLTHROUGH */ 1680180750Sdes case SSHCTL_MASTER_NO: 1681180750Sdes break; 1682180750Sdes default: 1683180750Sdes return; 1684180750Sdes } 1685180750Sdes 1686180750Sdes memset(&addr, '\0', sizeof(addr)); 1687180750Sdes addr.sun_family = AF_UNIX; 1688204917Sdes sun_len = offsetof(struct sockaddr_un, sun_path) + 1689180750Sdes strlen(path) + 1; 1690180750Sdes 1691180750Sdes if (strlcpy(addr.sun_path, path, 1692180750Sdes sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) 1693180750Sdes fatal("ControlPath too long"); 1694180750Sdes 1695180750Sdes if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) 1696180750Sdes fatal("%s socket(): %s", __func__, strerror(errno)); 1697180750Sdes 1698204917Sdes if (connect(sock, (struct sockaddr *)&addr, sun_len) == -1) { 1699204917Sdes switch (muxclient_command) { 1700204917Sdes case SSHMUX_COMMAND_OPEN: 1701204917Sdes case SSHMUX_COMMAND_STDIO_FWD: 1702204917Sdes break; 1703204917Sdes default: 1704180750Sdes fatal("Control socket connect(%.100s): %s", path, 1705180750Sdes strerror(errno)); 1706180750Sdes } 1707180750Sdes if (errno == ENOENT) 1708180750Sdes debug("Control socket \"%.100s\" does not exist", path); 1709180750Sdes else { 1710180750Sdes error("Control socket connect(%.100s): %s", path, 1711180750Sdes strerror(errno)); 1712180750Sdes } 1713180750Sdes close(sock); 1714180750Sdes return; 1715180750Sdes } 1716204917Sdes set_nonblock(sock); 1717180750Sdes 1718204917Sdes if (mux_client_hello_exchange(sock) != 0) { 1719204917Sdes error("%s: master hello exchange failed", __func__); 1720180750Sdes close(sock); 1721180750Sdes return; 1722180750Sdes } 1723180750Sdes 1724180750Sdes switch (muxclient_command) { 1725180750Sdes case SSHMUX_COMMAND_ALIVE_CHECK: 1726204917Sdes if ((pid = mux_client_request_alive(sock)) == 0) 1727204917Sdes fatal("%s: master alive check failed", __func__); 1728204917Sdes fprintf(stderr, "Master running (pid=%d)\r\n", pid); 1729180750Sdes exit(0); 1730180750Sdes case SSHMUX_COMMAND_TERMINATE: 1731204917Sdes mux_client_request_terminate(sock); 1732180750Sdes fprintf(stderr, "Exit request sent.\r\n"); 1733180750Sdes exit(0); 1734180750Sdes case SSHMUX_COMMAND_OPEN: 1735204917Sdes if (mux_client_request_forwards(sock) != 0) { 1736204917Sdes error("%s: master forward request failed", __func__); 1737204917Sdes return; 1738180750Sdes } 1739204917Sdes mux_client_request_session(sock); 1740204917Sdes return; 1741204917Sdes case SSHMUX_COMMAND_STDIO_FWD: 1742204917Sdes mux_client_request_stdio_fwd(sock); 1743204917Sdes exit(0); 1744180750Sdes default: 1745180750Sdes fatal("unrecognised muxclient_command %d", muxclient_command); 1746180750Sdes } 1747180750Sdes} 1748