version 1.18, 2017/04/18 18:41:46 |
version 1.18.4.1, 2017/12/04 10:55:18 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
/* $OpenBSD: mux.c,v 1.64 2017/01/21 11:32:04 guenther Exp $ */ |
/* $OpenBSD: mux.c,v 1.69 2017/09/20 05:19:00 dtucker Exp $ */ |
/* |
/* |
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> |
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> |
* |
* |
Line 151 struct mux_master_state { |
|
Line 151 struct mux_master_state { |
|
#define MUX_FWD_REMOTE 2 |
#define MUX_FWD_REMOTE 2 |
#define MUX_FWD_DYNAMIC 3 |
#define MUX_FWD_DYNAMIC 3 |
|
|
static void mux_session_confirm(int, int, void *); |
static void mux_session_confirm(struct ssh *, int, int, void *); |
static void mux_stdio_confirm(int, int, void *); |
static void mux_stdio_confirm(struct ssh *, int, int, void *); |
|
|
static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); |
static int process_mux_master_hello(struct ssh *, u_int, |
static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); |
Channel *, struct sshbuf *, struct sshbuf *); |
static int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *); |
static int process_mux_new_session(struct ssh *, u_int, |
static int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *); |
Channel *, struct sshbuf *, struct sshbuf *); |
static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); |
static int process_mux_alive_check(struct ssh *, u_int, |
static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); |
Channel *, struct sshbuf *, struct sshbuf *); |
static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); |
static int process_mux_terminate(struct ssh *, u_int, |
static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *); |
Channel *, struct sshbuf *, struct sshbuf *); |
static int process_mux_proxy(u_int, Channel *, Buffer *, Buffer *); |
static int process_mux_open_fwd(struct ssh *, u_int, |
|
Channel *, struct sshbuf *, struct sshbuf *); |
|
static int process_mux_close_fwd(struct ssh *, u_int, |
|
Channel *, struct sshbuf *, struct sshbuf *); |
|
static int process_mux_stdio_fwd(struct ssh *, u_int, |
|
Channel *, struct sshbuf *, struct sshbuf *); |
|
static int process_mux_stop_listening(struct ssh *, u_int, |
|
Channel *, struct sshbuf *, struct sshbuf *); |
|
static int process_mux_proxy(struct ssh *, u_int, |
|
Channel *, struct sshbuf *, struct sshbuf *); |
|
|
static const struct { |
static const struct { |
u_int type; |
u_int type; |
int (*handler)(u_int, Channel *, Buffer *, Buffer *); |
int (*handler)(struct ssh *, u_int, Channel *, |
|
struct sshbuf *, struct sshbuf *); |
} mux_master_handlers[] = { |
} mux_master_handlers[] = { |
{ MUX_MSG_HELLO, process_mux_master_hello }, |
{ MUX_MSG_HELLO, process_mux_master_hello }, |
{ MUX_C_NEW_SESSION, process_mux_new_session }, |
{ MUX_C_NEW_SESSION, process_mux_new_session }, |
Line 183 static const struct { |
|
Line 193 static const struct { |
|
/* Cleanup callback fired on closure of mux slave _session_ channel */ |
/* Cleanup callback fired on closure of mux slave _session_ channel */ |
/* ARGSUSED */ |
/* ARGSUSED */ |
static void |
static void |
mux_master_session_cleanup_cb(int cid, void *unused) |
mux_master_session_cleanup_cb(struct ssh *ssh, int cid, void *unused) |
{ |
{ |
Channel *cc, *c = channel_by_id(cid); |
Channel *cc, *c = channel_by_id(ssh, cid); |
|
|
debug3("%s: entering for channel %d", __func__, cid); |
debug3("%s: entering for channel %d", __func__, cid); |
if (c == NULL) |
if (c == NULL) |
fatal("%s: channel_by_id(%i) == NULL", __func__, cid); |
fatal("%s: channel_by_id(%i) == NULL", __func__, cid); |
if (c->ctl_chan != -1) { |
if (c->ctl_chan != -1) { |
if ((cc = channel_by_id(c->ctl_chan)) == NULL) |
if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL) |
fatal("%s: channel %d missing control channel %d", |
fatal("%s: channel %d missing control channel %d", |
__func__, c->self, c->ctl_chan); |
__func__, c->self, c->ctl_chan); |
c->ctl_chan = -1; |
c->ctl_chan = -1; |
cc->remote_id = -1; |
cc->remote_id = 0; |
chan_rcvd_oclose(cc); |
cc->have_remote_id = 0; |
|
chan_rcvd_oclose(ssh, cc); |
} |
} |
channel_cancel_cleanup(c->self); |
channel_cancel_cleanup(ssh, c->self); |
} |
} |
|
|
/* Cleanup callback fired on closure of mux slave _control_ channel */ |
/* Cleanup callback fired on closure of mux slave _control_ channel */ |
/* ARGSUSED */ |
/* ARGSUSED */ |
static void |
static void |
mux_master_control_cleanup_cb(int cid, void *unused) |
mux_master_control_cleanup_cb(struct ssh *ssh, int cid, void *unused) |
{ |
{ |
Channel *sc, *c = channel_by_id(cid); |
Channel *sc, *c = channel_by_id(ssh, cid); |
|
|
debug3("%s: entering for channel %d", __func__, cid); |
debug3("%s: entering for channel %d", __func__, cid); |
if (c == NULL) |
if (c == NULL) |
fatal("%s: channel_by_id(%i) == NULL", __func__, cid); |
fatal("%s: channel_by_id(%i) == NULL", __func__, cid); |
if (c->remote_id != -1) { |
if (c->have_remote_id) { |
if ((sc = channel_by_id(c->remote_id)) == NULL) |
if ((sc = channel_by_id(ssh, c->remote_id)) == NULL) |
fatal("%s: channel %d missing session channel %d", |
fatal("%s: channel %d missing session channel %u", |
__func__, c->self, c->remote_id); |
__func__, c->self, c->remote_id); |
c->remote_id = -1; |
c->remote_id = 0; |
|
c->have_remote_id = 0; |
sc->ctl_chan = -1; |
sc->ctl_chan = -1; |
if (sc->type != SSH_CHANNEL_OPEN && |
if (sc->type != SSH_CHANNEL_OPEN && |
sc->type != SSH_CHANNEL_OPENING) { |
sc->type != SSH_CHANNEL_OPENING) { |
debug2("%s: channel %d: not open", __func__, sc->self); |
debug2("%s: channel %d: not open", __func__, sc->self); |
chan_mark_dead(sc); |
chan_mark_dead(ssh, sc); |
} else { |
} else { |
if (sc->istate == CHAN_INPUT_OPEN) |
if (sc->istate == CHAN_INPUT_OPEN) |
chan_read_failed(sc); |
chan_read_failed(ssh, sc); |
if (sc->ostate == CHAN_OUTPUT_OPEN) |
if (sc->ostate == CHAN_OUTPUT_OPEN) |
chan_write_failed(sc); |
chan_write_failed(ssh, sc); |
} |
} |
} |
} |
channel_cancel_cleanup(c->self); |
channel_cancel_cleanup(ssh, c->self); |
} |
} |
|
|
/* Check mux client environment variables before passing them to mux master. */ |
/* Check mux client environment variables before passing them to mux master. */ |
Line 256 env_permitted(char *env) |
|
Line 268 env_permitted(char *env) |
|
/* Mux master protocol message handlers */ |
/* Mux master protocol message handlers */ |
|
|
static int |
static int |
process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r) |
process_mux_master_hello(struct ssh *ssh, u_int rid, |
|
Channel *c, Buffer *m, Buffer *r) |
{ |
{ |
u_int ver; |
u_int ver; |
struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; |
struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; |
Line 298 process_mux_master_hello(u_int rid, Chan |
|
Line 311 process_mux_master_hello(u_int rid, Chan |
|
} |
} |
|
|
static int |
static int |
process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) |
process_mux_new_session(struct ssh *ssh, u_int rid, |
|
Channel *c, Buffer *m, Buffer *r) |
{ |
{ |
Channel *nc; |
Channel *nc; |
struct mux_session_confirm_ctx *cctx; |
struct mux_session_confirm_ctx *cctx; |
Line 391 process_mux_new_session(u_int rid, Chann |
|
Line 405 process_mux_new_session(u_int rid, Chann |
|
new_fd[0], new_fd[1], new_fd[2]); |
new_fd[0], new_fd[1], new_fd[2]); |
|
|
/* XXX support multiple child sessions in future */ |
/* XXX support multiple child sessions in future */ |
if (c->remote_id != -1) { |
if (c->have_remote_id) { |
debug2("%s: session already open", __func__); |
debug2("%s: session already open", __func__); |
/* prepare reply */ |
/* prepare reply */ |
buffer_put_int(r, MUX_S_FAILURE); |
buffer_put_int(r, MUX_S_FAILURE); |
Line 443 process_mux_new_session(u_int rid, Chann |
|
Line 457 process_mux_new_session(u_int rid, Chann |
|
packetmax >>= 1; |
packetmax >>= 1; |
} |
} |
|
|
nc = channel_new("session", SSH_CHANNEL_OPENING, |
nc = channel_new(ssh, "session", SSH_CHANNEL_OPENING, |
new_fd[0], new_fd[1], new_fd[2], window, packetmax, |
new_fd[0], new_fd[1], new_fd[2], window, packetmax, |
CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); |
CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); |
|
|
nc->ctl_chan = c->self; /* link session -> control channel */ |
nc->ctl_chan = c->self; /* link session -> control channel */ |
c->remote_id = nc->self; /* link control -> session channel */ |
c->remote_id = nc->self; /* link control -> session channel */ |
|
c->have_remote_id = 1; |
|
|
if (cctx->want_tty && escape_char != 0xffffffff) { |
if (cctx->want_tty && escape_char != 0xffffffff) { |
channel_register_filter(nc->self, |
channel_register_filter(ssh, nc->self, |
client_simple_escape_filter, NULL, |
client_simple_escape_filter, NULL, |
client_filter_cleanup, |
client_filter_cleanup, |
client_new_escape_filter_ctx((int)escape_char)); |
client_new_escape_filter_ctx((int)escape_char)); |
Line 460 process_mux_new_session(u_int rid, Chann |
|
Line 475 process_mux_new_session(u_int rid, Chann |
|
debug2("%s: channel_new: %d linked to control channel %d", |
debug2("%s: channel_new: %d linked to control channel %d", |
__func__, nc->self, nc->ctl_chan); |
__func__, nc->self, nc->ctl_chan); |
|
|
channel_send_open(nc->self); |
channel_send_open(ssh, nc->self); |
channel_register_open_confirm(nc->self, mux_session_confirm, cctx); |
channel_register_open_confirm(ssh, nc->self, mux_session_confirm, cctx); |
c->mux_pause = 1; /* stop handling messages until open_confirm done */ |
c->mux_pause = 1; /* stop handling messages until open_confirm done */ |
channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); |
channel_register_cleanup(ssh, nc->self, |
|
mux_master_session_cleanup_cb, 1); |
|
|
/* reply is deferred, sent by mux_session_confirm */ |
/* reply is deferred, sent by mux_session_confirm */ |
return 0; |
return 0; |
} |
} |
|
|
static int |
static int |
process_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r) |
process_mux_alive_check(struct ssh *ssh, u_int rid, |
|
Channel *c, Buffer *m, Buffer *r) |
{ |
{ |
debug2("%s: channel %d: alive check", __func__, c->self); |
debug2("%s: channel %d: alive check", __func__, c->self); |
|
|
Line 483 process_mux_alive_check(u_int rid, Chann |
|
Line 500 process_mux_alive_check(u_int rid, Chann |
|
} |
} |
|
|
static int |
static int |
process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r) |
process_mux_terminate(struct ssh *ssh, u_int rid, |
|
Channel *c, Buffer *m, Buffer *r) |
{ |
{ |
debug2("%s: channel %d: terminate request", __func__, c->self); |
debug2("%s: channel %d: terminate request", __func__, c->self); |
|
|
Line 572 compare_forward(struct Forward *a, struc |
|
Line 590 compare_forward(struct Forward *a, struc |
|
} |
} |
|
|
static void |
static void |
mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) |
mux_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt) |
{ |
{ |
struct mux_channel_confirm_ctx *fctx = ctxt; |
struct mux_channel_confirm_ctx *fctx = ctxt; |
char *failmsg = NULL; |
char *failmsg = NULL; |
Line 580 mux_confirm_remote_forward(int type, u_i |
|
Line 598 mux_confirm_remote_forward(int type, u_i |
|
Channel *c; |
Channel *c; |
Buffer out; |
Buffer out; |
|
|
if ((c = channel_by_id(fctx->cid)) == NULL) { |
if ((c = channel_by_id(ssh, fctx->cid)) == NULL) { |
/* no channel for reply */ |
/* no channel for reply */ |
error("%s: unknown channel", __func__); |
error("%s: unknown channel", __func__); |
return; |
return; |
Line 606 mux_confirm_remote_forward(int type, u_i |
|
Line 624 mux_confirm_remote_forward(int type, u_i |
|
buffer_put_int(&out, MUX_S_REMOTE_PORT); |
buffer_put_int(&out, MUX_S_REMOTE_PORT); |
buffer_put_int(&out, fctx->rid); |
buffer_put_int(&out, fctx->rid); |
buffer_put_int(&out, rfwd->allocated_port); |
buffer_put_int(&out, rfwd->allocated_port); |
channel_update_permitted_opens(rfwd->handle, |
channel_update_permitted_opens(ssh, rfwd->handle, |
rfwd->allocated_port); |
rfwd->allocated_port); |
} else { |
} else { |
buffer_put_int(&out, MUX_S_OK); |
buffer_put_int(&out, MUX_S_OK); |
Line 615 mux_confirm_remote_forward(int type, u_i |
|
Line 633 mux_confirm_remote_forward(int type, u_i |
|
goto out; |
goto out; |
} else { |
} else { |
if (rfwd->listen_port == 0) |
if (rfwd->listen_port == 0) |
channel_update_permitted_opens(rfwd->handle, -1); |
channel_update_permitted_opens(ssh, rfwd->handle, -1); |
if (rfwd->listen_path != NULL) |
if (rfwd->listen_path != NULL) |
xasprintf(&failmsg, "remote port forwarding failed for " |
xasprintf(&failmsg, "remote port forwarding failed for " |
"listen path %s", rfwd->listen_path); |
"listen path %s", rfwd->listen_path); |
Line 641 mux_confirm_remote_forward(int type, u_i |
|
Line 659 mux_confirm_remote_forward(int type, u_i |
|
buffer_put_cstring(&out, failmsg); |
buffer_put_cstring(&out, failmsg); |
free(failmsg); |
free(failmsg); |
out: |
out: |
buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out)); |
buffer_put_string(c->output, buffer_ptr(&out), buffer_len(&out)); |
buffer_free(&out); |
buffer_free(&out); |
if (c->mux_pause <= 0) |
if (c->mux_pause <= 0) |
fatal("%s: mux_pause %d", __func__, c->mux_pause); |
fatal("%s: mux_pause %d", __func__, c->mux_pause); |
Line 649 mux_confirm_remote_forward(int type, u_i |
|
Line 667 mux_confirm_remote_forward(int type, u_i |
|
} |
} |
|
|
static int |
static int |
process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) |
process_mux_open_fwd(struct ssh *ssh, u_int rid, |
|
Channel *c, Buffer *m, Buffer *r) |
{ |
{ |
struct Forward fwd; |
struct Forward fwd; |
char *fwd_desc = NULL; |
char *fwd_desc = NULL; |
Line 717 process_mux_open_fwd(u_int rid, Channel |
|
Line 736 process_mux_open_fwd(u_int rid, Channel |
|
fwd.listen_port); |
fwd.listen_port); |
goto invalid; |
goto invalid; |
} |
} |
if ((fwd.connect_port != PORT_STREAMLOCAL && fwd.connect_port >= 65536) |
if ((fwd.connect_port != PORT_STREAMLOCAL && |
|| (ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) { |
fwd.connect_port >= 65536) || |
|
(ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE && |
|
fwd.connect_port == 0)) { |
logit("%s: invalid connect port %u", __func__, |
logit("%s: invalid connect port %u", __func__, |
fwd.connect_port); |
fwd.connect_port); |
goto invalid; |
goto invalid; |
} |
} |
if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL && fwd.connect_path == NULL) { |
if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL && |
|
fwd.connect_path == NULL) { |
logit("%s: missing connect host", __func__); |
logit("%s: missing connect host", __func__); |
goto invalid; |
goto invalid; |
} |
} |
Line 774 process_mux_open_fwd(u_int rid, Channel |
|
Line 796 process_mux_open_fwd(u_int rid, Channel |
|
} |
} |
|
|
if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { |
if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { |
if (!channel_setup_local_fwd_listener(&fwd, |
if (!channel_setup_local_fwd_listener(ssh, &fwd, |
&options.fwd_opts)) { |
&options.fwd_opts)) { |
fail: |
fail: |
logit("slave-requested %s failed", fwd_desc); |
logit("slave-requested %s failed", fwd_desc); |
Line 788 process_mux_open_fwd(u_int rid, Channel |
|
Line 810 process_mux_open_fwd(u_int rid, Channel |
|
} else { |
} else { |
struct mux_channel_confirm_ctx *fctx; |
struct mux_channel_confirm_ctx *fctx; |
|
|
fwd.handle = channel_request_remote_forwarding(&fwd); |
fwd.handle = channel_request_remote_forwarding(ssh, &fwd); |
if (fwd.handle < 0) |
if (fwd.handle < 0) |
goto fail; |
goto fail; |
add_remote_forward(&options, &fwd); |
add_remote_forward(&options, &fwd); |
Line 817 process_mux_open_fwd(u_int rid, Channel |
|
Line 839 process_mux_open_fwd(u_int rid, Channel |
|
} |
} |
|
|
static int |
static int |
process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) |
process_mux_close_fwd(struct ssh *ssh, u_int rid, |
|
Channel *c, Buffer *m, Buffer *r) |
{ |
{ |
struct Forward fwd, *found_fwd; |
struct Forward fwd, *found_fwd; |
char *fwd_desc = NULL; |
char *fwd_desc = NULL; |
Line 898 process_mux_close_fwd(u_int rid, Channel |
|
Line 921 process_mux_close_fwd(u_int rid, Channel |
|
* However, for dynamic allocated listen ports we need |
* However, for dynamic allocated listen ports we need |
* to use the actual listen port. |
* to use the actual listen port. |
*/ |
*/ |
if (channel_request_rforward_cancel(found_fwd) == -1) |
if (channel_request_rforward_cancel(ssh, found_fwd) == -1) |
error_reason = "port not in permitted opens"; |
error_reason = "port not in permitted opens"; |
} else { /* local and dynamic forwards */ |
} else { /* local and dynamic forwards */ |
/* Ditto */ |
/* Ditto */ |
if (channel_cancel_lport_listener(&fwd, fwd.connect_port, |
if (channel_cancel_lport_listener(ssh, &fwd, fwd.connect_port, |
&options.fwd_opts) == -1) |
&options.fwd_opts) == -1) |
error_reason = "port not found"; |
error_reason = "port not found"; |
} |
} |
Line 932 process_mux_close_fwd(u_int rid, Channel |
|
Line 955 process_mux_close_fwd(u_int rid, Channel |
|
} |
} |
|
|
static int |
static int |
process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) |
process_mux_stdio_fwd(struct ssh *ssh, u_int rid, |
|
Channel *c, Buffer *m, Buffer *r) |
{ |
{ |
Channel *nc; |
Channel *nc; |
char *reserved, *chost; |
char *reserved, *chost; |
Line 976 process_mux_stdio_fwd(u_int rid, Channel |
|
Line 1000 process_mux_stdio_fwd(u_int rid, Channel |
|
new_fd[0], new_fd[1]); |
new_fd[0], new_fd[1]); |
|
|
/* XXX support multiple child sessions in future */ |
/* XXX support multiple child sessions in future */ |
if (c->remote_id != -1) { |
if (c->have_remote_id) { |
debug2("%s: session already open", __func__); |
debug2("%s: session already open", __func__); |
/* prepare reply */ |
/* prepare reply */ |
buffer_put_int(r, MUX_S_FAILURE); |
buffer_put_int(r, MUX_S_FAILURE); |
Line 1008 process_mux_stdio_fwd(u_int rid, Channel |
|
Line 1032 process_mux_stdio_fwd(u_int rid, Channel |
|
if (!isatty(new_fd[1])) |
if (!isatty(new_fd[1])) |
set_nonblock(new_fd[1]); |
set_nonblock(new_fd[1]); |
|
|
nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]); |
nc = channel_connect_stdio_fwd(ssh, chost, cport, new_fd[0], new_fd[1]); |
|
|
nc->ctl_chan = c->self; /* link session -> control channel */ |
nc->ctl_chan = c->self; /* link session -> control channel */ |
c->remote_id = nc->self; /* link control -> session channel */ |
c->remote_id = nc->self; /* link control -> session channel */ |
|
c->have_remote_id = 1; |
|
|
debug2("%s: channel_new: %d linked to control channel %d", |
debug2("%s: channel_new: %d linked to control channel %d", |
__func__, nc->self, nc->ctl_chan); |
__func__, nc->self, nc->ctl_chan); |
|
|
channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1); |
channel_register_cleanup(ssh, nc->self, |
|
mux_master_session_cleanup_cb, 1); |
|
|
cctx = xcalloc(1, sizeof(*cctx)); |
cctx = xcalloc(1, sizeof(*cctx)); |
cctx->rid = rid; |
cctx->rid = rid; |
channel_register_open_confirm(nc->self, mux_stdio_confirm, cctx); |
channel_register_open_confirm(ssh, nc->self, mux_stdio_confirm, cctx); |
c->mux_pause = 1; /* stop handling messages until open_confirm done */ |
c->mux_pause = 1; /* stop handling messages until open_confirm done */ |
|
|
/* reply is deferred, sent by mux_session_confirm */ |
/* reply is deferred, sent by mux_session_confirm */ |
Line 1029 process_mux_stdio_fwd(u_int rid, Channel |
|
Line 1055 process_mux_stdio_fwd(u_int rid, Channel |
|
|
|
/* Callback on open confirmation in mux master for a mux stdio fwd session. */ |
/* Callback on open confirmation in mux master for a mux stdio fwd session. */ |
static void |
static void |
mux_stdio_confirm(int id, int success, void *arg) |
mux_stdio_confirm(struct ssh *ssh, int id, int success, void *arg) |
{ |
{ |
struct mux_stdio_confirm_ctx *cctx = arg; |
struct mux_stdio_confirm_ctx *cctx = arg; |
Channel *c, *cc; |
Channel *c, *cc; |
Line 1037 mux_stdio_confirm(int id, int success, v |
|
Line 1063 mux_stdio_confirm(int id, int success, v |
|
|
|
if (cctx == NULL) |
if (cctx == NULL) |
fatal("%s: cctx == NULL", __func__); |
fatal("%s: cctx == NULL", __func__); |
if ((c = channel_by_id(id)) == NULL) |
if ((c = channel_by_id(ssh, id)) == NULL) |
fatal("%s: no channel for id %d", __func__, id); |
fatal("%s: no channel for id %d", __func__, id); |
if ((cc = channel_by_id(c->ctl_chan)) == NULL) |
if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL) |
fatal("%s: channel %d lacks control channel %d", __func__, |
fatal("%s: channel %d lacks control channel %d", __func__, |
id, c->ctl_chan); |
id, c->ctl_chan); |
|
|
Line 1062 mux_stdio_confirm(int id, int success, v |
|
Line 1088 mux_stdio_confirm(int id, int success, v |
|
|
|
done: |
done: |
/* Send reply */ |
/* Send reply */ |
buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); |
buffer_put_string(cc->output, buffer_ptr(&reply), buffer_len(&reply)); |
buffer_free(&reply); |
buffer_free(&reply); |
|
|
if (cc->mux_pause <= 0) |
if (cc->mux_pause <= 0) |
Line 1073 mux_stdio_confirm(int id, int success, v |
|
Line 1099 mux_stdio_confirm(int id, int success, v |
|
} |
} |
|
|
static int |
static int |
process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r) |
process_mux_stop_listening(struct ssh *ssh, u_int rid, |
|
Channel *c, Buffer *m, Buffer *r) |
{ |
{ |
debug("%s: channel %d: stop listening", __func__, c->self); |
debug("%s: channel %d: stop listening", __func__, c->self); |
|
|
Line 1090 process_mux_stop_listening(u_int rid, Ch |
|
Line 1117 process_mux_stop_listening(u_int rid, Ch |
|
} |
} |
|
|
if (mux_listener_channel != NULL) { |
if (mux_listener_channel != NULL) { |
channel_free(mux_listener_channel); |
channel_free(ssh, mux_listener_channel); |
client_stop_mux(); |
client_stop_mux(); |
free(options.control_path); |
free(options.control_path); |
options.control_path = NULL; |
options.control_path = NULL; |
Line 1106 process_mux_stop_listening(u_int rid, Ch |
|
Line 1133 process_mux_stop_listening(u_int rid, Ch |
|
} |
} |
|
|
static int |
static int |
process_mux_proxy(u_int rid, Channel *c, Buffer *m, Buffer *r) |
process_mux_proxy(struct ssh *ssh, u_int rid, |
|
Channel *c, Buffer *m, Buffer *r) |
{ |
{ |
debug("%s: channel %d: proxy request", __func__, c->self); |
debug("%s: channel %d: proxy request", __func__, c->self); |
|
|
Line 1119 process_mux_proxy(u_int rid, Channel *c, |
|
Line 1147 process_mux_proxy(u_int rid, Channel *c, |
|
|
|
/* Channel callbacks fired on read/write from mux slave fd */ |
/* Channel callbacks fired on read/write from mux slave fd */ |
static int |
static int |
mux_master_read_cb(Channel *c) |
mux_master_read_cb(struct ssh *ssh, Channel *c) |
{ |
{ |
struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; |
struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; |
Buffer in, out; |
Buffer in, out; |
Line 1131 mux_master_read_cb(Channel *c) |
|
Line 1159 mux_master_read_cb(Channel *c) |
|
if (c->mux_ctx == NULL) { |
if (c->mux_ctx == NULL) { |
state = xcalloc(1, sizeof(*state)); |
state = xcalloc(1, sizeof(*state)); |
c->mux_ctx = state; |
c->mux_ctx = state; |
channel_register_cleanup(c->self, |
channel_register_cleanup(ssh, c->self, |
mux_master_control_cleanup_cb, 0); |
mux_master_control_cleanup_cb, 0); |
|
|
/* Send hello */ |
/* Send hello */ |
Line 1139 mux_master_read_cb(Channel *c) |
|
Line 1167 mux_master_read_cb(Channel *c) |
|
buffer_put_int(&out, MUX_MSG_HELLO); |
buffer_put_int(&out, MUX_MSG_HELLO); |
buffer_put_int(&out, SSHMUX_VER); |
buffer_put_int(&out, SSHMUX_VER); |
/* no extensions */ |
/* no extensions */ |
buffer_put_string(&c->output, buffer_ptr(&out), |
buffer_put_string(c->output, buffer_ptr(&out), |
buffer_len(&out)); |
buffer_len(&out)); |
buffer_free(&out); |
buffer_free(&out); |
debug3("%s: channel %d: hello sent", __func__, c->self); |
debug3("%s: channel %d: hello sent", __func__, c->self); |
Line 1150 mux_master_read_cb(Channel *c) |
|
Line 1178 mux_master_read_cb(Channel *c) |
|
buffer_init(&out); |
buffer_init(&out); |
|
|
/* Channel code ensures that we receive whole packets */ |
/* Channel code ensures that we receive whole packets */ |
if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) { |
if ((ptr = buffer_get_string_ptr_ret(c->input, &have)) == NULL) { |
malf: |
malf: |
error("%s: malformed message", __func__); |
error("%s: malformed message", __func__); |
goto out; |
goto out; |
Line 1176 mux_master_read_cb(Channel *c) |
|
Line 1204 mux_master_read_cb(Channel *c) |
|
|
|
for (i = 0; mux_master_handlers[i].handler != NULL; i++) { |
for (i = 0; mux_master_handlers[i].handler != NULL; i++) { |
if (type == mux_master_handlers[i].type) { |
if (type == mux_master_handlers[i].type) { |
ret = mux_master_handlers[i].handler(rid, c, &in, &out); |
ret = mux_master_handlers[i].handler(ssh, rid, |
|
c, &in, &out); |
break; |
break; |
} |
} |
} |
} |
Line 1189 mux_master_read_cb(Channel *c) |
|
Line 1218 mux_master_read_cb(Channel *c) |
|
} |
} |
/* Enqueue reply packet */ |
/* Enqueue reply packet */ |
if (buffer_len(&out) != 0) { |
if (buffer_len(&out) != 0) { |
buffer_put_string(&c->output, buffer_ptr(&out), |
buffer_put_string(c->output, buffer_ptr(&out), |
buffer_len(&out)); |
buffer_len(&out)); |
} |
} |
out: |
out: |
Line 1199 mux_master_read_cb(Channel *c) |
|
Line 1228 mux_master_read_cb(Channel *c) |
|
} |
} |
|
|
void |
void |
mux_exit_message(Channel *c, int exitval) |
mux_exit_message(struct ssh *ssh, Channel *c, int exitval) |
{ |
{ |
Buffer m; |
Buffer m; |
Channel *mux_chan; |
Channel *mux_chan; |
Line 1207 mux_exit_message(Channel *c, int exitval |
|
Line 1236 mux_exit_message(Channel *c, int exitval |
|
debug3("%s: channel %d: exit message, exitval %d", __func__, c->self, |
debug3("%s: channel %d: exit message, exitval %d", __func__, c->self, |
exitval); |
exitval); |
|
|
if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) |
if ((mux_chan = channel_by_id(ssh, c->ctl_chan)) == NULL) |
fatal("%s: channel %d missing mux channel %d", |
fatal("%s: channel %d missing mux channel %d", |
__func__, c->self, c->ctl_chan); |
__func__, c->self, c->ctl_chan); |
|
|
Line 1217 mux_exit_message(Channel *c, int exitval |
|
Line 1246 mux_exit_message(Channel *c, int exitval |
|
buffer_put_int(&m, c->self); |
buffer_put_int(&m, c->self); |
buffer_put_int(&m, exitval); |
buffer_put_int(&m, exitval); |
|
|
buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); |
buffer_put_string(mux_chan->output, buffer_ptr(&m), buffer_len(&m)); |
buffer_free(&m); |
buffer_free(&m); |
} |
} |
|
|
void |
void |
mux_tty_alloc_failed(Channel *c) |
mux_tty_alloc_failed(struct ssh *ssh, Channel *c) |
{ |
{ |
Buffer m; |
Buffer m; |
Channel *mux_chan; |
Channel *mux_chan; |
|
|
debug3("%s: channel %d: TTY alloc failed", __func__, c->self); |
debug3("%s: channel %d: TTY alloc failed", __func__, c->self); |
|
|
if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) |
if ((mux_chan = channel_by_id(ssh, c->ctl_chan)) == NULL) |
fatal("%s: channel %d missing mux channel %d", |
fatal("%s: channel %d missing mux channel %d", |
__func__, c->self, c->ctl_chan); |
__func__, c->self, c->ctl_chan); |
|
|
Line 1238 mux_tty_alloc_failed(Channel *c) |
|
Line 1267 mux_tty_alloc_failed(Channel *c) |
|
buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL); |
buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL); |
buffer_put_int(&m, c->self); |
buffer_put_int(&m, c->self); |
|
|
buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); |
buffer_put_string(mux_chan->output, buffer_ptr(&m), buffer_len(&m)); |
buffer_free(&m); |
buffer_free(&m); |
} |
} |
|
|
/* Prepare a mux master to listen on a Unix domain socket. */ |
/* Prepare a mux master to listen on a Unix domain socket. */ |
void |
void |
muxserver_listen(void) |
muxserver_listen(struct ssh *ssh) |
{ |
{ |
mode_t old_umask; |
mode_t old_umask; |
char *orig_control_path = options.control_path; |
char *orig_control_path = options.control_path; |
Line 1317 muxserver_listen(void) |
|
Line 1346 muxserver_listen(void) |
|
|
|
set_nonblock(muxserver_sock); |
set_nonblock(muxserver_sock); |
|
|
mux_listener_channel = channel_new("mux listener", |
mux_listener_channel = channel_new(ssh, "mux listener", |
SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, |
SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, |
0, options.control_path, 1); |
0, options.control_path, 1); |
Line 1328 muxserver_listen(void) |
|
Line 1357 muxserver_listen(void) |
|
|
|
/* Callback on open confirmation in mux master for a mux client session. */ |
/* Callback on open confirmation in mux master for a mux client session. */ |
static void |
static void |
mux_session_confirm(int id, int success, void *arg) |
mux_session_confirm(struct ssh *ssh, int id, int success, void *arg) |
{ |
{ |
struct mux_session_confirm_ctx *cctx = arg; |
struct mux_session_confirm_ctx *cctx = arg; |
const char *display; |
const char *display; |
Line 1338 mux_session_confirm(int id, int success, |
|
Line 1367 mux_session_confirm(int id, int success, |
|
|
|
if (cctx == NULL) |
if (cctx == NULL) |
fatal("%s: cctx == NULL", __func__); |
fatal("%s: cctx == NULL", __func__); |
if ((c = channel_by_id(id)) == NULL) |
if ((c = channel_by_id(ssh, id)) == NULL) |
fatal("%s: no channel for id %d", __func__, id); |
fatal("%s: no channel for id %d", __func__, id); |
if ((cc = channel_by_id(c->ctl_chan)) == NULL) |
if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL) |
fatal("%s: channel %d lacks control channel %d", __func__, |
fatal("%s: channel %d lacks control channel %d", __func__, |
id, c->ctl_chan); |
id, c->ctl_chan); |
|
|
Line 1359 mux_session_confirm(int id, int success, |
|
Line 1388 mux_session_confirm(int id, int success, |
|
char *proto, *data; |
char *proto, *data; |
|
|
/* Get reasonable local authentication information. */ |
/* Get reasonable local authentication information. */ |
if (client_x11_get_proto(display, options.xauth_location, |
if (client_x11_get_proto(ssh, display, options.xauth_location, |
options.forward_x11_trusted, options.forward_x11_timeout, |
options.forward_x11_trusted, options.forward_x11_timeout, |
&proto, &data) == 0) { |
&proto, &data) == 0) { |
/* Request forwarding with authentication spoofing. */ |
/* Request forwarding with authentication spoofing. */ |
debug("Requesting X11 forwarding with authentication " |
debug("Requesting X11 forwarding with authentication " |
"spoofing."); |
"spoofing."); |
x11_request_forwarding_with_spoofing(id, display, proto, |
x11_request_forwarding_with_spoofing(ssh, id, |
data, 1); |
display, proto, data, 1); |
/* XXX exit_on_forward_failure */ |
/* XXX exit_on_forward_failure */ |
client_expect_confirm(id, "X11 forwarding", |
client_expect_confirm(ssh, id, "X11 forwarding", |
CONFIRM_WARN); |
CONFIRM_WARN); |
} |
} |
} |
} |
|
|
if (cctx->want_agent_fwd && options.forward_agent) { |
if (cctx->want_agent_fwd && options.forward_agent) { |
debug("Requesting authentication agent forwarding."); |
debug("Requesting authentication agent forwarding."); |
channel_request_start(id, "auth-agent-req@openssh.com", 0); |
channel_request_start(ssh, id, "auth-agent-req@openssh.com", 0); |
packet_send(); |
packet_send(); |
} |
} |
|
|
client_session2_setup(id, cctx->want_tty, cctx->want_subsys, |
client_session2_setup(ssh, id, cctx->want_tty, cctx->want_subsys, |
cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); |
cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); |
|
|
debug3("%s: sending success reply", __func__); |
debug3("%s: sending success reply", __func__); |
Line 1391 mux_session_confirm(int id, int success, |
|
Line 1420 mux_session_confirm(int id, int success, |
|
|
|
done: |
done: |
/* Send reply */ |
/* Send reply */ |
buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply)); |
buffer_put_string(cc->output, buffer_ptr(&reply), buffer_len(&reply)); |
buffer_free(&reply); |
buffer_free(&reply); |
|
|
if (cc->mux_pause <= 0) |
if (cc->mux_pause <= 0) |
Line 1554 mux_client_hello_exchange(int fd) |
|
Line 1583 mux_client_hello_exchange(int fd) |
|
{ |
{ |
Buffer m; |
Buffer m; |
u_int type, ver; |
u_int type, ver; |
|
int ret = -1; |
|
|
buffer_init(&m); |
buffer_init(&m); |
buffer_put_int(&m, MUX_MSG_HELLO); |
buffer_put_int(&m, MUX_MSG_HELLO); |
buffer_put_int(&m, SSHMUX_VER); |
buffer_put_int(&m, SSHMUX_VER); |
/* no extensions */ |
/* no extensions */ |
|
|
if (mux_client_write_packet(fd, &m) != 0) |
if (mux_client_write_packet(fd, &m) != 0) { |
fatal("%s: write packet: %s", __func__, strerror(errno)); |
debug("%s: write packet: %s", __func__, strerror(errno)); |
|
goto out; |
|
} |
|
|
buffer_clear(&m); |
buffer_clear(&m); |
|
|
/* Read their HELLO */ |
/* Read their HELLO */ |
if (mux_client_read_packet(fd, &m) != 0) { |
if (mux_client_read_packet(fd, &m) != 0) { |
buffer_free(&m); |
debug("%s: read packet failed", __func__); |
return -1; |
goto out; |
} |
} |
|
|
type = buffer_get_int(&m); |
type = buffer_get_int(&m); |
if (type != MUX_MSG_HELLO) |
if (type != MUX_MSG_HELLO) { |
fatal("%s: expected HELLO (%u) received %u", |
error("%s: expected HELLO (%u) received %u", |
__func__, MUX_MSG_HELLO, type); |
__func__, MUX_MSG_HELLO, type); |
|
goto out; |
|
} |
ver = buffer_get_int(&m); |
ver = buffer_get_int(&m); |
if (ver != SSHMUX_VER) |
if (ver != SSHMUX_VER) { |
fatal("Unsupported multiplexing protocol version %d " |
error("Unsupported multiplexing protocol version %d " |
"(expected %d)", ver, SSHMUX_VER); |
"(expected %d)", ver, SSHMUX_VER); |
|
goto out; |
|
} |
debug2("%s: master version %u", __func__, ver); |
debug2("%s: master version %u", __func__, ver); |
/* No extensions are presently defined */ |
/* No extensions are presently defined */ |
while (buffer_len(&m) > 0) { |
while (buffer_len(&m) > 0) { |
Line 1589 mux_client_hello_exchange(int fd) |
|
Line 1625 mux_client_hello_exchange(int fd) |
|
free(name); |
free(name); |
free(value); |
free(value); |
} |
} |
|
/* success */ |
|
ret = 0; |
|
out: |
buffer_free(&m); |
buffer_free(&m); |
return 0; |
return ret; |
} |
} |
|
|
static u_int |
static u_int |
Line 1947 mux_client_request_session(int fd) |
|
Line 1986 mux_client_request_session(int fd) |
|
leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
|
|
if (muxclient_terminate) { |
if (muxclient_terminate) { |
debug2("Exiting on signal %ld", (long)muxclient_terminate); |
debug2("Exiting on signal: %s", strsignal(muxclient_terminate)); |
exitval = 255; |
exitval = 255; |
} else if (!exitval_seen) { |
} else if (!exitval_seen) { |
debug2("Control master terminated unexpectedly"); |
debug2("Control master terminated unexpectedly"); |