Commit c49b7f47 authored by Marco d'Itri's avatar Marco d'Itri

Imported Upstream version 7.6.q

parent 82d98ef7
@(#) BLURB 1.28 97/03/21 19:27:18
With this package you can monitor and filter incoming requests for the
SYSTAT, FINGER, FTP, TELNET, RLOGIN, RSH, EXEC, TFTP, TALK, and other
network services.
The package provides tiny daemon wrapper programs that can be installed
without any changes to existing software or to existing configuration
files. The wrappers report the name of the client host and of the
requested service; the wrappers do not exchange information with the
client or server applications, and impose no overhead on the actual
conversation between the client and server applications.
This patch upgrades the tcp wrappers version 7.5 source code to
version 7.6. The source-routing protection in version 7.5 was not
as strong as it could be. And all this effort was not needed with
modern UNIX systems that can already stop source-routed traffic in
the kernel. Examples are 4.4BSD derivatives, Solaris 2.x, and Linux.
This release does not introduce new features. Do not bother applying
this patch when you built your version 7.x tcp wrapper without
enabling the KILL_IP_OPTIONS compiler switch; when you can disable
IP source routing options in the kernel; when you run a UNIX version
that pre-dates 4.4BSD, such as SunOS 4. Such systems are unable to
receive source-routed connections and are therefore not vulnerable
to IP spoofing attacks with source-routed TCP connections.
A complete change log is given in the CHANGES document. As always,
problem reports and suggestions for improvement are welcome.
Wietse Venema (wietse@wzv.win.tue.nl),
Department of Mathematics and Computing Science,
Eindhoven University of Technology,
The Netherlands.
Currently visiting IBM T.J. Watson Research, Hawthorne NY, USA.
# @(#) Banners.Makefile 1.3 97/02/12 02:13:18
#
# Install this file as the Makefile in your directory with banner files.
# It will convert a prototype banner text to a form that is suitable for
# the ftp, telnet, rlogin, and other services.
#
# You'll have to comment out the IN definition below if your daemon
# names don't start with `in.'.
#
# The prototype text should live in the banners directory, as a file with
# the name "prototype". In the prototype text you can use %<character>
# sequences as described in the hosts_access.5 manual page (`nroff -man'
# format). The sequences will be expanded while the banner message is
# sent to the client. For example:
#
# Hello %u@%h, what brings you here?
#
# Expands to: Hello username@hostname, what brings you here? Note: the
# use of %u forces a client username lookup.
#
# In order to use banners, build the tcp wrapper with -DPROCESS_OPTIONS
# and use hosts.allow rules like this:
#
# daemons ... : clients ... : banners /some/directory ...
#
# Of course, nothing prevents you from using multiple banner directories.
# For example, one banner directory for clients that are granted service,
# one banner directory for rejected clients, and one banner directory for
# clients with a hostname problem.
#
SHELL = /bin/sh
IN = in.
BANNERS = $(IN)telnetd $(IN)ftpd $(IN)rlogind # $(IN)fingerd $(IN)rshd
all: $(BANNERS)
$(IN)telnetd: prototype
cp prototype $@
chmod 644 $@
$(IN)ftpd: prototype
sed 's/^/220-/' prototype > $@
chmod 644 $@
$(IN)rlogind: prototype nul
( ./nul ; cat prototype ) > $@
chmod 644 $@
# Other services: banners may interfere with normal operation
# so they should probably be used only when refusing service.
# In particular, banners don't work with standard rsh daemons.
# You would have to use an rshd that has built-in tcp wrapper
# support, for example the rshd that is part of the logdaemon
# utilities.
$(IN)fingerd: prototype
cp prototype $@
chmod 644 $@
$(IN)rshd: prototype nul
( ./nul ; cat prototype ) > $@
chmod 644 $@
# In case no /dev/zero available, let's hope they have at least
# a C compiler of some sort.
nul:
echo 'main() { write(1,"",1); return(0); }' >nul.c
$(CC) $(CFLAGS) -s -o nul nul.c
rm -f nul.c
This diff is collapsed.
/************************************************************************
* Copyright 1995 by Wietse Venema. All rights reserved. Some individual
* files may be covered by other copyrights.
*
* This material was originally written and compiled by Wietse Venema at
* Eindhoven University of Technology, The Netherlands, in 1990, 1991,
* 1992, 1993, 1994 and 1995.
*
* Redistribution and use in source and binary forms are permitted
* provided that this entire copyright notice is duplicated in all such
* copies.
*
* This software is provided "as is" and without any expressed or implied
* warranties, including, without limitation, the implied warranties of
* merchantibility and fitness for any particular purpose.
************************************************************************/
This diff is collapsed.
This diff is collapsed.
@(#) README.IRIX 1.2 94/12/28 18:45:58
In the past few months I received several messages with questions from
people that tried to use my tcp wrapper on IRIX 5.x. Some mysteries
could be solved via email, and then some remained.
Today I finally had a chance to do some tests on someones IRIX 5.2
system. Here is my first-hand experience with wrapper release 6.3.
(1) Inetd is broken. Normally one edits inetd.conf, sends a HUP signal
to inetd and that's it. With IRIX evil things happen: inetd is too
stupid to remember that it is already listening on a port.
In order to modify an entry in inetd.conf, first comment it out
with a # at the beginning of the line, kill -HUP the inetd, then
uncomment the inetd.conf entry and kill -HUP again.
Even with this amount of care I have seen inetd messing up, like
calling rusersd when I make a talk connection. Even killing and
restarting inetd does not solve all problems.
I find it hard to believe, it but the best thing to do with IRIX is
to reboot after changing inetd.conf.
(2) When tcpd is built according to the irix4 Makefile rules, it
appears to work as expected with TCP-based services such as
fingerd, and with UDP-based services such as ntalk and tftp.
(3) It does NOT work with RPC over UDP services such as rusersd and
rstatd: the wrapper hangs in the recvfrom() system call, and I
have spent several hours looking for ways to work around it. No
way. After finding that none of the applicable socket primitives
can be made to work (recvfrom recvmsg) I give up. So, the IRIX RPC
services cannot be wrapped until SGI fixes their system so that it
works like everyone elses code (HP Sun Dec AIX and so on).
(4) I didn't even bother to try the RPC over TCP services.
(5) When an IRIX 5.2 system is a NIS client, it can have problems with
hosts that have more than one address: the wrapper will see only
one address, and may complain when PARANOID mode is on. The fix is
to change the name service lookup order in /etc/resolv.conf so that
your system tries DNS before NIS (hostresorder bind nis local).
(6) IRIX 5.2 is not System V.4, and it shows. Do not link with the
-lsocket and -lnsl libraries. They are completely broken, and the
wrapper will be unable to figure out the client internet address.
So, TLI services cannot be wrapped until SGI fixes their system so
that it works the way it is supposed to.
I am not impressed by the quality of the IRIX system software. There
are many things that work on almost every other system except with IRIX.
Wietse
@(#) README.NIS 1.2 96/02/11 17:24:52
> Problem: I have several [machines] with multiple IP addresses, and
> when they try to connect to a daemon with tcp wrapper, they are often
> rejected. I assume this is due to the -DPARANOID option, and depends
> on which IP address is returned first from the nameserver for a given
> name. This behavior seems to be random, may depend on ordering in
> the YP host map?
[Note: the situation described below no longer exists. Presently, my
internet gateway uses the same IP address on all interfaces. To avoid
confusion I have removed the old name wzv-gw.win.tue.nl from the DNS. I
have kept the discussion below for educational reasons].
NIS was not designed to handle multi-homed hosts. With NIS, each
address should have its own hostname. For example, wzv-gw is my
gateway. It has two interfaces: one connected to the local ethernet,
the other to a serial link. In the NIS it is registered as:
131.155.210.23 wzv-gw-ether
131.155.12.78 wzv-gw-slip
In principle, wzv-gw could be the official name of one of these
interfaces, or it could be an alias for both.
The DNS was designed to handle multi-homed hosts. In the DNS my gateway
is registered in zone win.tue.nl, with one name that has two A records:
wzv-gw IN A 131.155.210.23
IN A 131.155.12.78
And of course there are PTR records in zones 210.155.131.in-addr.arpa
and 12.155.131.in-addr.arpa that point to wzv-gw.win.tue.nl.
This setup does not cause any problems. You can test your name service
with the two programs below. This is what they say on a local NIS client
(both client and server running SunOS 4.1.3_U1):
% gethostbyname wzv-gw
Hostname: wzv-gw.win.tue.nl
Aliases:
Addresses: 131.155.210.23 131.155.12.78
% gethostbyaddr 131.155.210.23
Hostname: wzv-gw-ether
Aliases:
Addresses: 131.155.210.23
% gethostbyaddr 131.155.12.78
Hostname: wzv-gw-slip
Aliases:
Addresses: 131.155.12.78
Things seem less confusing when seen by a NIS client in a different
domain (both client and server running SunOS 4.1.3_U1):
% gethostbyname wzv-gw.win.tue.nl
Hostname: wzv-gw.win.tue.nl
Aliases:
Addresses: 131.155.210.23 131.155.12.78
% gethostbyaddr 131.155.210.23
Hostname: wzv-gw.win.tue.nl
Aliases:
Addresses: 131.155.12.78 131.155.210.23
% gethostbyaddr 131.155.12.78
Hostname: wzv-gw.win.tue.nl
Aliases:
Addresses: 131.155.210.23 131.155.12.78
Alas, Solaris 2.4 still has problems. This is what I get on a Solaris
2.4 NIS client, with a SunOS 4.1.3_U1 NIS server:
% gethostbyname wzv-gw.win.tue.nl
Hostname: wzv-gw.win.tue.nl
Aliases: 131.155.210.23 wzv-gw.win.tue.nl
Addresses: 131.155.12.78
The tcpd source comes with a workaround for this problem. The
workaround is ugly and is not part of the programs attached below.
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: gethostbyaddr.c gethostbyname.c
# Wrapped by wietse@wzv on Sun Jan 8 17:08:48 1995
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f gethostbyaddr.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"gethostbyaddr.c\"
else
echo shar: Extracting \"gethostbyaddr.c\" \(1073 characters\)
sed "s/^X//" >gethostbyaddr.c <<'END_OF_gethostbyaddr.c'
X /*
X * gethostbyaddr tester. compile with:
X *
X * cc -o gethostbyaddr gethostbyaddr.c (SunOS 4.x)
X *
X * cc -o gethostbyaddr gethostbyaddr.c -lnsl (SunOS 5.x)
X *
X * run as: gethostbyaddr address
X *
X * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
X */
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X#include <netdb.h>
X#include <stdio.h>
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X struct hostent *hp;
X long addr;
X
X if (argc != 2) {
X fprintf(stderr, "usage: %s i.p.addres\n", argv[0]);
X exit(1);
X }
X addr = inet_addr(argv[1]);
X if (hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET)) {
X printf("Hostname:\t%s\n", hp->h_name);
X printf("Aliases:\t");
X while (hp->h_aliases[0])
X printf("%s ", *hp->h_aliases++);
X printf("\n");
X printf("Addresses:\t");
X while (hp->h_addr_list[0])
X printf("%s ", inet_ntoa(*(struct in_addr *) * hp->h_addr_list++));
X printf("\n");
X exit(0);
X }
X fprintf(stderr, "host %s not found\n", argv[1]);
X exit(1);
X}
END_OF_gethostbyaddr.c
if test 1073 -ne `wc -c <gethostbyaddr.c`; then
echo shar: \"gethostbyaddr.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f gethostbyname.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"gethostbyname.c\"
else
echo shar: Extracting \"gethostbyname.c\" \(999 characters\)
sed "s/^X//" >gethostbyname.c <<'END_OF_gethostbyname.c'
X /*
X * gethostbyname tester. compile with:
X *
X * cc -o gethostbyname gethostbyname.c (SunOS 4.x)
X *
X * cc -o gethostbyname gethostbyname.c -lnsl (SunOS 5.x)
X *
X * run as: gethostbyname hostname
X *
X * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
X */
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X#include <netdb.h>
X#include <stdio.h>
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X struct hostent *hp;
X
X if (argc != 2) {
X fprintf(stderr, "usage: %s hostname\n", argv[0]);
X exit(1);
X }
X if (hp = gethostbyname(argv[1])) {
X printf("Hostname:\t%s\n", hp->h_name);
X printf("Aliases:\t");
X while (hp->h_aliases[0])
X printf("%s ", *hp->h_aliases++);
X printf("\n");
X printf("Addresses:\t");
X while (hp->h_addr_list[0])
X printf("%s ", inet_ntoa(*(struct in_addr *) * hp->h_addr_list++));
X printf("\n");
X exit(0);
X } else {
X fprintf(stderr, "host %s not found\n", argv[1]);
X exit(1);
X }
X}
END_OF_gethostbyname.c
if test 999 -ne `wc -c <gethostbyname.c`; then
echo shar: \"gethostbyname.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
/*
* clean_exit() cleans up and terminates the program. It should be called
* instead of exit() when for some reason the real network daemon will not or
* cannot be run. Reason: in the case of a datagram-oriented service we must
* discard the not-yet received data from the client. Otherwise, inetd will
* see the same datagram again and again, and go into a loop.
*
* Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
*/
#ifndef lint
static char sccsid[] = "@(#) clean_exit.c 1.4 94/12/28 17:42:19";
#endif
#include <stdio.h>
extern void exit();
#include "tcpd.h"
/* clean_exit - clean up and exit */
void clean_exit(request)
struct request_info *request;
{
/*
* In case of unconnected protocols we must eat up the not-yet received
* data or inetd will loop.
*/
if (request->sink)
request->sink(request->fd);
/*
* Be kind to the inetd. We already reported the problem via the syslogd,
* and there is no need for additional garbage in the logfile.
*/
sleep(5);
exit(0);
}
/*
* Routines to report various classes of problems. Each report is decorated
* with the current context (file name and line number), if available.
*
* tcpd_warn() reports a problem and proceeds.
*
* tcpd_jump() reports a problem and jumps.
*
* Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
*/
#ifndef lint
static char sccsid[] = "@(#) diag.c 1.1 94/12/28 17:42:20";
#endif
/* System libraries */
#include <syslog.h>
#include <stdio.h>
#include <setjmp.h>
/* Local stuff */
#include "tcpd.h"
#include "mystdarg.h"
struct tcpd_context tcpd_context;
jmp_buf tcpd_buf;
/* tcpd_diag - centralize error reporter */
static void tcpd_diag(severity, tag, format, ap)
int severity;
char *tag;
char *format;
va_list ap;
{
char fmt[BUFSIZ];
if (tcpd_context.file)
sprintf(fmt, "%s: %s, line %d: %s",
tag, tcpd_context.file, tcpd_context.line, format);
else
sprintf(fmt, "%s: %s", tag, format);
vsyslog(severity, fmt, ap);
}
/* tcpd_warn - report problem of some sort and proceed */
void VARARGS(tcpd_warn, char *, format)
{
va_list ap;
VASTART(ap, char *, format);
tcpd_diag(LOG_ERR, "warning", format, ap);
VAEND(ap);
}
/* tcpd_jump - report serious problem and jump */
void VARARGS(tcpd_jump, char *, format)
{
va_list ap;
VASTART(ap, char *, format);
tcpd_diag(LOG_ERR, "error", format, ap);
VAEND(ap);
longjmp(tcpd_buf, AC_ERROR);
}
/*
* Many systems have putenv() but no setenv(). Other systems have setenv()
* but no putenv() (MIPS). Still other systems have neither (NeXT). This is a
* re-implementation that hopefully ends all problems.
*
* Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
*/
#ifndef lint
static char sccsid[] = "@(#) environ.c 1.2 94/03/23 16:09:46";
#endif
/* System libraries. */
extern char **environ;
extern char *strchr();
extern char *strcpy();
extern char *strncpy();
extern char *malloc();
extern char *realloc();
extern int strncmp();
extern void free();
#ifdef no_memcpy
#define memcpy(d,s,l) bcopy(s,d,l)
#else
extern char *memcpy();
#endif
/* Local stuff. */
static int addenv(); /* append entry to environment */
static int allocated = 0; /* environ is, or is not, allocated */
#define DO_CLOBBER 1
/* namelength - determine length of name in "name=whatever" */
static int namelength(name)
char *name;
{
char *equal;
equal = strchr(name, '=');
return ((equal == 0) ? strlen(name) : (equal - name));
}
/* findenv - given name, locate name=value */
static char **findenv(name, len)
char *name;
int len;
{
char **envp;
for (envp = environ; envp && *envp; envp++)
if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=')
return (envp);
return (0);
}
/* getenv - given name, locate value */
char *getenv(name)
char *name;
{
int len = namelength(name);
char **envp = findenv(name, len);
return (envp ? *envp + len + 1 : 0);
}
/* putenv - update or append environment (name,value) pair */
int putenv(nameval)
char *nameval;
{
char *equal = strchr(nameval, '=');
char *value = (equal ? equal : "");
return (setenv(nameval, value, DO_CLOBBER));
}
/* unsetenv - remove variable from environment */
void unsetenv(name)
char *name;
{
char **envp;
if ((envp = findenv(name, namelength(name))) != 0)
while (envp[0] = envp[1])
envp++;
}
/* setenv - update or append environment (name,value) pair */
int setenv(name, value, clobber)
char *name;
char *value;
int clobber;
{
char *destination;
char **envp;
int l_name; /* length of name part */
int l_nameval; /* length of name=value */
/* Permit name= and =value. */
l_name = namelength(name);
envp = findenv(name, l_name);
if (envp != 0 && clobber == 0)
return (0);
if (*value == '=')
value++;
l_nameval = l_name + strlen(value) + 1;
/*
* Use available memory if the old value is long enough. Never free an
* old name=value entry because it may not be allocated.
*/
destination = (envp != 0 && strlen(*envp) >= l_nameval) ?
*envp : malloc(l_nameval + 1);
if (destination == 0)
return (-1);
strncpy(destination, name, l_name);
destination[l_name] = '=';
strcpy(destination + l_name + 1, value);
return ((envp == 0) ? addenv(destination) : (*envp = destination, 0));
}
/* cmalloc - malloc and copy block of memory */
static char *cmalloc(new_len, old, old_len)
char *old;
int old_len;
{
char *new = malloc(new_len);
if (new != 0)
memcpy(new, old, old_len);
return (new);
}
/* addenv - append environment entry */
static int addenv(nameval)
char *nameval;
{
char **envp;
int n_used; /* number of environment entries */
int l_used; /* bytes used excl. terminator */
int l_need; /* bytes needed incl. terminator */
for (envp = environ; envp && *envp; envp++)
/* void */ ;
n_used = envp - environ;
l_used = n_used * sizeof(*envp);
l_need = l_used + 2 * sizeof(*envp);
envp = allocated ?
(char **) realloc((char *) environ, l_need) :
(char **) cmalloc(l_need, (char *) environ, l_used);
if (envp == 0) {
return (-1);
} else {
allocated = 1;
environ = envp;
environ[n_used++] = nameval; /* add new entry */
environ[n_used] = 0; /* terminate list */
return (0);
}
}
#ifdef TEST
/*
* Stand-alone program for test purposes.
*/
/* printenv - display environment */
static void printenv()
{
char **envp;
for (envp = environ; envp && *envp; envp++)
printf("%s\n", *envp);
}
int main(argc, argv)
int argc;
char **argv;
{
char *cp;
int changed = 0;
if (argc < 2) {
printf("usage: %s name[=value]...\n", argv[0]);
return (1);
}
while (--argc && *++argv) {
if (argv[0][0] == '-') { /* unsetenv() test */
unsetenv(argv[0] + 1);
changed = 1;
} else if (strchr(argv[0], '=') == 0) { /* getenv() test */
cp = getenv(argv[0]);
printf("%s: %s\n", argv[0], cp ? cp : "not found");
} else { /* putenv() test */
if (putenv(argv[0])) {
perror("putenv");
return (1);
}
changed = 1;
}
}
if (changed)
printenv();
return (0);
}
#endif /* TEST */
/*
* Routines for controlled evaluation of host names, user names, and so on.
* They are, in fact, wrappers around the functions that are specific for
* the sockets or TLI programming interfaces. The request_info and host_info
* structures are used for result cacheing.
*
* These routines allows us to postpone expensive operations until their
* results are really needed. Examples are hostname lookups and double
* checks, or username lookups. Information that cannot be retrieved is
* given the value "unknown" ("paranoid" in case of hostname problems).
*
* When ALWAYS_HOSTNAME is off, hostname lookup is done only when required by
* tcpd paranoid mode, by access control patterns, or by %letter expansions.
*
* When ALWAYS_RFC931 mode is off, user lookup is done only when required by
* access control patterns or %letter expansions.
*
* Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
*/
#ifndef lint
static char sccsid[] = "@(#) eval.c 1.3 95/01/30 19:51:45";
#endif
/* System libraries. */
#include <stdio.h>
#include <string.h>
/* Local stuff. */
#include "tcpd.h"
/*
* When a string has the value STRING_UNKNOWN, it means: don't bother, I<