17a0395d0Smrg/*
296402570Smrg *
37a0395d0SmrgCopyright 1989, 1998  The Open Group
47a0395d0Smrg
57a0395d0SmrgPermission to use, copy, modify, distribute, and sell this software and its
67a0395d0Smrgdocumentation for any purpose is hereby granted without fee, provided that
77a0395d0Smrgthe above copyright notice appear in all copies and that both that
87a0395d0Smrgcopyright notice and this permission notice appear in supporting
97a0395d0Smrgdocumentation.
107a0395d0Smrg
117a0395d0SmrgThe above copyright notice and this permission notice shall be included in
127a0395d0Smrgall copies or substantial portions of the Software.
137a0395d0Smrg
147a0395d0SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
157a0395d0SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
167a0395d0SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
177a0395d0SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
187a0395d0SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
197a0395d0SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
207a0395d0Smrg
217a0395d0SmrgExcept as contained in this notice, the name of The Open Group shall not be
227a0395d0Smrgused in advertising or otherwise to promote the sale, use or other dealings
237a0395d0Smrgin this Software without prior written authorization from The Open Group.
247a0395d0Smrg * *
257a0395d0Smrg * Author:  Jim Fulton, MIT X Consortium
267a0395d0Smrg */
277a0395d0Smrg
287a0395d0Smrg#ifdef HAVE_CONFIG_H
297a0395d0Smrg#include "config.h"
307a0395d0Smrg#endif
317a0395d0Smrg
327a0395d0Smrg#ifdef WIN32
337a0395d0Smrg#include <X11/Xwinsock.h>
347a0395d0Smrg#define EPROTOTYPE WSAEPROTOTYPE
357a0395d0Smrg#endif
367a0395d0Smrg#include <X11/X.h>
377a0395d0Smrg#include <signal.h>
387a0395d0Smrg#include <setjmp.h>
397a0395d0Smrg#include <ctype.h>
407a0395d0Smrg#ifndef __TYPES__
417a0395d0Smrg#include <sys/types.h>
427a0395d0Smrg#define __TYPES__
437a0395d0Smrg#endif
447a0395d0Smrg#ifndef WIN32
457a0395d0Smrg#include <sys/socket.h>
467a0395d0Smrg#include <netdb.h>
477a0395d0Smrg#include <netinet/in.h>
487a0395d0Smrg#include <arpa/inet.h>
497a0395d0Smrg#ifdef HAVE_NET_ERRNO_H
507a0395d0Smrg#include <net/errno.h>
517a0395d0Smrg#endif /* HAVE_NET_ERRNO_H */
527a0395d0Smrg#endif /* !WIN32 */
537a0395d0Smrg#include <errno.h>
547a0395d0Smrg#include "xauth.h"
557a0395d0Smrg
5640c5344fSmrg#include <sys/stat.h>
5740c5344fSmrg#include <limits.h>
587a0395d0Smrg
597a0395d0Smrg#ifndef WIN32
607a0395d0Smrg#include <arpa/inet.h>
617a0395d0Smrg#endif
627a0395d0Smrg
63f6d57fdeSmrg#if defined(IPv6) && !defined(AF_INET6)
64f6d57fdeSmrg#error "Cannot build IPv6 support without AF_INET6"
65f6d57fdeSmrg#endif
66f6d57fdeSmrg
6796402570Smrgconst char *
687a0395d0Smrgget_hostname (Xauth *auth)
697a0395d0Smrg{
707a0395d0Smrg    if (auth->address_length == 0)
717a0395d0Smrg	return "Illegal Address";
727a0395d0Smrg#ifdef TCPCONN
737a0395d0Smrg    if (auth->family == FamilyInternet
74f6d57fdeSmrg#ifdef IPv6
757a0395d0Smrg      || auth->family == FamilyInternet6
7696402570Smrg#endif
777a0395d0Smrg	)
787a0395d0Smrg    {
79273c00b8Smrg	static struct hostent *hp = NULL;
80f6d57fdeSmrg#ifdef IPv6
81f6d57fdeSmrg	static char addr[INET6_ADDRSTRLEN+2];
82f6d57fdeSmrg#elif defined(HAVE_INET_NTOP)
83f6d57fdeSmrg	static char addr[INET_ADDRSTRLEN];
84f6d57fdeSmrg#endif
85273c00b8Smrg	int af;
86273c00b8Smrg
87f6d57fdeSmrg#ifdef IPv6
887a0395d0Smrg	if (auth->family == FamilyInternet6)
897a0395d0Smrg	    af = AF_INET6;
907a0395d0Smrg	else
917a0395d0Smrg#endif
927a0395d0Smrg	    af = AF_INET;
937a0395d0Smrg	if (no_name_lookups == False) {
947a0395d0Smrg	    hp = gethostbyaddr (auth->address, auth->address_length, af);
957a0395d0Smrg	}
967a0395d0Smrg	if (hp)
977a0395d0Smrg	  return (hp->h_name);
98f6d57fdeSmrg#ifdef IPv6
997a0395d0Smrg	else if (af == AF_INET6) {
1007a0395d0Smrg	  /* Add [] for clarity to distinguish between address & display,
1017a0395d0Smrg	     like RFC 2732 for URL's.  Not required, since X display syntax
1027a0395d0Smrg	     always ends in :<display>, but makes it easier for people to read
1037a0395d0Smrg	     and less confusing to those who expect the RFC 2732 style. */
1047a0395d0Smrg	  addr[0] = '[';
1057a0395d0Smrg	  if (inet_ntop(af, auth->address, addr + 1, INET6_ADDRSTRLEN) == NULL)
1067a0395d0Smrg	    return NULL;
1077a0395d0Smrg	  strcat(addr, "]");
1087a0395d0Smrg          return addr;
1097a0395d0Smrg	}
1107a0395d0Smrg#endif
1117a0395d0Smrg	else {
112f6d57fdeSmrg#ifdef HAVE_INET_NTOP
113f6d57fdeSmrg	  return (inet_ntop(af, auth->address, addr, sizeof(addr)));
114f6d57fdeSmrg#else
1157a0395d0Smrg	  return (inet_ntoa(*((struct in_addr *)(auth->address))));
116f6d57fdeSmrg#endif
1177a0395d0Smrg	}
1187a0395d0Smrg    }
1197a0395d0Smrg#endif
1207a0395d0Smrg
1217a0395d0Smrg    return (NULL);
1227a0395d0Smrg}
1237a0395d0Smrg
124f6d57fdeSmrg#if defined(TCPCONN) && !defined(HAVE_GETADDRINFO)
1257a0395d0Smrg/*
1267a0395d0Smrg * cribbed from lib/X/XConnDis.c
1277a0395d0Smrg */
12896402570Smrgstatic Bool
1297a0395d0Smrgget_inet_address(char *name, unsigned int *resultp)
1307a0395d0Smrg{
1317a0395d0Smrg    unsigned int hostinetaddr = inet_addr (name);
1327a0395d0Smrg    struct hostent *host_ptr;
1337a0395d0Smrg    struct sockaddr_in inaddr;		/* dummy variable for size calcs */
1347a0395d0Smrg
1357a0395d0Smrg#ifndef INADDR_NONE
1367a0395d0Smrg#define INADDR_NONE -1
1377a0395d0Smrg#endif
1387a0395d0Smrg
1397a0395d0Smrg    if (hostinetaddr == INADDR_NONE) {
1407a0395d0Smrg	if ((host_ptr = gethostbyname (name)) == NULL) {
1417a0395d0Smrg	    /* No such host! */
1427a0395d0Smrg	    errno = EINVAL;
1437a0395d0Smrg	    return False;
1447a0395d0Smrg	}
1457a0395d0Smrg	/* Check the address type for an internet host. */
1467a0395d0Smrg	if (host_ptr->h_addrtype != AF_INET) {
1477a0395d0Smrg	    /* Not an Internet host! */
1487a0395d0Smrg	    errno = EPROTOTYPE;
1497a0395d0Smrg	    return False;
1507a0395d0Smrg	}
15196402570Smrg
15296402570Smrg	memmove( (char *)&hostinetaddr, (char *)host_ptr->h_addr,
1537a0395d0Smrg	      sizeof(inaddr.sin_addr));
1547a0395d0Smrg    }
1557a0395d0Smrg    *resultp = hostinetaddr;
1567a0395d0Smrg    return True;
1577a0395d0Smrg}
1587a0395d0Smrg#endif
1597a0395d0Smrg
1607a0395d0Smrg
1617a0395d0Smrgstruct addrlist *get_address_info (
1627a0395d0Smrg    int family,
16396402570Smrg    const char *fulldpyname,
1647a0395d0Smrg    int prefix,
1657a0395d0Smrg    char *host)
1667a0395d0Smrg{
1677a0395d0Smrg    struct addrlist *retval = NULL;
1687a0395d0Smrg    int len = 0;
16996402570Smrg    const void *src = NULL;
1707a0395d0Smrg#ifdef TCPCONN
171f6d57fdeSmrg#ifdef HAVE_GETADDRINFO
1727a0395d0Smrg    struct addrlist *lastrv = NULL;
1737a0395d0Smrg    struct addrinfo *firstai = NULL;
1747a0395d0Smrg    struct addrinfo hints;
1757a0395d0Smrg#else
1767a0395d0Smrg    unsigned int hostinetaddr;
1777a0395d0Smrg#endif
1787a0395d0Smrg#endif
1797a0395d0Smrg    char buf[255];
1807a0395d0Smrg
1817a0395d0Smrg    /*
1827a0395d0Smrg     * based on the family, set the pointer src to the start of the address
1837a0395d0Smrg     * information to be copied and set len to the number of bytes.
1847a0395d0Smrg     */
1857a0395d0Smrg    switch (family) {
1867a0395d0Smrg      case FamilyLocal:			/* hostname/unix:0 */
1877a0395d0Smrg					/* handle unix:0 and :0 specially */
1887a0395d0Smrg	if (prefix == 0 && (strncmp (fulldpyname, "unix:", 5) == 0 ||
1897a0395d0Smrg			    fulldpyname[0] == ':')) {
1907a0395d0Smrg
1917a0395d0Smrg	    if (!get_local_hostname (buf, sizeof buf)) {
1927a0395d0Smrg		len = 0;
1937a0395d0Smrg	    } else {
1947a0395d0Smrg		src = buf;
1957a0395d0Smrg		len = strlen (buf);
1967a0395d0Smrg	    }
19740c5344fSmrg	} else {
19840c5344fSmrg	    char path[PATH_MAX];
19940c5344fSmrg	    struct stat sbuf;
20040c5344fSmrg	    int is_path_to_socket = 0;
20140c5344fSmrg
20240c5344fSmrg#ifdef HAVE_STRLCPY
20340c5344fSmrg	    strlcpy(path, fulldpyname, sizeof(path));
20440c5344fSmrg#else
2050d22642bSmrg	    strncpy(path, fulldpyname, sizeof(path) - 1);
20640c5344fSmrg	    path[sizeof(path) - 1] = '\0';
20740c5344fSmrg#endif
2080d22642bSmrg	    if (0 == stat(path, &sbuf) && S_ISSOCK(sbuf.st_mode) ) {
20940c5344fSmrg		is_path_to_socket = 1;
21040c5344fSmrg	    } else {
21140c5344fSmrg		char *dot = strrchr(path, '.');
21240c5344fSmrg		if (dot) {
21340c5344fSmrg		    *dot = '\0';
21440c5344fSmrg		    /* screen = atoi(dot + 1); */
2150d22642bSmrg		    if (0 == stat(path, &sbuf) && S_ISSOCK(sbuf.st_mode)) {
21640c5344fSmrg		        is_path_to_socket = 1;
21740c5344fSmrg		    }
21840c5344fSmrg		}
21940c5344fSmrg	    }
22040c5344fSmrg
22140c5344fSmrg	    if (is_path_to_socket) {
22240c5344fSmrg		/* Use the bundle id (part preceding : in the basename) as our src id */
22340c5344fSmrg		char *c;
2240d22642bSmrg		c = strrchr(fulldpyname, '/');
2252adc0320Smrg#ifdef HAVE_STRLCPY
2260d22642bSmrg		strlcpy(buf, (NULL != c) ? c + 1 : fulldpyname, sizeof(buf));
2272adc0320Smrg#else
2280d22642bSmrg		strncpy(buf, (NULL != c) ? c + 1 : fulldpyname, sizeof(buf) - 1);
22940c5344fSmrg		buf[sizeof(buf) - 1] = '\0';
2302adc0320Smrg#endif
2312adc0320Smrg
23240c5344fSmrg		c = strchr(buf, ':');
23396402570Smrg
23440c5344fSmrg		/* In the legacy case with no bundle id, use the full path */
23540c5344fSmrg		if(c == buf) {
23640c5344fSmrg			src = fulldpyname;
23740c5344fSmrg		} else {
23840c5344fSmrg			*c = '\0';
23940c5344fSmrg			src = buf;
24040c5344fSmrg		}
2412adc0320Smrg
24240c5344fSmrg		len = strlen(src);
24340c5344fSmrg	    } else {
24440c5344fSmrg		src = fulldpyname;
24540c5344fSmrg		len = prefix;
24640c5344fSmrg            }
2477a0395d0Smrg	}
2487a0395d0Smrg	break;
2497a0395d0Smrg      case FamilyInternet:		/* host:0 */
2507a0395d0Smrg#ifdef TCPCONN
251f6d57fdeSmrg#ifdef HAVE_GETADDRINFO
252f6d57fdeSmrg#ifdef IPv6
2537a0395d0Smrg      case FamilyInternet6:
254f6d57fdeSmrg#endif
2557a0395d0Smrg	memset(&hints, 0, sizeof(hints));
256f6d57fdeSmrg#ifdef IPv6
2577a0395d0Smrg	hints.ai_family = PF_UNSPEC; /* IPv4 or IPv6 */
258f6d57fdeSmrg#else
259f6d57fdeSmrg	hints.ai_family = PF_INET;   /* IPv4 only */
260f6d57fdeSmrg#endif
2617a0395d0Smrg	hints.ai_socktype = SOCK_STREAM; /* only interested in TCP */
26296402570Smrg	hints.ai_protocol = 0;
2637a0395d0Smrg        if (getaddrinfo(host,NULL,&hints,&firstai) !=0) return NULL;
264273c00b8Smrg	for (struct addrinfo *ai = firstai; ai != NULL; ai = ai->ai_next) {
2657366012aSmrg	    struct addrlist *duplicate;
2667366012aSmrg
2678abc0ccfSmrg            len = 0;
2687a0395d0Smrg	    if (ai->ai_family == AF_INET) {
2697a0395d0Smrg		struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
2707a0395d0Smrg		src = &(sin->sin_addr);
2718abc0ccfSmrg                if (*(const in_addr_t *) src == htonl(INADDR_LOOPBACK)) {
2728abc0ccfSmrg                    family = FamilyLocal;
2738abc0ccfSmrg                    if (get_local_hostname (buf, sizeof buf)) {
2748abc0ccfSmrg                        src = buf;
2758abc0ccfSmrg                        len = strlen (buf);
2768abc0ccfSmrg                    } else
2778abc0ccfSmrg                        src = NULL;
2788abc0ccfSmrg                } else {
2798abc0ccfSmrg                    len = sizeof(sin->sin_addr);
2808abc0ccfSmrg                    family = FamilyInternet;
2818abc0ccfSmrg                }
282f6d57fdeSmrg#ifdef IPv6
2837a0395d0Smrg	    } else if (ai->ai_family == AF_INET6) {
2847a0395d0Smrg		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
2857a0395d0Smrg		src = &(sin6->sin6_addr);
2868abc0ccfSmrg                if (!IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) {
2878abc0ccfSmrg                    if (IN6_IS_ADDR_LOOPBACK((const struct in6_addr *)src)) {
2888abc0ccfSmrg                        family = FamilyLocal;
2898abc0ccfSmrg                        if (get_local_hostname (buf, sizeof buf)) {
2908abc0ccfSmrg                            src = buf;
2918abc0ccfSmrg                            len = strlen (buf);
2928abc0ccfSmrg                        } else
2938abc0ccfSmrg                            src = NULL;
2948abc0ccfSmrg                    } else {
2958abc0ccfSmrg                        len = sizeof(sin6->sin6_addr);
2968abc0ccfSmrg                        family = FamilyInternet6;
2978abc0ccfSmrg                    }
2988abc0ccfSmrg                } else {
2998abc0ccfSmrg                    src = &(sin6->sin6_addr.s6_addr[12]);
3008abc0ccfSmrg                    len = sizeof(((struct sockaddr_in *)
3018abc0ccfSmrg                                  ai->ai_addr)->sin_addr);
3028abc0ccfSmrg                    family = FamilyInternet;
3038abc0ccfSmrg                }
304f6d57fdeSmrg#endif
3057a0395d0Smrg	    }
3067a0395d0Smrg
3077a0395d0Smrg	    for(duplicate = retval; duplicate != NULL; duplicate = duplicate->next) {
3087a0395d0Smrg		if(duplicate->family == family && duplicate->len == len &&
3097a0395d0Smrg                   memcmp(duplicate->address, src, len) == 0) {
3107a0395d0Smrg		    break;
3117a0395d0Smrg                }
3127a0395d0Smrg	    }
3137a0395d0Smrg
3147a0395d0Smrg	    if (len > 0 && src != NULL && duplicate == NULL) {
3157a0395d0Smrg		struct addrlist *newrv = malloc (sizeof(struct addrlist));
3167a0395d0Smrg		if (newrv) {
3177a0395d0Smrg		    newrv->address = malloc (len);
3187a0395d0Smrg		    if (newrv->address) {
3197a0395d0Smrg			memcpy(newrv->address, src, len);
3207a0395d0Smrg			newrv->next = NULL;
3217a0395d0Smrg			newrv->family = family;
3227a0395d0Smrg			newrv->len = len;
3237a0395d0Smrg			if (retval == NULL) {
3247a0395d0Smrg			    lastrv = retval = newrv;
3257a0395d0Smrg			} else {
3267a0395d0Smrg			    lastrv->next = newrv;
3277a0395d0Smrg			    lastrv = newrv;
3287a0395d0Smrg			}
3297a0395d0Smrg		    } else {
3307a0395d0Smrg			free(newrv);
3317a0395d0Smrg		    }
3327a0395d0Smrg		}
3337a0395d0Smrg	    }
3347a0395d0Smrg	    /* reset to avoid copying into list twice */
3357a0395d0Smrg	    len = 0;
3367a0395d0Smrg	    src = NULL;
3377a0395d0Smrg	}
3387a0395d0Smrg	freeaddrinfo(firstai);
3397a0395d0Smrg	break;
340f6d57fdeSmrg#else /* !HAVE_GETADDRINFO */
3417a0395d0Smrg	if (!get_inet_address (host, &hostinetaddr)) return NULL;
3427a0395d0Smrg	src = (char *) &hostinetaddr;
3438abc0ccfSmrg        if (*(const in_addr_t *) src == htonl(INADDR_LOOPBACK)) {
3448abc0ccfSmrg            family = FamilyLocal;
3458abc0ccfSmrg            if (get_local_hostname (buf, sizeof buf)) {
3468abc0ccfSmrg                src = buf;
3478abc0ccfSmrg                len = strlen (buf);
3488abc0ccfSmrg            } else {
3498abc0ccfSmrg                len = 0;
3508abc0ccfSmrg                src = NULL;
3518abc0ccfSmrg            }
3528abc0ccfSmrg        } else
3538abc0ccfSmrg            len = 4; /* sizeof inaddr.sin_addr, would fail on Cray */
3547a0395d0Smrg	break;
355f6d57fdeSmrg#endif /* HAVE_GETADDRINFO */
356f6d57fdeSmrg#else /* !TCPCONN */
3577a0395d0Smrg	return NULL;
3587a0395d0Smrg#endif
3597a0395d0Smrg      case FamilyDECnet:		/* host::0 */
3607a0395d0Smrg	/* fall through since we don't have code for it */
3617a0395d0Smrg      default:
3627a0395d0Smrg	src = NULL;
3637a0395d0Smrg	len = 0;
3647a0395d0Smrg    }
3657a0395d0Smrg
3667a0395d0Smrg    /*
3677a0395d0Smrg     * if source was provided, allocate space and copy it
3687a0395d0Smrg     */
3697a0395d0Smrg    if (len > 0 && src != NULL) {
3707a0395d0Smrg	retval = malloc (sizeof(struct addrlist));
3717a0395d0Smrg	if (retval) {
3727a0395d0Smrg	    retval->address = malloc (len);
3737a0395d0Smrg	    if (retval->address) {
3747a0395d0Smrg		memcpy(retval->address, src, len);
3757a0395d0Smrg		retval->next = NULL;
3767a0395d0Smrg		retval->family = family;
3777a0395d0Smrg		retval->len = len;
3787a0395d0Smrg	    } else {
3797a0395d0Smrg		free(retval);
3807a0395d0Smrg		retval = NULL;
3817a0395d0Smrg	    }
3827a0395d0Smrg	}
3837a0395d0Smrg    }
3847a0395d0Smrg    return retval;
3857a0395d0Smrg}
386