xhost.c revision aadd013e
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
163#if defined(__CYGWIN__) || defined(WIN32)
164void sethostent(int x)
165{}
166
167void endhostent()
168{}
169#endif
170
171int
172main(int argc, char *argv[])
173{
174    register char *arg;
175    int i, nhosts = 0;
176    const char *hostname;
177    int nfailed = 0;
178    XHostAddress *list;
179    Bool enabled = False;
180    Display *dpy;
181
182    ProgramName = argv[0];
183
184    if (argc == 2 && !strcmp(argv[1], "-help")) {
185	fprintf(stderr, "usage: %s [[+-]hostname ...]\n", argv[0]);
186	exit(1);
187    }
188
189    if ((dpy = XOpenDisplay(NULL)) == NULL) {
190	fprintf(stderr, "%s:  unable to open display \"%s\"\n",
191		ProgramName, XDisplayName (NULL));
192	exit(1);
193    }
194
195    XSetErrorHandler(local_xerror);
196
197
198    if (argc == 1) {
199	sethostent(1);		/* don't close the data base each time */
200	list = XListHosts(dpy, &nhosts, &enabled);
201	if (enabled)
202	    printf ("access control enabled, only authorized clients can connect\n");
203	else
204	    printf ("access control disabled, clients can connect from any host\n");
205
206	if (nhosts != 0) {
207	    for (i = 0; i < nhosts; i++ )  {
208		hostname = get_hostname(&list[i]);
209		if (hostname) {
210		    switch (list[i].family) {
211		    case FamilyInternet:
212			printf("INET:");
213			break;
214		    case FamilyInternet6:
215			printf("INET6:");
216			break;
217		    case FamilyDECnet:
218			printf("DNET:");
219			break;
220		    case FamilyNetname:
221			printf("NIS:");
222			break;
223		    case FamilyKrb5Principal:
224			printf("KRB:");
225			break;
226		    case FamilyLocalHost:
227			printf("LOCAL:");
228			break;
229		    case FamilyServerInterpreted:
230			printf("SI:");
231			break;
232		    default:
233			printf("<unknown family type %d>:", list[i].family);
234			break;
235		    }
236		    printf ("%s", hostname);
237		} else {
238		    printf ("<unknown address in family %d>",
239			    list[i].family);
240		}
241		if (nameserver_timedout) {
242		    printf("\t(no nameserver response within %d seconds)\n",
243			   NAMESERVER_TIMEOUT);
244		    nameserver_timedout = 0;
245		} else
246		    printf("\n");
247	    }
248	    free(list);
249	    endhostent();
250	}
251	exit(0);
252    }
253
254    for (i = 1; i < argc; i++) {
255	arg = argv[i];
256	if (*arg == '-') {
257
258	    if (!argv[i][1] && ((i+1) == argc)) {
259		printf ("access control enabled, only authorized clients can connect\n");
260		XEnableAccessControl(dpy);
261	    } else {
262		arg = argv[i][1]? &argv[i][1] : argv[++i];
263		if (!change_host (dpy, arg, False)) {
264		    fprintf (stderr, "%s:  bad hostname \"%s\"\n",
265			     ProgramName, arg);
266		    nfailed++;
267		}
268	    }
269	} else {
270	    if (*arg == '+' && !argv[i][1] && ((i+1) == argc)) {
271		printf ("access control disabled, clients can connect from any host\n");
272		XDisableAccessControl(dpy);
273	    } else {
274		if (*arg == '+') {
275		    arg = argv[i][1]? &argv[i][1] : argv[++i];
276		}
277		if (!change_host (dpy, arg, True)) {
278		    fprintf (stderr, "%s:  bad hostname \"%s\"\n",
279			     ProgramName, arg);
280		    nfailed++;
281		}
282	    }
283	}
284    }
285    XCloseDisplay (dpy);	/* does an XSync first */
286    exit(nfailed);
287}
288
289
290
291/*
292 * change_host - edit the list of hosts that may connect to the server;
293 * it parses DECnet names (expo::), Internet addresses (18.30.0.212), or
294 * Internet names (expo.lcs.mit.edu); if 4.3bsd macro h_addr is defined
295 * (from <netdb.h>), it will add or remove all addresses with the given
296 * address.
297 */
298
299static int
300change_host(Display *dpy, char *name, Bool add)
301{
302    XHostAddress ha;
303    char *lname;
304    size_t namelen, i;
305    int family = FamilyWild;
306#ifdef K5AUTH
307    krb5_principal princ;
308    krb5_data kbuf;
309#endif
310#ifdef NEEDSOCKETS
311    static struct in_addr addr;	/* so we can point at it */
312#if defined(IPv6) && defined(AF_INET6)
313    static struct in6_addr addr6; /* so we can point at it */
314#else
315    struct hostent *hp;
316#endif
317#endif
318    char *cp;
319    static const char *add_msg = "being added to access control list";
320    static const char *remove_msg = "being removed from access control list";
321
322    namelen = strlen(name);
323    if ((lname = (char *)malloc(namelen+1)) == NULL) {
324	fprintf (stderr, "%s: malloc bombed in change_host\n", ProgramName);
325	exit (1);
326    }
327    for (i = 0; i < namelen; i++) {
328	lname[i] = tolower(name[i]);
329    }
330    lname[namelen] = '\0';
331    if (!strncmp("inet:", lname, 5)) {
332#ifdef TCPCONN
333	family = FamilyInternet;
334	name += 5;
335#else
336	fprintf (stderr, "%s: not compiled for TCP/IP\n", ProgramName);
337	free(lname);
338	return 0;
339#endif
340    }
341    else if (!strncmp("inet6:", lname, 6)) {
342#if defined(TCPCONN) && defined(IPv6) && defined(AF_INET6)
343	family = FamilyInternet6;
344	name += 6;
345#else
346	fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
347	free(lname);
348	return 0;
349#endif
350    }
351#ifdef ACCEPT_INETV6 /* Allow inetv6 as an alias for inet6 for compatibility
352			with original X11 over IPv6 draft. */
353    else if (!strncmp("inetv6:", lname, 7)) {
354#if defined(TCPCONN) && defined(IPv6) && defined(AF_INET6)
355	family = FamilyInternet6;
356	name += 7;
357#else
358	fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
359	free(lname);
360	return 0;
361#endif
362    }
363#endif /* ACCEPT_INETV6 */
364    else if (!strncmp("dnet:", lname, 5)) {
365	fprintf (stderr, "%s: not compiled for DECnet\n", ProgramName);
366	free(lname);
367	return 0;
368    }
369    else if (!strncmp("nis:", lname, 4)) {
370#ifdef SECURE_RPC
371	family = FamilyNetname;
372	name += 4;
373#else
374	fprintf (stderr, "%s: not compiled for Secure RPC\n", ProgramName);
375	free(lname);
376	return 0;
377#endif
378    }
379    else if (!strncmp("krb:", lname, 4)) {
380#ifdef K5AUTH
381	family = FamilyKrb5Principal;
382	name +=4;
383#else
384	fprintf (stderr, "%s: not compiled for Kerberos 5\n", ProgramName);
385	free(lname);
386	return 0;
387#endif
388    }
389    else if (!strncmp("local:", lname, 6)) {
390	family = FamilyLocalHost;
391    }
392    else if (!strncmp("si:", lname, 3)) {
393	family = FamilyServerInterpreted;
394	name += 3;
395    }
396    if (family == FamilyWild && (cp = strchr(lname, ':'))) {
397	*cp = '\0';
398	fprintf (stderr, "%s: unknown address family \"%s\"\n",
399		 ProgramName, lname);
400	free(lname);
401	return 0;
402    }
403    free(lname);
404
405    if (family == FamilyServerInterpreted) {
406	XServerInterpretedAddress siaddr;
407	int rc;
408
409	cp = strchr(name, ':');
410	if (cp == NULL || cp == name) {
411	    fprintf(stderr,
412	   "%s: type must be specified for server interpreted family \"%s\"\n",
413	      ProgramName, name);
414	    return 0;
415	}
416	siaddr.type = name;
417	siaddr.typelength = cp - name;
418	siaddr.value = ++cp;
419	siaddr.valuelength = strlen(cp);
420	ha.family = FamilyServerInterpreted;
421	ha.address = (char *) &siaddr;
422	if (add)
423	    rc = XAddHost(dpy, &ha);
424	else
425	    rc = XRemoveHost(dpy, &ha);
426	printf( "%s %s%s\n", name, rc == 1 ? "" : "failed when ",
427		add ? add_msg : remove_msg);
428	if (rc != 1)
429	    return 0;
430	return 1;
431    }
432
433#ifdef K5AUTH
434    if (family == FamilyKrb5Principal) {
435	krb5_error_code retval;
436
437	retval = krb5_parse_name(name, &princ);
438	if (retval) {
439	    krb5_init_ets();	/* init krb errs for error_message() */
440	    fprintf(stderr, "%s: cannot parse Kerberos name: %s\n",
441		    ProgramName, error_message(retval));
442	    return 0;
443	}
444	XauKrb5Encode(princ, &kbuf);
445	ha.length = kbuf.length;
446	ha.address = kbuf.data;
447	ha.family = family;
448	if (add)
449	    XAddHost(dpy, &ha);
450	else
451	    XRemoveHost(dpy, &ha);
452	krb5_free_principal(princ);
453	free(kbuf.data);
454	printf( "%s %s\n", name, add ? add_msg : remove_msg);
455	return 1;
456    }
457#endif
458    if (family == FamilyLocalHost) {
459	char empty[] = "";
460	ha.length = 0;
461	ha.address = empty;
462	ha.family = family;
463	if (add)
464	    XAddHost(dpy, &ha);
465	else
466	    XRemoveHost(dpy, &ha);
467	printf( "non-network local connections %s\n", add ? add_msg : remove_msg);
468	return 1;
469    }
470    /*
471     * If it has an '@', it's a netname
472     */
473    if ((family == FamilyNetname && (cp = strchr(name, '@'))) ||
474	(cp = strchr(name, '@'))) {
475        char *netname = name;
476#ifdef SECURE_RPC
477	static char username[MAXNETNAMELEN];
478
479	if (!cp[1]) {
480	    struct passwd *pwd;
481	    static char domainname[128];
482
483	    *cp = '\0';
484	    pwd = getpwnam(name);
485	    if (!pwd) {
486		fprintf(stderr, "no such user \"%s\"\n", name);
487		return 0;
488	    }
489	    getdomainname(domainname, sizeof(domainname));
490	    if (!user2netname(username, pwd->pw_uid, domainname)) {
491		fprintf(stderr, "failed to get netname for \"%s\"\n", name);
492		return 0;
493	    }
494	    netname = username;
495	}
496#endif
497	ha.family = FamilyNetname;
498	ha.length = strlen(netname);
499	ha.address = netname;
500	if (add)
501	    XAddHost (dpy, &ha);
502	else
503	    XRemoveHost (dpy, &ha);
504	if (netname != name)
505	    printf ("%s@ (%s) %s\n", name, netname, add ? add_msg : remove_msg);
506	else
507	    printf ("%s %s\n", netname, add ? add_msg : remove_msg);
508        return 1;
509    }
510#ifdef NEEDSOCKETS
511    /*
512     * First see if inet_aton/inet_addr can grok the name; if so, then use it.
513     */
514    if (((family == FamilyWild) || (family == FamilyInternet)) &&
515#ifdef HAVE_INET_ATON
516	(inet_aton (name, &addr) != 0)
517#else
518	((addr.s_addr = inet_addr(name)) != -1)
519#endif
520        ) {
521	ha.family = FamilyInternet;
522	ha.length = sizeof(addr.s_addr);
523	ha.address = (char *) &addr.s_addr;
524	if (add) {
525	    XAddHost (dpy, &ha);
526	    printf ("%s %s\n", name, add_msg);
527	} else {
528	    XRemoveHost (dpy, &ha);
529	    printf ("%s %s\n", name, remove_msg);
530	}
531	return 1;
532    }
533#if defined(IPv6) && defined(AF_INET6)
534    /*
535     * Check to see if inet_pton() can grok it as an IPv6 address
536     */
537    else if (((family == FamilyWild) || (family == FamilyInternet6)) &&
538	     (inet_pton(AF_INET6, name, &addr6.s6_addr) == 1)) {
539	ha.family = FamilyInternet6;
540	ha.length = sizeof(addr6.s6_addr);
541	ha.address = (char *) &addr6.s6_addr;
542	if (add) {
543	    XAddHost (dpy, &ha);
544	    printf ("%s %s\n", name, add_msg);
545	} else {
546	    XRemoveHost (dpy, &ha);
547	    printf ("%s %s\n", name, remove_msg);
548	}
549	return 1;
550    } else {
551    /*
552     * Is it in the namespace?
553     *
554     * If no family was specified, use both Internet v4 & v6 addresses.
555     * Otherwise, use only addresses matching specified family.
556     */
557	struct addrinfo *addresses;
558	struct addrinfo *a;
559	Bool didit = False;
560
561	if (getaddrinfo(name, NULL, NULL, &addresses) != 0)
562	    return 0;
563
564	for (a = addresses; a != NULL; a = a->ai_next) {
565	    if ( ((a->ai_family == AF_INET) && (family != FamilyInternet6))
566	      || ((a->ai_family == AF_INET6) && (family != FamilyInternet)) ) {
567		char ad[INET6_ADDRSTRLEN];
568		ha.family = XFamily(a->ai_family);
569		if (a->ai_family == AF_INET6) {
570		    ha.address = (char *)
571		      &((struct sockaddr_in6 *) a->ai_addr)->sin6_addr;
572		    ha.length =
573		      sizeof (((struct sockaddr_in6 *) a->ai_addr)->sin6_addr);
574		} else {
575		    ha.address = (char *)
576		      &((struct sockaddr_in *) a->ai_addr)->sin_addr;
577		    ha.length =
578		      sizeof (((struct sockaddr_in *) a->ai_addr)->sin_addr);
579		}
580		inet_ntop(a->ai_family, ha.address, ad, sizeof(ad));
581	/* printf("Family: %d\nLength: %d\n", a->ai_family, ha.length); */
582		/* printf("Address: %s\n", ad); */
583
584		if (add) {
585		    XAddHost (dpy, &ha);
586		} else {
587		    XRemoveHost (dpy, &ha);
588		}
589		didit = True;
590	    }
591	}
592	if (didit == True) {
593	    printf ("%s %s\n", name, add ? add_msg : remove_msg);
594	} else {
595	    const char *familyMsg = "";
596
597	    if (family == FamilyInternet6) {
598		familyMsg = "inet6 ";
599	    } else if (family == FamilyInternet) {
600		familyMsg = "inet ";
601	    }
602
603	    fprintf(stderr, "%s: unable to get %saddress for \"%s\"\n",
604		ProgramName, familyMsg, name);
605	}
606	freeaddrinfo(addresses);
607	return 1;
608    }
609#else /* !IPv6 */
610    /*
611     * Is it in the namespace?
612     */
613    else if (((hp = gethostbyname(name)) == (struct hostent *)NULL)
614	     || hp->h_addrtype != AF_INET) {
615	return 0;
616    } else {
617	ha.family = XFamily(hp->h_addrtype);
618	ha.length = hp->h_length;
619#ifdef h_addr			/* new 4.3bsd version of gethostent */
620    {
621	char **list;
622
623	/* iterate over the hosts */
624	for (list = hp->h_addr_list; *list; list++) {
625	    ha.address = *list;
626	    if (add) {
627		XAddHost (dpy, &ha);
628	    } else {
629		XRemoveHost (dpy, &ha);
630	    }
631	}
632    }
633#else
634	ha.address = hp->h_addr;
635	if (add) {
636	    XAddHost (dpy, &ha);
637	} else {
638	    XRemoveHost (dpy, &ha);
639	}
640#endif
641	printf ("%s %s\n", name, add ? add_msg : remove_msg);
642	return 1;
643    }
644#endif /* IPv6 */
645#else /* NEEDSOCKETS */
646    return 0;
647#endif /* NEEDSOCKETS */
648}
649
650
651/*
652 * get_hostname - Given an internet address, return a name (CHARON.MIT.EDU)
653 * or a string representing the address (18.58.0.13) if the name cannot
654 * be found.
655 */
656
657
658static const char *
659get_hostname(XHostAddress *ha)
660{
661#if defined(TCPCONN) && (!defined(IPv6) || !defined(AF_INET6))
662    static struct hostent *hp = NULL;
663#endif
664#ifdef K5AUTH
665    krb5_principal princ;
666    krb5_data kbuf;
667    char *kname;
668    static char kname_out[255];
669#endif
670#ifdef SIGALRM
671    struct sigaction sa;
672#endif
673
674#ifdef TCPCONN
675#if defined(IPv6) && defined(AF_INET6)
676    if ((ha->family == FamilyInternet) || (ha->family == FamilyInternet6)) {
677	struct sockaddr_storage saddr;
678	static char inetname[NI_MAXHOST];
679	unsigned int saddrlen;
680
681	inetname[0] = '\0';
682	memset(&saddr, 0, sizeof saddr);
683	if (ha->family == FamilyInternet) {
684	    struct sockaddr_in *sin = (struct sockaddr_in *) &saddr;
685#ifdef BSD44SOCKETS
686	    sin->sin_len = sizeof(struct sockaddr_in);
687#endif
688	    sin->sin_family = AF_INET;
689	    sin->sin_port = 0;
690	    if (sizeof(sin->sin_addr) > ha->length)
691		return "";
692	    memcpy(&sin->sin_addr, ha->address, sizeof(sin->sin_addr));
693	    saddrlen = sizeof(struct sockaddr_in);
694	} else {
695	    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &saddr;
696#ifdef SIN6_LEN
697	    sin6->sin6_len = sizeof(struct sockaddr_in6);
698#endif
699	    sin6->sin6_family = AF_INET6;
700	    sin6->sin6_port = 0;
701	    if (sizeof(sin6->sin6_addr) > ha->length)
702		return "";
703	    memcpy(&sin6->sin6_addr, ha->address, sizeof(sin6->sin6_addr));
704	    saddrlen = sizeof(struct sockaddr_in6);
705	}
706
707	/* gethostbyaddr can take a LONG time if the host does not exist.
708	   Assume that if it does not respond in NAMESERVER_TIMEOUT seconds
709	   that something is wrong and do not make the user wait.
710	   gethostbyaddr will continue after a signal, so we have to
711	   jump out of it.
712	   */
713#ifdef SIGALRM
714	memset(&sa, 0, sizeof sa);
715	sa.sa_handler = nameserver_lost;
716	sa.sa_flags = 0;	/* don't restart syscalls */
717	sigaction(SIGALRM, &sa, NULL);
718	alarm(NAMESERVER_TIMEOUT);
719#endif
720	getnameinfo((struct sockaddr *) &saddr, saddrlen, inetname,
721		    sizeof(inetname), NULL, 0, 0);
722#ifdef SIGALRM
723	alarm(0);
724#endif
725	if (nameserver_timedout || inetname[0] == '\0')
726	    inet_ntop(((struct sockaddr *)&saddr)->sa_family, ha->address,
727		inetname, sizeof(inetname));
728	return inetname;
729    }
730#else
731    if (ha->family == FamilyInternet) {
732	/* gethostbyaddr can take a LONG time if the host does not exist.
733	   Assume that if it does not respond in NAMESERVER_TIMEOUT seconds
734	   that something is wrong and do not make the user wait.
735	   gethostbyaddr will continue after a signal, so we have to
736	   jump out of it.
737	   */
738#ifdef SIGALRM
739	memset(&sa, 0, sizeof sa);
740	sa.sa_handler = nameserver_lost;
741	sa.sa_flags = 0;	/* don't restart syscalls */
742	sigaction(SIGALRM, &sa, NULL);
743	alarm(4);
744#endif
745	hp = gethostbyaddr (ha->address, ha->length, AF_INET);
746#ifdef SIGALRM
747	alarm(0);
748#endif
749	if (hp)
750	    return (hp->h_name);
751	else return (inet_ntoa(*((struct in_addr *)(ha->address))));
752    }
753#endif /* IPv6 */
754#endif
755    if (ha->family == FamilyNetname) {
756	static char netname[512];
757	int len;
758#ifdef SECURE_RPC
759	int gidlen;
760	uid_t uid;
761	gid_t gid, gidlist[NGROUPS_MAX];
762#endif
763
764	if (ha->length < sizeof(netname) - 1)
765	    len = ha->length;
766	else
767	    len = sizeof(netname) - 1;
768	memmove( netname, ha->address, len);
769	netname[len] = '\0';
770#ifdef SECURE_RPC
771	if (netname2user(netname, &uid, &gid, &gidlen, gidlist)) {
772	    struct passwd *pwd;
773
774	    pwd = getpwuid(uid);
775	    if (pwd)
776		snprintf(netname, sizeof(netname), "%s@ (%*.*s)",
777			 pwd->pw_name, ha->length, ha->length, ha->address);
778	}
779#endif
780	return (netname);
781    }
782#ifdef K5AUTH
783    if (ha->family == FamilyKrb5Principal) {
784	kbuf.data = ha->address;
785	kbuf.length = ha->length;
786	XauKrb5Decode(kbuf, &princ);
787	krb5_unparse_name(princ, &kname);
788	krb5_free_principal(princ);
789	strncpy(kname_out, kname, sizeof (kname_out));
790	free(kname);
791	return kname_out;
792    }
793#endif
794    if (ha->family == FamilyLocalHost) {
795	return "";
796    }
797    if (ha->family == FamilyServerInterpreted) {
798	XServerInterpretedAddress *sip;
799	static char *addressString;
800	static size_t addressStringSize;
801	size_t neededSize;
802
803	sip = (XServerInterpretedAddress *) ha->address;
804	neededSize = sip->typelength + sip->valuelength + 2;
805
806	if (addressStringSize < neededSize) {
807	    if (addressString != NULL) {
808		free(addressString);
809	    }
810	    addressStringSize = neededSize;
811	    addressString = malloc(addressStringSize);
812	}
813	if (addressString != NULL) {
814	    char *cp = addressString;
815
816	    memcpy(cp, sip->type, sip->typelength);
817	    cp += sip->typelength;
818	    *cp++ = ':';
819	    memcpy(cp, sip->value, sip->valuelength);
820	    cp += sip->valuelength;
821	    *cp = '\0';
822	}
823	return addressString;
824    }
825    return (NULL);
826}
827
828/*ARGUSED*/
829static void
830nameserver_lost(_X_UNUSED int sig)
831{
832    nameserver_timedout = 1;
833}
834
835/*
836 * local_xerror - local non-fatal error handling routine. If the error was
837 * that an X_GetHosts request for an unknown address format was received, just
838 * return, otherwise print the normal error message and continue.
839 */
840static int
841local_xerror(Display *dpy, XErrorEvent *rep)
842{
843    if ((rep->error_code == BadAccess) && (rep->request_code == X_ChangeHosts)) {
844	fprintf (stderr,
845		 "%s:  must be on local machine to add or remove hosts.\n",
846		 ProgramName);
847	return 1;
848    } else if ((rep->error_code == BadAccess) &&
849	       (rep->request_code == X_SetAccessControl)) {
850	fprintf (stderr,
851	"%s:  must be on local machine to enable or disable access control.\n",
852		 ProgramName);
853	return 1;
854    } else if ((rep->error_code == BadValue) &&
855	       (rep->request_code == X_ListHosts)) {
856	return 1;
857    }
858
859    XmuPrintDefaultErrorMessage (dpy, rep, stderr);
860    return 0;
861}
862