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