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