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
11: char sccsid[] = "@(#) workarounds.c 1.4 95/01/08 21:08:00";
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:
24: extern int errno;
25:
26: #include "tcpd.h"
27:
28: /*
29: * Some AIX versions advertise a too small MAXHOSTNAMELEN value (32).
30: * Result: long hostnames would be truncated, and connections would be
31: * dropped because of host name verification failures. Adrian van Bloois
32: * (A.vanBloois@info.nic.surfnet.nl) figured out what was the problem.
33: */
34:
35: #if (MAXHOSTNAMELEN < 64)
36: #undef MAXHOSTNAMELEN
37: #endif
38:
39: /* In case not defined in <sys/param.h>. */
40:
41: #ifndef MAXHOSTNAMELEN
42: #define MAXHOSTNAMELEN 256 /* storage for host name */
43: #endif
44:
45: /*
46: * Some DG/UX inet_addr() versions return a struct/union instead of a long.
47: * You have this problem when the compiler complains about illegal lvalues
48: * or something like that. The following code fixes this mutant behaviour.
49: * It should not be enabled on "normal" systems.
50: *
51: * Bug reported by ben@piglet.cr.usgs.gov (Rev. Ben A. Mesander).
52: */
53:
54: #ifdef INET_ADDR_BUG
55:
56: #undef inet_addr
57:
58: long fix_inet_addr(string)
59: char *string;
60: {
61: return (inet_addr(string).s_addr);
62: }
63:
64: #endif /* INET_ADDR_BUG */
65:
66: /*
67: * With some System-V versions, the fgets() library function does not
68: * account for partial reads from e.g. sockets. The result is that fgets()
69: * gives up too soon, causing username lookups to fail. Problem first
70: * reported for IRIX 4.0.5, by Steve Kotsopoulos <steve@ecf.toronto.edu>.
71: * The following code works around the problem. It does no harm on "normal"
72: * systems.
73: */
74:
75: #ifdef BROKEN_FGETS
76:
77: #undef fgets
78:
79: char *fix_fgets(buf, len, fp)
80: char *buf;
81: int len;
82: FILE *fp;
83: {
84: char *cp = buf;
85: int c;
86:
87: /*
88: * Copy until the buffer fills up, until EOF, or until a newline is
89: * found.
90: */
91: while (len > 1 && (c = getc(fp)) != EOF) {
92: len--;
93: *cp++ = c;
94: if (c == '\n')
95: break;
96: }
97:
98: /*
99: * Return 0 if nothing was read. This is correct even when a silly buffer
100: * length was specified.
101: */
102: if (cp > buf) {
103: *cp = 0;
104: return (buf);
105: } else {
106: return (0);
107: }
108: }
109:
110: #endif /* BROKEN_FGETS */
111:
112: /*
113: * With early SunOS 5 versions, recvfrom() does not completely fill in the
114: * source address structure when doing a non-destructive read. The following
115: * code works around the problem. It does no harm on "normal" systems.
116: */
117:
118: #ifdef RECVFROM_BUG
119:
120: #undef recvfrom
121:
122: int fix_recvfrom(sock, buf, buflen, flags, from, fromlen)
123: int sock;
124: char *buf;
125: int buflen;
126: int flags;
127: struct sockaddr *from;
128: int *fromlen;
129: {
130: int ret;
131:
132: /* Assume that both ends of a socket belong to the same address family. */
133:
134: if ((ret = recvfrom(sock, buf, buflen, flags, from, fromlen)) >= 0) {
135: if (from->sa_family == 0) {
136: struct sockaddr my_addr;
137: int my_addr_len = sizeof(my_addr);
138:
139: if (getsockname(0, &my_addr, &my_addr_len)) {
140: tcpd_warn("getsockname: %m");
141: } else {
142: from->sa_family = my_addr.sa_family;
143: }
144: }
145: }
146: return (ret);
147: }
148:
149: #endif /* RECVFROM_BUG */
150:
151: /*
152: * The Apollo SR10.3 and some SYSV4 getpeername(2) versions do not return an
153: * error in case of a datagram-oriented socket. Instead, they claim that all
154: * UDP requests come from address 0.0.0.0. The following code works around
155: * the problem. It does no harm on "normal" systems.
156: */
157:
158: #ifdef GETPEERNAME_BUG
159:
160: #undef getpeername
161:
162: int fix_getpeername(sock, sa, len)
163: int sock;
164: struct sockaddr *sa;
165: int *len;
166: {
167: int ret;
168: struct sockaddr_in *sin = (struct sockaddr_in *) sa;
169:
170: if ((ret = getpeername(sock, sa, len)) >= 0
171: && sa->sa_family == AF_INET
172: && sin->sin_addr.s_addr == 0) {
173: errno = ENOTCONN;
174: return (-1);
175: } else {
176: return (ret);
177: }
178: }
179:
180: #endif /* GETPEERNAME_BUG */
181:
182: /*
183: * According to Karl Vogel (vogelke@c-17igp.wpafb.af.mil) some Pyramid
184: * versions have no yp_default_domain() function. We use getdomainname()
185: * instead.
186: */
187:
188: #ifdef USE_GETDOMAIN
189:
190: int yp_get_default_domain(ptr)
191: char **ptr;
192: {
193: static char mydomain[MAXHOSTNAMELEN];
194:
195: *ptr = mydomain;
196: return (getdomainname(mydomain, MAXHOSTNAMELEN));
197: }
198:
199: #endif /* USE_GETDOMAIN */
200:
201: #ifndef INADDR_NONE
202: #define INADDR_NONE 0xffffffff
203: #endif
204:
205: /*
206: * Solaris 2.4 gethostbyname() has problems with multihomed hosts. When
207: * doing DNS through NIS, only one host address ends up in the address list.
208: * All other addresses end up in the hostname alias list, interspersed with
209: * copies of the official host name. This would wreak havoc with tcpd's
210: * hostname double checks. Below is a workaround that should do no harm when
211: * accidentally left in. A side effect of the workaround is that address
212: * list members are no longer properly aligned for structure access.
213: */
214:
215: #ifdef SOLARIS_24_GETHOSTBYNAME_BUG
216:
217: #undef gethostbyname
218:
219: struct hostent *fix_gethostbyname(name)
220: char *name;
221: {
222: struct hostent *hp;
223: struct in_addr addr;
224: char **o_addr_list;
225: char **o_aliases;
226: char **n_addr_list;
227: int broken_gethostbyname = 0;
228:
229: if ((hp = gethostbyname(name)) && !hp->h_addr_list[1] && hp->h_aliases[1]) {
230: for (o_aliases = n_addr_list = hp->h_aliases; *o_aliases; o_aliases++) {
231: if ((addr.s_addr = inet_addr(*o_aliases)) != INADDR_NONE) {
232: memcpy(*n_addr_list++, (char *) &addr, hp->h_length);
233: broken_gethostbyname = 1;
234: }
235: }
236: if (broken_gethostbyname) {
237: o_addr_list = hp->h_addr_list;
238: memcpy(*n_addr_list++, *o_addr_list, hp->h_length);
239: *n_addr_list = 0;
240: hp->h_addr_list = hp->h_aliases;
241: hp->h_aliases = o_addr_list + 1;
242: }
243: }
244: return (hp);
245: }
246:
247: #endif /* SOLARIS_24_GETHOSTBYNAME_BUG */
Defined functions
Defined variables
Defined macros