xref: /illumos-gate/usr/src/lib/libwrap/workarounds.c (revision 1da57d55)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright 2001 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate  /*
77c478bd9Sstevel@tonic-gate   * Workarounds for known system software bugs. This module provides wrappers
87c478bd9Sstevel@tonic-gate   * around library functions and system calls that are known to have problems
97c478bd9Sstevel@tonic-gate   * on some systems. Most of these workarounds won't do any harm on regular
107c478bd9Sstevel@tonic-gate   * systems.
11*1da57d55SToomas Soome   *
127c478bd9Sstevel@tonic-gate   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
137c478bd9Sstevel@tonic-gate   */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #ifndef lint
167c478bd9Sstevel@tonic-gate char    sccsid[] = "@(#) workarounds.c 1.6 96/03/19 16:22:25";
177c478bd9Sstevel@tonic-gate #endif
187c478bd9Sstevel@tonic-gate 
197c478bd9Sstevel@tonic-gate #include <sys/types.h>
207c478bd9Sstevel@tonic-gate #include <sys/param.h>
217c478bd9Sstevel@tonic-gate #include <sys/socket.h>
227c478bd9Sstevel@tonic-gate #include <netinet/in.h>
237c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
247c478bd9Sstevel@tonic-gate #include <netdb.h>
257c478bd9Sstevel@tonic-gate #include <errno.h>
267c478bd9Sstevel@tonic-gate #include <stdio.h>
277c478bd9Sstevel@tonic-gate #include <syslog.h>
287c478bd9Sstevel@tonic-gate #include <string.h>
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate extern int errno;
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include "tcpd.h"
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate  /*
357c478bd9Sstevel@tonic-gate   * Some AIX versions advertise a too small MAXHOSTNAMELEN value (32).
367c478bd9Sstevel@tonic-gate   * Result: long hostnames would be truncated, and connections would be
377c478bd9Sstevel@tonic-gate   * dropped because of host name verification failures. Adrian van Bloois
387c478bd9Sstevel@tonic-gate   * (A.vanBloois@info.nic.surfnet.nl) figured out what was the problem.
397c478bd9Sstevel@tonic-gate   */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #if (MAXHOSTNAMELEN < 64)
427c478bd9Sstevel@tonic-gate #undef MAXHOSTNAMELEN
437c478bd9Sstevel@tonic-gate #endif
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /* In case not defined in <sys/param.h>. */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #ifndef MAXHOSTNAMELEN
487c478bd9Sstevel@tonic-gate #define MAXHOSTNAMELEN  256             /* storage for host name */
497c478bd9Sstevel@tonic-gate #endif
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate  /*
527c478bd9Sstevel@tonic-gate   * Some DG/UX inet_addr() versions return a struct/union instead of a long.
537c478bd9Sstevel@tonic-gate   * You have this problem when the compiler complains about illegal lvalues
547c478bd9Sstevel@tonic-gate   * or something like that. The following code fixes this mutant behaviour.
557c478bd9Sstevel@tonic-gate   * It should not be enabled on "normal" systems.
56*1da57d55SToomas Soome   *
577c478bd9Sstevel@tonic-gate   * Bug reported by ben@piglet.cr.usgs.gov (Rev. Ben A. Mesander).
587c478bd9Sstevel@tonic-gate   */
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #ifdef INET_ADDR_BUG
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #undef inet_addr
637c478bd9Sstevel@tonic-gate 
fix_inet_addr(string)647c478bd9Sstevel@tonic-gate long    fix_inet_addr(string)
657c478bd9Sstevel@tonic-gate char   *string;
667c478bd9Sstevel@tonic-gate {
677c478bd9Sstevel@tonic-gate     return (inet_addr(string).s_addr);
687c478bd9Sstevel@tonic-gate }
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #endif /* INET_ADDR_BUG */
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate  /*
737c478bd9Sstevel@tonic-gate   * With some System-V versions, the fgets() library function does not
747c478bd9Sstevel@tonic-gate   * account for partial reads from e.g. sockets. The result is that fgets()
757c478bd9Sstevel@tonic-gate   * gives up too soon, causing username lookups to fail. Problem first
767c478bd9Sstevel@tonic-gate   * reported for IRIX 4.0.5, by Steve Kotsopoulos <steve@ecf.toronto.edu>.
777c478bd9Sstevel@tonic-gate   * The following code works around the problem. It does no harm on "normal"
787c478bd9Sstevel@tonic-gate   * systems.
797c478bd9Sstevel@tonic-gate   */
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate #ifdef BROKEN_FGETS
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate #undef fgets
847c478bd9Sstevel@tonic-gate 
fix_fgets(buf,len,fp)857c478bd9Sstevel@tonic-gate char   *fix_fgets(buf, len, fp)
867c478bd9Sstevel@tonic-gate char   *buf;
877c478bd9Sstevel@tonic-gate int     len;
887c478bd9Sstevel@tonic-gate FILE   *fp;
897c478bd9Sstevel@tonic-gate {
907c478bd9Sstevel@tonic-gate     char   *cp = buf;
917c478bd9Sstevel@tonic-gate     int     c;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate     /*
947c478bd9Sstevel@tonic-gate      * Copy until the buffer fills up, until EOF, or until a newline is
957c478bd9Sstevel@tonic-gate      * found.
967c478bd9Sstevel@tonic-gate      */
977c478bd9Sstevel@tonic-gate     while (len > 1 && (c = getc(fp)) != EOF) {
987c478bd9Sstevel@tonic-gate 	len--;
997c478bd9Sstevel@tonic-gate 	*cp++ = c;
1007c478bd9Sstevel@tonic-gate 	if (c == '\n')
1017c478bd9Sstevel@tonic-gate 	    break;
1027c478bd9Sstevel@tonic-gate     }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate     /*
1057c478bd9Sstevel@tonic-gate      * Return 0 if nothing was read. This is correct even when a silly buffer
1067c478bd9Sstevel@tonic-gate      * length was specified.
1077c478bd9Sstevel@tonic-gate      */
1087c478bd9Sstevel@tonic-gate     if (cp > buf) {
1097c478bd9Sstevel@tonic-gate 	*cp = 0;
1107c478bd9Sstevel@tonic-gate 	return (buf);
1117c478bd9Sstevel@tonic-gate     } else {
1127c478bd9Sstevel@tonic-gate 	return (0);
1137c478bd9Sstevel@tonic-gate     }
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate #endif /* BROKEN_FGETS */
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate  /*
1197c478bd9Sstevel@tonic-gate   * With early SunOS 5 versions, recvfrom() does not completely fill in the
1207c478bd9Sstevel@tonic-gate   * source address structure when doing a non-destructive read. The following
1217c478bd9Sstevel@tonic-gate   * code works around the problem. It does no harm on "normal" systems.
1227c478bd9Sstevel@tonic-gate   */
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate #ifdef RECVFROM_BUG
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate #undef recvfrom
1277c478bd9Sstevel@tonic-gate 
fix_recvfrom(sock,buf,buflen,flags,from,fromlen)1287c478bd9Sstevel@tonic-gate int     fix_recvfrom(sock, buf, buflen, flags, from, fromlen)
1297c478bd9Sstevel@tonic-gate int     sock;
1307c478bd9Sstevel@tonic-gate char   *buf;
1317c478bd9Sstevel@tonic-gate int     buflen;
1327c478bd9Sstevel@tonic-gate int     flags;
1337c478bd9Sstevel@tonic-gate struct sockaddr *from;
1347c478bd9Sstevel@tonic-gate int    *fromlen;
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate     int     ret;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate     /* Assume that both ends of a socket belong to the same address family. */
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate     if ((ret = recvfrom(sock, buf, buflen, flags, from, fromlen)) >= 0) {
1417c478bd9Sstevel@tonic-gate 	if (from->sa_family == 0) {
1427c478bd9Sstevel@tonic-gate 	    struct sockaddr my_addr;
1437c478bd9Sstevel@tonic-gate 	    int     my_addr_len = sizeof(my_addr);
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	    if (getsockname(0, &my_addr, &my_addr_len)) {
1467c478bd9Sstevel@tonic-gate 		tcpd_warn("getsockname: %m");
1477c478bd9Sstevel@tonic-gate 	    } else {
1487c478bd9Sstevel@tonic-gate 		from->sa_family = my_addr.sa_family;
1497c478bd9Sstevel@tonic-gate 	    }
1507c478bd9Sstevel@tonic-gate 	}
1517c478bd9Sstevel@tonic-gate     }
1527c478bd9Sstevel@tonic-gate     return (ret);
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate #endif /* RECVFROM_BUG */
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate  /*
1587c478bd9Sstevel@tonic-gate   * The Apollo SR10.3 and some SYSV4 getpeername(2) versions do not return an
1597c478bd9Sstevel@tonic-gate   * error in case of a datagram-oriented socket. Instead, they claim that all
1607c478bd9Sstevel@tonic-gate   * UDP requests come from address 0.0.0.0. The following code works around
1617c478bd9Sstevel@tonic-gate   * the problem. It does no harm on "normal" systems.
1627c478bd9Sstevel@tonic-gate   */
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate #ifdef GETPEERNAME_BUG
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate #undef getpeername
1677c478bd9Sstevel@tonic-gate 
fix_getpeername(sock,sa,len)1687c478bd9Sstevel@tonic-gate int     fix_getpeername(sock, sa, len)
1697c478bd9Sstevel@tonic-gate int     sock;
1707c478bd9Sstevel@tonic-gate struct sockaddr *sa;
1717c478bd9Sstevel@tonic-gate int    *len;
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate     int     ret;
1747c478bd9Sstevel@tonic-gate     struct sockaddr_in *sin = (struct sockaddr_in *) sa;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate     if ((ret = getpeername(sock, sa, len)) >= 0
1777c478bd9Sstevel@tonic-gate 	&& sa->sa_family == AF_INET
1787c478bd9Sstevel@tonic-gate 	&& sin->sin_addr.s_addr == 0) {
1797c478bd9Sstevel@tonic-gate 	errno = ENOTCONN;
1807c478bd9Sstevel@tonic-gate 	return (-1);
1817c478bd9Sstevel@tonic-gate     } else {
1827c478bd9Sstevel@tonic-gate 	return (ret);
1837c478bd9Sstevel@tonic-gate     }
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate #endif /* GETPEERNAME_BUG */
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate  /*
1897c478bd9Sstevel@tonic-gate   * According to Karl Vogel (vogelke@c-17igp.wpafb.af.mil) some Pyramid
1907c478bd9Sstevel@tonic-gate   * versions have no yp_default_domain() function. We use getdomainname()
1917c478bd9Sstevel@tonic-gate   * instead.
1927c478bd9Sstevel@tonic-gate   */
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate #ifdef USE_GETDOMAIN
1957c478bd9Sstevel@tonic-gate 
yp_get_default_domain(ptr)1967c478bd9Sstevel@tonic-gate int     yp_get_default_domain(ptr)
1977c478bd9Sstevel@tonic-gate char  **ptr;
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate     static char mydomain[MAXHOSTNAMELEN];
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate     *ptr = mydomain;
2027c478bd9Sstevel@tonic-gate     return (getdomainname(mydomain, MAXHOSTNAMELEN));
2037c478bd9Sstevel@tonic-gate }
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate #endif /* USE_GETDOMAIN */
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate #ifndef INADDR_NONE
2087c478bd9Sstevel@tonic-gate #define INADDR_NONE 0xffffffff
2097c478bd9Sstevel@tonic-gate #endif
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate  /*
2127c478bd9Sstevel@tonic-gate   * Solaris 2.4 gethostbyname() has problems with multihomed hosts. When
2137c478bd9Sstevel@tonic-gate   * doing DNS through NIS, only one host address ends up in the address list.
2147c478bd9Sstevel@tonic-gate   * All other addresses end up in the hostname alias list, interspersed with
2157c478bd9Sstevel@tonic-gate   * copies of the official host name. This would wreak havoc with tcpd's
2167c478bd9Sstevel@tonic-gate   * hostname double checks. Below is a workaround that should do no harm when
2177c478bd9Sstevel@tonic-gate   * accidentally left in. A side effect of the workaround is that address
2187c478bd9Sstevel@tonic-gate   * list members are no longer properly aligned for structure access.
2197c478bd9Sstevel@tonic-gate   */
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate #ifdef SOLARIS_24_GETHOSTBYNAME_BUG
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate #undef gethostbyname
2247c478bd9Sstevel@tonic-gate 
fix_gethostbyname(name)2257c478bd9Sstevel@tonic-gate struct hostent *fix_gethostbyname(name)
2267c478bd9Sstevel@tonic-gate char   *name;
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate     struct hostent *hp;
2297c478bd9Sstevel@tonic-gate     struct in_addr addr;
2307c478bd9Sstevel@tonic-gate     char  **o_addr_list;
2317c478bd9Sstevel@tonic-gate     char  **o_aliases;
2327c478bd9Sstevel@tonic-gate     char  **n_addr_list;
2337c478bd9Sstevel@tonic-gate     int     broken_gethostbyname = 0;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate     if ((hp = gethostbyname(name)) && !hp->h_addr_list[1] && hp->h_aliases[1]) {
2367c478bd9Sstevel@tonic-gate 	for (o_aliases = n_addr_list = hp->h_aliases; *o_aliases; o_aliases++) {
2377c478bd9Sstevel@tonic-gate 	    if ((addr.s_addr = inet_addr(*o_aliases)) != INADDR_NONE) {
2387c478bd9Sstevel@tonic-gate 		memcpy(*n_addr_list++, (char *) &addr, hp->h_length);
2397c478bd9Sstevel@tonic-gate 		broken_gethostbyname = 1;
2407c478bd9Sstevel@tonic-gate 	    }
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 	if (broken_gethostbyname) {
2437c478bd9Sstevel@tonic-gate 	    o_addr_list = hp->h_addr_list;
2447c478bd9Sstevel@tonic-gate 	    memcpy(*n_addr_list++, *o_addr_list, hp->h_length);
2457c478bd9Sstevel@tonic-gate 	    *n_addr_list = 0;
2467c478bd9Sstevel@tonic-gate 	    hp->h_addr_list = hp->h_aliases;
2477c478bd9Sstevel@tonic-gate 	    hp->h_aliases = o_addr_list + 1;
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate     }
2507c478bd9Sstevel@tonic-gate     return (hp);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate #endif /* SOLARIS_24_GETHOSTBYNAME_BUG */
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate  /*
2567c478bd9Sstevel@tonic-gate   * Horror! Some FreeBSD 2.0 libc routines call strtok(). Since tcpd depends
2577c478bd9Sstevel@tonic-gate   * heavily on strtok(), strange things may happen. Workaround: use our
2587c478bd9Sstevel@tonic-gate   * private strtok(). This has been fixed in the meantime.
2597c478bd9Sstevel@tonic-gate   */
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate #ifdef USE_STRSEP
2627c478bd9Sstevel@tonic-gate 
fix_strtok(buf,sep)2637c478bd9Sstevel@tonic-gate char   *fix_strtok(buf, sep)
2647c478bd9Sstevel@tonic-gate char   *buf;
2657c478bd9Sstevel@tonic-gate char   *sep;
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate     static char *state;
2687c478bd9Sstevel@tonic-gate     char   *result;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate     if (buf)
2717c478bd9Sstevel@tonic-gate 	state = buf;
2727c478bd9Sstevel@tonic-gate     while ((result = strsep(&state, sep)) && result[0] == 0)
2737c478bd9Sstevel@tonic-gate 	 /* void */ ;
2747c478bd9Sstevel@tonic-gate     return (result);
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate #endif /* USE_STRSEP */
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate  /*
2807c478bd9Sstevel@tonic-gate   * IRIX 5.3 (and possibly earlier versions, too) library routines call the
2817c478bd9Sstevel@tonic-gate   * non-reentrant strtok() library routine, causing hosts to slip through
2827c478bd9Sstevel@tonic-gate   * allow/deny filters. Workaround: don't rely on the vendor and use our own
2837c478bd9Sstevel@tonic-gate   * strtok() function. FreeBSD 2.0 has a similar problem (fixed in 2.0.5).
2847c478bd9Sstevel@tonic-gate   */
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate #ifdef LIBC_CALLS_STRTOK
2877c478bd9Sstevel@tonic-gate 
my_strtok(buf,sep)2887c478bd9Sstevel@tonic-gate char   *my_strtok(buf, sep)
2897c478bd9Sstevel@tonic-gate char   *buf;
2907c478bd9Sstevel@tonic-gate char   *sep;
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate     static char *state;
2937c478bd9Sstevel@tonic-gate     char   *result;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate     if (buf)
2967c478bd9Sstevel@tonic-gate 	state = buf;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate     /*
2997c478bd9Sstevel@tonic-gate      * Skip over separator characters and detect end of string.
3007c478bd9Sstevel@tonic-gate      */
3017c478bd9Sstevel@tonic-gate     if (*(state += strspn(state, sep)) == 0)
3027c478bd9Sstevel@tonic-gate 	return (0);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate     /*
3057c478bd9Sstevel@tonic-gate      * Skip over non-separator characters and terminate result.
3067c478bd9Sstevel@tonic-gate      */
3077c478bd9Sstevel@tonic-gate     result = state;
3087c478bd9Sstevel@tonic-gate     if (*(state += strcspn(state, sep)) != 0)
3097c478bd9Sstevel@tonic-gate 	*state++ = 0;
3107c478bd9Sstevel@tonic-gate     return (result);
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate #endif /* LIBC_CALLS_STRTOK */
314