summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--auth-options.c28
-rw-r--r--channels.c82
-rw-r--r--channels.h10
-rw-r--r--clientloop.c49
-rw-r--r--compat.c20
-rw-r--r--compat.h3
-rw-r--r--misc.c44
-rw-r--r--misc.h3
-rw-r--r--readconf.c157
-rw-r--r--readconf.h14
-rw-r--r--servconf.c65
-rw-r--r--ssh.159
-rw-r--r--ssh.c110
-rw-r--r--ssh_config.570
-rw-r--r--sshd_config.515
16 files changed, 525 insertions, 214 deletions
diff --git a/ChangeLog b/ChangeLog
index e4ec748f..f31a5266 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -19,6 +19,14 @@
[ssh_config.5]
bz#849: document timeout on untrusted x11 forwarding sessions. Reported by
orion AT cora.nwra.com; ok markus@
+ - djm@cvs.openbsd.org 2005/03/01 10:09:52
+ [auth-options.c channels.c channels.h clientloop.c compat.c compat.h]
+ [misc.c misc.h readconf.c readconf.h servconf.c ssh.1 ssh.c ssh_config.5]
+ [sshd_config.5]
+ bz#413: allow optional specification of bind address for port forwardings.
+ Patch originally by Dan Astorian, but worked on by several people
+ Adds GatewayPorts=clientspecified option on server to allow remote
+ forwards to bind to client-specified ports.
20050226
- (dtucker) [openbsd-compat/bsd-openpty.c openbsd-compat/inet_ntop.c]
@@ -2195,4 +2203,4 @@
- (djm) Trim deprecated options from INSTALL. Mention UsePAM
- (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
-$Id: ChangeLog,v 1.3671 2005/03/01 10:17:31 djm Exp $
+$Id: ChangeLog,v 1.3672 2005/03/01 10:24:33 djm Exp $
diff --git a/auth-options.c b/auth-options.c
index 0e146ab1..04d12d66 100644
--- a/auth-options.c
+++ b/auth-options.c
@@ -10,7 +10,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: auth-options.c,v 1.28 2003/06/02 09:17:34 markus Exp $");
+RCSID("$OpenBSD: auth-options.c,v 1.29 2005/03/01 10:09:52 djm Exp $");
#include "xmalloc.h"
#include "match.h"
@@ -217,7 +217,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
}
cp = "permitopen=\"";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
- char host[256], sport[6];
+ char *host, *p;
u_short port;
char *patterns = xmalloc(strlen(opts) + 1);
@@ -236,25 +236,29 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
if (!*opts) {
debug("%.100s, line %lu: missing end quote",
file, linenum);
- auth_debug_add("%.100s, line %lu: missing end quote",
- file, linenum);
+ auth_debug_add("%.100s, line %lu: missing "
+ "end quote", file, linenum);
xfree(patterns);
goto bad_option;
}
patterns[i] = 0;
opts++;
- if (sscanf(patterns, "%255[^:]:%5[0-9]", host, sport) != 2 &&
- sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) {
- debug("%.100s, line %lu: Bad permitopen specification "
- "<%.100s>", file, linenum, patterns);
+ p = patterns;
+ host = hpdelim(&p);
+ if (host == NULL || strlen(host) >= NI_MAXHOST) {
+ debug("%.100s, line %lu: Bad permitopen "
+ "specification <%.100s>", file, linenum,
+ patterns);
auth_debug_add("%.100s, line %lu: "
- "Bad permitopen specification", file, linenum);
+ "Bad permitopen specification", file,
+ linenum);
xfree(patterns);
goto bad_option;
}
- if ((port = a2port(sport)) == 0) {
- debug("%.100s, line %lu: Bad permitopen port <%.100s>",
- file, linenum, sport);
+ host = cleanhostname(host);
+ if (p == NULL || (port = a2port(p)) == 0) {
+ debug("%.100s, line %lu: Bad permitopen port "
+ "<%.100s>", file, linenum, p ? p : "");
auth_debug_add("%.100s, line %lu: "
"Bad permitopen port", file, linenum);
xfree(patterns);
diff --git a/channels.c b/channels.c
index 8550e51c..1be213bc 100644
--- a/channels.c
+++ b/channels.c
@@ -39,7 +39,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.211 2004/10/29 21:47:15 djm Exp $");
+RCSID("$OpenBSD: channels.c,v 1.212 2005/03/01 10:09:52 djm Exp $");
#include "ssh.h"
#include "ssh1.h"
@@ -2179,14 +2179,14 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
const char *host_to_connect, u_short port_to_connect, int gateway_ports)
{
Channel *c;
- int success, sock, on = 1;
+ int sock, r, success = 0, on = 1, wildcard = 0, is_client;
struct addrinfo hints, *ai, *aitop;
- const char *host;
+ const char *host, *addr;
char ntop[NI_MAXHOST], strport[NI_MAXSERV];
- success = 0;
host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
listen_addr : host_to_connect;
+ is_client = (type == SSH_CHANNEL_PORT_LISTENER);
if (host == NULL) {
error("No forward host name.");
@@ -2198,16 +2198,60 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
}
/*
+ * Determine whether or not a port forward listens to loopback,
+ * specified address or wildcard. On the client, a specified bind
+ * address will always override gateway_ports. On the server, a
+ * gateway_ports of 1 (``yes'') will override the client's
+ * specification and force a wildcard bind, whereas a value of 2
+ * (``clientspecified'') will bind to whatever address the client
+ * asked for.
+ *
+ * Special-case listen_addrs are:
+ *
+ * "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
+ * "" (empty string), "*" -> wildcard v4/v6
+ * "localhost" -> loopback v4/v6
+ */
+ addr = NULL;
+ if (listen_addr == NULL) {
+ /* No address specified: default to gateway_ports setting */
+ if (gateway_ports)
+ wildcard = 1;
+ } else if (gateway_ports || is_client) {
+ if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
+ strcmp(listen_addr, "0.0.0.0") == 0) ||
+ *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
+ (!is_client && gateway_ports == 1))
+ wildcard = 1;
+ else if (strcmp(listen_addr, "localhost") != 0)
+ addr = listen_addr;
+ }
+
+ debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s",
+ type, wildcard, (addr == NULL) ? "NULL" : addr);
+
+ /*
* getaddrinfo returns a loopback address if the hostname is
* set to NULL and hints.ai_flags is not AI_PASSIVE
*/
memset(&hints, 0, sizeof(hints));
hints.ai_family = IPv4or6;
- hints.ai_flags = gateway_ports ? AI_PASSIVE : 0;
+ hints.ai_flags = wildcard ? AI_PASSIVE : 0;
hints.ai_socktype = SOCK_STREAM;
snprintf(strport, sizeof strport, "%d", listen_port);
- if (getaddrinfo(NULL, strport, &hints, &aitop) != 0)
- packet_disconnect("getaddrinfo: fatal error");
+ if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) {
+ if (addr == NULL) {
+ /* This really shouldn't happen */
+ packet_disconnect("getaddrinfo: fatal error: %s",
+ gai_strerror(r));
+ } else {
+ verbose("channel_setup_fwd_listener: "
+ "getaddrinfo(%.64s): %s", addr, gai_strerror(r));
+ packet_send_debug("channel_setup_fwd_listener: "
+ "getaddrinfo(%.64s): %s", addr, gai_strerror(r));
+ }
+ aitop = NULL;
+ }
for (ai = aitop; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
@@ -2290,11 +2334,12 @@ channel_cancel_rport_listener(const char *host, u_short port)
/* protocol local port fwd, used by ssh (and sshd in v1) */
int
-channel_setup_local_fwd_listener(u_short listen_port,
+channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port,
const char *host_to_connect, u_short port_to_connect, int gateway_ports)
{
return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER,
- NULL, listen_port, host_to_connect, port_to_connect, gateway_ports);
+ listen_host, listen_port, host_to_connect, port_to_connect,
+ gateway_ports);
}
/* protocol v2 remote port fwd, used by sshd */
@@ -2312,7 +2357,7 @@ channel_setup_remote_fwd_listener(const char *listen_address,
*/
void
-channel_request_remote_forwarding(u_short listen_port,
+channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
const char *host_to_connect, u_short port_to_connect)
{
int type, success = 0;
@@ -2323,7 +2368,14 @@ channel_request_remote_forwarding(u_short listen_port,
/* Send the forward request to the remote side. */
if (compat20) {
- const char *address_to_bind = "0.0.0.0";
+ const char *address_to_bind;
+ if (listen_host == NULL)
+ address_to_bind = "localhost";
+ else if (*listen_host == '\0' || strcmp(listen_host, "*") == 0)
+ address_to_bind = "";
+ else
+ address_to_bind = listen_host;
+
packet_start(SSH2_MSG_GLOBAL_REQUEST);
packet_put_cstring("tcpip-forward");
packet_put_char(1); /* boolean: want reply */
@@ -2369,10 +2421,9 @@ channel_request_remote_forwarding(u_short listen_port,
* local side.
*/
void
-channel_request_rforward_cancel(u_short port)
+channel_request_rforward_cancel(const char *host, u_short port)
{
int i;
- const char *address_to_bind = "0.0.0.0";
if (!compat20)
return;
@@ -2389,7 +2440,7 @@ channel_request_rforward_cancel(u_short port)
packet_start(SSH2_MSG_GLOBAL_REQUEST);
packet_put_cstring("cancel-tcpip-forward");
packet_put_char(0);
- packet_put_cstring(address_to_bind);
+ packet_put_cstring(host == NULL ? "" : host);
packet_put_int(port);
packet_send();
@@ -2430,7 +2481,8 @@ channel_input_port_forward_request(int is_root, int gateway_ports)
#endif
/* Initiate forwarding */
- channel_setup_local_fwd_listener(port, hostname, host_port, gateway_ports);
+ channel_setup_local_fwd_listener(NULL, port, hostname,
+ host_port, gateway_ports);
/* Free the argument string. */
xfree(hostname);
diff --git a/channels.h b/channels.h
index c47de55c..fc20fb2c 100644
--- a/channels.h
+++ b/channels.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.75 2004/10/29 21:47:15 djm Exp $ */
+/* $OpenBSD: channels.h,v 1.76 2005/03/01 10:09:52 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -203,9 +203,11 @@ void channel_clear_permitted_opens(void);
void channel_input_port_forward_request(int, int);
int channel_connect_to(const char *, u_short);
int channel_connect_by_listen_address(u_short);
-void channel_request_remote_forwarding(u_short, const char *, u_short);
-void channel_request_rforward_cancel(u_short port);
-int channel_setup_local_fwd_listener(u_short, const char *, u_short, int);
+void channel_request_remote_forwarding(const char *, u_short,
+ const char *, u_short);
+int channel_setup_local_fwd_listener(const char *, u_short,
+ const char *, u_short, int);
+void channel_request_rforward_cancel(const char *host, u_short port);
int channel_setup_remote_fwd_listener(const char *, u_short, int);
int channel_cancel_rport_listener(const char *, u_short);
diff --git a/clientloop.c b/clientloop.c
index 033a98a5..1e250883 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -59,7 +59,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: clientloop.c,v 1.134 2004/11/07 00:01:46 djm Exp $");
+RCSID("$OpenBSD: clientloop.c,v 1.135 2005/03/01 10:09:52 djm Exp $");
#include "ssh.h"
#include "ssh1.h"
@@ -763,11 +763,11 @@ static void
process_cmdline(void)
{
void (*handler)(int);
- char *s, *cmd;
- u_short fwd_port, fwd_host_port;
- char buf[1024], sfwd_port[6], sfwd_host_port[6];
+ char *s, *cmd, *cancel_host;
int delete = 0;
int local = 0;
+ u_short cancel_port;
+ Forward fwd;
leave_raw_mode();
handler = signal(SIGINT, SIG_IGN);
@@ -813,37 +813,38 @@ process_cmdline(void)
s++;
if (delete) {
- if (sscanf(s, "%5[0-9]", sfwd_host_port) != 1) {
- logit("Bad forwarding specification.");
- goto out;
+ cancel_port = 0;
+ cancel_host = hpdelim(&s); /* may be NULL */
+ if (s != NULL) {
+ cancel_port = a2port(s);
+ cancel_host = cleanhostname(cancel_host);
+ } else {
+ cancel_port = a2port(cancel_host);
+ cancel_host = NULL;
}
- if ((fwd_host_port = a2port(sfwd_host_port)) == 0) {
- logit("Bad forwarding port(s).");
+ if (cancel_port == 0) {
+ logit("Bad forwarding close port");
goto out;
}
- channel_request_rforward_cancel(fwd_host_port);
+ channel_request_rforward_cancel(cancel_host, cancel_port);
} else {
- if (sscanf(s, "%5[0-9]:%255[^:]:%5[0-9]",
- sfwd_port, buf, sfwd_host_port) != 3 &&
- sscanf(s, "%5[0-9]/%255[^/]/%5[0-9]",
- sfwd_port, buf, sfwd_host_port) != 3) {
+ if (!parse_forward(&fwd, s)) {
logit("Bad forwarding specification.");
goto out;
}
- if ((fwd_port = a2port(sfwd_port)) == 0 ||
- (fwd_host_port = a2port(sfwd_host_port)) == 0) {
- logit("Bad forwarding port(s).");
- goto out;
- }
if (local) {
- if (channel_setup_local_fwd_listener(fwd_port, buf,
- fwd_host_port, options.gateway_ports) < 0) {
+ if (channel_setup_local_fwd_listener(fwd.listen_host,
+ fwd.listen_port, fwd.connect_host,
+ fwd.connect_port, options.gateway_ports) < 0) {
logit("Port forwarding failed.");
goto out;
}
- } else
- channel_request_remote_forwarding(fwd_port, buf,
- fwd_host_port);
+ } else {
+ channel_request_remote_forwarding(fwd.listen_host,
+ fwd.listen_port, fwd.connect_host,
+ fwd.connect_port);
+ }
+
logit("Forwarding port.");
}
diff --git a/compat.c b/compat.c
index 2fdebe7f..4086e853 100644
--- a/compat.c
+++ b/compat.c
@@ -23,7 +23,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: compat.c,v 1.70 2003/11/02 11:01:03 markus Exp $");
+RCSID("$OpenBSD: compat.c,v 1.71 2005/03/01 10:09:52 djm Exp $");
#include "buffer.h"
#include "packet.h"
@@ -62,24 +62,28 @@ compat_datafellows(const char *version)
"OpenSSH_2.1*,"
"OpenSSH_2.2*", SSH_OLD_SESSIONID|SSH_BUG_BANNER|
SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
- SSH_BUG_EXTEOF},
+ SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
{ "OpenSSH_2.3.0*", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES|
SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
- SSH_BUG_EXTEOF},
+ SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
{ "OpenSSH_2.3.*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
- SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
+ SSH_BUG_NOREKEY|SSH_BUG_EXTEOF|
+ SSH_OLD_FORWARD_ADDR},
{ "OpenSSH_2.5.0p1*,"
"OpenSSH_2.5.1p1*",
SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
- SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
+ SSH_BUG_NOREKEY|SSH_BUG_EXTEOF|
+ SSH_OLD_FORWARD_ADDR},
{ "OpenSSH_2.5.0*,"
"OpenSSH_2.5.1*,"
"OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
- SSH_BUG_EXTEOF},
- { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
+ SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
+ { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF|
+ SSH_OLD_FORWARD_ADDR},
{ "OpenSSH_2.*,"
"OpenSSH_3.0*,"
- "OpenSSH_3.1*", SSH_BUG_EXTEOF},
+ "OpenSSH_3.1*", SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
+ { "OpenSSH_3.*", SSH_OLD_FORWARD_ADDR },
{ "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
{ "OpenSSH*", 0 },
{ "*MindTerm*", 0 },
diff --git a/compat.h b/compat.h
index 5efb5c29..cf92dbde 100644
--- a/compat.h
+++ b/compat.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: compat.h,v 1.38 2004/07/11 17:48:47 deraadt Exp $ */
+/* $OpenBSD: compat.h,v 1.39 2005/03/01 10:09:52 djm Exp $ */
/*
* Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
@@ -55,6 +55,7 @@
#define SSH_BUG_EXTEOF 0x00200000
#define SSH_BUG_PROBE 0x00400000
#define SSH_BUG_FIRSTKEX 0x00800000
+#define SSH_OLD_FORWARD_ADDR 0x01000000
void enable_compat13(void);
void enable_compat20(void);
diff --git a/misc.c b/misc.c
index a9012550..2e366f81 100644
--- a/misc.c
+++ b/misc.c
@@ -23,7 +23,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: misc.c,v 1.27 2004/12/11 01:48:56 dtucker Exp $");
+RCSID("$OpenBSD: misc.c,v 1.28 2005/03/01 10:09:52 djm Exp $");
#include "misc.h"
#include "log.h"
@@ -275,6 +275,48 @@ convtime(const char *s)
return total;
}
+/*
+ * Search for next delimiter between hostnames/addresses and ports.
+ * Argument may be modified (for termination).
+ * Returns *cp if parsing succeeds.
+ * *cp is set to the start of the next delimiter, if one was found.
+ * If this is the last field, *cp is set to NULL.
+ */
+char *
+hpdelim(char **cp)
+{
+ char *s, *old;
+
+ if (cp == NULL || *cp == NULL)
+ return NULL;
+
+ old = s = *cp;
+ if (*s == '[') {
+ if ((s = strchr(s, ']')) == NULL)
+ return NULL;
+ else
+ s++;
+ } else if ((s = strpbrk(s, ":/")) == NULL)
+ s = *cp + strlen(*cp); /* skip to end (see first case below) */
+
+ switch (*s) {
+ case '\0':
+ *cp = NULL; /* no more fields*/
+ break;
+
+ case ':':
+ case '/':
+ *s = '\0'; /* terminate */
+ *cp = s + 1;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ return old;
+}
+
char *
cleanhostname(char *host)
{
diff --git a/misc.h b/misc.h
index 193216fa..8bbc87f0 100644
--- a/misc.h
+++ b/misc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.h,v 1.20 2004/12/11 01:48:56 dtucker Exp $ */
+/* $OpenBSD: misc.h,v 1.21 2005/03/01 10:09:52 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -20,6 +20,7 @@ int set_nonblock(int);
int unset_nonblock(int);
void set_nodelay(int);
int a2port(const char *);
+char *hpdelim(char **);
char *cleanhostname(char *);
char *colon(char *);
long convtime(const char *);
diff --git a/readconf.c b/readconf.c
index a4fe1fe0..c3dc71e6 100644
--- a/readconf.c
+++ b/readconf.c
@@ -12,7 +12,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: readconf.c,v 1.134 2004/07/11 17:48:47 deraadt Exp $");
+RCSID("$OpenBSD: readconf.c,v 1.135 2005/03/01 10:09:52 djm Exp $");
#include "ssh.h"
#include "xmalloc.h"
@@ -206,21 +206,23 @@ static struct {
*/
void
-add_local_forward(Options *options, u_short port, const char *host,
- u_short host_port)
+add_local_forward(Options *options, const Forward *newfwd)
{
Forward *fwd;
#ifndef NO_IPPORT_RESERVED_CONCEPT
extern uid_t original_real_uid;
- if (port < IPPORT_RESERVED && original_real_uid != 0)
+ if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
fatal("Privileged ports can only be forwarded by root.");
#endif
if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
fwd = &options->local_forwards[options->num_local_forwards++];
- fwd->port = port;
- fwd->host = xstrdup(host);
- fwd->host_port = host_port;
+
+ fwd->listen_host = (newfwd->listen_host == NULL) ?
+ NULL : xstrdup(newfwd->listen_host);
+ fwd->listen_port = newfwd->listen_port;
+ fwd->connect_host = xstrdup(newfwd->connect_host);
+ fwd->connect_port = newfwd->connect_port;
}
/*
@@ -229,17 +231,19 @@ add_local_forward(Options *options, u_short port, const char *host,
*/
void
-add_remote_forward(Options *options, u_short port, const char *host,
- u_short host_port)
+add_remote_forward(Options *options, const Forward *newfwd)
{
Forward *fwd;
if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
fatal("Too many remote forwards (max %d).",
SSH_MAX_FORWARDS_PER_DIRECTION);
fwd = &options->remote_forwards[options->num_remote_forwards++];
- fwd->port = port;
- fwd->host = xstrdup(host);
- fwd->host_port = host_port;
+
+ fwd->listen_host = (newfwd->listen_host == NULL) ?
+ NULL : xstrdup(newfwd->listen_host);
+ fwd->listen_port = newfwd->listen_port;
+ fwd->connect_host = xstrdup(newfwd->connect_host);
+ fwd->connect_port = newfwd->connect_port;
}
static void
@@ -247,11 +251,15 @@ clear_forwardings(Options *options)
{
int i;
- for (i = 0; i < options->num_local_forwards; i++)
- xfree(options->local_forwards[i].host);
+ for (i = 0; i < options->num_local_forwards; i++) {
+ xfree(options->local_forwards[i].listen_host);
+ xfree(options->local_forwards[i].connect_host);
+ }
options->num_local_forwards = 0;
- for (i = 0; i < options->num_remote_forwards; i++)
- xfree(options->remote_forwards[i].host);
+ for (i = 0; i < options->num_remote_forwards; i++) {
+ xfree(options->remote_forwards[i].listen_host);
+ xfree(options->remote_forwards[i].connect_host);
+ }
options->num_remote_forwards = 0;
}
@@ -284,11 +292,10 @@ process_config_line(Options *options, const char *host,
char *line, const char *filename, int linenum,
int *activep)
{
- char buf[256], *s, **charptr, *endofnumber, *keyword, *arg;
+ char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
int opcode, *intptr, value;
size_t len;
- u_short fwd_port, fwd_host_port;
- char sfwd_host_port[6];
+ Forward fwd;
/* Strip trailing whitespace */
for(len = strlen(line) - 1; len > 0; len--) {
@@ -645,30 +652,26 @@ parse_int:
case oLocalForward:
case oRemoteForward:
arg = strdelim(&s);
- if (!arg || *arg == '\0')
+ if (arg == NULL || *arg == '\0')
fatal("%.200s line %d: Missing port argument.",
filename, linenum);
- if ((fwd_port = a2port(arg)) == 0)
- fatal("%.200s line %d: Bad listen port.",
+ arg2 = strdelim(&s);
+ if (arg2 == NULL || *arg2 == '\0')
+ fatal("%.200s line %d: Missing target argument.",
filename, linenum);
- arg = strdelim(&s);
- if (!arg || *arg == '\0')
- fatal("%.200s line %d: Missing second argument.",
- filename, linenum);
- if (sscanf(arg, "%255[^:]:%5[0-9]", buf, sfwd_host_port) != 2 &&
- sscanf(arg, "%255[^/]/%5[0-9]", buf, sfwd_host_port) != 2)
+
+ /* construct a string for parse_forward */
+ snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
+
+ if (parse_forward(&fwd, fwdarg) == 0)
fatal("%.200s line %d: Bad forwarding specification.",
filename, linenum);
- if ((fwd_host_port = a2port(sfwd_host_port)) == 0)
- fatal("%.200s line %d: Bad forwarding port.",
- filename, linenum);
+
if (*activep) {
if (opcode == oLocalForward)
- add_local_forward(options, fwd_port, buf,
- fwd_host_port);
+ add_local_forward(options, &fwd);
else if (opcode == oRemoteForward)
- add_remote_forward(options, fwd_port, buf,
- fwd_host_port);
+ add_remote_forward(options, &fwd);
}
break;
@@ -677,12 +680,25 @@ parse_int:
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing port argument.",
filename, linenum);
- fwd_port = a2port(arg);
- if (fwd_port == 0)
+ memset(&fwd, '\0', sizeof(fwd));
+ fwd.connect_host = "socks";
+ fwd.listen_host = hpdelim(&arg);
+ if (fwd.listen_host == NULL ||
+ strlen(fwd.listen_host) >= NI_MAXHOST)
+ fatal("%.200s line %d: Bad forwarding specification.",
+ filename, linenum);
+ if (arg) {
+ fwd.listen_port = a2port(arg);
+ fwd.listen_host = cleanhostname(fwd.listen_host);
+ } else {
+ fwd.listen_port = a2port(fwd.listen_host);
+ fwd.listen_host = "";
+ }
+ if (fwd.listen_port == 0)
fatal("%.200s line %d: Badly formatted port number.",
filename, linenum);
if (*activep)
- add_local_forward(options, fwd_port, "socks", 0);
+ add_local_forward(options, &fwd);
break;
case oClearAllForwardings:
@@ -1045,3 +1061,68 @@ fill_default_options(Options * options)
/* options->host_key_alias should not be set by default */
/* options->preferred_authentications will be set in ssh */
}
+
+/*
+ * parse_forward
+ * parses a string containing a port forwarding specification of the form:
+ * [listenhost:]listenport:connecthost:connectport
+ * returns number of arguments parsed or zero on error
+ */
+int
+parse_forward(Forward *fwd, const char *fwdspec)
+{
+ int i;
+ char *p, *cp, *fwdarg[4];
+
+ memset(fwd, '\0', sizeof(*fwd));
+
+ cp = p = xstrdup(fwdspec);
+
+ /* skip leading spaces */
+ while (*cp && isspace(*cp))
+ cp++;
+
+ for (i = 0; i < 4; ++i)
+ if ((fwdarg[i] = hpdelim(&cp)) == NULL)
+ break;
+
+ /* Check for trailing garbage in 4-arg case*/
+ if (cp != NULL)
+ i = 0; /* failure */
+
+ switch (i) {
+ case 3:
+ fwd->listen_host = NULL;
+ fwd->listen_port = a2port(fwdarg[0]);
+ fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
+ fwd->connect_port = a2port(fwdarg[2]);
+ break;
+
+ case 4:
+ fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
+ fwd->listen_port = a2port(fwdarg[1]);
+ fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
+ fwd->connect_port = a2port(fwdarg[3]);
+ break;
+ default:
+ i = 0; /* failure */
+ }
+
+ xfree(p);
+
+ if (fwd->listen_port == 0 && fwd->connect_port == 0)
+ goto fail_free;
+
+ if (fwd->connect_host != NULL &&
+ strlen(fwd->connect_host) >= NI_MAXHOST)
+ goto fail_free;
+
+ return (i);
+
+ fail_free:
+ if (fwd->connect_host != NULL)
+ xfree(fwd->connect_host);
+ if (fwd->listen_host != NULL)
+ xfree(fwd->listen_host);
+ return (0);
+}
diff --git a/readconf.h b/readconf.h
index ded42258..03b772a2 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.h,v 1.64 2004/07/11 17:48:47 deraadt Exp $ */
+/* $OpenBSD: readconf.h,v 1.65 2005/03/01 10:09:52 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -21,9 +21,10 @@
/* Data structure for representing a forwarding request. */
typedef struct {
- u_short port; /* Port to forward. */
- char *host; /* Host to connect. */
- u_short host_port; /* Port to connect on host. */
+ char *listen_host; /* Host (address) to listen on. */
+ u_short listen_port; /* Port to forward. */
+ char *connect_host; /* Host to connect. */
+ u_short connect_port; /* Port to connect on connect_host. */
} Forward;
/* Data structure for representing option data. */
@@ -117,11 +118,12 @@ typedef struct {
void initialize_options(Options *);
void fill_default_options(Options *);
int read_config_file(const char *, const char *, Options *, int);
+int parse_forward(Forward *, const char *);
int
process_config_line(Options *, const char *, char *, const char *, int, int *);
-void add_local_forward(Options *, u_short, const char *, u_short);
-void add_remote_forward(Options *, u_short, const char *, u_short);
+void add_local_forward(Options *, const Forward *);
+void add_remote_forward(Options *, const Forward *);
#endif /* READCONF_H */
diff --git a/servconf.c b/servconf.c
index 541a9c85..2d1a0c36 100644
--- a/servconf.c
+++ b/servconf.c
@@ -10,7 +10,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: servconf.c,v 1.138 2004/12/23 23:11:00 djm Exp $");
+RCSID("$OpenBSD: servconf.c,v 1.139 2005/03/01 10:09:52 djm Exp $");
#include "ssh.h"
#include "log.h"
@@ -440,6 +440,7 @@ process_server_config_line(ServerOptions *options, char *line,
char *cp, **charptr, *arg, *p;
int *intptr, value, i, n;
ServerOpCodes opcode;
+ u_short port;
cp = line;
arg = strdelim(&cp);
@@ -512,39 +513,21 @@ parse_time:
case sListenAddress:
arg = strdelim(&cp);
- if (!arg || *arg == '\0' || strncmp(arg, "[]", 2) == 0)
- fatal("%s line %d: missing inet addr.",
+ if (arg == NULL || *arg == '\0')
+ fatal("%s line %d: missing address",
filename, linenum);
- if (*arg == '[') {
- if ((p = strchr(arg, ']')) == NULL)
- fatal("%s line %d: bad ipv6 inet addr usage.",
- filename, linenum);
- arg++;
- memmove(p, p+1, strlen(p+1)+1);
- } else if (((p = strchr(arg, ':')) == NULL) ||
- (strchr(p+1, ':') != NULL)) {
- add_listen_addr(options, arg, 0);
- break;
- }
- if (*p == ':') {
- u_short port;
-
- p++;
- if (*p == '\0')
- fatal("%s line %d: bad inet addr:port usage.",
- filename, linenum);
- else {
- *(p-1) = '\0';
- if ((port = a2port(p)) == 0)
- fatal("%s line %d: bad port number.",
- filename, linenum);
- add_listen_addr(options, arg, port);
- }
- } else if (*p == '\0')
- add_listen_addr(options, arg, 0);
- else
- fatal("%s line %d: bad inet addr usage.",
+ p = hpdelim(&arg);
+ if (p == NULL)
+ fatal("%s line %d: bad address:port usage",
filename, linenum);
+ p = cleanhostname(p);
+ if (arg == NULL)
+ port = 0;
+ else if ((port = a2port(arg)) == 0)
+ fatal("%s line %d: bad port number", filename, linenum);
+
+ add_listen_addr(options, p, port);
+
break;
case sAddressFamily:
@@ -742,7 +725,23 @@ parse_flag:
case sGatewayPorts:
intptr = &options->gateway_ports;
- goto parse_flag;
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: missing yes/no/clientspecified "
+ "argument.", filename, linenum);
+ value = 0; /* silence compiler */
+ if (strcmp(arg, "clientspecified") == 0)
+ value = 2;
+ else if (strcmp(arg, "yes") == 0)
+ value = 1;
+ else if (strcmp(arg, "no") == 0)
+ value = 0;
+ else
+ fatal("%s line %d: Bad yes/no/clientspecified "
+ "argument: %s", filename, linenum, arg);
+ if (*intptr == -1)
+ *intptr = value;
+ break;
case sUseDNS:
intptr = &options->use_dns;
diff --git a/ssh.1 b/ssh.1
index b8a91a16..27da08c6 100644
--- a/ssh.1
+++ b/ssh.1
@@ -34,7 +34,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $OpenBSD: ssh.1,v 1.199 2004/11/07 17:42:36 jmc Exp $
+.\" $OpenBSD: ssh.1,v 1.200 2005/03/01 10:09:52 djm Exp $
.Dd September 25, 1999
.Dt SSH 1
.Os
@@ -53,13 +53,13 @@
.Op Fl i Ar identity_file
.Oo Fl L Xo
.Sm off
+.Oo Ar bind_address : Oc
.Ar port :
.Ar host :
.Ar hostport
.Sm on
.Xc
.Oc
-.Ek
.Op Fl l Ar login_name
.Op Fl m Ar mac_spec
.Op Fl O Ar ctl_cmd
@@ -69,6 +69,7 @@
.Ek
.Oo Fl R Xo
.Sm off
+.Oo Ar bind_address : Oc
.Ar port :
.Ar host :
.Ar hostport
@@ -570,6 +571,7 @@ configuration files).
Disables forwarding (delegation) of GSSAPI credentials to the server.
.It Fl L Xo
.Sm off
+.Oo Ar bind_address : Oc
.Ar port : host : hostport
.Sm on
.Xc
@@ -577,7 +579,9 @@ Specifies that the given port on the local (client) host is to be
forwarded to the given host and p