gethost.c revision 0d22642b
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#include <sys/stat.h> 61#include <limits.h> 62 63#ifndef WIN32 64#include <arpa/inet.h> 65#endif 66 67const char * 68get_hostname (Xauth *auth) 69{ 70#ifdef TCPCONN 71 static struct hostent *hp; 72 int af; 73 74 hp = NULL; 75#endif 76 77 if (auth->address_length == 0) 78 return "Illegal Address"; 79#ifdef TCPCONN 80 if (auth->family == FamilyInternet 81#if defined(IPv6) && defined(AF_INET6) 82 || auth->family == FamilyInternet6 83#endif 84 ) 85 { 86#if defined(IPv6) && defined(AF_INET6) 87 if (auth->family == FamilyInternet6) 88 af = AF_INET6; 89 else 90#endif 91 af = AF_INET; 92 if (no_name_lookups == False) { 93 hp = gethostbyaddr (auth->address, auth->address_length, af); 94 } 95 if (hp) 96 return (hp->h_name); 97#if defined(IPv6) && defined(AF_INET6) 98 else if (af == AF_INET6) { 99 static char addr[INET6_ADDRSTRLEN+2]; 100 /* Add [] for clarity to distinguish between address & display, 101 like RFC 2732 for URL's. Not required, since X display syntax 102 always ends in :<display>, but makes it easier for people to read 103 and less confusing to those who expect the RFC 2732 style. */ 104 addr[0] = '['; 105 if (inet_ntop(af, auth->address, addr + 1, INET6_ADDRSTRLEN) == NULL) 106 return NULL; 107 strcat(addr, "]"); 108 return addr; 109 } 110#endif 111 else { 112 return (inet_ntoa(*((struct in_addr *)(auth->address)))); 113 } 114 } 115#endif 116 117 return (NULL); 118} 119 120#if defined(TCPCONN) && (!defined(IPv6) || !defined(AF_INET6)) 121/* 122 * cribbed from lib/X/XConnDis.c 123 */ 124static Bool 125get_inet_address(char *name, unsigned int *resultp) 126{ 127 unsigned int hostinetaddr = inet_addr (name); 128 struct hostent *host_ptr; 129 struct sockaddr_in inaddr; /* dummy variable for size calcs */ 130 131#ifndef INADDR_NONE 132#define INADDR_NONE -1 133#endif 134 135 if (hostinetaddr == INADDR_NONE) { 136 if ((host_ptr = gethostbyname (name)) == NULL) { 137 /* No such host! */ 138 errno = EINVAL; 139 return False; 140 } 141 /* Check the address type for an internet host. */ 142 if (host_ptr->h_addrtype != AF_INET) { 143 /* Not an Internet host! */ 144 errno = EPROTOTYPE; 145 return False; 146 } 147 148 memmove( (char *)&hostinetaddr, (char *)host_ptr->h_addr, 149 sizeof(inaddr.sin_addr)); 150 } 151 *resultp = hostinetaddr; 152 return True; 153} 154#endif 155 156 157struct addrlist *get_address_info ( 158 int family, 159 const char *fulldpyname, 160 int prefix, 161 char *host) 162{ 163 struct addrlist *retval = NULL; 164 int len = 0; 165 const void *src = NULL; 166#ifdef TCPCONN 167#if defined(IPv6) && defined(AF_INET6) 168 struct addrlist *lastrv = NULL; 169 struct addrinfo *firstai = NULL; 170 struct addrinfo *ai = NULL; 171 struct addrinfo hints; 172#else 173 unsigned int hostinetaddr; 174#endif 175#endif 176 char buf[255]; 177 178 /* 179 * based on the family, set the pointer src to the start of the address 180 * information to be copied and set len to the number of bytes. 181 */ 182 switch (family) { 183 case FamilyLocal: /* hostname/unix:0 */ 184 /* handle unix:0 and :0 specially */ 185 if (prefix == 0 && (strncmp (fulldpyname, "unix:", 5) == 0 || 186 fulldpyname[0] == ':')) { 187 188 if (!get_local_hostname (buf, sizeof buf)) { 189 len = 0; 190 } else { 191 src = buf; 192 len = strlen (buf); 193 } 194 } else { 195 char path[PATH_MAX]; 196 struct stat sbuf; 197 int is_path_to_socket = 0; 198 199#ifdef HAVE_STRLCPY 200 strlcpy(path, fulldpyname, sizeof(path)); 201#else 202 strncpy(path, fulldpyname, sizeof(path) - 1); 203 path[sizeof(path) - 1] = '\0'; 204#endif 205 if (0 == stat(path, &sbuf) && S_ISSOCK(sbuf.st_mode) ) { 206 is_path_to_socket = 1; 207 } else { 208 char *dot = strrchr(path, '.'); 209 if (dot) { 210 *dot = '\0'; 211 /* screen = atoi(dot + 1); */ 212 if (0 == stat(path, &sbuf) && S_ISSOCK(sbuf.st_mode)) { 213 is_path_to_socket = 1; 214 } 215 } 216 } 217 218 if (is_path_to_socket) { 219 /* Use the bundle id (part preceding : in the basename) as our src id */ 220 char *c; 221 c = strrchr(fulldpyname, '/'); 222#ifdef HAVE_STRLCPY 223 strlcpy(buf, (NULL != c) ? c + 1 : fulldpyname, sizeof(buf)); 224#else 225 strncpy(buf, (NULL != c) ? c + 1 : fulldpyname, sizeof(buf) - 1); 226 buf[sizeof(buf) - 1] = '\0'; 227#endif 228 229 c = strchr(buf, ':'); 230 231 /* In the legacy case with no bundle id, use the full path */ 232 if(c == buf) { 233 src = fulldpyname; 234 } else { 235 *c = '\0'; 236 src = buf; 237 } 238 239 len = strlen(src); 240 } else { 241 src = fulldpyname; 242 len = prefix; 243 } 244 } 245 break; 246 case FamilyInternet: /* host:0 */ 247#ifdef TCPCONN 248#if defined(IPv6) && defined(AF_INET6) 249 case FamilyInternet6: 250 memset(&hints, 0, sizeof(hints)); 251 hints.ai_family = PF_UNSPEC; /* IPv4 or IPv6 */ 252 hints.ai_socktype = SOCK_STREAM; /* only interested in TCP */ 253 hints.ai_protocol = 0; 254 if (getaddrinfo(host,NULL,&hints,&firstai) !=0) return NULL; 255 for (ai = firstai; ai != NULL; ai = ai->ai_next) { 256 struct addrlist *duplicate; 257 258 len = 0; 259 if (ai->ai_family == AF_INET) { 260 struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr; 261 src = &(sin->sin_addr); 262 if (*(const in_addr_t *) src == htonl(INADDR_LOOPBACK)) { 263 family = FamilyLocal; 264 if (get_local_hostname (buf, sizeof buf)) { 265 src = buf; 266 len = strlen (buf); 267 } else 268 src = NULL; 269 } else { 270 len = sizeof(sin->sin_addr); 271 family = FamilyInternet; 272 } 273 } else if (ai->ai_family == AF_INET6) { 274 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr; 275 src = &(sin6->sin6_addr); 276 if (!IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) { 277 if (IN6_IS_ADDR_LOOPBACK((const struct in6_addr *)src)) { 278 family = FamilyLocal; 279 if (get_local_hostname (buf, sizeof buf)) { 280 src = buf; 281 len = strlen (buf); 282 } else 283 src = NULL; 284 } else { 285 len = sizeof(sin6->sin6_addr); 286 family = FamilyInternet6; 287 } 288 } else { 289 src = &(sin6->sin6_addr.s6_addr[12]); 290 len = sizeof(((struct sockaddr_in *) 291 ai->ai_addr)->sin_addr); 292 family = FamilyInternet; 293 } 294 } 295 296 for(duplicate = retval; duplicate != NULL; duplicate = duplicate->next) { 297 if(duplicate->family == family && duplicate->len == len && 298 memcmp(duplicate->address, src, len) == 0) { 299 break; 300 } 301 } 302 303 if (len > 0 && src != NULL && duplicate == NULL) { 304 struct addrlist *newrv = malloc (sizeof(struct addrlist)); 305 if (newrv) { 306 newrv->address = malloc (len); 307 if (newrv->address) { 308 memcpy(newrv->address, src, len); 309 newrv->next = NULL; 310 newrv->family = family; 311 newrv->len = len; 312 if (retval == NULL) { 313 lastrv = retval = newrv; 314 } else { 315 lastrv->next = newrv; 316 lastrv = newrv; 317 } 318 } else { 319 free(newrv); 320 } 321 } 322 } 323 /* reset to avoid copying into list twice */ 324 len = 0; 325 src = NULL; 326 } 327 freeaddrinfo(firstai); 328 break; 329#else 330 if (!get_inet_address (host, &hostinetaddr)) return NULL; 331 src = (char *) &hostinetaddr; 332 if (*(const in_addr_t *) src == htonl(INADDR_LOOPBACK)) { 333 family = FamilyLocal; 334 if (get_local_hostname (buf, sizeof buf)) { 335 src = buf; 336 len = strlen (buf); 337 } else { 338 len = 0; 339 src = NULL; 340 } 341 } else 342 len = 4; /* sizeof inaddr.sin_addr, would fail on Cray */ 343 break; 344#endif /* IPv6 */ 345#else 346 return NULL; 347#endif 348 case FamilyDECnet: /* host::0 */ 349 /* fall through since we don't have code for it */ 350 default: 351 src = NULL; 352 len = 0; 353 } 354 355 /* 356 * if source was provided, allocate space and copy it 357 */ 358 if (len > 0 && src != NULL) { 359 retval = malloc (sizeof(struct addrlist)); 360 if (retval) { 361 retval->address = malloc (len); 362 if (retval->address) { 363 memcpy(retval->address, src, len); 364 retval->next = NULL; 365 retval->family = family; 366 retval->len = len; 367 } else { 368 free(retval); 369 retval = NULL; 370 } 371 } 372 } 373 return retval; 374} 375