- 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.
This commit is contained in:
Damien Miller 2005-03-01 21:24:33 +11:00
parent 1717fd422f
commit f91ee4c3de
16 changed files with 528 additions and 217 deletions

View File

@ -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 $

View File

@ -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);

View File

@ -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.");
@ -2197,17 +2197,61 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
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)
@ -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);

View File

@ -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);

View File

@ -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.");
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 (cancel_port == 0) {
logit("Bad forwarding close port");
goto out;
}
if ((fwd_host_port = a2port(sfwd_host_port)) == 0) {
logit("Bad forwarding port(s).");
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.");
}

View File

@ -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 },

View File

@ -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);

44
misc.c
View File

@ -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)
{

3
misc.h
View File

@ -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 *);

View File

@ -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);
}

View File

@ -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 */

View File

@ -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 = 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);
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.",
filename, linenum);
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;

59
ssh.1
View File

@ -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 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
@ -585,14 +589,30 @@ port
.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.
@ -724,6 +744,7 @@ Quiet mode.
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
@ -738,16 +759,34 @@ made to
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

114
ssh.c
View File

@ -40,7 +40,7 @@
*/
#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>
@ -158,9 +158,10 @@ usage(void)
{
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);
@ -178,14 +179,13 @@ int
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();
@ -401,39 +401,51 @@ again:
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 */
}
if ((fwd_port = a2port(sfwd_port)) == 0 ||
(fwd_host_port = a2port(sfwd_host_port)) == 0) {
fprintf(stderr,
"Bad forwarding port(s) '%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 'R':
if (parse_forward(&fwd, optarg)) {
add_remote_forward(&options, &fwd);
} else {
fprintf(stderr,
"Bad remote forwarding specification "
"'%s'\n", optarg);
exit(1);
}
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':
@ -842,14 +854,19 @@ ssh_init_forwarding(void)
/* 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)
@ -857,14 +874,17 @@ ssh_init_forwarding(void)
/* 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);
}
}
@ -1040,12 +1060,12 @@ client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt)
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

View File

@ -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_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
@ -480,12 +480,37 @@ The default is to use the server specified list.
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 .
@ -592,12 +617,39 @@ This option applies to protocol version 2 only.
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.

View File

@ -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: 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
@ -256,12 +256,15 @@ This prevents other remote hosts from connecting to forwarded ports.
.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