- (dtucker) OpenBSD CVS Sync

- dtucker@cvs.openbsd.org 2012/05/13 01:42:32
     [servconf.h servconf.c sshd.8 sshd.c auth.c sshd_config.5]
     Add "Match LocalAddress" and "Match LocalPort" to sshd and adjust tests
     to match.  Feedback and ok djm@ markus@.
This commit is contained in:
Darren Tucker 2012-05-19 19:37:01 +10:00
parent 593538911a
commit fbcf827559
7 changed files with 181 additions and 67 deletions

View File

@ -4,6 +4,11 @@
- (dtucker) [configure.ac contrib/Makefile] bz#1996: use AC_PATH_TOOL to find - (dtucker) [configure.ac contrib/Makefile] bz#1996: use AC_PATH_TOOL to find
pkg-config so it does the right thing when cross-compiling. Patch from pkg-config so it does the right thing when cross-compiling. Patch from
cjwatson at debian org. cjwatson at debian org.
- (dtucker) OpenBSD CVS Sync
- dtucker@cvs.openbsd.org 2012/05/13 01:42:32
[servconf.h servconf.c sshd.8 sshd.c auth.c sshd_config.5]
Add "Match LocalAddress" and "Match LocalPort" to sshd and adjust tests
to match. Feedback and ok djm@ markus@.
20120504 20120504
- (dtucker) [configure.ac] Include <sys/param.h> rather than <sys/types.h> - (dtucker) [configure.ac] Include <sys/param.h> rather than <sys/types.h>

7
auth.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.c,v 1.95 2012/04/11 13:17:54 djm Exp $ */ /* $OpenBSD: auth.c,v 1.96 2012/05/13 01:42:32 dtucker Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -545,9 +545,10 @@ getpwnamallow(const char *user)
#endif #endif
#endif #endif
struct passwd *pw; struct passwd *pw;
struct connection_info *ci = get_connection_info(1, options.use_dns);
parse_server_match_config(&options, user, ci->user = user;
get_canonical_hostname(options.use_dns), get_remote_ipaddr()); parse_server_match_config(&options, ci);
#if defined(_AIX) && defined(HAVE_SETAUTHDB) #if defined(_AIX) && defined(HAVE_SETAUTHDB)
aix_setauthdb(user); aix_setauthdb(user);

View File

@ -1,4 +1,5 @@
/* $OpenBSD: servconf.c,v 1.225 2012/04/12 02:42:32 djm Exp $ */
/* $OpenBSD: servconf.c,v 1.226 2012/05/13 01:42:32 dtucker Exp $ */
/* /*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
@ -45,6 +46,8 @@
#include "match.h" #include "match.h"
#include "channels.h" #include "channels.h"
#include "groupaccess.h" #include "groupaccess.h"
#include "canohost.h"
#include "packet.h"
static void add_listen_addr(ServerOptions *, char *, int); static void add_listen_addr(ServerOptions *, char *, int);
static void add_one_listen_addr(ServerOptions *, char *, int); static void add_one_listen_addr(ServerOptions *, char *, int);
@ -539,6 +542,20 @@ add_one_listen_addr(ServerOptions *options, char *addr, int port)
options->listen_addrs = aitop; options->listen_addrs = aitop;
} }
struct connection_info *
get_connection_info(int populate, int use_dns)
{
static struct connection_info ci;
if (!populate)
return &ci;
ci.host = get_canonical_hostname(use_dns);
ci.address = get_remote_ipaddr();
ci.laddress = get_local_ipaddr(packet_get_connection_in());
ci.lport = get_local_port();
return &ci;
}
/* /*
* The strategy for the Match blocks is that the config file is parsed twice. * The strategy for the Match blocks is that the config file is parsed twice.
* *
@ -600,20 +617,25 @@ out:
return result; return result;
} }
/*
* All of the attributes on a single Match line are ANDed together, so we need to check every
* attribute and set the result to zero if any attribute does not match.
*/
static int static int
match_cfg_line(char **condition, int line, const char *user, const char *host, match_cfg_line(char **condition, int line, struct connection_info *ci)
const char *address)
{ {
int result = 1; int result = 1, port;
char *arg, *attrib, *cp = *condition; char *arg, *attrib, *cp = *condition;
size_t len; size_t len;
if (user == NULL) if (ci == NULL)
debug3("checking syntax for 'Match %s'", cp); debug3("checking syntax for 'Match %s'", cp);
else else
debug3("checking match for '%s' user %s host %s addr %s", cp, debug3("checking match for '%s' user %s host %s addr %s "
user ? user : "(null)", host ? host : "(null)", "laddr %s lport %d", cp, ci->user ? ci->user : "(null)",
address ? address : "(null)"); ci->host ? ci->host : "(null)",
ci->address ? ci->address : "(null)",
ci->laddress ? ci->laddress : "(null)", ci->lport);
while ((attrib = strdelim(&cp)) && *attrib != '\0') { while ((attrib = strdelim(&cp)) && *attrib != '\0') {
if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
@ -622,37 +644,45 @@ match_cfg_line(char **condition, int line, const char *user, const char *host,
} }
len = strlen(arg); len = strlen(arg);
if (strcasecmp(attrib, "user") == 0) { if (strcasecmp(attrib, "user") == 0) {
if (!user) { if (ci == NULL || ci->user == NULL) {
result = 0; result = 0;
continue; continue;
} }
if (match_pattern_list(user, arg, len, 0) != 1) if (match_pattern_list(ci->user, arg, len, 0) != 1)
result = 0; result = 0;
else else
debug("user %.100s matched 'User %.100s' at " debug("user %.100s matched 'User %.100s' at "
"line %d", user, arg, line); "line %d", ci->user, arg, line);
} else if (strcasecmp(attrib, "group") == 0) { } else if (strcasecmp(attrib, "group") == 0) {
switch (match_cfg_line_group(arg, line, user)) { if (ci == NULL || ci->user == NULL) {
result = 0;
continue;
}
switch (match_cfg_line_group(arg, line, ci->user)) {
case -1: case -1:
return -1; return -1;
case 0: case 0:
result = 0; result = 0;
} }
} else if (strcasecmp(attrib, "host") == 0) { } else if (strcasecmp(attrib, "host") == 0) {
if (!host) { if (ci == NULL || ci->host == NULL) {
result = 0; result = 0;
continue; continue;
} }
if (match_hostname(host, arg, len) != 1) if (match_hostname(ci->host, arg, len) != 1)
result = 0; result = 0;
else else
debug("connection from %.100s matched 'Host " debug("connection from %.100s matched 'Host "
"%.100s' at line %d", host, arg, line); "%.100s' at line %d", ci->host, arg, line);
} else if (strcasecmp(attrib, "address") == 0) { } else if (strcasecmp(attrib, "address") == 0) {
switch (addr_match_list(address, arg)) { if (ci == NULL || ci->address == NULL) {
result = 0;
continue;
}
switch (addr_match_list(ci->address, arg)) {
case 1: case 1:
debug("connection from %.100s matched 'Address " debug("connection from %.100s matched 'Address "
"%.100s' at line %d", address, arg, line); "%.100s' at line %d", ci->address, arg, line);
break; break;
case 0: case 0:
case -1: case -1:
@ -661,12 +691,47 @@ match_cfg_line(char **condition, int line, const char *user, const char *host,
case -2: case -2:
return -1; return -1;
} }
} else if (strcasecmp(attrib, "localaddress") == 0){
if (ci == NULL || ci->laddress == NULL) {
result = 0;
continue;
}
switch (addr_match_list(ci->laddress, arg)) {
case 1:
debug("connection from %.100s matched "
"'LocalAddress %.100s' at line %d",
ci->laddress, arg, line);
break;
case 0:
case -1:
result = 0;
break;
case -2:
return -1;
}
} else if (strcasecmp(attrib, "localport") == 0) {
if ((port = a2port(arg)) == -1) {
error("Invalid LocalPort '%s' on Match line",
arg);
return -1;
}
if (ci == NULL || ci->lport == 0) {
result = 0;
continue;
}
/* TODO support port lists */
if (port == ci->lport)
debug("connection from %.100s matched "
"'LocalPort %d' at line %d",
ci->laddress, port, line);
else
result = 0;
} else { } else {
error("Unsupported Match attribute %s", attrib); error("Unsupported Match attribute %s", attrib);
return -1; return -1;
} }
} }
if (user != NULL) if (ci != NULL)
debug3("match %sfound", result ? "" : "not "); debug3("match %sfound", result ? "" : "not ");
*condition = cp; *condition = cp;
return result; return result;
@ -713,8 +778,8 @@ static const struct multistate multistate_privsep[] = {
int int
process_server_config_line(ServerOptions *options, char *line, process_server_config_line(ServerOptions *options, char *line,
const char *filename, int linenum, int *activep, const char *user, const char *filename, int linenum, int *activep,
const char *host, const char *address) struct connection_info *connectinfo)
{ {
char *cp, **charptr, *arg, *p; char *cp, **charptr, *arg, *p;
int cmdline = 0, *intptr, value, value2, n; int cmdline = 0, *intptr, value, value2, n;
@ -745,7 +810,7 @@ process_server_config_line(ServerOptions *options, char *line,
if (*activep && opcode != sMatch) if (*activep && opcode != sMatch)
debug3("%s:%d setting %s %s", filename, linenum, arg, cp); debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
if (*activep == 0 && !(flags & SSHCFG_MATCH)) { if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
if (user == NULL) { if (connectinfo == NULL) {
fatal("%s line %d: Directive '%s' is not allowed " fatal("%s line %d: Directive '%s' is not allowed "
"within a Match block", filename, linenum, arg); "within a Match block", filename, linenum, arg);
} else { /* this is a directive we have already processed */ } else { /* this is a directive we have already processed */
@ -1316,7 +1381,7 @@ process_server_config_line(ServerOptions *options, char *line,
if (cmdline) if (cmdline)
fatal("Match directive not supported as a command-line " fatal("Match directive not supported as a command-line "
"option"); "option");
value = match_cfg_line(&cp, linenum, user, host, address); value = match_cfg_line(&cp, linenum, connectinfo);
if (value < 0) if (value < 0)
fatal("%s line %d: Bad Match condition", filename, fatal("%s line %d: Bad Match condition", filename,
linenum); linenum);
@ -1478,16 +1543,58 @@ load_server_config(const char *filename, Buffer *conf)
} }
void void
parse_server_match_config(ServerOptions *options, const char *user, parse_server_match_config(ServerOptions *options,
const char *host, const char *address) struct connection_info *connectinfo)
{ {
ServerOptions mo; ServerOptions mo;
initialize_server_options(&mo); initialize_server_options(&mo);
parse_server_config(&mo, "reprocess config", &cfg, user, host, address); parse_server_config(&mo, "reprocess config", &cfg, connectinfo);
copy_set_server_options(options, &mo, 0); copy_set_server_options(options, &mo, 0);
} }
int parse_server_match_testspec(struct connection_info *ci, char *spec)
{
char *p;
while ((p = strsep(&spec, ",")) && *p != '\0') {
if (strncmp(p, "addr=", 5) == 0) {
ci->address = xstrdup(p + 5);
} else if (strncmp(p, "host=", 5) == 0) {
ci->host = xstrdup(p + 5);
} else if (strncmp(p, "user=", 5) == 0) {
ci->user = xstrdup(p + 5);
} else if (strncmp(p, "laddr=", 6) == 0) {
ci->laddress = xstrdup(p + 6);
} else if (strncmp(p, "lport=", 6) == 0) {
ci->lport = a2port(p + 6);
if (ci->lport == -1) {
fprintf(stderr, "Invalid port '%s' in test mode"
" specification %s\n", p+6, p);
return -1;
}
} else {
fprintf(stderr, "Invalid test mode specification %s\n",
p);
return -1;
}
}
return 0;
}
/*
* returns 1 for a complete spec, 0 for partial spec and -1 for an
* empty spec.
*/
int server_match_spec_complete(struct connection_info *ci)
{
if (ci->user && ci->host && ci->address)
return 1; /* complete */
if (!ci->user && !ci->host && !ci->address)
return -1; /* empty */
return 0; /* partial */
}
/* Helper macros */ /* Helper macros */
#define M_CP_INTOPT(n) do {\ #define M_CP_INTOPT(n) do {\
if (src->n != -1) \ if (src->n != -1) \
@ -1561,7 +1668,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
void void
parse_server_config(ServerOptions *options, const char *filename, Buffer *conf, parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
const char *user, const char *host, const char *address) struct connection_info *connectinfo)
{ {
int active, linenum, bad_options = 0; int active, linenum, bad_options = 0;
char *cp, *obuf, *cbuf; char *cp, *obuf, *cbuf;
@ -1569,11 +1676,11 @@ parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
debug2("%s: config %s len %d", __func__, filename, buffer_len(conf)); debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
obuf = cbuf = xstrdup(buffer_ptr(conf)); obuf = cbuf = xstrdup(buffer_ptr(conf));
active = user ? 0 : 1; active = connectinfo ? 0 : 1;
linenum = 1; linenum = 1;
while ((cp = strsep(&cbuf, "\n")) != NULL) { while ((cp = strsep(&cbuf, "\n")) != NULL) {
if (process_server_config_line(options, cp, filename, if (process_server_config_line(options, cp, filename,
linenum++, &active, user, host, address) != 0) linenum++, &active, connectinfo) != 0)
bad_options++; bad_options++;
} }
xfree(obuf); xfree(obuf);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: servconf.h,v 1.100 2012/04/12 02:42:32 djm Exp $ */ /* $OpenBSD: servconf.h,v 1.101 2012/05/13 01:42:32 dtucker Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -170,6 +170,16 @@ typedef struct {
char *version_addendum; /* Appended to SSH banner */ char *version_addendum; /* Appended to SSH banner */
} ServerOptions; } ServerOptions;
/* Information about the incoming connection as used by Match */
struct connection_info {
const char *user;
const char *host; /* possibly resolved hostname */
const char *address; /* remote address */
const char *laddress; /* local address */
int lport; /* local port */
};
/* /*
* These are string config options that must be copied between the * These are string config options that must be copied between the
* Match sub-config and the main config, and must be sent from the * Match sub-config and the main config, and must be sent from the
@ -184,15 +194,17 @@ typedef struct {
M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \ M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \
} while (0) } while (0)
struct connection_info *get_connection_info(int, int);
void initialize_server_options(ServerOptions *); void initialize_server_options(ServerOptions *);
void fill_default_server_options(ServerOptions *); void fill_default_server_options(ServerOptions *);
int process_server_config_line(ServerOptions *, char *, const char *, int, int process_server_config_line(ServerOptions *, char *, const char *, int,
int *, const char *, const char *, const char *); int *, struct connection_info *);
void load_server_config(const char *, Buffer *); void load_server_config(const char *, Buffer *);
void parse_server_config(ServerOptions *, const char *, Buffer *, void parse_server_config(ServerOptions *, const char *, Buffer *,
const char *, const char *, const char *); struct connection_info *);
void parse_server_match_config(ServerOptions *, const char *, const char *, void parse_server_match_config(ServerOptions *, struct connection_info *);
const char *); int parse_server_match_testspec(struct connection_info *, char *);
int server_match_spec_complete(struct connection_info *);
void copy_set_server_options(ServerOptions *, ServerOptions *, int); void copy_set_server_options(ServerOptions *, ServerOptions *, int);
void dump_config(ServerOptions *); void dump_config(ServerOptions *);
char *derelativise_path(const char *); char *derelativise_path(const char *);

6
sshd.8
View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: sshd.8,v 1.264 2011/09/23 00:22:04 dtucker Exp $ .\" $OpenBSD: sshd.8,v 1.265 2012/05/13 01:42:32 dtucker Exp $
.Dd $Mdocdate: September 23 2011 $ .Dd $Mdocdate: May 13 2012 $
.Dt SSHD 8 .Dt SSHD 8
.Os .Os
.Sh NAME .Sh NAME
@ -114,6 +114,8 @@ The connection parameters are supplied as keyword=value pairs.
The keywords are The keywords are
.Dq user , .Dq user ,
.Dq host , .Dq host ,
.Dq laddr ,
.Dq lport ,
and and
.Dq addr . .Dq addr .
All are required and may be supplied in any order, either with multiple All are required and may be supplied in any order, either with multiple

39
sshd.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshd.c,v 1.390 2012/04/12 02:42:32 djm Exp $ */ /* $OpenBSD: sshd.c,v 1.391 2012/05/13 01:42:32 dtucker Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1325,14 +1325,14 @@ main(int ac, char **av)
int opt, i, j, on = 1; int opt, i, j, on = 1;
int sock_in = -1, sock_out = -1, newsock = -1; int sock_in = -1, sock_out = -1, newsock = -1;
const char *remote_ip; const char *remote_ip;
char *test_user = NULL, *test_host = NULL, *test_addr = NULL;
int remote_port; int remote_port;
char *line, *p, *cp; char *line;
int config_s[2] = { -1 , -1 }; int config_s[2] = { -1 , -1 };
u_int64_t ibytes, obytes; u_int64_t ibytes, obytes;
mode_t new_umask; mode_t new_umask;
Key *key; Key *key;
Authctxt *authctxt; Authctxt *authctxt;
struct connection_info *connection_info = get_connection_info(0, 0);
#ifdef HAVE_SECUREWARE #ifdef HAVE_SECUREWARE
(void)set_auth_parameters(ac, av); (void)set_auth_parameters(ac, av);
@ -1454,20 +1454,9 @@ main(int ac, char **av)
test_flag = 2; test_flag = 2;
break; break;
case 'C': case 'C':
cp = optarg; if (parse_server_match_testspec(connection_info,
while ((p = strsep(&cp, ",")) && *p != '\0') { optarg) == -1)
if (strncmp(p, "addr=", 5) == 0) exit(1);
test_addr = xstrdup(p + 5);
else if (strncmp(p, "host=", 5) == 0)
test_host = xstrdup(p + 5);
else if (strncmp(p, "user=", 5) == 0)
test_user = xstrdup(p + 5);
else {
fprintf(stderr, "Invalid test "
"mode specification %s\n", p);
exit(1);
}
}
break; break;
case 'u': case 'u':
utmp_len = (u_int)strtonum(optarg, 0, MAXHOSTNAMELEN+1, NULL); utmp_len = (u_int)strtonum(optarg, 0, MAXHOSTNAMELEN+1, NULL);
@ -1479,7 +1468,7 @@ main(int ac, char **av)
case 'o': case 'o':
line = xstrdup(optarg); line = xstrdup(optarg);
if (process_server_config_line(&options, line, if (process_server_config_line(&options, line,
"command-line", 0, NULL, NULL, NULL, NULL) != 0) "command-line", 0, NULL, NULL) != 0)
exit(1); exit(1);
xfree(line); xfree(line);
break; break;
@ -1535,13 +1524,10 @@ main(int ac, char **av)
* the parameters we need. If we're not doing an extended test, * the parameters we need. If we're not doing an extended test,
* do not silently ignore connection test params. * do not silently ignore connection test params.
*/ */
if (test_flag >= 2 && if (test_flag >= 2 && server_match_spec_complete(connection_info) == 0)
(test_user != NULL || test_host != NULL || test_addr != NULL)
&& (test_user == NULL || test_host == NULL || test_addr == NULL))
fatal("user, host and addr are all required when testing " fatal("user, host and addr are all required when testing "
"Match configs"); "Match configs");
if (test_flag < 2 && (test_user != NULL || test_host != NULL || if (test_flag < 2 && server_match_spec_complete(connection_info) >= 0)
test_addr != NULL))
fatal("Config test connection parameter (-C) provided without " fatal("Config test connection parameter (-C) provided without "
"test mode (-T)"); "test mode (-T)");
@ -1553,7 +1539,7 @@ main(int ac, char **av)
load_server_config(config_file_name, &cfg); load_server_config(config_file_name, &cfg);
parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name,
&cfg, NULL, NULL, NULL); &cfg, NULL);
seed_rng(); seed_rng();
@ -1715,9 +1701,8 @@ main(int ac, char **av)
} }
if (test_flag > 1) { if (test_flag > 1) {
if (test_user != NULL && test_addr != NULL && test_host != NULL) if (server_match_spec_complete(connection_info) == 1)
parse_server_match_config(&options, test_user, parse_server_match_config(&options, connection_info);
test_host, test_addr);
dump_config(&options); dump_config(&options);
} }

View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: sshd_config.5,v 1.138 2012/04/12 02:43:55 djm Exp $ .\" $OpenBSD: sshd_config.5,v 1.139 2012/05/13 01:42:32 dtucker Exp $
.Dd $Mdocdate: April 12 2012 $ .Dd $Mdocdate: May 13 2012 $
.Dt SSHD_CONFIG 5 .Dt SSHD_CONFIG 5
.Os .Os
.Sh NAME .Sh NAME
@ -677,6 +677,8 @@ The available criteria are
.Cm User , .Cm User ,
.Cm Group , .Cm Group ,
.Cm Host , .Cm Host ,
.Cm LocalAddress ,
.Cm LocalPort ,
and and
.Cm Address . .Cm Address .
The match patterns may consist of single entries or comma-separated The match patterns may consist of single entries or comma-separated