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