diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 1997-04-08 00:29:19 +0000 |
---|---|---|
committer | <> | 2013-02-25 15:20:59 +0000 |
commit | f8d9d05cfb1ea783457a14d3cf7fdf4d8fa450f2 (patch) | |
tree | 058251f5aa8af2365812daa56d936e91720a6027 /workarounds.c | |
download | tcp-wrappers-master.tar.gz |
Imported from /home/lorry/working-area/delta_tcp-wrappers/tcp_wrappers_7.6.tar.gz.HEADtcp_wrappers_7.6master
Diffstat (limited to 'workarounds.c')
-rw-r--r-- | workarounds.c | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/workarounds.c b/workarounds.c new file mode 100644 index 0000000..9ffa247 --- /dev/null +++ b/workarounds.c @@ -0,0 +1,308 @@ + /* + * Workarounds for known system software bugs. This module provides wrappers + * around library functions and system calls that are known to have problems + * on some systems. Most of these workarounds won't do any harm on regular + * systems. + * + * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. + */ + +#ifndef lint +char sccsid[] = "@(#) workarounds.c 1.6 96/03/19 16:22:25"; +#endif + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <errno.h> +#include <stdio.h> +#include <syslog.h> +#include <string.h> + +extern int errno; + +#include "tcpd.h" + + /* + * Some AIX versions advertise a too small MAXHOSTNAMELEN value (32). + * Result: long hostnames would be truncated, and connections would be + * dropped because of host name verification failures. Adrian van Bloois + * (A.vanBloois@info.nic.surfnet.nl) figured out what was the problem. + */ + +#if (MAXHOSTNAMELEN < 64) +#undef MAXHOSTNAMELEN +#endif + +/* In case not defined in <sys/param.h>. */ + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 /* storage for host name */ +#endif + + /* + * Some DG/UX inet_addr() versions return a struct/union instead of a long. + * You have this problem when the compiler complains about illegal lvalues + * or something like that. The following code fixes this mutant behaviour. + * It should not be enabled on "normal" systems. + * + * Bug reported by ben@piglet.cr.usgs.gov (Rev. Ben A. Mesander). + */ + +#ifdef INET_ADDR_BUG + +#undef inet_addr + +long fix_inet_addr(string) +char *string; +{ + return (inet_addr(string).s_addr); +} + +#endif /* INET_ADDR_BUG */ + + /* + * With some System-V versions, the fgets() library function does not + * account for partial reads from e.g. sockets. The result is that fgets() + * gives up too soon, causing username lookups to fail. Problem first + * reported for IRIX 4.0.5, by Steve Kotsopoulos <steve@ecf.toronto.edu>. + * The following code works around the problem. It does no harm on "normal" + * systems. + */ + +#ifdef BROKEN_FGETS + +#undef fgets + +char *fix_fgets(buf, len, fp) +char *buf; +int len; +FILE *fp; +{ + char *cp = buf; + int c; + + /* + * Copy until the buffer fills up, until EOF, or until a newline is + * found. + */ + while (len > 1 && (c = getc(fp)) != EOF) { + len--; + *cp++ = c; + if (c == '\n') + break; + } + + /* + * Return 0 if nothing was read. This is correct even when a silly buffer + * length was specified. + */ + if (cp > buf) { + *cp = 0; + return (buf); + } else { + return (0); + } +} + +#endif /* BROKEN_FGETS */ + + /* + * With early SunOS 5 versions, recvfrom() does not completely fill in the + * source address structure when doing a non-destructive read. The following + * code works around the problem. It does no harm on "normal" systems. + */ + +#ifdef RECVFROM_BUG + +#undef recvfrom + +int fix_recvfrom(sock, buf, buflen, flags, from, fromlen) +int sock; +char *buf; +int buflen; +int flags; +struct sockaddr *from; +int *fromlen; +{ + int ret; + + /* Assume that both ends of a socket belong to the same address family. */ + + if ((ret = recvfrom(sock, buf, buflen, flags, from, fromlen)) >= 0) { + if (from->sa_family == 0) { + struct sockaddr my_addr; + int my_addr_len = sizeof(my_addr); + + if (getsockname(0, &my_addr, &my_addr_len)) { + tcpd_warn("getsockname: %m"); + } else { + from->sa_family = my_addr.sa_family; + } + } + } + return (ret); +} + +#endif /* RECVFROM_BUG */ + + /* + * The Apollo SR10.3 and some SYSV4 getpeername(2) versions do not return an + * error in case of a datagram-oriented socket. Instead, they claim that all + * UDP requests come from address 0.0.0.0. The following code works around + * the problem. It does no harm on "normal" systems. + */ + +#ifdef GETPEERNAME_BUG + +#undef getpeername + +int fix_getpeername(sock, sa, len) +int sock; +struct sockaddr *sa; +int *len; +{ + int ret; + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + + if ((ret = getpeername(sock, sa, len)) >= 0 + && sa->sa_family == AF_INET + && sin->sin_addr.s_addr == 0) { + errno = ENOTCONN; + return (-1); + } else { + return (ret); + } +} + +#endif /* GETPEERNAME_BUG */ + + /* + * According to Karl Vogel (vogelke@c-17igp.wpafb.af.mil) some Pyramid + * versions have no yp_default_domain() function. We use getdomainname() + * instead. + */ + +#ifdef USE_GETDOMAIN + +int yp_get_default_domain(ptr) +char **ptr; +{ + static char mydomain[MAXHOSTNAMELEN]; + + *ptr = mydomain; + return (getdomainname(mydomain, MAXHOSTNAMELEN)); +} + +#endif /* USE_GETDOMAIN */ + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + + /* + * Solaris 2.4 gethostbyname() has problems with multihomed hosts. When + * doing DNS through NIS, only one host address ends up in the address list. + * All other addresses end up in the hostname alias list, interspersed with + * copies of the official host name. This would wreak havoc with tcpd's + * hostname double checks. Below is a workaround that should do no harm when + * accidentally left in. A side effect of the workaround is that address + * list members are no longer properly aligned for structure access. + */ + +#ifdef SOLARIS_24_GETHOSTBYNAME_BUG + +#undef gethostbyname + +struct hostent *fix_gethostbyname(name) +char *name; +{ + struct hostent *hp; + struct in_addr addr; + char **o_addr_list; + char **o_aliases; + char **n_addr_list; + int broken_gethostbyname = 0; + + if ((hp = gethostbyname(name)) && !hp->h_addr_list[1] && hp->h_aliases[1]) { + for (o_aliases = n_addr_list = hp->h_aliases; *o_aliases; o_aliases++) { + if ((addr.s_addr = inet_addr(*o_aliases)) != INADDR_NONE) { + memcpy(*n_addr_list++, (char *) &addr, hp->h_length); + broken_gethostbyname = 1; + } + } + if (broken_gethostbyname) { + o_addr_list = hp->h_addr_list; + memcpy(*n_addr_list++, *o_addr_list, hp->h_length); + *n_addr_list = 0; + hp->h_addr_list = hp->h_aliases; + hp->h_aliases = o_addr_list + 1; + } + } + return (hp); +} + +#endif /* SOLARIS_24_GETHOSTBYNAME_BUG */ + + /* + * Horror! Some FreeBSD 2.0 libc routines call strtok(). Since tcpd depends + * heavily on strtok(), strange things may happen. Workaround: use our + * private strtok(). This has been fixed in the meantime. + */ + +#ifdef USE_STRSEP + +char *fix_strtok(buf, sep) +char *buf; +char *sep; +{ + static char *state; + char *result; + + if (buf) + state = buf; + while ((result = strsep(&state, sep)) && result[0] == 0) + /* void */ ; + return (result); +} + +#endif /* USE_STRSEP */ + + /* + * IRIX 5.3 (and possibly earlier versions, too) library routines call the + * non-reentrant strtok() library routine, causing hosts to slip through + * allow/deny filters. Workaround: don't rely on the vendor and use our own + * strtok() function. FreeBSD 2.0 has a similar problem (fixed in 2.0.5). + */ + +#ifdef LIBC_CALLS_STRTOK + +char *my_strtok(buf, sep) +char *buf; +char *sep; +{ + static char *state; + char *result; + + if (buf) + state = buf; + + /* + * Skip over separator characters and detect end of string. + */ + if (*(state += strspn(state, sep)) == 0) + return (0); + + /* + * Skip over non-separator characters and terminate result. + */ + result = state; + if (*(state += strcspn(state, sep)) != 0) + *state++ = 0; + return (result); +} + +#endif /* LIBC_CALLS_STRTOK */ |