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