[PATCH/RFC 2/6] merge local and remote forward lists

Bert Wesarg bert.wesarg at googlemail.com
Thu May 3 21:33:48 EST 2012


---
 mux.c        |   99 ++++++++++++++++++++--------------------------------------
 readconf.c   |   87 +++++++++++++++-----------------------------------
 readconf.h   |   13 ++-----
 ssh.c        |   74 ++++++++++++++++++++++++-------------------
 sshconnect.c |    8 ++--
 5 files changed, 110 insertions(+), 171 deletions(-)

diff --git a/mux.c b/mux.c
index e7b81d1..d57c1de 100644
--- a/mux.c
+++ b/mux.c
@@ -584,11 +584,15 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
 		return;
 	}
 	buffer_init(&out);
-	if (fctx->fid >= options.num_remote_forwards) {
+	if (fctx->fid >= options.num_forwards) {
 		xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid);
 		goto fail;
 	}
-	rfwd = &options.remote_forwards[fctx->fid];
+	rfwd = &options.forwards[fctx->fid];
+	if (rfwd->type != SSH_FWD_REMOTE) {
+		xasprintf(&failmsg, "non-remote forwarding id %d", fctx->fid);
+		goto fail;
+	}
 	debug("%s: %s for: listen %d, connect %s:%d", __func__,
 	    type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
 	    rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
@@ -688,37 +692,23 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
 	}
 
 	/* Skip forwards that have already been requested */
-	switch (fwd.type) {
-	case MUX_FWD_LOCAL:
-	case MUX_FWD_DYNAMIC:
-		for (i = 0; i < options.num_local_forwards; i++) {
-			if (compare_forward(&fwd,
-			    options.local_forwards + i)) {
- exists:
-				debug2("%s: found existing forwarding",
-				    __func__);
-				buffer_put_int(r, MUX_S_OK);
-				buffer_put_int(r, rid);
-				goto out;
-			}
-		}
-		break;
-	case MUX_FWD_REMOTE:
-		for (i = 0; i < options.num_remote_forwards; i++) {
-			if (compare_forward(&fwd,
-			    options.remote_forwards + i)) {
-				if (fwd.listen_port != 0)
-					goto exists;
-				debug2("%s: found allocated port",
-				    __func__);
-				buffer_put_int(r, MUX_S_REMOTE_PORT);
-				buffer_put_int(r, rid);
-				buffer_put_int(r,
-				    options.remote_forwards[i].allocated_port);
-				goto out;
-			}
+	for (i = 0; i < options.num_forwards; i++) {
+		if (!compare_forward(&fwd, &options.forwards[i]))
+			continue;
+		if (fwd.type == MUX_FWD_REMOTE && fwd.listen_port == 0) {
+			debug2("%s: found allocated port",
+			    __func__);
+			buffer_put_int(r, MUX_S_REMOTE_PORT);
+			buffer_put_int(r, rid);
+			buffer_put_int(r,
+			    options.forwards[i].allocated_port);
+		} else {
+			debug2("%s: found existing forwarding",
+			    __func__);
+			buffer_put_int(r, MUX_S_OK);
+			buffer_put_int(r, rid);
 		}
-		break;
+		goto out;
 	}
 
 	if (options.control_master == SSHCTL_MASTER_ASK ||
@@ -743,7 +733,7 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
 			buffer_put_cstring(r, "Port forwarding failed");
 			goto out;
 		}
-		add_local_forward(&options, &fwd);
+		add_forward(&options, &fwd);
 		freefwd = 0;
 	} else {
 		struct mux_channel_confirm_ctx *fctx;
@@ -752,11 +742,11 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
 		    fwd.listen_port, fwd.connect_host, fwd.connect_port);
 		if (fwd.handle < 0)
 			goto fail;
-		add_remote_forward(&options, &fwd);
+		add_forward(&options, &fwd);
 		fctx = xcalloc(1, sizeof(*fctx));
 		fctx->cid = c->self;
 		fctx->rid = rid;
-		fctx->fid = options.num_remote_forwards - 1;
+		fctx->fid = options.num_forwards - 1;
 		client_register_global_confirm(mux_confirm_remote_forward,
 		    fctx);
 		freefwd = 0;
@@ -811,26 +801,11 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
 
 	/* make sure this has been requested */
 	found_fwd = NULL;
-	switch (fwd.type) {
-	case MUX_FWD_LOCAL:
-	case MUX_FWD_DYNAMIC:
-		for (i = 0; i < options.num_local_forwards; i++) {
-			if (compare_forward(&fwd,
-			    options.local_forwards + i)) {
-				found_fwd = options.local_forwards + i;
-				break;
-			}
-		}
-		break;
-	case MUX_FWD_REMOTE:
-		for (i = 0; i < options.num_remote_forwards; i++) {
-			if (compare_forward(&fwd,
-			    options.remote_forwards + i)) {
-				found_fwd = options.remote_forwards + i;
-				break;
-			}
+	for (i = 0; i < options.num_forwards; i++) {
+		if (compare_forward(&fwd, &options.forwards[i])) {
+			found_fwd = &options.forwards[i];
+			break;
 		}
-		break;
 	}
 
 	if (found_fwd == NULL)
@@ -838,7 +813,7 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
 	else if (found_fwd->type == MUX_FWD_REMOTE) {
 		/*
 		 * This shouldn't fail unless we confused the host/port
-		 * between options.remote_forwards and permitted_opens.
+		 * between options.forwards and permitted_opens.
 		 * However, for dynamic allocated listen ports we need
 		 * to lookup the actual listen port.
 		 */
@@ -1674,19 +1649,13 @@ mux_client_forwards(int fd, int cancel_flag)
 {
 	int i, ret = 0;
 
-	debug3("%s: %s forwardings: %d local, %d remote", __func__,
-	    cancel_flag ? "cancel" : "request",
-	    options.num_local_forwards, options.num_remote_forwards);
+	debug3("%s: %s %d forwardings", __func__,
+	    cancel_flag ? "cancel" : "request", options.num_forwards);
 
 	/* XXX ExitOnForwardingFailure */
-	for (i = 0; i < options.num_local_forwards; i++) {
-		if (mux_client_forward(fd, cancel_flag,
-		    options.local_forwards + i) != 0)
-			ret = -1;
-	}
-	for (i = 0; i < options.num_remote_forwards; i++) {
+	for (i = 0; i < options.num_forwards; i++) {
 		if (mux_client_forward(fd, cancel_flag,
-		    options.remote_forwards + i) != 0)
+		    &options.forwards[i]) != 0)
 			ret = -1;
 	}
 	return ret;
diff --git a/readconf.c b/readconf.c
index 29e12bd..d0687af 100644
--- a/readconf.c
+++ b/readconf.c
@@ -256,48 +256,30 @@ static struct {
  */
 
 void
-add_local_forward(Options *options, const Forward *newfwd)
+add_forward(Options *options, const Forward *newfwd)
 {
 	Forward *fwd;
 #ifndef NO_IPPORT_RESERVED_CONCEPT
-	extern uid_t original_real_uid;
-	if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
-		fatal("Privileged ports can only be forwarded by root.");
+	if (newfwd->type != SSH_FWD_REMOTE) {
+		extern uid_t original_real_uid;
+		if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
+			fatal("Privileged ports can only be forwarded by root.");
+	}
 #endif
-	options->local_forwards = xrealloc(options->local_forwards,
-	    options->num_local_forwards + 1,
-	    sizeof(*options->local_forwards));
-	fwd = &options->local_forwards[options->num_local_forwards++];
-
-	fwd->type = newfwd->type;
-	fwd->listen_host = newfwd->listen_host;
-	fwd->listen_port = newfwd->listen_port;
-	fwd->connect_host = newfwd->connect_host;
-	fwd->connect_port = newfwd->connect_port;
-}
-
-/*
- * Adds a remote TCP/IP port forward to options.  Never returns if there is
- * an error.
- */
-
-void
-add_remote_forward(Options *options, const Forward *newfwd)
-{
-	Forward *fwd;
-
-	options->remote_forwards = xrealloc(options->remote_forwards,
-	    options->num_remote_forwards + 1,
-	    sizeof(*options->remote_forwards));
-	fwd = &options->remote_forwards[options->num_remote_forwards++];
+	options->forwards = xrealloc(options->forwards,
+	    options->num_forwards + 1,
+	    sizeof(*options->forwards));
+	fwd = &options->forwards[options->num_forwards++];
 
 	fwd->type = newfwd->type;
 	fwd->listen_host = newfwd->listen_host;
 	fwd->listen_port = newfwd->listen_port;
 	fwd->connect_host = newfwd->connect_host;
 	fwd->connect_port = newfwd->connect_port;
-	fwd->handle = newfwd->handle;
-	fwd->allocated_port = 0;
+	if (newfwd->type == SSH_FWD_REMOTE) {
+		fwd->handle = newfwd->handle;
+		fwd->allocated_port = 0;
+	}
 }
 
 static void
@@ -305,26 +287,16 @@ clear_forwardings(Options *options)
 {
 	int i;
 
-	for (i = 0; i < options->num_local_forwards; i++) {
-		if (options->local_forwards[i].listen_host != NULL)
-			xfree(options->local_forwards[i].listen_host);
-		xfree(options->local_forwards[i].connect_host);
+	for (i = 0; i < options->num_forwards; i++) {
+		if (options->forwards[i].listen_host != NULL)
+			xfree(options->forwards[i].listen_host);
+		xfree(options->forwards[i].connect_host);
 	}
-	if (options->num_local_forwards > 0) {
-		xfree(options->local_forwards);
-		options->local_forwards = NULL;
+	if (options->num_forwards > 0) {
+		xfree(options->forwards);
+		options->forwards = NULL;
 	}
-	options->num_local_forwards = 0;
-	for (i = 0; i < options->num_remote_forwards; i++) {
-		if (options->remote_forwards[i].listen_host != NULL)
-			xfree(options->remote_forwards[i].listen_host);
-		xfree(options->remote_forwards[i].connect_host);
-	}
-	if (options->num_remote_forwards > 0) {
-		xfree(options->remote_forwards);
-		options->remote_forwards = NULL;
-	}
-	options->num_remote_forwards = 0;
+	options->num_forwards = 0;
 	options->tun_open = SSH_TUNMODE_NO;
 }
 
@@ -792,13 +764,8 @@ parse_int:
 			fatal("%.200s line %d: Bad forwarding specification.",
 			    filename, linenum);
 
-		if (*activep) {
-			if (opcode == oLocalForward ||
-			    opcode == oDynamicForward)
-				add_local_forward(options, &fwd);
-			else if (opcode == oRemoteForward)
-				add_remote_forward(options, &fwd);
-		}
+		if (*activep)
+			add_forward(options, &fwd);
 		break;
 
 	case oClearAllForwardings:
@@ -1173,10 +1140,8 @@ initialize_options(Options * options)
 	options->escape_char = -1;
 	options->num_system_hostfiles = 0;
 	options->num_user_hostfiles = 0;
-	options->local_forwards = NULL;
-	options->num_local_forwards = 0;
-	options->remote_forwards = NULL;
-	options->num_remote_forwards = 0;
+	options->forwards = NULL;
+	options->num_forwards = 0;
 	options->clear_forwardings = -1;
 	options->log_level = SYSLOG_LEVEL_NOT_SET;
 	options->preferred_authentications = NULL;
diff --git a/readconf.h b/readconf.h
index b15d916..c4ce149 100644
--- a/readconf.h
+++ b/readconf.h
@@ -104,13 +104,9 @@ typedef struct {
 	char   *identity_files[SSH_MAX_IDENTITY_FILES];
 	Key    *identity_keys[SSH_MAX_IDENTITY_FILES];
 
-	/* Local TCP/IP forward requests. */
-	int     num_local_forwards;
-	Forward *local_forwards;
-
-	/* Remote TCP/IP forward requests. */
-	int     num_remote_forwards;
-	Forward *remote_forwards;
+	/* Local and remote TCP/IP forward requests. */
+	int     num_forwards;
+	Forward *forwards;
 	int	clear_forwardings;
 
 	int	enable_ssh_keysign;
@@ -162,7 +158,6 @@ int
 process_config_line(Options *, const char *, char *, const char *, int, int *);
 
 int	 parse_forward(Forward *, const char *, u_int);
-void	 add_local_forward(Options *, const Forward *);
-void	 add_remote_forward(Options *, const Forward *);
+void	 add_forward(Options *, const Forward *);
 
 #endif				/* READCONF_H */
diff --git a/ssh.c b/ssh.c
index a63bfab..c29f522 100644
--- a/ssh.c
+++ b/ssh.c
@@ -184,7 +184,7 @@ Buffer command;
 int subsystem_flag = 0;
 
 /* # of replies received for global requests */
-static int remote_forward_confirms_received = 0;
+static int remote_forward_confirms_pending = 0;
 
 /* mux.c */
 extern int muxserver_sock;
@@ -539,7 +539,7 @@ main(int ac, char **av)
 
 		case 'L':
 			if (parse_forward(&fwd, optarg, SSH_FWD_LOCAL))
-				add_local_forward(&options, &fwd);
+				add_forward(&options, &fwd);
 			else {
 				fprintf(stderr,
 				    "Bad local forwarding specification '%s'\n",
@@ -550,7 +550,7 @@ main(int ac, char **av)
 
 		case 'R':
 			if (parse_forward(&fwd, optarg, SSH_FWD_REMOTE)) {
-				add_remote_forward(&options, &fwd);
+				add_forward(&options, &fwd);
 			} else {
 				fprintf(stderr,
 				    "Bad remote forwarding specification "
@@ -561,7 +561,7 @@ main(int ac, char **av)
 
 		case 'D':
 			if (parse_forward(&fwd, optarg, SSH_FWD_DYNAMIC)) {
-				add_local_forward(&options, &fwd);
+				add_forward(&options, &fwd);
 			} else {
 				fprintf(stderr,
 				    "Bad dynamic forwarding specification "
@@ -1019,6 +1019,7 @@ static void
 ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
 {
 	Forward *rfwd = (Forward *)ctxt;
+	remote_forward_confirms_pending--;
 
 	/* XXX verbose() on failure? */
 	debug("remote forward %s for: listen %d, connect %s:%d",
@@ -1045,7 +1046,7 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
 			logit("Warning: remote port forwarding failed for "
 			    "listen port %d", rfwd->listen_port);
 	}
-	if (++remote_forward_confirms_received == options.num_remote_forwards) {
+	if (remote_forward_confirms_pending == 0) {
 		debug("All remote forwarding requests processed");
 		if (fork_after_authentication_flag)
 			fork_postauth();
@@ -1085,54 +1086,63 @@ static void
 ssh_init_forwarding(void)
 {
 	int success = 0;
+	int num_local_forwards = 0;
 	int i;
 
 	/* Initiate local TCP/IP port forwardings. */
-	for (i = 0; i < options.num_local_forwards; i++) {
+	for (i = 0; i < options.num_forwards; i++) {
+		if (options.forwards[i].type == SSH_FWD_REMOTE)
+			continue;
+		num_local_forwards++;
 		debug("Local connections to %.200s:%d forwarded to remote "
 		    "address %.200s:%d",
-		    (options.local_forwards[i].listen_host == NULL) ?
+		    (options.forwards[i].listen_host == NULL) ?
 		    (options.gateway_ports ? "*" : "LOCALHOST") :
-		    options.local_forwards[i].listen_host,
-		    options.local_forwards[i].listen_port,
-		    options.local_forwards[i].connect_host,
-		    options.local_forwards[i].connect_port);
+		    options.forwards[i].listen_host,
+		    options.forwards[i].listen_port,
+		    options.forwards[i].connect_host,
+		    options.forwards[i].connect_port);
 		success += channel_setup_local_fwd_listener(
-		    options.local_forwards[i].listen_host,
-		    options.local_forwards[i].listen_port,
-		    options.local_forwards[i].connect_host,
-		    options.local_forwards[i].connect_port,
+		    options.forwards[i].listen_host,
+		    options.forwards[i].listen_port,
+		    options.forwards[i].connect_host,
+		    options.forwards[i].connect_port,
 		    options.gateway_ports);
 	}
-	if (i > 0 && success != i && options.exit_on_forward_failure)
+	if (num_local_forwards > 0 &&
+	    success != num_local_forwards &&
+	    options.exit_on_forward_failure)
 		fatal("Could not request local forwarding.");
-	if (i > 0 && success == 0)
+	if (num_local_forwards > 0 && success == 0)
 		error("Could not request local forwarding.");
 
 	/* Initiate remote TCP/IP port forwardings. */
-	for (i = 0; i < options.num_remote_forwards; i++) {
+	for (i = 0; i < options.num_forwards; i++) {
+		if (options.forwards[i].type != SSH_FWD_REMOTE)
+			continue;
 		debug("Remote connections from %.200s:%d forwarded to "
 		    "local address %.200s:%d",
-		    (options.remote_forwards[i].listen_host == NULL) ?
-		    "LOCALHOST" : options.remote_forwards[i].listen_host,
-		    options.remote_forwards[i].listen_port,
-		    options.remote_forwards[i].connect_host,
-		    options.remote_forwards[i].connect_port);
-		options.remote_forwards[i].handle =
+		    (options.forwards[i].listen_host == NULL) ?
+		    "LOCALHOST" : options.forwards[i].listen_host,
+		    options.forwards[i].listen_port,
+		    options.forwards[i].connect_host,
+		    options.forwards[i].connect_port);
+		options.forwards[i].handle =
 		    channel_request_remote_forwarding(
-		    options.remote_forwards[i].listen_host,
-		    options.remote_forwards[i].listen_port,
-		    options.remote_forwards[i].connect_host,
-		    options.remote_forwards[i].connect_port);
-		if (options.remote_forwards[i].handle < 0) {
+		    options.forwards[i].listen_host,
+		    options.forwards[i].listen_port,
+		    options.forwards[i].connect_host,
+		    options.forwards[i].connect_port);
+		if (options.forwards[i].handle < 0) {
 			if (options.exit_on_forward_failure)
 				fatal("Could not request remote forwarding.");
 			else
 				logit("Warning: Could not request remote "
 				    "forwarding.");
 		} else {
+			remote_forward_confirms_pending++;
 			client_register_global_confirm(ssh_confirm_remote_forward,
-			    &options.remote_forwards[i]);
+			    &options.forwards[i]);
 		}
 	}
 
@@ -1291,7 +1301,7 @@ ssh_session(void)
 	 */
 	if (fork_after_authentication_flag) {
 		if (options.exit_on_forward_failure &&
-		    options.num_remote_forwards > 0) {
+		    remote_forward_confirms_pending) {
 			debug("deferring postauth fork until remote forward "
 			    "confirmation received");
 		} else
@@ -1475,7 +1485,7 @@ ssh_session2(void)
 	 */
 	if (fork_after_authentication_flag) {
 		if (options.exit_on_forward_failure &&
-		    options.num_remote_forwards > 0) {
+		    remote_forward_confirms_pending) {
 			debug("deferring postauth fork until remote forward "
 			    "confirmation received");
 		} else
diff --git a/sshconnect.c b/sshconnect.c
index 0ee7266..9e98346 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1014,12 +1014,12 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
 			options.forward_x11 = 0;
 			cancelled_forwarding = 1;
 		}
-		if (options.num_local_forwards > 0 ||
-		    options.num_remote_forwards > 0) {
+		if (options.num_forwards > 0) {
 			error("Port forwarding is disabled to avoid "
 			    "man-in-the-middle attacks.");
-			options.num_local_forwards =
-			    options.num_remote_forwards = 0;
+			options.num_forwards = 0;
+			xfree(options.forwards);
+			options.forwards = NULL;
 			cancelled_forwarding = 1;
 		}
 		if (options.tun_open != SSH_TUNMODE_NO) {
-- 
1.7.9.rc0.542.g07ca1



More information about the openssh-unix-dev mailing list