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