[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]
*/
#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"
}
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);
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);
*/
#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"
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.");
return success;
}
+ /*
+ * 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)
/* 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 */
*/
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;
/* 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 */
* 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;
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();
#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);
-/* $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>
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);
*/
#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"
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);
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.");
}
*/
#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"
"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 },
-/* $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.
#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);
*/
#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"
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)
{
-/* $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>
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 *);
*/
#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"
*/
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;
}
/*
*/
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
{
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;
}
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--) {
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;
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:
/* 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);
+}
-/* $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>
/* 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. */
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 */
*/
#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"
char *cp, **charptr, *arg, *p;
int *intptr, value, i, n;
ServerOpCodes opcode;
+ u_short port;
cp = line;
arg = strdelim(&cp);
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:
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;
.\" (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
.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
.Ek
.Oo Fl R Xo
.Sm off
+.Oo Ar bind_address : Oc
.Ar port :
.Ar host :
.Ar hostport
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
forwarded to the given host and port on the remote side.
This works by allocating a socket to listen to
.Ar port
-on the local side, and whenever a connection is made to this port, the
+on the local side, optionally bound to the specified
+.Ar bind_address .
+Whenever a connection is made to this port, the
connection is forwarded over the secure channel, and a connection is
made to
.Ar host
.Ar hostport
from the remote machine.
Port forwardings can also be specified in the configuration file.
-Only root can forward privileged ports.
IPv6 addresses can be specified with an alternative syntax:
.Sm off
.Xo
+.Oo Ar bind_address / Oc
.Ar port No / Ar host No /
-.Ar hostport .
+.Ar hostport
.Xc
.Sm on
+or by enclosing the address in square brackets.
+Only the superuser can forward privileged ports.
+By default, the local port is bound in accordance with the
+.Cm GatewayPorts
+setting.
+However, an explicit
+.Ar bind_address
+may be used to bind the connection to a specific address.
+The
+.Ar bind_address
+of
+.Dq localhost
+indicates that the listening port be bound for local use only, while an
+empty address or
+.Dq *
+indicates that the port should be available from all interfaces.
.It Fl l Ar login_name
Specifies the user to log in as on the remote machine.
This also may be specified on a per-host basis in the configuration file.
Causes all warning and diagnostic messages to be suppressed.
.It Fl R Xo
.Sm off
+.Oo Ar bind_address : Oc
.Ar port : host : hostport
.Sm on
.Xc
port
.Ar hostport
from the local machine.
+.Pp
Port forwardings can also be specified in the configuration file.
Privileged ports can be forwarded only when
logging in as root on the remote machine.
-IPv6 addresses can be specified with an alternative syntax:
-.Sm off
+IPv6 addresses can be specified by enclosing the address in square braces or
+using an alternative syntax:
.Xo
-.Ar port No / Ar host No /
-.Ar hostport .
-.Xc
+.Sm off
+.Oo Ar bind_address / Oc
+.Ar host/port/hostport
.Sm on
+.Xc .
+.Pp
+By default, the listening socket on the server will be bound to the loopback
+interface only.
+This may be overriden by specifying a
+.Ar bind_address .
+An empty
+.Ar bind_address ,
+or the address
+.Ql *
+indicates that the remote socket should listen on all interfaces.
+Specifying a remote
+.Ar bind_address
+will only succeed if the server's
+.Cm GatewayPorts
+option is enabled (see
+.Xr sshd_config 5 ).
.It Fl S Ar ctl_path
Specifies the location of a control socket for connection sharing.
Refer to the description of
*/
#include "includes.h"
-RCSID("$OpenBSD: ssh.c,v 1.231 2005/02/16 09:56:44 otto Exp $");
+RCSID("$OpenBSD: ssh.c,v 1.232 2005/03/01 10:09:52 djm Exp $");
#include <openssl/evp.h>
#include <openssl/err.h>
{
fprintf(stderr,
"usage: ssh [-1246AaCfgkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]\n"
-" [-D port] [-e escape_char] [-F configfile] [-i identity_file]\n"
-" [-L port:host:hostport] [-l login_name] [-m mac_spec] [-O ctl_cmd]\n"
-" [-o option] [-p port] [-R port:host:hostport] [-S ctl_path]\n"
+" [-D [listen-host:]port] [-e escape_char] [-F configfile]\n"
+" [-i identity_file] [-L [listen-host:]port:host:hostport]\n"
+" [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n"
+" [-R [listen-host:]port:host:hostport] [-S ctl_path]\n"
" [user@]hostname [command]\n"
);
exit(1);
main(int ac, char **av)
{
int i, opt, exit_status;
- u_short fwd_port, fwd_host_port;
- char sfwd_port[6], sfwd_host_port[6];
char *p, *cp, *line, buf[256];
struct stat st;
struct passwd *pw;
int dummy;
extern int optind, optreset;
extern char *optarg;
+ Forward fwd;
__progname = ssh_get_progname(av[0]);
init_rng();
break;
case 'L':
- case 'R':
- if (sscanf(optarg, "%5[0123456789]:%255[^:]:%5[0123456789]",
- sfwd_port, buf, sfwd_host_port) != 3 &&
- sscanf(optarg, "%5[0123456789]/%255[^/]/%5[0123456789]",
- sfwd_port, buf, sfwd_host_port) != 3) {
+ if (parse_forward(&fwd, optarg))
+ add_local_forward(&options, &fwd);
+ else {
fprintf(stderr,
- "Bad forwarding specification '%s'\n",
+ "Bad local forwarding specification '%s'\n",
optarg);
- usage();
- /* NOTREACHED */
+ exit(1);
}
- if ((fwd_port = a2port(sfwd_port)) == 0 ||
- (fwd_host_port = a2port(sfwd_host_port)) == 0) {
+ break;
+
+ case 'R':
+ if (parse_forward(&fwd, optarg)) {
+ add_remote_forward(&options, &fwd);
+ } else {
fprintf(stderr,
- "Bad forwarding port(s) '%s'\n", optarg);
+ "Bad remote forwarding specification "
+ "'%s'\n", optarg);
exit(1);
}
- if (opt == 'L')
- add_local_forward(&options, fwd_port, buf,
- fwd_host_port);
- else if (opt == 'R')
- add_remote_forward(&options, fwd_port, buf,
- fwd_host_port);
break;
case 'D':
- fwd_port = a2port(optarg);
- if (fwd_port == 0) {
+ cp = p = xstrdup(optarg);
+ memset(&fwd, '\0', sizeof(fwd));
+ fwd.connect_host = "socks";
+ if ((fwd.listen_host = hpdelim(&cp)) == NULL) {
+ fprintf(stderr, "Bad dynamic forwarding "
+ "specification '%.100s'\n", optarg);
+ exit(1);
+ }
+ if (cp != NULL) {
+ fwd.listen_port = a2port(cp);
+ fwd.listen_host = cleanhostname(fwd.listen_host);
+ } else {
+ fwd.listen_port = a2port(fwd.listen_host);
+ fwd.listen_host = "";
+ }
+
+ if (fwd.listen_port == 0) {
fprintf(stderr, "Bad dynamic port '%s'\n",
optarg);
exit(1);
}
- add_local_forward(&options, fwd_port, "socks", 0);
+ add_local_forward(&options, &fwd);
+ xfree(p);
break;
case 'C':
/* Initiate local TCP/IP port forwardings. */
for (i = 0; i < options.num_local_forwards; i++) {
- debug("Connections to local port %d forwarded to remote address %.200s:%d",
- options.local_forwards[i].port,
- options.local_forwards[i].host,
- options.local_forwards[i].host_port);
+ debug("Local connections to %.200s:%d forwarded to remote "
+ "address %.200s:%d",
+ (options.local_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);
success += channel_setup_local_fwd_listener(
- options.local_forwards[i].port,
- options.local_forwards[i].host,
- options.local_forwards[i].host_port,
+ 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.gateway_ports);
}
if (i > 0 && success == 0)
/* Initiate remote TCP/IP port forwardings. */
for (i = 0; i < options.num_remote_forwards; i++) {
- debug("Connections to remote port %d forwarded to local address %.200s:%d",
- options.remote_forwards[i].port,
- options.remote_forwards[i].host,
- options.remote_forwards[i].host_port);
+ debug("Remote connections from %.200s:%d forwarded to "
+ "local address %.200s:%d",
+ options.remote_forwards[i].listen_host,
+ options.remote_forwards[i].listen_port,
+ options.remote_forwards[i].connect_host,
+ options.remote_forwards[i].connect_port);
channel_request_remote_forwarding(
- options.remote_forwards[i].port,
- options.remote_forwards[i].host,
- options.remote_forwards[i].host_port);
+ options.remote_forwards[i].listen_host,
+ options.remote_forwards[i].listen_port,
+ options.remote_forwards[i].connect_host,
+ options.remote_forwards[i].connect_port);
}
}
return;
debug("remote forward %s for: listen %d, connect %s:%d",
type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
- options.remote_forwards[i].port,
- options.remote_forwards[i].host,
- options.remote_forwards[i].host_port);
+ options.remote_forwards[i].listen_port,
+ options.remote_forwards[i].connect_host,
+ options.remote_forwards[i].connect_port);
if (type == SSH2_MSG_REQUEST_FAILURE)
- logit("Warning: remote port forwarding failed for listen port %d",
- options.remote_forwards[i].port);
+ logit("Warning: remote port forwarding failed for listen "
+ "port %d", options.remote_forwards[i].listen_port);
}
static void
.\" (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_config.5,v 1.42 2005/02/28 00:54:10 djm Exp $
+.\" $OpenBSD: ssh_config.5,v 1.43 2005/03/01 10:09:52 djm Exp $
.Dd September 25, 1999
.Dt SSH_CONFIG 5
.Os
Specifies that a TCP/IP port on the local machine be forwarded over
the secure channel to the specified host and port from the remote machine.
The first argument must be a port number, and the second must be
-.Ar host:port .
-IPv6 addresses can be specified with an alternative syntax:
-.Ar host/port .
-Multiple forwardings may be specified, and additional
-forwardings can be given on the command line.
+.Xo
+.Sm off
+.Oo Ar bind_address : Oc
+.Ar host:port
+.Sm on
+.Xc .
+IPv6 addresses can be specified by enclosing addresses in square brackets or
+by using an alternative syntax:
+.Xo
+.Sm off
+.Oo Ar bind_address / Oc
+.Ar host/port
+.Sm on
+.Xc .
+Multiple forwardings may be specified, and additional forwardings can be
+given on the command line.
Only the superuser can forward privileged ports.
+By default, the local port is bound in accordance with the
+.Cm GatewayPorts
+setting.
+However, an explicit
+.Ar bind_address
+may be used to bind the connection to a specific address.
+The
+.Ar bind_address
+of
+.Dq localhost
+indicates that the listening port be bound for local use only, while an
+empty address or
+.Dq *
+indicates that the port should be available from all interfaces.
.It Cm LogLevel
Gives the verbosity level that is used when logging messages from
.Nm ssh .
Specifies that a TCP/IP port on the remote machine be forwarded over
the secure channel to the specified host and port from the local machine.
The first argument must be a port number, and the second must be
-.Ar host:port .
-IPv6 addresses can be specified with an alternative syntax:
-.Ar host/port .
+.Xo
+.Sm off
+.Oo Ar bind_address : Oc
+.Ar host:port
+.Sm on
+.Xc .
+IPv6 addresses can be specified by enclosing any addresses in square brackets
+or by using the alternative syntax:
+.Xo
+.Sm off
+.Oo Ar bind_address / Oc
+.Ar host/port
+.Sm on
+.Xc .
Multiple forwardings may be specified, and additional
forwardings can be given on the command line.
Only the superuser can forward privileged ports.
+.Pp
+If the
+.Ar bind_address
+is not specified, the default is to only bind to loopback addresses.
+If the
+.Ar bind_address
+is
+.Ql *
+or an empty string, then the forwarding is requested to listen on all
+interfaces.
+Specifying a remote
+.Ar bind_address
+will only succeed if the server's
+.Cm GatewayPorts
+option is enabled (see
+.Xr sshd_config 5 ).
.It Cm RhostsRSAAuthentication
Specifies whether to try rhosts based authentication with RSA host
authentication.
.\" (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: sshd_config.5,v 1.38 2005/01/08 00:41:19 jmc Exp $
+.\" $OpenBSD: sshd_config.5,v 1.39 2005/03/01 10:09:52 djm Exp $
.Dd September 25, 1999
.Dt SSHD_CONFIG 5
.Os
.Cm GatewayPorts
can be used to specify that
.Nm sshd
-should bind remote port forwardings to the wildcard address,
-thus allowing remote hosts to connect to forwarded ports.
-The argument must be
+should allow remote port forwardings to bind to non-loopback addresses, thus
+allowing other hosts to connect.
+The argument may be
+.Dq no
+to force remote port forwardings to be available to the local host only,
.Dq yes
-or
-.Dq no .
+to force remote port forwardings to bind to the wildcard address, or
+.Dq clientspecified
+to allow the client to select the address to which the forwarding is bound.
The default is
.Dq no .
.It Cm GSSAPIAuthentication