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