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