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