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