
dtucker at zip
May 1, 2012, 3:48 AM
Post #5 of 5
(235 views)
Permalink
|
On Thu, Apr 26, 2012 at 08:34:32AM +0200, Philipp Marek wrote: > Could you put that in OpenSSH, so that -portable and the distributions can > pick that up sometime? We're looking at it. In the mean time, here's an updated patch that: - fixes a problem with the "Match Port" code - fixes the regress tests and adds a couple more - some minor cleanups - applies to openssh-6.0p1 Index: auth.c =================================================================== RCS file: /usr/local/src/security/openssh/cvs/openssh/auth.c,v retrieving revision 1.149 diff -u -p -r1.149 auth.c --- auth.c 29 May 2011 11:40:42 -0000 1.149 +++ auth.c 1 May 2012 10:36:24 -0000 @@ -544,9 +544,14 @@ getpwnamallow(const char *user) #endif #endif struct passwd *pw; + ConnectionInfo connection_info; - parse_server_match_config(&options, user, - get_canonical_hostname(options.use_dns), get_remote_ipaddr()); + connection_info.user = user; + connection_info.host = get_canonical_hostname(options.use_dns); + connection_info.address = get_remote_ipaddr(); + connection_info.laddress = get_local_ipaddr(packet_get_connection_in()); + connection_info.lport = get_local_port(); + parse_server_match_config(&options, &connection_info); #if defined(_AIX) && defined(HAVE_SETAUTHDB) aix_setauthdb(user); Index: servconf.c =================================================================== RCS file: /usr/local/src/security/openssh/cvs/openssh/servconf.c,v retrieving revision 1.220 diff -u -p -r1.220 servconf.c --- servconf.c 2 Oct 2011 07:57:38 -0000 1.220 +++ servconf.c 1 May 2012 10:36:24 -0000 @@ -598,19 +598,20 @@ out: } static int -match_cfg_line(char **condition, int line, const char *user, const char *host, - const char *address) +match_cfg_line(char **condition, int line, ConnectionInfo *ci) { - int result = 1; + int result = 1, port; char *arg, *attrib, *cp = *condition; size_t len; - if (user == NULL) + if (ci == NULL) debug3("checking syntax for 'Match %s'", cp); else - debug3("checking match for '%s' user %s host %s addr %s", cp, - user ? user : "(null)", host ? host : "(null)", - address ? address : "(null)"); + debug3("checking match for '%s' user %s host %s addr %s " + "laddr %s lport %d", cp, ci->user ? ci->user : "(null)", + ci->host ? ci->host : "(null)", + ci->address ? ci->address : "(null)", + ci->laddress ? ci->laddress : "(null)", ci->lport); while ((attrib = strdelim(&cp)) && *attrib != '\0') { if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { @@ -619,37 +620,63 @@ match_cfg_line(char **condition, int lin } len = strlen(arg); if (strcasecmp(attrib, "user") == 0) { - if (!user) { + if (ci == NULL || ci->user == NULL) { result = 0; continue; } - if (match_pattern_list(user, arg, len, 0) != 1) + if (match_pattern_list(ci->user, arg, len, 0) != 1) result = 0; else debug("user %.100s matched 'User %.100s' at " - "line %d", user, arg, line); + "line %d", ci->user, arg, line); } 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: return -1; case 0: result = 0; } } else if (strcasecmp(attrib, "host") == 0) { - if (!host) { + if (ci == NULL || ci->host == NULL) { result = 0; continue; } - if (match_hostname(host, arg, len) != 1) + if (match_hostname(ci->host, arg, len) != 1) result = 0; else 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) { - switch (addr_match_list(address, arg)) { + if (ci == NULL || ci->address == NULL) { + result = 0; + continue; + } + switch (addr_match_list(ci->address, arg)) { case 1: debug("connection from %.100s matched 'Address " - "%.100s' at line %d", address, arg, line); + "%.100s' at line %d", ci->address, arg, line); + break; + case 0: + case -1: + result = 0; + break; + case -2: + 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: @@ -658,12 +685,25 @@ match_cfg_line(char **condition, int lin 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) { + result = 0; + continue; + } + /* TODO support port lists */ + if (port != ci->lport) + result = 0; } else { error("Unsupported Match attribute %s", attrib); return -1; } } - if (user != NULL) + if (ci != NULL) debug3("match %sfound", result ? "" : "not "); *condition = cp; return result; @@ -710,8 +750,8 @@ static const struct multistate multistat int process_server_config_line(ServerOptions *options, char *line, - const char *filename, int linenum, int *activep, const char *user, - const char *host, const char *address) + const char *filename, int linenum, int *activep, + ConnectionInfo *connectinfo) { char *cp, **charptr, *arg, *p; int cmdline = 0, *intptr, value, value2, n; @@ -742,7 +782,7 @@ process_server_config_line(ServerOptions if (*activep && opcode != sMatch) debug3("%s:%d setting %s %s", filename, linenum, arg, cp); if (*activep == 0 && !(flags & SSHCFG_MATCH)) { - if (user == NULL) { + if (connectinfo == NULL) { fatal("%s line %d: Directive '%s' is not allowed " "within a Match block", filename, linenum, arg); } else { /* this is a directive we have already processed */ @@ -1313,7 +1353,7 @@ process_server_config_line(ServerOptions if (cmdline) fatal("Match directive not supported as a command-line " "option"); - value = match_cfg_line(&cp, linenum, user, host, address); + value = match_cfg_line(&cp, linenum, connectinfo); if (value < 0) fatal("%s line %d: Bad Match condition", filename, linenum); @@ -1451,16 +1491,57 @@ load_server_config(const char *filename, } void -parse_server_match_config(ServerOptions *options, const char *user, - const char *host, const char *address) +parse_server_match_config(ServerOptions *options, ConnectionInfo *connectinfo) { ServerOptions 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); } +int parse_server_match_testspec(ConnectionInfo *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(ConnectionInfo *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 */ #define M_CP_INTOPT(n) do {\ if (src->n != -1) \ @@ -1534,7 +1615,7 @@ copy_set_server_options(ServerOptions *d void parse_server_config(ServerOptions *options, const char *filename, Buffer *conf, - const char *user, const char *host, const char *address) + ConnectionInfo *connectinfo) { int active, linenum, bad_options = 0; char *cp, *obuf, *cbuf; @@ -1542,11 +1623,11 @@ parse_server_config(ServerOptions *optio debug2("%s: config %s len %d", __func__, filename, buffer_len(conf)); obuf = cbuf = xstrdup(buffer_ptr(conf)); - active = user ? 0 : 1; + active = connectinfo ? 0 : 1; linenum = 1; while ((cp = strsep(&cbuf, "\n")) != NULL) { if (process_server_config_line(options, cp, filename, - linenum++, &active, user, host, address) != 0) + linenum++, &active, connectinfo) != 0) bad_options++; } xfree(obuf); Index: servconf.h =================================================================== RCS file: /usr/local/src/security/openssh/cvs/openssh/servconf.h,v retrieving revision 1.91 diff -u -p -r1.91 servconf.h --- servconf.h 22 Jun 2011 22:30:03 -0000 1.91 +++ servconf.h 1 May 2012 10:36:24 -0000 @@ -168,6 +168,17 @@ typedef struct { char *authorized_principals_file; } ServerOptions; + +/* Information about the incoming connection as used by Match */ +typedef struct { + const char *user; + const char *host; /* possibly resolved hostname */ + const char *address; /* remote address */ + const char *laddress; /* local address */ + int lport; /* local port */ +} ConnectionInfo; + + /* * These are string config options that must be copied between the * Match sub-config and the main config, and must be sent from the @@ -185,12 +196,13 @@ typedef struct { void initialize_server_options(ServerOptions *); void fill_default_server_options(ServerOptions *); int process_server_config_line(ServerOptions *, char *, const char *, int, - int *, const char *, const char *, const char *); + int *, ConnectionInfo *); void load_server_config(const char *, Buffer *); void parse_server_config(ServerOptions *, const char *, Buffer *, - const char *, const char *, const char *); -void parse_server_match_config(ServerOptions *, const char *, const char *, - const char *); + ConnectionInfo *); +void parse_server_match_config(ServerOptions *, ConnectionInfo *); +int parse_server_match_testspec(ConnectionInfo *, char *); +int server_match_spec_complete(ConnectionInfo *); void copy_set_server_options(ServerOptions *, ServerOptions *, int); void dump_config(ServerOptions *); char *derelativise_path(const char *); Index: sshd.8 =================================================================== RCS file: /usr/local/src/security/openssh/cvs/openssh/sshd.8,v retrieving revision 1.225 diff -u -p -r1.225 sshd.8 --- sshd.8 2 Oct 2011 07:57:38 -0000 1.225 +++ sshd.8 10 Oct 2011 06:14:47 -0000 @@ -114,6 +114,8 @@ The connection parameters are supplied a The keywords are .Dq user , .Dq host , +.Dq laddr , +.Dq lport , and .Dq addr . All are required and may be supplied in any order, either with multiple Index: sshd.c =================================================================== RCS file: /usr/local/src/security/openssh/cvs/openssh/sshd.c,v retrieving revision 1.411 diff -u -p -r1.411 sshd.c --- sshd.c 14 Feb 2012 18:03:31 -0000 1.411 +++ sshd.c 1 May 2012 10:36:24 -0000 @@ -1320,14 +1320,14 @@ main(int ac, char **av) int opt, i, j, on = 1; int sock_in = -1, sock_out = -1, newsock = -1; const char *remote_ip; - char *test_user = NULL, *test_host = NULL, *test_addr = NULL; int remote_port; - char *line, *p, *cp; + char *line; int config_s[2] = { -1 , -1 }; u_int64_t ibytes, obytes; mode_t new_umask; Key *key; Authctxt *authctxt; + ConnectionInfo connection_info; #ifdef HAVE_SECUREWARE (void)set_auth_parameters(ac, av); @@ -1357,6 +1357,10 @@ main(int ac, char **av) /* Initialize configuration options to their default values. */ initialize_server_options(&options); + connection_info.user = connection_info.host = connection_info.address + = connection_info.laddress = NULL; + connection_info.lport = 0; + /* Parse command-line arguments. */ while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:C:dDeiqrtQRT46")) != -1) { switch (opt) { @@ -1449,20 +1453,9 @@ main(int ac, char **av) test_flag = 2; break; case 'C': - cp = optarg; - while ((p = strsep(&cp, ",")) && *p != '\0') { - if (strncmp(p, "addr=", 5) == 0) - 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); - } - } + if (parse_server_match_testspec(&connection_info, + optarg) == -1) + exit(1); break; case 'u': utmp_len = (u_int)strtonum(optarg, 0, MAXHOSTNAMELEN+1, NULL); @@ -1474,7 +1467,7 @@ main(int ac, char **av) case 'o': line = xstrdup(optarg); if (process_server_config_line(&options, line, - "command-line", 0, NULL, NULL, NULL, NULL) != 0) + "command-line", 0, NULL, NULL) != 0) exit(1); xfree(line); break; @@ -1530,13 +1523,10 @@ main(int ac, char **av) * the parameters we need. If we're not doing an extended test, * do not silently ignore connection test params. */ - if (test_flag >= 2 && - (test_user != NULL || test_host != NULL || test_addr != NULL) - && (test_user == NULL || test_host == NULL || test_addr == NULL)) + if (test_flag >= 2 && server_match_spec_complete(&connection_info) == 0) fatal("user, host and addr are all required when testing " "Match configs"); - if (test_flag < 2 && (test_user != NULL || test_host != NULL || - test_addr != NULL)) + if (test_flag < 2 && server_match_spec_complete(&connection_info) >= 0) fatal("Config test connection parameter (-C) provided without " "test mode (-T)"); @@ -1548,7 +1538,7 @@ main(int ac, char **av) load_server_config(config_file_name, &cfg); parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, - &cfg, NULL, NULL, NULL); + &cfg, NULL); seed_rng(); @@ -1710,9 +1700,8 @@ main(int ac, char **av) } if (test_flag > 1) { - if (test_user != NULL && test_addr != NULL && test_host != NULL) - parse_server_match_config(&options, test_user, - test_host, test_addr); + if (server_match_spec_complete(&connection_info) == 1) + parse_server_match_config(&options, &connection_info); dump_config(&options); } Index: sshd_config.5 =================================================================== RCS file: /usr/local/src/security/openssh/cvs/openssh/sshd_config.5,v retrieving revision 1.143 diff -u -p -r1.143 sshd_config.5 --- sshd_config.5 22 Sep 2011 11:37:13 -0000 1.143 +++ sshd_config.5 1 May 2012 10:36:24 -0000 @@ -675,6 +675,8 @@ The available criteria are .Cm User , .Cm Group , .Cm Host , +.Cm LocalAddress , +.Cm LocalPort , and .Cm Address . The match patterns may consist of single entries or comma-separated Index: regress/addrmatch.sh =================================================================== RCS file: /usr/local/src/security/openssh/cvs/openssh/regress/addrmatch.sh,v retrieving revision 1.5 diff -u -p -r1.5 addrmatch.sh --- regress/addrmatch.sh 24 Feb 2010 06:26:39 -0000 1.5 +++ regress/addrmatch.sh 1 May 2012 10:36:46 -0000 @@ -7,39 +7,47 @@ mv $OBJ/sshd_proxy $OBJ/sshd_proxy_bak run_trial() { - user="$1"; addr="$2"; host="$3"; expected="$4"; descr="$5" + user="$1"; addr="$2"; host="$3"; laddr="$4"; lport="$5" + expected="$6"; descr="$7" verbose "test $descr for $user $addr $host" result=`${SSHD} -f $OBJ/sshd_proxy -T \ - -C user=${user},addr=${addr},host=${host} | \ - awk '/^passwordauthentication/ {print $2}'` + -C user=${user},addr=${addr},host=${host},laddr=${laddr},lport=${lport} | \ + awk '/^forcecommand/ {print $2}'` if [ "$result" != "$expected" ]; then - fail "failed for $user $addr $host: expected $expected, got $result" + fail "failed '$descr' expected $expected got $result" fi } cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy cat >>$OBJ/sshd_proxy <<EOD -PasswordAuthentication no +ForceCommand nomatch Match Address 192.168.0.0/16,!192.168.30.0/24,10.0.0.0/8,host.example.com - PasswordAuthentication yes + ForceCommand match1 Match Address 1.1.1.1,::1,!::3,2000::/16 - PasswordAuthentication yes + ForceCommand match2 +Match LocalAddress 127.0.0.1,::1 + ForceCommand match3 +Match LocalPort 5678 + ForceCommand match4 EOD -run_trial user 192.168.0.1 somehost yes "permit, first entry" -run_trial user 192.168.30.1 somehost no "deny, negative match" -run_trial user 19.0.0.1 somehost no "deny, no match" -run_trial user 10.255.255.254 somehost yes "permit, list middle" -run_trial user 192.168.30.1 192.168.0.1 no "deny, faked IP in hostname" -run_trial user 1.1.1.1 somehost.example.com yes "permit, bare IP4 address" -test "$TEST_SSH_IPV6" = "no" && exit -run_trial user ::1 somehost.example.com yes "permit, bare IP6 address" -run_trial user ::2 somehost.exaple.com no "deny IPv6" -run_trial user ::3 somehost no "deny IP6 negated" -run_trial user ::4 somehost no "deny, IP6 no match" -run_trial user 2000::1 somehost yes "permit, IP6 network" -run_trial user 2001::1 somehost no "deny, IP6 network" +run_trial user 192.168.0.1 somehost 1.2.3.4 1234 match1 "first entry" +run_trial user 192.168.30.1 somehost 1.2.3.4 1234 nomatch "negative match" +run_trial user 19.0.0.1 somehost 1.2.3.4 1234 nomatch "no match" +run_trial user 10.255.255.254 somehost 1.2.3.4 1234 match1 "list middle" +run_trial user 192.168.30.1 192.168.0.1 1.2.3.4 1234 nomatch "faked IP in hostname" +run_trial user 1.1.1.1 somehost.example.com 1.2.3.4 1234 match2 "bare IP4 address" +run_trial user 19.0.0.1 somehost 127.0.0.1 1234 match3 "localaddress" +run_trial user 19.0.0.1 somehost 1.2.3.4 5678 match4 "localport" +run_trial user ::1 somehost.example.com ::2 1234 match2 "bare IP6 address" +run_trial user ::2 somehost.exaple.com ::2 1234 nomatch "deny IPv6" +run_trial user ::3 somehost ::2 1234 nomatch "IP6 negated" +run_trial user ::4 somehost ::2 1234 nomatch "IP6 no match" +run_trial user 2000::1 somehost ::2 1234 match2 "IP6 network" +run_trial user 2001::1 somehost ::2 1234 nomatch "IP6 network" +run_trial user ::5 somehost ::1 1234 match3 "IP6 localaddress" +run_trial user ::5 somehost ::2 5678 match4 "IP6 localport" cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy rm $OBJ/sshd_proxy_bak -- Darren Tucker (dtucker at zip.com.au) GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4 37C9 C982 80C7 8FF4 FA69 Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement. _______________________________________________ openssh-unix-dev mailing list openssh-unix-dev [at] mindrot https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
|