xhost.c revision 81440437
1/*
2 * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23/*
24
25Copyright 1985, 1986, 1987, 1998  The Open Group
26
27All rights reserved.
28
29Permission is hereby granted, free of charge, to any person obtaining a
30copy of this software and associated documentation files (the
31"Software"), to deal in the Software without restriction, including
32without limitation the rights to use, copy, modify, merge, publish,
33distribute, and/or sell copies of the Software, and to permit persons
34to whom the Software is furnished to do so, provided that the above
35copyright notice(s) and this permission notice appear in all copies of
36the Software and that both the above copyright notice(s) and this
37permission notice appear in supporting documentation.
38
39THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
40OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
41MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
42OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
43HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
44INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
45FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
46NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
47WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
48
49Except as contained in this notice, the name of a copyright holder
50shall not be used in advertising or otherwise to promote the sale, use
51or other dealings in this Software without prior written authorization
52of the copyright holder.
53
54X Window System is a trademark of The Open Group.
55
56*/
57
58#ifdef HAVE_CONFIG_H
59#include "config.h"
60#endif
61
62#ifdef TCPCONN
63#define NEEDSOCKETS
64#endif
65#ifdef UNIXCONN
66#define NEEDSOCKETS
67#endif
68
69#include <X11/Xlib.h>
70#include <X11/Xos.h>
71#include <X11/Xproto.h>
72#include <X11/Xfuncs.h>
73#include <stdio.h>
74#include <stdlib.h>
75#include <signal.h>
76#include <ctype.h>
77#include <X11/Xauth.h>
78#include <X11/Xmu/Error.h>
79#include <stdlib.h>
80
81#ifdef NEEDSOCKETS
82#ifdef WIN32
83#include <X11/Xwinsock.h>
84#else
85#include <sys/socket.h>
86#include <netdb.h>
87#include <netinet/in.h>
88#endif
89#endif /* NEEDSOCKETS */
90
91#ifndef WIN32
92#include <arpa/inet.h>
93#endif
94
95
96#ifdef SECURE_RPC
97#include <pwd.h>
98#include <rpc/rpc.h>
99#ifdef X_POSIX_C_SOURCE
100#define _POSIX_C_SOURCE X_POSIX_C_SOURCE
101#include <limits.h>
102#undef _POSIX_C_SOURCE
103#else
104#ifdef _POSIX_SOURCE
105#include <limits.h>
106#else
107#define _POSIX_SOURCE
108#include <limits.h>
109#undef _POSIX_SOURCE
110#endif
111#endif
112#ifndef NGROUPS_MAX
113#include <sys/param.h>
114#define NGROUPS_MAX NGROUPS
115#endif
116#ifdef sun
117/* Go figure, there's no getdomainname() prototype available */
118extern int getdomainname(char *name, size_t len);
119#endif
120#endif
121
122static int change_host(Display *dpy, char *name, Bool add);
123static const char *get_hostname(XHostAddress *ha);
124static int local_xerror(Display *dpy, XErrorEvent *rep);
125static void nameserver_lost(int sig);
126
127#define NAMESERVER_TIMEOUT 5	/* time to wait for nameserver */
128
129static volatile int nameserver_timedout;
130
131static char *ProgramName;
132
133#ifdef NEEDSOCKETS
134static int
135XFamily(int af)
136{
137    unsigned int i;
138    static struct _familyMap {
139	int af, xf;
140    } familyMap[] = {
141#ifdef	AF_DECnet
142        { AF_DECnet, FamilyDECnet },
143#endif
144#ifdef	AF_CHAOS
145        { AF_CHAOS, FamilyChaos },
146#endif
147#ifdef	AF_INET
148        { AF_INET, FamilyInternet },
149#if defined(IPv6) && defined(AF_INET6)
150        { AF_INET6, FamilyInternet6 },
151#endif
152#endif
153};
154
155#define FAMILIES ((sizeof familyMap)/(sizeof familyMap[0]))
156
157    for (i = 0; i < FAMILIES; i++)
158	if (familyMap[i].af == af) return familyMap[i].xf;
159    return -1;
160}
161#endif /* NEEDSOCKETS */
162
163int
164main(int argc, char *argv[])
165{
166    register char *arg;
167    int i, nhosts = 0;
168    const char *hostname;
169    int nfailed = 0;
170    XHostAddress *list;
171    Bool enabled = False;
172    Display *dpy;
173
174    ProgramName = argv[0];
175
176    if (argc == 2 && !strcmp(argv[1], "-help")) {
177	fprintf(stderr, "usage: %s [[+-]hostname ...]\n", argv[0]);
178	exit(1);
179    }
180
181    if ((dpy = XOpenDisplay(NULL)) == NULL) {
182	fprintf(stderr, "%s:  unable to open display \"%s\"\n",
183		ProgramName, XDisplayName (NULL));
184	exit(1);
185    }
186
187    XSetErrorHandler(local_xerror);
188
189
190    if (argc == 1) {
191	sethostent(1);		/* don't close the data base each time */
192	list = XListHosts(dpy, &nhosts, &enabled);
193	if (enabled)
194	    printf ("access control enabled, only authorized clients can connect\n");
195	else
196	    printf ("access control disabled, clients can connect from any host\n");
197
198	if (nhosts != 0) {
199	    for (i = 0; i < nhosts; i++ )  {
200		hostname = get_hostname(&list[i]);
201		if (hostname) {
202		    switch (list[i].family) {
203		    case FamilyInternet:
204			printf("INET:");
205			break;
206		    case FamilyInternet6:
207			printf("INET6:");
208			break;
209		    case FamilyDECnet:
210			printf("DNET:");
211			break;
212		    case FamilyNetname:
213			printf("NIS:");
214			break;
215		    case FamilyKrb5Principal:
216			printf("KRB:");
217			break;
218		    case FamilyLocalHost:
219			printf("LOCAL:");
220			break;
221		    case FamilyServerInterpreted:
222			printf("SI:");
223			break;
224		    default:
225			printf("<unknown family type %d>:", list[i].family);
226			break;
227		    }
228		    printf ("%s", hostname);
229		} else {
230		    printf ("<unknown address in family %d>",
231			    list[i].family);
232		}
233		if (nameserver_timedout) {
234		    printf("\t(no nameserver response within %d seconds)\n",
235			   NAMESERVER_TIMEOUT);
236		    nameserver_timedout = 0;
237		} else
238		    printf("\n");
239	    }
240	    free(list);
241	    endhostent();
242	}
243	exit(0);
244    }
245
246    for (i = 1; i < argc; i++) {
247	arg = argv[i];
248	if (*arg == '-') {
249
250	    if (!argv[i][1] && ((i+1) == argc)) {
251		printf ("access control enabled, only authorized clients can connect\n");
252		XEnableAccessControl(dpy);
253	    } else {
254		arg = argv[i][1]? &argv[i][1] : argv[++i];
255		if (!change_host (dpy, arg, False)) {
256		    fprintf (stderr, "%s:  bad hostname \"%s\"\n",
257			     ProgramName, arg);
258		    nfailed++;
259		}
260	    }
261	} else {
262	    if (*arg == '+' && !argv[i][1] && ((i+1) == argc)) {
263		printf ("access control disabled, clients can connect from any host\n");
264		XDisableAccessControl(dpy);
265	    } else {
266		if (*arg == '+') {
267		    arg = argv[i][1]? &argv[i][1] : argv[++i];
268		}
269		if (!change_host (dpy, arg, True)) {
270		    fprintf (stderr, "%s:  bad hostname \"%s\"\n",
271			     ProgramName, arg);
272		    nfailed++;
273		}
274	    }
275	}
276    }
277    XCloseDisplay (dpy);	/* does an XSync first */
278    exit(nfailed);
279}
280
281
282
283/*
284 * change_host - edit the list of hosts that may connect to the server;
285 * it parses DECnet names (expo::), Internet addresses (18.30.0.212), or
286 * Internet names (expo.lcs.mit.edu); if 4.3bsd macro h_addr is defined
287 * (from <netdb.h>), it will add or remove all addresses with the given
288 * address.
289 */
290
291static int
292change_host(Display *dpy, char *name, Bool add)
293{
294    XHostAddress ha;
295    char *lname;
296    size_t namelen, i;
297    int family = FamilyWild;
298#ifdef K5AUTH
299    krb5_principal princ;
300    krb5_data kbuf;
301#endif
302#ifdef NEEDSOCKETS
303    static struct in_addr addr;	/* so we can point at it */
304#if defined(IPv6) && defined(AF_INET6)
305    static struct in6_addr addr6; /* so we can point at it */
306#else
307    struct hostent *hp;
308#endif
309#endif
310    char *cp;
311    static const char *add_msg = "being added to access control list";
312    static const char *remove_msg = "being removed from access control list";
313
314    namelen = strlen(name);
315    if ((lname = (char *)malloc(namelen+1)) == NULL) {
316	fprintf (stderr, "%s: malloc bombed in change_host\n", ProgramName);
317	exit (1);
318    }
319    for (i = 0; i < namelen; i++) {
320	lname[i] = tolower(name[i]);
321    }
322    lname[namelen] = '\0';
323    if (!strncmp("inet:", lname, 5)) {
324#ifdef TCPCONN
325	family = FamilyInternet;
326	name += 5;
327#else
328	fprintf (stderr, "%s: not compiled for TCP/IP\n", ProgramName);
329	free(lname);
330	return 0;
331#endif
332    }
333    else if (!strncmp("inet6:", lname, 6)) {
334#if defined(TCPCONN) && defined(IPv6) && defined(AF_INET6)
335	family = FamilyInternet6;
336	name += 6;
337#else
338	fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
339	free(lname);
340	return 0;
341#endif
342    }
343#ifdef ACCEPT_INETV6 /* Allow inetv6 as an alias for inet6 for compatibility
344			with original X11 over IPv6 draft. */
345    else if (!strncmp("inetv6:", lname, 7)) {
346#if defined(TCPCONN) && defined(IPv6) && defined(AF_INET6)
347	family = FamilyInternet6;
348	name += 7;
349#else
350	fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
351	free(lname);
352	return 0;
353#endif
354    }
355#endif /* ACCEPT_INETV6 */
356    else if (!strncmp("dnet:", lname, 5)) {
357	fprintf (stderr, "%s: not compiled for DECnet\n", ProgramName);
358	free(lname);
359	return 0;
360    }
361    else if (!strncmp("nis:", lname, 4)) {
362#ifdef SECURE_RPC
363	family = FamilyNetname;
364	name += 4;
365#else
366	fprintf (stderr, "%s: not compiled for Secure RPC\n", ProgramName);
367	free(lname);
368	return 0;
369#endif
370    }
371    else if (!strncmp("krb:", lname, 4)) {
372#ifdef K5AUTH
373	family = FamilyKrb5Principal;
374	name +=4;
375#else
376	fprintf (stderr, "%s: not compiled for Kerberos 5\n", ProgramName);
377	free(lname);
378	return 0;
379#endif
380    }
381    else if (!strncmp("local:", lname, 6)) {
382	family = FamilyLocalHost;
383    }
384    else if (!strncmp("si:", lname, 3)) {
385	family = FamilyServerInterpreted;
386	name += 3;
387    }
388    if (family == FamilyWild && (cp = strchr(lname, ':'))) {
389	*cp = '\0';
390	fprintf (stderr, "%s: unknown address family \"%s\"\n",
391		 ProgramName, lname);
392	free(lname);
393	return 0;
394    }
395    free(lname);
396
397    if (family == FamilyServerInterpreted) {
398	XServerInterpretedAddress siaddr;
399	int rc;
400
401	cp = strchr(name, ':');
402	if (cp == NULL || cp == name) {
403	    fprintf(stderr,
404	   "%s: type must be specified for server interpreted family \"%s\"\n",
405	      ProgramName, name);
406	    return 0;
407	}
408	siaddr.type = name;
409	siaddr.typelength = cp - name;
410	siaddr.value = ++cp;
411	siaddr.valuelength = strlen(cp);
412	ha.family = FamilyServerInterpreted;
413	ha.address = (char *) &siaddr;
414	if (add)
415	    rc = XAddHost(dpy, &ha);
416	else
417	    rc = XRemoveHost(dpy, &ha);
418	printf( "%s %s%s\n", name, rc == 1 ? "" : "failed when ",
419		add ? add_msg : remove_msg);
420	if (rc != 1)
421	    return 0;
422	return 1;
423    }
424
425#ifdef K5AUTH
426    if (family == FamilyKrb5Principal) {
427	krb5_error_code retval;
428
429	retval = krb5_parse_name(name, &princ);
430	if (retval) {
431	    krb5_init_ets();	/* init krb errs for error_message() */
432	    fprintf(stderr, "%s: cannot parse Kerberos name: %s\n",
433		    ProgramName, error_message(retval));
434	    return 0;
435	}
436	XauKrb5Encode(princ, &kbuf);
437	ha.length = kbuf.length;
438	ha.address = kbuf.data;
439	ha.family = family;
440	if (add)
441	    XAddHost(dpy, &ha);
442	else
443	    XRemoveHost(dpy, &ha);
444	krb5_free_principal(princ);
445	free(kbuf.data);
446	printf( "%s %s\n", name, add ? add_msg : remove_msg);
447	return 1;
448    }
449#endif
450    if (family == FamilyLocalHost) {
451	char empty[] = "";
452	ha.length = 0;
453	ha.address = empty;
454	ha.family = family;
455	if (add)
456	    XAddHost(dpy, &ha);
457	else
458	    XRemoveHost(dpy, &ha);
459	printf( "non-network local connections %s\n", add ? add_msg : remove_msg);
460	return 1;
461    }
462    /*
463     * If it has an '@', it's a netname
464     */
465    if ((family == FamilyNetname && (cp = strchr(name, '@'))) ||
466	(cp = strchr(name, '@'))) {
467        char *netname = name;
468#ifdef SECURE_RPC
469	static char username[MAXNETNAMELEN];
470
471	if (!cp[1]) {
472	    struct passwd *pwd;
473	    static char domainname[128];
474
475	    *cp = '\0';
476	    pwd = getpwnam(name);
477	    if (!pwd) {
478		fprintf(stderr, "no such user \"%s\"\n", name);
479		return 0;
480	    }
481	    getdomainname(domainname, sizeof(domainname));
482	    if (!user2netname(username, pwd->pw_uid, domainname)) {
483		fprintf(stderr, "failed to get netname for \"%s\"\n", name);
484		return 0;
485	    }
486	    netname = username;
487	}
488#endif
489	ha.family = FamilyNetname;
490	ha.length = strlen(netname);
491	ha.address = netname;
492	if (add)
493	    XAddHost (dpy, &ha);
494	else
495	    XRemoveHost (dpy, &ha);
496	if (netname != name)
497	    printf ("%s@ (%s) %s\n", name, netname, add ? add_msg : remove_msg);
498	else
499	    printf ("%s %s\n", netname, add ? add_msg : remove_msg);
500        return 1;
501    }
502#ifdef NEEDSOCKETS
503    /*
504     * First see if inet_addr() can grok the name; if so, then use it.
505     */
506    if (((family == FamilyWild) || (family == FamilyInternet)) &&
507	((addr.s_addr = inet_addr(name)) != -1)) {
508	ha.family = FamilyInternet;
509	ha.length = 4;		/* but for Cray would be sizeof(addr.s_addr) */
510	ha.address = (char *)&addr; /* but for Cray would be &addr.s_addr */
511	if (add) {
512	    XAddHost (dpy, &ha);
513	    printf ("%s %s\n", name, add_msg);
514	} else {
515	    XRemoveHost (dpy, &ha);
516	    printf ("%s %s\n", name, remove_msg);
517	}
518	return 1;
519    }
520#if defined(IPv6) && defined(AF_INET6)
521    /*
522     * Check to see if inet_pton() can grok it as an IPv6 address
523     */
524    else if (((family == FamilyWild) || (family == FamilyInternet6)) &&
525	     (inet_pton(AF_INET6, name, &addr6.s6_addr) == 1)) {
526	ha.family = FamilyInternet6;
527	ha.length = sizeof(addr6.s6_addr);
528	ha.address = (char *) &addr6.s6_addr;
529	if (add) {
530	    XAddHost (dpy, &ha);
531	    printf ("%s %s\n", name, add_msg);
532	} else {
533	    XRemoveHost (dpy, &ha);
534	    printf ("%s %s\n", name, remove_msg);
535	}
536	return 1;
537    } else {
538    /*
539     * Is it in the namespace?
540     *
541     * If no family was specified, use both Internet v4 & v6 addresses.
542     * Otherwise, use only addresses matching specified family.
543     */
544	struct addrinfo *addresses;
545	struct addrinfo *a;
546	Bool didit = False;
547
548	if (getaddrinfo(name, NULL, NULL, &addresses) != 0)
549	    return 0;
550
551	for (a = addresses; a != NULL; a = a->ai_next) {
552	    if ( ((a->ai_family == AF_INET) && (family != FamilyInternet6))
553	      || ((a->ai_family == AF_INET6) && (family != FamilyInternet)) ) {
554		char ad[INET6_ADDRSTRLEN];
555		ha.family = XFamily(a->ai_family);
556		if (a->ai_family == AF_INET6) {
557		    ha.address = (char *)
558		      &((struct sockaddr_in6 *) a->ai_addr)->sin6_addr;
559		    ha.length =
560		      sizeof (((struct sockaddr_in6 *) a->ai_addr)->sin6_addr);
561		} else {
562		    ha.address = (char *)
563		      &((struct sockaddr_in *) a->ai_addr)->sin_addr;
564		    ha.length =
565		      sizeof (((struct sockaddr_in *) a->ai_addr)->sin_addr);
566		}
567		inet_ntop(a->ai_family, ha.address, ad, sizeof(ad));
568	/* printf("Family: %d\nLength: %d\n", a->ai_family, ha.length); */
569		/* printf("Address: %s\n", ad); */
570
571		if (add) {
572		    XAddHost (dpy, &ha);
573		} else {
574		    XRemoveHost (dpy, &ha);
575		}
576		didit = True;
577	    }
578	}
579	if (didit == True) {
580	    printf ("%s %s\n", name, add ? add_msg : remove_msg);
581	} else {
582	    const char *familyMsg = "";
583
584	    if (family == FamilyInternet6) {
585		familyMsg = "inet6 ";
586	    } else if (family == FamilyInternet) {
587		familyMsg = "inet ";
588	    }
589
590	    fprintf(stderr, "%s: unable to get %saddress for \"%s\"\n",
591		ProgramName, familyMsg, name);
592	}
593	freeaddrinfo(addresses);
594	return 1;
595    }
596#else /* !IPv6 */
597    /*
598     * Is it in the namespace?
599     */
600    else if (((hp = gethostbyname(name)) == (struct hostent *)NULL)
601	     || hp->h_addrtype != AF_INET) {
602	return 0;
603    } else {
604	ha.family = XFamily(hp->h_addrtype);
605	ha.length = hp->h_length;
606#ifdef h_addr			/* new 4.3bsd version of gethostent */
607    {
608	char **list;
609
610	/* iterate over the hosts */
611	for (list = hp->h_addr_list; *list; list++) {
612	    ha.address = *list;
613	    if (add) {
614		XAddHost (dpy, &ha);
615	    } else {
616		XRemoveHost (dpy, &ha);
617	    }
618	}
619    }
620#else
621	ha.address = hp->h_addr;
622	if (add) {
623	    XAddHost (dpy, &ha);
624	} else {
625	    XRemoveHost (dpy, &ha);
626	}
627#endif
628	printf ("%s %s\n", name, add ? add_msg : remove_msg);
629	return 1;
630    }
631#endif /* IPv6 */
632#else /* NEEDSOCKETS */
633    return 0;
634#endif /* NEEDSOCKETS */
635}
636
637
638/*
639 * get_hostname - Given an internet address, return a name (CHARON.MIT.EDU)
640 * or a string representing the address (18.58.0.13) if the name cannot
641 * be found.
642 */
643
644
645static const char *
646get_hostname(XHostAddress *ha)
647{
648#if defined(TCPCONN) && (!defined(IPv6) || !defined(AF_INET6))
649    static struct hostent *hp = NULL;
650#endif
651#ifdef K5AUTH
652    krb5_principal princ;
653    krb5_data kbuf;
654    char *kname;
655    static char kname_out[255];
656#endif
657#ifdef SIGALRM
658    struct sigaction sa;
659#endif
660
661#ifdef TCPCONN
662#if defined(IPv6) && defined(AF_INET6)
663    if ((ha->family == FamilyInternet) || (ha->family == FamilyInternet6)) {
664	struct sockaddr_storage saddr;
665	static char inetname[NI_MAXHOST];
666	unsigned int saddrlen;
667
668	inetname[0] = '\0';
669	memset(&saddr, 0, sizeof saddr);
670	if (ha->family == FamilyInternet) {
671	    struct sockaddr_in *sin = (struct sockaddr_in *) &saddr;
672#ifdef BSD44SOCKETS
673	    sin->sin_len = sizeof(struct sockaddr_in);
674#endif
675	    sin->sin_family = AF_INET;
676	    sin->sin_port = 0;
677	    memcpy(&sin->sin_addr, ha->address, sizeof(sin->sin_addr));
678	    saddrlen = sizeof(struct sockaddr_in);
679	} else {
680	    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &saddr;
681#ifdef SIN6_LEN
682	    sin6->sin6_len = sizeof(struct sockaddr_in6);
683#endif
684	    sin6->sin6_family = AF_INET6;
685	    sin6->sin6_port = 0;
686	    memcpy(&sin6->sin6_addr, ha->address, sizeof(sin6->sin6_addr));
687	    saddrlen = sizeof(struct sockaddr_in6);
688	}
689
690	/* gethostbyaddr can take a LONG time if the host does not exist.
691	   Assume that if it does not respond in NAMESERVER_TIMEOUT seconds
692	   that something is wrong and do not make the user wait.
693	   gethostbyaddr will continue after a signal, so we have to
694	   jump out of it.
695	   */
696#ifdef SIGALRM
697	memset(&sa, 0, sizeof sa);
698	sa.sa_handler = nameserver_lost;
699	sa.sa_flags = 0;	/* don't restart syscalls */
700	sigaction(SIGALRM, &sa, NULL);
701	alarm(NAMESERVER_TIMEOUT);
702#endif
703	getnameinfo((struct sockaddr *) &saddr, saddrlen, inetname,
704		    sizeof(inetname), NULL, 0, 0);
705#ifdef SIGALRM
706	alarm(0);
707#endif
708	if (nameserver_timedout || inetname[0] == '\0')
709	    inet_ntop(((struct sockaddr *)&saddr)->sa_family, ha->address,
710		inetname, sizeof(inetname));
711	return inetname;
712    }
713#else
714    if (ha->family == FamilyInternet) {
715	/* gethostbyaddr can take a LONG time if the host does not exist.
716	   Assume that if it does not respond in NAMESERVER_TIMEOUT seconds
717	   that something is wrong and do not make the user wait.
718	   gethostbyaddr will continue after a signal, so we have to
719	   jump out of it.
720	   */
721#ifdef SIGALRM
722	memset(&sa, 0, sizeof sa);
723	sa.sa_handler = nameserver_lost;
724	sa.sa_flags = 0;	/* don't restart syscalls */
725	sigaction(SIGALRM, &sa, NULL);
726	alarm(4);
727#endif
728	hp = gethostbyaddr (ha->address, ha->length, AF_INET);
729#ifdef SIGALRM
730	alarm(0);
731#endif
732	if (hp)
733	    return (hp->h_name);
734	else return (inet_ntoa(*((struct in_addr *)(ha->address))));
735    }
736#endif /* IPv6 */
737#endif
738    if (ha->family == FamilyNetname) {
739	static char netname[512];
740	int len;
741#ifdef SECURE_RPC
742	int gidlen;
743	uid_t uid;
744	gid_t gid, gidlist[NGROUPS_MAX];
745#endif
746
747	if (ha->length < sizeof(netname) - 1)
748	    len = ha->length;
749	else
750	    len = sizeof(netname) - 1;
751	memmove( netname, ha->address, len);
752	netname[len] = '\0';
753#ifdef SECURE_RPC
754	if (netname2user(netname, &uid, &gid, &gidlen, gidlist)) {
755	    struct passwd *pwd;
756
757	    pwd = getpwuid(uid);
758	    if (pwd)
759		snprintf(netname, sizeof(netname), "%s@ (%*.*s)",
760			 pwd->pw_name, ha->length, ha->length, ha->address);
761	}
762#endif
763	return (netname);
764    }
765#ifdef K5AUTH
766    if (ha->family == FamilyKrb5Principal) {
767	kbuf.data = ha->address;
768	kbuf.length = ha->length;
769	XauKrb5Decode(kbuf, &princ);
770	krb5_unparse_name(princ, &kname);
771	krb5_free_principal(princ);
772	strncpy(kname_out, kname, sizeof (kname_out));
773	free(kname);
774	return kname_out;
775    }
776#endif
777    if (ha->family == FamilyLocalHost) {
778	return "";
779    }
780    if (ha->family == FamilyServerInterpreted) {
781	XServerInterpretedAddress *sip;
782	static char *addressString;
783	static size_t addressStringSize;
784	size_t neededSize;
785
786	sip = (XServerInterpretedAddress *) ha->address;
787	neededSize = sip->typelength + sip->valuelength + 2;
788
789	if (addressStringSize < neededSize) {
790	    if (addressString != NULL) {
791		free(addressString);
792	    }
793	    addressStringSize = neededSize;
794	    addressString = malloc(addressStringSize);
795	}
796	if (addressString != NULL) {
797	    char *cp = addressString;
798
799	    memcpy(cp, sip->type, sip->typelength);
800	    cp += sip->typelength;
801	    *cp++ = ':';
802	    memcpy(cp, sip->value, sip->valuelength);
803	    cp += sip->valuelength;
804	    *cp = '\0';
805	}
806	return addressString;
807    }
808    return (NULL);
809}
810
811/*ARGUSED*/
812static void
813nameserver_lost(_X_UNUSED int sig)
814{
815    nameserver_timedout = 1;
816}
817
818/*
819 * local_xerror - local non-fatal error handling routine. If the error was
820 * that an X_GetHosts request for an unknown address format was received, just
821 * return, otherwise print the normal error message and continue.
822 */
823static int
824local_xerror(Display *dpy, XErrorEvent *rep)
825{
826    if ((rep->error_code == BadAccess) && (rep->request_code == X_ChangeHosts)) {
827	fprintf (stderr,
828		 "%s:  must be on local machine to add or remove hosts.\n",
829		 ProgramName);
830	return 1;
831    } else if ((rep->error_code == BadAccess) &&
832	       (rep->request_code == X_SetAccessControl)) {
833	fprintf (stderr,
834	"%s:  must be on local machine to enable or disable access control.\n",
835		 ProgramName);
836	return 1;
837    } else if ((rep->error_code == BadValue) &&
838	       (rep->request_code == X_ListHosts)) {
839	return 1;
840    }
841
842    XmuPrintDefaultErrorMessage (dpy, rep, stderr);
843    return 0;
844}
845
846#if defined(__CYGWIN__) || defined(WIN32)
847void sethostent(int x)
848{}
849
850void endhostent()
851{}
852#endif
853
854