Path: news.porcupine.org!news.porcupine.org!not-for-mail From: Wietse Venema Newsgroups: comp.mail.sendmail,comp.security.unix Subject: TCP Wrapper Blacklist Extension Followup-To: poster Date: 8 Sep 1997 18:53:13 -0400 Organization: Wietse's hangout while on sabattical in the USA Lines: 147 Sender: wietse@spike.porcupine.org Message-ID: <5v1vkp$h4f$1@spike.porcupine.org> NNTP-Posting-Host: spike.porcupine.org Xref: news.porcupine.org comp.mail.sendmail:3541 comp.security.unix:7158 The patch below adds a new host pattern to the TCP Wrapper access control language. Instead of a host name or address pattern, you can specify an external /file/name with host name or address patterns. The feature can be used recursively. The /file/name extension makes it easy to blacklist bad sites, for example, to block unwanted electronic mail when libwrap is linked into sendmail. Adding hosts to a simple text file is much easier than having to edit a more complex hosts.allow/deny file. I developed this a year or so ago as a substitute for NIS netgroups. At that time, I did not consider it of sufficient interest for inclusion in the TCP Wrapper distribution. How times have changed. The patch is relative to TCP Wrappers version 7.6. The main archive site is ftp://ftp.win.tue.nl/pub/security/tcp_wrappers_7.6.tar.gz Thanks to the Debian LINUX folks for expressing their interest in this patch. Wietse [diff updated by Md] diff -ruN tcp_wrappers_7.6.orig/hosts_access.5 tcp_wrappers_7.6/hosts_access.5 --- tcp_wrappers_7.6.orig/hosts_access.5 2004-04-10 19:28:09.000000000 +0200 +++ tcp_wrappers_7.6/hosts_access.5 2004-04-10 19:28:01.000000000 +0200 @@ -97,6 +97,13 @@ `[3ffe:505:2:1::]/64\' matches every address in the range `3ffe:505:2:1::\' through `3ffe:505:2:1:ffff:ffff:ffff:ffff\'. .IP \(bu +A string that begins with a `/\' character is treated as a file +name. A host name or address is matched if it matches any host name +or address pattern listed in the named file. The file format is +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 `.\'. diff -ruN tcp_wrappers_7.6.orig/hosts_access.c tcp_wrappers_7.6/hosts_access.c --- tcp_wrappers_7.6.orig/hosts_access.c 2004-04-10 19:28:09.000000000 +0200 +++ tcp_wrappers_7.6/hosts_access.c 2004-04-10 19:27:05.000000000 +0200 @@ -253,6 +253,26 @@ } } +/* hostfile_match - look up host patterns from file */ + +static int hostfile_match(path, host) +char *path; +struct hosts_info *host; +{ + char tok[BUFSIZ]; + int match = NO; + FILE *fp; + + if ((fp = fopen(path, "r")) != 0) { + while (fscanf(fp, "%s", tok) == 1 && !(match = host_match(tok, host))) + /* void */ ; + fclose(fp); + } else if (errno != ENOENT) { + tcpd_warn("open %s: %m", path); + } + return (match); +} + /* host_match - match host name and/or address against pattern */ static int host_match(tok, host) @@ -280,6 +300,8 @@ tcpd_warn("netgroup support is disabled"); /* not tcpd_jump() */ return (NO); #endif + } else if (tok[0] == '/') { /* /file hack */ + return (hostfile_match(tok, host)); } else if (STR_EQ(tok, "KNOWN")) { /* check address and name */ char *name = eval_hostname(host); return (STR_NE(eval_hostaddr(host), unknown) && HOSTNAME_KNOWN(name)); diff -ruN tcp_wrappers_7.6.orig/tcpdchk.c tcp_wrappers_7.6/tcpdchk.c --- tcp_wrappers_7.6.orig/tcpdchk.c 2004-04-10 19:28:09.000000000 +0200 +++ tcp_wrappers_7.6/tcpdchk.c 2004-04-10 19:27:05.000000000 +0200 @@ -353,6 +353,8 @@ { if (pat[0] == '@') { tcpd_warn("%s: daemon name begins with \"@\"", pat); + } else if (pat[0] == '/') { + tcpd_warn("%s: daemon name begins with \"/\"", pat); } else if (pat[0] == '.') { tcpd_warn("%s: daemon name begins with dot", pat); } else if (pat[strlen(pat) - 1] == '.') { @@ -385,6 +387,8 @@ { if (pat[0] == '@') { /* @netgroup */ tcpd_warn("%s: user name begins with \"@\"", pat); + } else if (pat[0] == '/') { + tcpd_warn("%s: user name begins with \"/\"", pat); } else if (pat[0] == '.') { tcpd_warn("%s: user name begins with dot", pat); } else if (pat[strlen(pat) - 1] == '.') { @@ -430,8 +434,13 @@ static int check_host(pat) char *pat; { + char buf[BUFSIZ]; char *mask; int addr_count = 1; + FILE *fp; + struct tcpd_context saved_context; + char *cp; + char *wsp = " \t\r\n"; if (pat[0] == '@') { /* @netgroup */ #ifdef NO_NETGRENT @@ -450,6 +459,21 @@ tcpd_warn("netgroup support disabled"); #endif #endif + } else if (pat[0] == '/') { /* /path/name */ + if ((fp = fopen(pat, "r")) != 0) { + saved_context = tcpd_context; + tcpd_context.file = pat; + tcpd_context.line = 0; + while (fgets(buf, sizeof(buf), fp)) { + tcpd_context.line++; + for (cp = strtok(buf, wsp); cp; cp = strtok((char *) 0, wsp)) + check_host(cp); + } + tcpd_context = saved_context; + fclose(fp); + } else if (errno != ENOENT) { + tcpd_warn("open %s: %m", pat); + } } else if (mask = split_at(pat, '/')) { /* network/netmask */ #ifdef INET6 int mask_len;