gethost.c revision 2adc0320
1/* 2 * $Xorg: gethost.c,v 1.5 2001/02/09 02:05:38 xorgcvs Exp $ 3 * $XdotOrg: $ 4 * 5Copyright 1989, 1998 The Open Group 6 7Permission to use, copy, modify, distribute, and sell this software and its 8documentation for any purpose is hereby granted without fee, provided that 9the above copyright notice appear in all copies and that both that 10copyright notice and this permission notice appear in supporting 11documentation. 12 13The above copyright notice and this permission notice shall be included in 14all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 23Except as contained in this notice, the name of The Open Group shall not be 24used in advertising or otherwise to promote the sale, use or other dealings 25in this Software without prior written authorization from The Open Group. 26 * * 27 * Author: Jim Fulton, MIT X Consortium 28 */ 29 30/* $XFree86: xc/programs/xauth/gethost.c,v 3.20 2003/07/27 12:34:25 herrb Exp $ */ 31 32#ifdef HAVE_CONFIG_H 33#include "config.h" 34#endif 35 36/* sorry, streams support does not really work yet */ 37#if defined(STREAMSCONN) && defined(SVR4) 38#undef STREAMSCONN 39#define TCPCONN 40#endif 41 42#ifdef WIN32 43#include <X11/Xwinsock.h> 44#define EPROTOTYPE WSAEPROTOTYPE 45#endif 46#include <X11/X.h> 47#include <signal.h> 48#include <setjmp.h> 49#include <ctype.h> 50#ifndef __TYPES__ 51#include <sys/types.h> 52#define __TYPES__ 53#endif 54#ifndef WIN32 55#ifndef STREAMSCONN 56#ifndef Lynx 57#include <sys/socket.h> 58#else 59#include <socket.h> 60#endif 61#include <netdb.h> 62#include <netinet/in.h> 63#include <arpa/inet.h> 64#ifdef HAVE_NET_ERRNO_H 65#include <net/errno.h> 66#endif /* HAVE_NET_ERRNO_H */ 67#endif /* !STREAMSCONN */ 68#endif /* !WIN32 */ 69#include <errno.h> 70#include "xauth.h" 71 72#ifdef DNETCONN 73#include <netdnet/dn.h> 74#include <netdnet/dnetdb.h> 75#endif 76 77#ifndef WIN32 78#include <arpa/inet.h> 79#endif 80 81#ifdef SIGALRM 82static volatile Bool nameserver_timedout = False; 83 84 85/* 86 * get_hostname - Given an internet address, return a name (CHARON.MIT.EDU) 87 * or a string representing the address (18.58.0.13) if the name cannot 88 * be found. Stolen from xhost. 89 */ 90 91static jmp_buf env; 92static RETSIGTYPE 93nameserver_lost(int sig) 94{ 95 nameserver_timedout = True; 96 longjmp (env, -1); 97 /* NOTREACHED */ 98#ifdef SIGNALRETURNSINT 99 return -1; /* for picky compilers */ 100#endif 101} 102#endif 103 104char * 105get_hostname (Xauth *auth) 106{ 107 static struct hostent *hp; 108 int af; 109#ifdef DNETCONN 110 struct nodeent *np; 111 static char nodeaddr[4 + 2 * DN_MAXADDL]; 112#endif /* DNETCONN */ 113 114 hp = NULL; 115 if (auth->address_length == 0) 116 return "Illegal Address"; 117#ifdef TCPCONN 118 if (auth->family == FamilyInternet 119#if defined(IPv6) && defined(AF_INET6) 120 || auth->family == FamilyInternet6 121#endif 122 ) 123 { 124#if defined(IPv6) && defined(AF_INET6) 125 if (auth->family == FamilyInternet6) 126 af = AF_INET6; 127 else 128#endif 129 af = AF_INET; 130 if (no_name_lookups == False) { 131#ifdef SIGALRM 132 /* gethostbyaddr can take a LONG time if the host does not exist. 133 Assume that if it does not respond in NAMESERVER_TIMEOUT seconds 134 that something is wrong and do not make the user wait. 135 gethostbyaddr will continue after a signal, so we have to 136 jump out of it. 137 */ 138 nameserver_timedout = False; 139 signal (SIGALRM, nameserver_lost); 140 alarm (4); 141 if (setjmp(env) == 0) { 142#endif 143 hp = gethostbyaddr (auth->address, auth->address_length, af); 144#ifdef SIGALRM 145 } 146 alarm (0); 147#endif 148 } 149 if (hp) 150 return (hp->h_name); 151#if defined(IPv6) && defined(AF_INET6) 152 else if (af == AF_INET6) { 153 static char addr[INET6_ADDRSTRLEN+2]; 154 /* Add [] for clarity to distinguish between address & display, 155 like RFC 2732 for URL's. Not required, since X display syntax 156 always ends in :<display>, but makes it easier for people to read 157 and less confusing to those who expect the RFC 2732 style. */ 158 addr[0] = '['; 159 if (inet_ntop(af, auth->address, addr + 1, INET6_ADDRSTRLEN) == NULL) 160 return NULL; 161 strcat(addr, "]"); 162 return addr; 163 } 164#endif 165 else { 166 return (inet_ntoa(*((struct in_addr *)(auth->address)))); 167 } 168 } 169#endif 170#ifdef DNETCONN 171 if (auth->family == FamilyDECnet) { 172 struct dn_naddr *addr_ptr = (struct dn_naddr *) auth->address; 173 174 if ((no_name_lookups == False) && 175 (np = getnodebyaddr(addr_ptr->a_addr, addr_ptr->a_len, AF_DECnet))) { 176 sprintf(nodeaddr, "%s:", np->n_name); 177 } else { 178 sprintf(nodeaddr, "%s:", dnet_htoa(auth->address)); 179 } 180 return(nodeaddr); 181 } 182#endif 183 184 return (NULL); 185} 186 187#if defined(TCPCONN) && (!defined(IPv6) || !defined(AF_INET6)) 188/* 189 * cribbed from lib/X/XConnDis.c 190 */ 191static Bool 192get_inet_address(char *name, unsigned int *resultp) 193{ 194 unsigned int hostinetaddr = inet_addr (name); 195 struct hostent *host_ptr; 196 struct sockaddr_in inaddr; /* dummy variable for size calcs */ 197 198#ifndef INADDR_NONE 199#define INADDR_NONE -1 200#endif 201 202 if (hostinetaddr == INADDR_NONE) { 203 if ((host_ptr = gethostbyname (name)) == NULL) { 204 /* No such host! */ 205 errno = EINVAL; 206 return False; 207 } 208 /* Check the address type for an internet host. */ 209 if (host_ptr->h_addrtype != AF_INET) { 210 /* Not an Internet host! */ 211 errno = EPROTOTYPE; 212 return False; 213 } 214 215 memmove( (char *)&hostinetaddr, (char *)host_ptr->h_addr, 216 sizeof(inaddr.sin_addr)); 217 } 218 *resultp = hostinetaddr; 219 return True; 220} 221#endif 222 223#ifdef DNETCONN 224static Bool get_dnet_address (name, resultp) 225 char *name; 226 struct dn_naddr *resultp; 227{ 228 struct dn_naddr *dnaddrp, dnaddr; 229 struct nodeent *np; 230 231 if (dnaddrp = dnet_addr (name)) { /* stolen from xhost */ 232 dnaddr = *dnaddrp; 233 } else { 234 if ((np = getnodebyname (name)) == NULL) return False; 235 dnaddr.a_len = np->n_length; 236 memmove( dnaddr.a_addr, np->n_addr, np->n_length); 237 } 238 *resultp = dnaddr; 239 return True; 240} 241#endif 242 243struct addrlist *get_address_info ( 244 int family, 245 char *fulldpyname, 246 int prefix, 247 char *host) 248{ 249 struct addrlist *retval = NULL; 250 int len = 0; 251 void *src = NULL; 252#ifdef TCPCONN 253#if defined(IPv6) && defined(AF_INET6) 254 struct addrlist *lastrv = NULL; 255 struct addrinfo *firstai = NULL; 256 struct addrinfo *ai = NULL; 257 struct addrinfo hints; 258#else 259 unsigned int hostinetaddr; 260#endif 261#endif 262#ifdef DNETCONN 263 struct dn_naddr dnaddr; 264#endif 265 char buf[255]; 266 267 /* 268 * based on the family, set the pointer src to the start of the address 269 * information to be copied and set len to the number of bytes. 270 */ 271 switch (family) { 272 case FamilyLocal: /* hostname/unix:0 */ 273 /* handle unix:0 and :0 specially */ 274 if (prefix == 0 && (strncmp (fulldpyname, "unix:", 5) == 0 || 275 fulldpyname[0] == ':')) { 276 277 if (!get_local_hostname (buf, sizeof buf)) { 278 len = 0; 279 } else { 280 src = buf; 281 len = strlen (buf); 282 } 283 } else if(prefix == 0 && (strncmp (fulldpyname, "/tmp/launch", 11) == 0)) { 284 /* Use the bundle id (part preceding : in the basename) as our src id */ 285 char *c; 286#ifdef HAVE_STRLCPY 287 strlcpy(buf, strrchr(fulldpyname, '/') + 1, sizeof(buf)); 288#else 289 strncpy(buf, strrchr(fulldpyname, '/') + 1, sizeof(buf)); 290 buf[sizeof(buf) - 1] = '\0'; 291#endif 292 293 c = strchr(buf, ':'); 294 295 /* In the legacy case with no bundle id, use the full path */ 296 if(c == buf) { 297 src = fulldpyname; 298 } else { 299 *c = '\0'; 300 src = buf; 301 } 302 303 len = strlen(src); 304 } else { 305 src = fulldpyname; 306 len = prefix; 307 } 308 break; 309 case FamilyInternet: /* host:0 */ 310#ifdef TCPCONN 311#if defined(IPv6) && defined(AF_INET6) 312 case FamilyInternet6: 313 memset(&hints, 0, sizeof(hints)); 314 hints.ai_family = PF_UNSPEC; /* IPv4 or IPv6 */ 315 hints.ai_socktype = SOCK_STREAM; /* only interested in TCP */ 316 hints.ai_protocol = 0; 317 if (getaddrinfo(host,NULL,&hints,&firstai) !=0) return NULL; 318 for (ai = firstai; ai != NULL; ai = ai->ai_next) { 319 struct addrlist *duplicate; 320 321 if (ai->ai_family == AF_INET) { 322 struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr; 323 src = &(sin->sin_addr); 324 len = sizeof(sin->sin_addr); 325 family = FamilyInternet; 326 } else if (ai->ai_family == AF_INET6) { 327 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr; 328 src = &(sin6->sin6_addr); 329 len = sizeof(sin6->sin6_addr); 330 family = FamilyInternet6; 331 } 332 333 for(duplicate = retval; duplicate != NULL; duplicate = duplicate->next) { 334 if(duplicate->family == family && duplicate->len == len && 335 memcmp(duplicate->address, src, len) == 0) { 336 break; 337 } 338 } 339 340 if (len > 0 && src != NULL && duplicate == NULL) { 341 struct addrlist *newrv = malloc (sizeof(struct addrlist)); 342 if (newrv) { 343 newrv->address = malloc (len); 344 if (newrv->address) { 345 memcpy(newrv->address, src, len); 346 newrv->next = NULL; 347 newrv->family = family; 348 newrv->len = len; 349 if (retval == NULL) { 350 lastrv = retval = newrv; 351 } else { 352 lastrv->next = newrv; 353 lastrv = newrv; 354 } 355 } else { 356 free(newrv); 357 } 358 } 359 } 360 /* reset to avoid copying into list twice */ 361 len = 0; 362 src = NULL; 363 } 364 freeaddrinfo(firstai); 365 break; 366#else 367 if (!get_inet_address (host, &hostinetaddr)) return NULL; 368 src = (char *) &hostinetaddr; 369 len = 4; /* sizeof inaddr.sin_addr, would fail on Cray */ 370 break; 371#endif /* IPv6 */ 372#else 373 return NULL; 374#endif 375 case FamilyDECnet: /* host::0 */ 376#ifdef DNETCONN 377 if (!get_dnet_address (host, &dnaddr)) return NULL; 378 src = (char *) &dnaddr; 379 len = (sizeof dnaddr); 380 break; 381#else 382 /* fall through since we don't have code for it */ 383#endif 384 default: 385 src = NULL; 386 len = 0; 387 } 388 389 /* 390 * if source was provided, allocate space and copy it 391 */ 392 if (len > 0 && src != NULL) { 393 retval = malloc (sizeof(struct addrlist)); 394 if (retval) { 395 retval->address = malloc (len); 396 if (retval->address) { 397 memcpy(retval->address, src, len); 398 retval->next = NULL; 399 retval->family = family; 400 retval->len = len; 401 } else { 402 free(retval); 403 retval = NULL; 404 } 405 } 406 } 407 return retval; 408} 409