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