Corinna Vinschen
2000-Oct-07 21:40 UTC
[PATCH]: Add tcp_wrappers protection to port forwarding
Hi, attached is a patch by Chris Faylor <cgf at cygnus.com> relative to 2.2.0p1. Description: OpenSSH does not allow port gatewaying by default. This means that only the local host can access forwarded ports. Adding "GatewayPorts yes" to .ssh/config usually does this job. Unfortunately, OpenSSH does not recognize the same hosts.allow/ hosts.deny options as ssh.com's sshd client, i.e., it dosn't recognize the sshfwd settings in hosts.allow. So adding "GatewayPorts" opens up all forwarded ports to outside inspection not considering using a firewall. The patch uses basically the same method as ssh.com. A lookup is made in hosts.allow/hosts.deny on sshfwd-<port number> (not port name -- this is different from ssh.com) and if the tcp_wrappers don't allow the lookup then the connection is closed immediately. ChangeLog: 20001007 - Add tcp_wrappers protection to port forwarding. From <Christopher Faylor> cgf at cygnus.com. Corinna -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Developer mailto:cygwin at sources.redhat.com Red Hat, Inc. mailto:vinschen at cygnus.com -------------- next part -------------- --- channels.c.orig Tue Aug 22 20:46:24 2000 +++ channels.c Mon Oct 2 22:49:22 2000 @@ -38,6 +38,11 @@ RCSID("$OpenBSD: channels.c,v 1.66 2000/ #include "key.h" #include "authfd.h" +#ifdef LIBWRAP +#include <tcpd.h> +#include <syslog.h> +#endif /* LIBWRAP */ + /* Maximum number of fake X11 displays to try. */ #define MAX_DISPLAYS 1000 @@ -581,6 +586,30 @@ channel_post_port_listener(Channel *c, f } remote_hostname = get_remote_hostname(newsock); remote_port = get_peer_port(newsock); +#ifdef LIBWRAP + { + char fwd[80]; + void (*sigch) (int); + int res; + struct request_info req; + + snprintf(fwd, sizeof(fwd), "sshdfwd-%d", c->host_port); + request_init(&req, RQ_DAEMON, fwd, RQ_FILE, newsock, NULL); + fromhost(&req); + sigch = signal(SIGCHLD, SIG_DFL); + res = hosts_access(&req); + signal(SIGCHLD, sigch); + if (!res) { + packet_send_debug("refused forwarded connection from %.500s to local port %d.", + eval_client(&req), c->host_port); + error("forwarded connection from %.500s to local port %d refused.", + eval_client(&req), c->host_port); + shutdown(newsock, SHUT_RDWR); + close(newsock); + return; + } + } +#endif /* LIBWRAP */ snprintf(buf, sizeof buf, "listen port %d for %.100s port %d, " "connect from %.200s port %d", --- ssh.c.orig Mon Aug 28 20:33:51 2000 +++ ssh.c Mon Oct 2 22:50:29 2000 @@ -30,6 +30,11 @@ RCSID("$OpenBSD: ssh.c,v 1.63 2000/08/28 #include "key.h" #include "authfd.h" #include "authfile.h" +#ifdef LIBWRAP +#include <syslog.h> +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING; +#endif /* LIBWRAP */ #ifdef HAVE___PROGNAME extern char *__progname;
Markus Friedl
2000-Oct-08 14:19 UTC
[PATCH]: Add tcp_wrappers protection to port forwarding
On Sat, Oct 07, 2000 at 11:40:39PM +0200, Corinna Vinschen wrote:> + snprintf(fwd, sizeof(fwd), "sshdfwd-%d", c->host_port);i don't like this feature. should it be for -R or -L style forwarding? why should a client programm read /etc/hosts.allow? at least it should not be the default, even if you use tcp-wrappers in sshd. -markus
Pekka Savola
2000-Oct-08 16:01 UTC
[PATCH]: Add tcp_wrappers protection to port forwarding
On Sat, 7 Oct 2000, Corinna Vinschen wrote:> The patch uses basically the same method as ssh.com. A lookup is made > in hosts.allow/hosts.deny on sshfwd-<port number> (not port name -- > this is different from ssh.com) and if the tcp_wrappers don't allow > the lookup then the connection is closed immediately.Speaking of tcp_wrappers, I think this might be of interest to some of you even though it isn't exactly an _OpenSSH_ patch. Before, I was griping why OpenSSH didn't include AllowHosts capabilities. One of the best side of these was that you could use *? -wildcards when matching IP addresses and hostnames. I've adapted the attached patch from SSH-1.2.12 (no changes to the code since then) to tcp_wrappers to make it possible to match *? wildcards with certain exceptions. Combined with the feature in e.g. FreeBSD to import hostnames / IP addresses from separate files (patch available), tcp_wrappers becomes even more powerful than before :-). Perhaps someone else will find this useful too :-). Comments welcome. -- Pekka Savola "Tell me of difficulties surmounted, Pekka.Savola at netcore.fi not those you stumble over and fall" -------------- next part -------------- diff -uNr tcp_wrappers_7.6/hosts_access.5 tcp_wrappers_7.6.new/hosts_access.5 --- tcp_wrappers_7.6/hosts_access.5 Fri Sep 22 21:29:24 2000 +++ tcp_wrappers_7.6.new/hosts_access.5 Fri Sep 22 21:28:44 2000 @@ -96,6 +96,10 @@ zero or more lines with zero or more host name or address patterns separated by whitespace. A file name pattern can be used anywhere a host name or address pattern can be used. +.IP \(bu +Wildcards `*\' and `?\' can be used to match hostnames or IP addresses. This +method of matching cannot be used in conjunction with `net/mask\' matching, +hostname matching beginning with `.\' or IP address matching ending with `.\'. .SH WILDCARDS The access control language supports explicit wildcards: .IP ALL diff -uNr tcp_wrappers_7.6/hosts_access.c tcp_wrappers_7.6.new/hosts_access.c --- tcp_wrappers_7.6/hosts_access.c Fri Sep 22 21:29:24 2000 +++ tcp_wrappers_7.6.new/hosts_access.c Fri Sep 22 21:18:09 2000 @@ -311,6 +311,11 @@ { int n; +#ifndef DISABLE_WILDCARD_MATCHING + if (strchr(tok, '*') || strchr(tok,'?')) { /* contains '*' or '?' */ + return (match_pattern_ylo(string,tok)); + } else +#endif if (tok[0] == '.') { /* suffix */ n = strlen(string) - strlen(tok); return (n > 0 && STR_EQ(tok, string + n)); @@ -351,3 +356,71 @@ } return ((addr & mask) == net); } + +#ifndef DISABLE_WILDCARD_MATCHING +/* Note: this feature has been adapted in a pretty straightforward way + from Tatu Ylonen's last SSH version under a free license by + Pekka Savola <pekkas at netcore.fi>. + + Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland +*/ + +/* Returns true if the given string matches the pattern (which may contain + ? and * as wildcards), and zero if it does not match. */ + +int match_pattern_ylo(const char *s, const char *pattern) +{ + while (1) + { + /* If at end of pattern, accept if also at end of string. */ + if (!*pattern) + return !*s; + + /* Process '*'. */ + if (*pattern == '*') + { + /* Skip the asterisk. */ + pattern++; + + /* If at end of pattern, accept immediately. */ + if (!*pattern) + return 1; + + /* If next character in pattern is known, optimize. */ + if (*pattern != '?' && *pattern != '*') + { + /* Look instances of the next character in pattern, and try + to match starting from those. */ + for (; *s; s++) + if (*s == *pattern && + match_pattern_ylo(s + 1, pattern + 1)) + return 1; + /* Failed. */ + return 0; + } + + /* Move ahead one character at a time and try to match at each + position. */ + for (; *s; s++) + if (match_pattern_ylo(s, pattern)) + return 1; + /* Failed. */ + return 0; + } + + /* There must be at least one more character in the string. If we are + at the end, fail. */ + if (!*s) + return 0; + + /* Check if the next character of the string is acceptable. */ + if (*pattern != '?' && *pattern != *s) + return 0; + + /* Move to the next character, both in string and in pattern. */ + s++; + pattern++; + } + /*NOTREACHED*/ +} +#endif /* DISABLE_WILDCARD_MATCHING */