diff options
author | Darren Tucker <dtucker@zip.com.au> | 2008-06-13 04:50:27 +1000 |
---|---|---|
committer | Darren Tucker <dtucker@zip.com.au> | 2008-06-13 04:50:27 +1000 |
commit | 9f407c4422a7f8283eda674e10755d0b4f1c2413 (patch) | |
tree | 64b489e36a0e022ecd27b87c19d7529bf3733464 | |
parent | 2fb66caca2c9e69c6a0584060114fcd52e59d5ff (diff) |
- djm@cvs.openbsd.org 2008/06/12 04:06:00
[clientloop.h ssh.c clientloop.c]
maintain an ordered queue of outstanding global requests that we
expect replies to, similar to the per-channel confirmation queue.
Use this queue to verify success or failure for remote forward
establishment in a race free way.
ok dtucker@
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | clientloop.c | 49 | ||||
-rw-r--r-- | clientloop.h | 6 | ||||
-rw-r--r-- | ssh.c | 53 |
4 files changed, 86 insertions, 31 deletions
@@ -78,6 +78,13 @@ mux client will not be able to connect to a running old ssh mux master. ok dtucker@ + - djm@cvs.openbsd.org 2008/06/12 04:06:00 + [clientloop.h ssh.c clientloop.c] + maintain an ordered queue of outstanding global requests that we + expect replies to, similar to the per-channel confirmation queue. + Use this queue to verify success or failure for remote forward + establishment in a race free way. + ok dtucker@ 20080611 - (djm) [channels.c configure.ac] @@ -4240,4 +4247,4 @@ OpenServer 6 and add osr5bigcrypt support so when someone migrates passwords between UnixWare and OpenServer they will still work. OK dtucker@ -$Id: ChangeLog,v 1.4977 2008/06/12 18:49:33 dtucker Exp $ +$Id: ChangeLog,v 1.4978 2008/06/12 18:50:27 dtucker Exp $ diff --git a/clientloop.c b/clientloop.c index b45e7298..37cecf5a 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.195 2008/06/12 03:40:52 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.196 2008/06/12 04:06:00 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -174,6 +174,17 @@ struct channel_reply_ctx { int id, do_close; }; +/* Global request success/failure callbacks */ +struct global_confirm { + TAILQ_ENTRY(global_confirm) entry; + global_confirm_cb *cb; + void *ctx; + int ref_count; +}; +TAILQ_HEAD(global_confirms, global_confirm); +static struct global_confirms global_confirms = + TAILQ_HEAD_INITIALIZER(global_confirms); + /*XXX*/ extern Kex *xxx_kex; @@ -468,8 +479,19 @@ client_check_window_change(void) static void client_global_request_reply(int type, u_int32_t seq, void *ctxt) { + struct global_confirm *gc; + + if ((gc = TAILQ_FIRST(&global_confirms)) == NULL) + return; + if (gc->cb != NULL) + gc->cb(type, seq, gc->ctx); + if (--gc->ref_count <= 0) { + TAILQ_REMOVE(&global_confirms, gc, entry); + bzero(gc, sizeof(*gc)); + xfree(gc); + } + keep_alive_timeouts = 0; - client_global_request_reply_fwd(type, seq, ctxt); } static void @@ -483,6 +505,8 @@ server_alive_check(void) packet_put_cstring("keepalive@openssh.com"); packet_put_char(1); /* boolean: want reply */ packet_send(); + /* Insert an empty placeholder to maintain ordering */ + client_register_global_confirm(NULL, NULL); } /* @@ -702,6 +726,27 @@ client_expect_confirm(int id, const char *request, int do_close) client_abandon_status_confirm, cr); } +void +client_register_global_confirm(global_confirm_cb *cb, void *ctx) +{ + struct global_confirm *gc, *first_gc; + + /* Coalesce identical callbacks */ + first_gc = TAILQ_FIRST(&global_confirms); + if (first_gc && first_gc->cb == cb && first_gc->ctx == ctx) { + if (++first_gc->ref_count >= INT_MAX) + fatal("%s: first_gc->ref_count = %d", + __func__, first_gc->ref_count); + return; + } + + gc = xmalloc(sizeof(*gc)); + gc->cb = cb; + gc->ctx = ctx; + gc->ref_count = 1; + TAILQ_INSERT_TAIL(&global_confirms, gc, entry); +} + static void process_cmdline(void) { diff --git a/clientloop.h b/clientloop.h index cecbfb1a..3353a9a8 100644 --- a/clientloop.h +++ b/clientloop.h @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.h,v 1.20 2008/06/12 03:40:52 djm Exp $ */ +/* $OpenBSD: clientloop.h,v 1.21 2008/06/12 04:06:00 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -50,6 +50,10 @@ int client_request_tun_fwd(int, int, int); void *client_new_escape_filter_ctx(int); int client_simple_escape_filter(Channel *, char *, int); +/* Global request confirmation callbacks */ +typedef void global_confirm_cb(int, u_int32_t seq, void *); +void client_register_global_confirm(global_confirm_cb *, void *); + /* Multiplexing protocol version */ #define SSHMUX_VER 2 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.314 2008/06/10 22:15:23 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.315 2008/06/12 04:06:00 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -164,7 +164,7 @@ Buffer command; int subsystem_flag = 0; /* # of replies received for global requests */ -static int client_global_request_id = 0; +static int remote_forward_confirms_received = 0; /* pid of proxycommand child process */ pid_t proxy_command_pid = 0; @@ -817,6 +817,28 @@ main(int ac, char **av) return exit_status; } +/* Callback for remote forward global requests */ +static void +ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) +{ + Forward *rfwd = (Forward *)ctxt; + + debug("remote forward %s for: listen %d, connect %s:%d", + type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", + rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); + if (type == SSH2_MSG_REQUEST_FAILURE) { + if (options.exit_on_forward_failure) + fatal("Error: remote port forwarding failed for " + "listen port %d", rfwd->listen_port); + else + logit("Warning: remote port forwarding failed for " + "listen port %d", rfwd->listen_port); + } + if (++remote_forward_confirms_received == options.num_remote_forwards) + debug("All remote forwarding requests processed"); + /* XXX fork-after-authentication */ +} + static void ssh_init_forwarding(void) { @@ -865,6 +887,8 @@ ssh_init_forwarding(void) logit("Warning: Could not request remote " "forwarding."); } + client_register_global_confirm(ssh_confirm_remote_forward, + &options.remote_forwards[i]); } /* Initiate tunnel forwarding. */ @@ -1034,31 +1058,6 @@ ssh_session(void) options.escape_char : SSH_ESCAPECHAR_NONE, 0); } -void -client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt) -{ - int i; - - i = client_global_request_id++; - if (i >= options.num_remote_forwards) - return; - debug("remote forward %s for: listen %d, connect %s:%d", - type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", - options.remote_forwards[i].listen_port, - options.remote_forwards[i].connect_host, - options.remote_forwards[i].connect_port); - if (type == SSH2_MSG_REQUEST_FAILURE) { - if (options.exit_on_forward_failure) - fatal("Error: remote port forwarding failed for " - "listen port %d", - options.remote_forwards[i].listen_port); - else - logit("Warning: remote port forwarding failed for " - "listen port %d", - options.remote_forwards[i].listen_port); - } -} - /* request pty/x11/agent/tcpfwd/shell for channel */ static void ssh_session2_setup(int id, void *arg) |