gethost.c revision 2adc0320
1/*
2 * $Xorg: gethost.c,v 1.5 2001/02/09 02:05:38 xorgcvs Exp $
3 * $XdotOrg: $
4 *
5Copyright 1989, 1998  The Open Group
6
7Permission to use, copy, modify, distribute, and sell this software and its
8documentation for any purpose is hereby granted without fee, provided that
9the above copyright notice appear in all copies and that both that
10copyright notice and this permission notice appear in supporting
11documentation.
12
13The above copyright notice and this permission notice shall be included in
14all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the name of The Open Group shall not be
24used in advertising or otherwise to promote the sale, use or other dealings
25in this Software without prior written authorization from The Open Group.
26 * *
27 * Author:  Jim Fulton, MIT X Consortium
28 */
29
30/* $XFree86: xc/programs/xauth/gethost.c,v 3.20 2003/07/27 12:34:25 herrb Exp $ */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36/* sorry, streams support does not really work yet */
37#if defined(STREAMSCONN) && defined(SVR4)
38#undef STREAMSCONN
39#define TCPCONN
40#endif
41
42#ifdef WIN32
43#include <X11/Xwinsock.h>
44#define EPROTOTYPE WSAEPROTOTYPE
45#endif
46#include <X11/X.h>
47#include <signal.h>
48#include <setjmp.h>
49#include <ctype.h>
50#ifndef __TYPES__
51#include <sys/types.h>
52#define __TYPES__
53#endif
54#ifndef WIN32
55#ifndef STREAMSCONN
56#ifndef Lynx
57#include <sys/socket.h>
58#else
59#include <socket.h>
60#endif
61#include <netdb.h>
62#include <netinet/in.h>
63#include <arpa/inet.h>
64#ifdef HAVE_NET_ERRNO_H
65#include <net/errno.h>
66#endif /* HAVE_NET_ERRNO_H */
67#endif /* !STREAMSCONN */
68#endif /* !WIN32 */
69#include <errno.h>
70#include "xauth.h"
71
72#ifdef DNETCONN
73#include <netdnet/dn.h>
74#include <netdnet/dnetdb.h>
75#endif
76
77#ifndef WIN32
78#include <arpa/inet.h>
79#endif
80
81#ifdef SIGALRM
82static volatile Bool nameserver_timedout = False;
83
84
85/*
86 * get_hostname - Given an internet address, return a name (CHARON.MIT.EDU)
87 * or a string representing the address (18.58.0.13) if the name cannot
88 * be found.  Stolen from xhost.
89 */
90
91static jmp_buf env;
92static RETSIGTYPE
93nameserver_lost(int sig)
94{
95  nameserver_timedout = True;
96  longjmp (env, -1);
97  /* NOTREACHED */
98#ifdef SIGNALRETURNSINT
99  return -1;				/* for picky compilers */
100#endif
101}
102#endif
103
104char *
105get_hostname (Xauth *auth)
106{
107    static struct hostent *hp;
108    int af;
109#ifdef DNETCONN
110    struct nodeent *np;
111    static char nodeaddr[4 + 2 * DN_MAXADDL];
112#endif /* DNETCONN */
113
114    hp = NULL;
115    if (auth->address_length == 0)
116	return "Illegal Address";
117#ifdef TCPCONN
118    if (auth->family == FamilyInternet
119#if defined(IPv6) && defined(AF_INET6)
120      || auth->family == FamilyInternet6
121#endif
122	)
123    {
124#if defined(IPv6) && defined(AF_INET6)
125	if (auth->family == FamilyInternet6)
126	    af = AF_INET6;
127	else
128#endif
129	    af = AF_INET;
130	if (no_name_lookups == False) {
131#ifdef SIGALRM
132	/* gethostbyaddr can take a LONG time if the host does not exist.
133	   Assume that if it does not respond in NAMESERVER_TIMEOUT seconds
134	   that something is wrong and do not make the user wait.
135	   gethostbyaddr will continue after a signal, so we have to
136	   jump out of it.
137	   */
138	nameserver_timedout = False;
139	signal (SIGALRM, nameserver_lost);
140	alarm (4);
141	if (setjmp(env) == 0) {
142#endif
143	    hp = gethostbyaddr (auth->address, auth->address_length, af);
144#ifdef SIGALRM
145	}
146	alarm (0);
147#endif
148	}
149	if (hp)
150	  return (hp->h_name);
151#if defined(IPv6) && defined(AF_INET6)
152	else if (af == AF_INET6) {
153	  static char addr[INET6_ADDRSTRLEN+2];
154	  /* Add [] for clarity to distinguish between address & display,
155	     like RFC 2732 for URL's.  Not required, since X display syntax
156	     always ends in :<display>, but makes it easier for people to read
157	     and less confusing to those who expect the RFC 2732 style. */
158	  addr[0] = '[';
159	  if (inet_ntop(af, auth->address, addr + 1, INET6_ADDRSTRLEN) == NULL)
160	    return NULL;
161	  strcat(addr, "]");
162          return addr;
163	}
164#endif
165	else {
166	  return (inet_ntoa(*((struct in_addr *)(auth->address))));
167	}
168    }
169#endif
170#ifdef DNETCONN
171    if (auth->family == FamilyDECnet) {
172	struct dn_naddr *addr_ptr = (struct dn_naddr *) auth->address;
173
174	if ((no_name_lookups == False) &&
175	    (np = getnodebyaddr(addr_ptr->a_addr, addr_ptr->a_len, AF_DECnet))) {
176	    sprintf(nodeaddr, "%s:", np->n_name);
177	} else {
178	    sprintf(nodeaddr, "%s:", dnet_htoa(auth->address));
179	}
180	return(nodeaddr);
181    }
182#endif
183
184    return (NULL);
185}
186
187#if defined(TCPCONN) && (!defined(IPv6) || !defined(AF_INET6))
188/*
189 * cribbed from lib/X/XConnDis.c
190 */
191static Bool
192get_inet_address(char *name, unsigned int *resultp)
193{
194    unsigned int hostinetaddr = inet_addr (name);
195    struct hostent *host_ptr;
196    struct sockaddr_in inaddr;		/* dummy variable for size calcs */
197
198#ifndef INADDR_NONE
199#define INADDR_NONE -1
200#endif
201
202    if (hostinetaddr == INADDR_NONE) {
203	if ((host_ptr = gethostbyname (name)) == NULL) {
204	    /* No such host! */
205	    errno = EINVAL;
206	    return False;
207	}
208	/* Check the address type for an internet host. */
209	if (host_ptr->h_addrtype != AF_INET) {
210	    /* Not an Internet host! */
211	    errno = EPROTOTYPE;
212	    return False;
213	}
214
215	memmove( (char *)&hostinetaddr, (char *)host_ptr->h_addr,
216	      sizeof(inaddr.sin_addr));
217    }
218    *resultp = hostinetaddr;
219    return True;
220}
221#endif
222
223#ifdef DNETCONN
224static Bool get_dnet_address (name, resultp)
225    char *name;
226    struct dn_naddr *resultp;
227{
228    struct dn_naddr *dnaddrp, dnaddr;
229    struct nodeent *np;
230
231    if (dnaddrp = dnet_addr (name)) {	/* stolen from xhost */
232	dnaddr = *dnaddrp;
233    } else {
234	if ((np = getnodebyname (name)) == NULL) return False;
235	dnaddr.a_len = np->n_length;
236	memmove( dnaddr.a_addr, np->n_addr, np->n_length);
237    }
238    *resultp = dnaddr;
239    return True;
240}
241#endif
242
243struct addrlist *get_address_info (
244    int family,
245    char *fulldpyname,
246    int prefix,
247    char *host)
248{
249    struct addrlist *retval = NULL;
250    int len = 0;
251    void *src = NULL;
252#ifdef TCPCONN
253#if defined(IPv6) && defined(AF_INET6)
254    struct addrlist *lastrv = NULL;
255    struct addrinfo *firstai = NULL;
256    struct addrinfo *ai = NULL;
257    struct addrinfo hints;
258#else
259    unsigned int hostinetaddr;
260#endif
261#endif
262#ifdef DNETCONN
263    struct dn_naddr dnaddr;
264#endif
265    char buf[255];
266
267    /*
268     * based on the family, set the pointer src to the start of the address
269     * information to be copied and set len to the number of bytes.
270     */
271    switch (family) {
272      case FamilyLocal:			/* hostname/unix:0 */
273					/* handle unix:0 and :0 specially */
274	if (prefix == 0 && (strncmp (fulldpyname, "unix:", 5) == 0 ||
275			    fulldpyname[0] == ':')) {
276
277	    if (!get_local_hostname (buf, sizeof buf)) {
278		len = 0;
279	    } else {
280		src = buf;
281		len = strlen (buf);
282	    }
283	} else if(prefix == 0 && (strncmp (fulldpyname, "/tmp/launch", 11) == 0)) {
284        /* Use the bundle id (part preceding : in the basename) as our src id */
285        char *c;
286#ifdef HAVE_STRLCPY
287        strlcpy(buf, strrchr(fulldpyname, '/') + 1, sizeof(buf));
288#else
289        strncpy(buf, strrchr(fulldpyname, '/') + 1, sizeof(buf));
290	buf[sizeof(buf) - 1] = '\0';
291#endif
292
293        c = strchr(buf, ':');
294
295        /* In the legacy case with no bundle id, use the full path */
296        if(c == buf) {
297            src = fulldpyname;
298        } else {
299            *c = '\0';
300            src = buf;
301        }
302
303        len = strlen(src);
304    } else {
305	    src = fulldpyname;
306	    len = prefix;
307	}
308	break;
309      case FamilyInternet:		/* host:0 */
310#ifdef TCPCONN
311#if defined(IPv6) && defined(AF_INET6)
312      case FamilyInternet6:
313	memset(&hints, 0, sizeof(hints));
314	hints.ai_family = PF_UNSPEC; /* IPv4 or IPv6 */
315	hints.ai_socktype = SOCK_STREAM; /* only interested in TCP */
316	hints.ai_protocol = 0;
317        if (getaddrinfo(host,NULL,&hints,&firstai) !=0) return NULL;
318	for (ai = firstai; ai != NULL; ai = ai->ai_next) {
319	    struct addrlist *duplicate;
320
321	    if (ai->ai_family == AF_INET) {
322		struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
323		src = &(sin->sin_addr);
324		len = sizeof(sin->sin_addr);
325		family = FamilyInternet;
326	    } else if (ai->ai_family == AF_INET6) {
327		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
328		src = &(sin6->sin6_addr);
329		len = sizeof(sin6->sin6_addr);
330		family = FamilyInternet6;
331	    }
332
333	    for(duplicate = retval; duplicate != NULL; duplicate = duplicate->next) {
334		if(duplicate->family == family && duplicate->len == len &&
335                   memcmp(duplicate->address, src, len) == 0) {
336		    break;
337                }
338	    }
339
340	    if (len > 0 && src != NULL && duplicate == NULL) {
341		struct addrlist *newrv = malloc (sizeof(struct addrlist));
342		if (newrv) {
343		    newrv->address = malloc (len);
344		    if (newrv->address) {
345			memcpy(newrv->address, src, len);
346			newrv->next = NULL;
347			newrv->family = family;
348			newrv->len = len;
349			if (retval == NULL) {
350			    lastrv = retval = newrv;
351			} else {
352			    lastrv->next = newrv;
353			    lastrv = newrv;
354			}
355		    } else {
356			free(newrv);
357		    }
358		}
359	    }
360	    /* reset to avoid copying into list twice */
361	    len = 0;
362	    src = NULL;
363	}
364	freeaddrinfo(firstai);
365	break;
366#else
367	if (!get_inet_address (host, &hostinetaddr)) return NULL;
368	src = (char *) &hostinetaddr;
369	len = 4; /* sizeof inaddr.sin_addr, would fail on Cray */
370	break;
371#endif /* IPv6 */
372#else
373	return NULL;
374#endif
375      case FamilyDECnet:		/* host::0 */
376#ifdef DNETCONN
377	if (!get_dnet_address (host, &dnaddr)) return NULL;
378	src = (char *) &dnaddr;
379	len = (sizeof dnaddr);
380	break;
381#else
382	/* fall through since we don't have code for it */
383#endif
384      default:
385	src = NULL;
386	len = 0;
387    }
388
389    /*
390     * if source was provided, allocate space and copy it
391     */
392    if (len > 0 && src != NULL) {
393	retval = malloc (sizeof(struct addrlist));
394	if (retval) {
395	    retval->address = malloc (len);
396	    if (retval->address) {
397		memcpy(retval->address, src, len);
398		retval->next = NULL;
399		retval->family = family;
400		retval->len = len;
401	    } else {
402		free(retval);
403		retval = NULL;
404	    }
405	}
406    }
407    return retval;
408}
409