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