xref: /illumos-gate/usr/src/lib/libwrap/workarounds.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2001 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate  /*
7*7c478bd9Sstevel@tonic-gate   * Workarounds for known system software bugs. This module provides wrappers
8*7c478bd9Sstevel@tonic-gate   * around library functions and system calls that are known to have problems
9*7c478bd9Sstevel@tonic-gate   * on some systems. Most of these workarounds won't do any harm on regular
10*7c478bd9Sstevel@tonic-gate   * systems.
11*7c478bd9Sstevel@tonic-gate   *
12*7c478bd9Sstevel@tonic-gate   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
13*7c478bd9Sstevel@tonic-gate   */
14*7c478bd9Sstevel@tonic-gate 
15*7c478bd9Sstevel@tonic-gate #ifndef lint
16*7c478bd9Sstevel@tonic-gate char    sccsid[] = "@(#) workarounds.c 1.6 96/03/19 16:22:25";
17*7c478bd9Sstevel@tonic-gate #endif
18*7c478bd9Sstevel@tonic-gate 
19*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
20*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
21*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
22*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
23*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
24*7c478bd9Sstevel@tonic-gate #include <netdb.h>
25*7c478bd9Sstevel@tonic-gate #include <errno.h>
26*7c478bd9Sstevel@tonic-gate #include <stdio.h>
27*7c478bd9Sstevel@tonic-gate #include <syslog.h>
28*7c478bd9Sstevel@tonic-gate #include <string.h>
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate extern int errno;
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #include "tcpd.h"
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate  /*
35*7c478bd9Sstevel@tonic-gate   * Some AIX versions advertise a too small MAXHOSTNAMELEN value (32).
36*7c478bd9Sstevel@tonic-gate   * Result: long hostnames would be truncated, and connections would be
37*7c478bd9Sstevel@tonic-gate   * dropped because of host name verification failures. Adrian van Bloois
38*7c478bd9Sstevel@tonic-gate   * (A.vanBloois@info.nic.surfnet.nl) figured out what was the problem.
39*7c478bd9Sstevel@tonic-gate   */
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #if (MAXHOSTNAMELEN < 64)
42*7c478bd9Sstevel@tonic-gate #undef MAXHOSTNAMELEN
43*7c478bd9Sstevel@tonic-gate #endif
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate /* In case not defined in <sys/param.h>. */
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #ifndef MAXHOSTNAMELEN
48*7c478bd9Sstevel@tonic-gate #define MAXHOSTNAMELEN  256             /* storage for host name */
49*7c478bd9Sstevel@tonic-gate #endif
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate  /*
52*7c478bd9Sstevel@tonic-gate   * Some DG/UX inet_addr() versions return a struct/union instead of a long.
53*7c478bd9Sstevel@tonic-gate   * You have this problem when the compiler complains about illegal lvalues
54*7c478bd9Sstevel@tonic-gate   * or something like that. The following code fixes this mutant behaviour.
55*7c478bd9Sstevel@tonic-gate   * It should not be enabled on "normal" systems.
56*7c478bd9Sstevel@tonic-gate   *
57*7c478bd9Sstevel@tonic-gate   * Bug reported by ben@piglet.cr.usgs.gov (Rev. Ben A. Mesander).
58*7c478bd9Sstevel@tonic-gate   */
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate #ifdef INET_ADDR_BUG
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate #undef inet_addr
63*7c478bd9Sstevel@tonic-gate 
fix_inet_addr(string)64*7c478bd9Sstevel@tonic-gate long    fix_inet_addr(string)
65*7c478bd9Sstevel@tonic-gate char   *string;
66*7c478bd9Sstevel@tonic-gate {
67*7c478bd9Sstevel@tonic-gate     return (inet_addr(string).s_addr);
68*7c478bd9Sstevel@tonic-gate }
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate #endif /* INET_ADDR_BUG */
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate  /*
73*7c478bd9Sstevel@tonic-gate   * With some System-V versions, the fgets() library function does not
74*7c478bd9Sstevel@tonic-gate   * account for partial reads from e.g. sockets. The result is that fgets()
75*7c478bd9Sstevel@tonic-gate   * gives up too soon, causing username lookups to fail. Problem first
76*7c478bd9Sstevel@tonic-gate   * reported for IRIX 4.0.5, by Steve Kotsopoulos <steve@ecf.toronto.edu>.
77*7c478bd9Sstevel@tonic-gate   * The following code works around the problem. It does no harm on "normal"
78*7c478bd9Sstevel@tonic-gate   * systems.
79*7c478bd9Sstevel@tonic-gate   */
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate #ifdef BROKEN_FGETS
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate #undef fgets
84*7c478bd9Sstevel@tonic-gate 
fix_fgets(buf,len,fp)85*7c478bd9Sstevel@tonic-gate char   *fix_fgets(buf, len, fp)
86*7c478bd9Sstevel@tonic-gate char   *buf;
87*7c478bd9Sstevel@tonic-gate int     len;
88*7c478bd9Sstevel@tonic-gate FILE   *fp;
89*7c478bd9Sstevel@tonic-gate {
90*7c478bd9Sstevel@tonic-gate     char   *cp = buf;
91*7c478bd9Sstevel@tonic-gate     int     c;
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate     /*
94*7c478bd9Sstevel@tonic-gate      * Copy until the buffer fills up, until EOF, or until a newline is
95*7c478bd9Sstevel@tonic-gate      * found.
96*7c478bd9Sstevel@tonic-gate      */
97*7c478bd9Sstevel@tonic-gate     while (len > 1 && (c = getc(fp)) != EOF) {
98*7c478bd9Sstevel@tonic-gate 	len--;
99*7c478bd9Sstevel@tonic-gate 	*cp++ = c;
100*7c478bd9Sstevel@tonic-gate 	if (c == '\n')
101*7c478bd9Sstevel@tonic-gate 	    break;
102*7c478bd9Sstevel@tonic-gate     }
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate     /*
105*7c478bd9Sstevel@tonic-gate      * Return 0 if nothing was read. This is correct even when a silly buffer
106*7c478bd9Sstevel@tonic-gate      * length was specified.
107*7c478bd9Sstevel@tonic-gate      */
108*7c478bd9Sstevel@tonic-gate     if (cp > buf) {
109*7c478bd9Sstevel@tonic-gate 	*cp = 0;
110*7c478bd9Sstevel@tonic-gate 	return (buf);
111*7c478bd9Sstevel@tonic-gate     } else {
112*7c478bd9Sstevel@tonic-gate 	return (0);
113*7c478bd9Sstevel@tonic-gate     }
114*7c478bd9Sstevel@tonic-gate }
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate #endif /* BROKEN_FGETS */
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate  /*
119*7c478bd9Sstevel@tonic-gate   * With early SunOS 5 versions, recvfrom() does not completely fill in the
120*7c478bd9Sstevel@tonic-gate   * source address structure when doing a non-destructive read. The following
121*7c478bd9Sstevel@tonic-gate   * code works around the problem. It does no harm on "normal" systems.
122*7c478bd9Sstevel@tonic-gate   */
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate #ifdef RECVFROM_BUG
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate #undef recvfrom
127*7c478bd9Sstevel@tonic-gate 
fix_recvfrom(sock,buf,buflen,flags,from,fromlen)128*7c478bd9Sstevel@tonic-gate int     fix_recvfrom(sock, buf, buflen, flags, from, fromlen)
129*7c478bd9Sstevel@tonic-gate int     sock;
130*7c478bd9Sstevel@tonic-gate char   *buf;
131*7c478bd9Sstevel@tonic-gate int     buflen;
132*7c478bd9Sstevel@tonic-gate int     flags;
133*7c478bd9Sstevel@tonic-gate struct sockaddr *from;
134*7c478bd9Sstevel@tonic-gate int    *fromlen;
135*7c478bd9Sstevel@tonic-gate {
136*7c478bd9Sstevel@tonic-gate     int     ret;
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate     /* Assume that both ends of a socket belong to the same address family. */
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate     if ((ret = recvfrom(sock, buf, buflen, flags, from, fromlen)) >= 0) {
141*7c478bd9Sstevel@tonic-gate 	if (from->sa_family == 0) {
142*7c478bd9Sstevel@tonic-gate 	    struct sockaddr my_addr;
143*7c478bd9Sstevel@tonic-gate 	    int     my_addr_len = sizeof(my_addr);
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	    if (getsockname(0, &my_addr, &my_addr_len)) {
146*7c478bd9Sstevel@tonic-gate 		tcpd_warn("getsockname: %m");
147*7c478bd9Sstevel@tonic-gate 	    } else {
148*7c478bd9Sstevel@tonic-gate 		from->sa_family = my_addr.sa_family;
149*7c478bd9Sstevel@tonic-gate 	    }
150*7c478bd9Sstevel@tonic-gate 	}
151*7c478bd9Sstevel@tonic-gate     }
152*7c478bd9Sstevel@tonic-gate     return (ret);
153*7c478bd9Sstevel@tonic-gate }
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate #endif /* RECVFROM_BUG */
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate  /*
158*7c478bd9Sstevel@tonic-gate   * The Apollo SR10.3 and some SYSV4 getpeername(2) versions do not return an
159*7c478bd9Sstevel@tonic-gate   * error in case of a datagram-oriented socket. Instead, they claim that all
160*7c478bd9Sstevel@tonic-gate   * UDP requests come from address 0.0.0.0. The following code works around
161*7c478bd9Sstevel@tonic-gate   * the problem. It does no harm on "normal" systems.
162*7c478bd9Sstevel@tonic-gate   */
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate #ifdef GETPEERNAME_BUG
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate #undef getpeername
167*7c478bd9Sstevel@tonic-gate 
fix_getpeername(sock,sa,len)168*7c478bd9Sstevel@tonic-gate int     fix_getpeername(sock, sa, len)
169*7c478bd9Sstevel@tonic-gate int     sock;
170*7c478bd9Sstevel@tonic-gate struct sockaddr *sa;
171*7c478bd9Sstevel@tonic-gate int    *len;
172*7c478bd9Sstevel@tonic-gate {
173*7c478bd9Sstevel@tonic-gate     int     ret;
174*7c478bd9Sstevel@tonic-gate     struct sockaddr_in *sin = (struct sockaddr_in *) sa;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate     if ((ret = getpeername(sock, sa, len)) >= 0
177*7c478bd9Sstevel@tonic-gate 	&& sa->sa_family == AF_INET
178*7c478bd9Sstevel@tonic-gate 	&& sin->sin_addr.s_addr == 0) {
179*7c478bd9Sstevel@tonic-gate 	errno = ENOTCONN;
180*7c478bd9Sstevel@tonic-gate 	return (-1);
181*7c478bd9Sstevel@tonic-gate     } else {
182*7c478bd9Sstevel@tonic-gate 	return (ret);
183*7c478bd9Sstevel@tonic-gate     }
184*7c478bd9Sstevel@tonic-gate }
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate #endif /* GETPEERNAME_BUG */
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate  /*
189*7c478bd9Sstevel@tonic-gate   * According to Karl Vogel (vogelke@c-17igp.wpafb.af.mil) some Pyramid
190*7c478bd9Sstevel@tonic-gate   * versions have no yp_default_domain() function. We use getdomainname()
191*7c478bd9Sstevel@tonic-gate   * instead.
192*7c478bd9Sstevel@tonic-gate   */
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate #ifdef USE_GETDOMAIN
195*7c478bd9Sstevel@tonic-gate 
yp_get_default_domain(ptr)196*7c478bd9Sstevel@tonic-gate int     yp_get_default_domain(ptr)
197*7c478bd9Sstevel@tonic-gate char  **ptr;
198*7c478bd9Sstevel@tonic-gate {
199*7c478bd9Sstevel@tonic-gate     static char mydomain[MAXHOSTNAMELEN];
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate     *ptr = mydomain;
202*7c478bd9Sstevel@tonic-gate     return (getdomainname(mydomain, MAXHOSTNAMELEN));
203*7c478bd9Sstevel@tonic-gate }
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate #endif /* USE_GETDOMAIN */
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate #ifndef INADDR_NONE
208*7c478bd9Sstevel@tonic-gate #define INADDR_NONE 0xffffffff
209*7c478bd9Sstevel@tonic-gate #endif
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate  /*
212*7c478bd9Sstevel@tonic-gate   * Solaris 2.4 gethostbyname() has problems with multihomed hosts. When
213*7c478bd9Sstevel@tonic-gate   * doing DNS through NIS, only one host address ends up in the address list.
214*7c478bd9Sstevel@tonic-gate   * All other addresses end up in the hostname alias list, interspersed with
215*7c478bd9Sstevel@tonic-gate   * copies of the official host name. This would wreak havoc with tcpd's
216*7c478bd9Sstevel@tonic-gate   * hostname double checks. Below is a workaround that should do no harm when
217*7c478bd9Sstevel@tonic-gate   * accidentally left in. A side effect of the workaround is that address
218*7c478bd9Sstevel@tonic-gate   * list members are no longer properly aligned for structure access.
219*7c478bd9Sstevel@tonic-gate   */
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate #ifdef SOLARIS_24_GETHOSTBYNAME_BUG
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate #undef gethostbyname
224*7c478bd9Sstevel@tonic-gate 
fix_gethostbyname(name)225*7c478bd9Sstevel@tonic-gate struct hostent *fix_gethostbyname(name)
226*7c478bd9Sstevel@tonic-gate char   *name;
227*7c478bd9Sstevel@tonic-gate {
228*7c478bd9Sstevel@tonic-gate     struct hostent *hp;
229*7c478bd9Sstevel@tonic-gate     struct in_addr addr;
230*7c478bd9Sstevel@tonic-gate     char  **o_addr_list;
231*7c478bd9Sstevel@tonic-gate     char  **o_aliases;
232*7c478bd9Sstevel@tonic-gate     char  **n_addr_list;
233*7c478bd9Sstevel@tonic-gate     int     broken_gethostbyname = 0;
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate     if ((hp = gethostbyname(name)) && !hp->h_addr_list[1] && hp->h_aliases[1]) {
236*7c478bd9Sstevel@tonic-gate 	for (o_aliases = n_addr_list = hp->h_aliases; *o_aliases; o_aliases++) {
237*7c478bd9Sstevel@tonic-gate 	    if ((addr.s_addr = inet_addr(*o_aliases)) != INADDR_NONE) {
238*7c478bd9Sstevel@tonic-gate 		memcpy(*n_addr_list++, (char *) &addr, hp->h_length);
239*7c478bd9Sstevel@tonic-gate 		broken_gethostbyname = 1;
240*7c478bd9Sstevel@tonic-gate 	    }
241*7c478bd9Sstevel@tonic-gate 	}
242*7c478bd9Sstevel@tonic-gate 	if (broken_gethostbyname) {
243*7c478bd9Sstevel@tonic-gate 	    o_addr_list = hp->h_addr_list;
244*7c478bd9Sstevel@tonic-gate 	    memcpy(*n_addr_list++, *o_addr_list, hp->h_length);
245*7c478bd9Sstevel@tonic-gate 	    *n_addr_list = 0;
246*7c478bd9Sstevel@tonic-gate 	    hp->h_addr_list = hp->h_aliases;
247*7c478bd9Sstevel@tonic-gate 	    hp->h_aliases = o_addr_list + 1;
248*7c478bd9Sstevel@tonic-gate 	}
249*7c478bd9Sstevel@tonic-gate     }
250*7c478bd9Sstevel@tonic-gate     return (hp);
251*7c478bd9Sstevel@tonic-gate }
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate #endif /* SOLARIS_24_GETHOSTBYNAME_BUG */
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate  /*
256*7c478bd9Sstevel@tonic-gate   * Horror! Some FreeBSD 2.0 libc routines call strtok(). Since tcpd depends
257*7c478bd9Sstevel@tonic-gate   * heavily on strtok(), strange things may happen. Workaround: use our
258*7c478bd9Sstevel@tonic-gate   * private strtok(). This has been fixed in the meantime.
259*7c478bd9Sstevel@tonic-gate   */
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate #ifdef USE_STRSEP
262*7c478bd9Sstevel@tonic-gate 
fix_strtok(buf,sep)263*7c478bd9Sstevel@tonic-gate char   *fix_strtok(buf, sep)
264*7c478bd9Sstevel@tonic-gate char   *buf;
265*7c478bd9Sstevel@tonic-gate char   *sep;
266*7c478bd9Sstevel@tonic-gate {
267*7c478bd9Sstevel@tonic-gate     static char *state;
268*7c478bd9Sstevel@tonic-gate     char   *result;
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate     if (buf)
271*7c478bd9Sstevel@tonic-gate 	state = buf;
272*7c478bd9Sstevel@tonic-gate     while ((result = strsep(&state, sep)) && result[0] == 0)
273*7c478bd9Sstevel@tonic-gate 	 /* void */ ;
274*7c478bd9Sstevel@tonic-gate     return (result);
275*7c478bd9Sstevel@tonic-gate }
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate #endif /* USE_STRSEP */
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate  /*
280*7c478bd9Sstevel@tonic-gate   * IRIX 5.3 (and possibly earlier versions, too) library routines call the
281*7c478bd9Sstevel@tonic-gate   * non-reentrant strtok() library routine, causing hosts to slip through
282*7c478bd9Sstevel@tonic-gate   * allow/deny filters. Workaround: don't rely on the vendor and use our own
283*7c478bd9Sstevel@tonic-gate   * strtok() function. FreeBSD 2.0 has a similar problem (fixed in 2.0.5).
284*7c478bd9Sstevel@tonic-gate   */
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate #ifdef LIBC_CALLS_STRTOK
287*7c478bd9Sstevel@tonic-gate 
my_strtok(buf,sep)288*7c478bd9Sstevel@tonic-gate char   *my_strtok(buf, sep)
289*7c478bd9Sstevel@tonic-gate char   *buf;
290*7c478bd9Sstevel@tonic-gate char   *sep;
291*7c478bd9Sstevel@tonic-gate {
292*7c478bd9Sstevel@tonic-gate     static char *state;
293*7c478bd9Sstevel@tonic-gate     char   *result;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate     if (buf)
296*7c478bd9Sstevel@tonic-gate 	state = buf;
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate     /*
299*7c478bd9Sstevel@tonic-gate      * Skip over separator characters and detect end of string.
300*7c478bd9Sstevel@tonic-gate      */
301*7c478bd9Sstevel@tonic-gate     if (*(state += strspn(state, sep)) == 0)
302*7c478bd9Sstevel@tonic-gate 	return (0);
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate     /*
305*7c478bd9Sstevel@tonic-gate      * Skip over non-separator characters and terminate result.
306*7c478bd9Sstevel@tonic-gate      */
307*7c478bd9Sstevel@tonic-gate     result = state;
308*7c478bd9Sstevel@tonic-gate     if (*(state += strcspn(state, sep)) != 0)
309*7c478bd9Sstevel@tonic-gate 	*state++ = 0;
310*7c478bd9Sstevel@tonic-gate     return (result);
311*7c478bd9Sstevel@tonic-gate }
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate #endif /* LIBC_CALLS_STRTOK */
314