source: trunk/third/tcp_wrappers/workarounds.c @ 11717

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