Tizen 2.0 Release
[framework/uifw/xorg/util/x11-xserver-utils.git] / xhost / xhost.c
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
25 Copyright 1985, 1986, 1987, 1998  The Open Group
26
27 All rights reserved.
28
29 Permission is hereby granted, free of charge, to any person obtaining a
30 copy of this software and associated documentation files (the
31 "Software"), to deal in the Software without restriction, including
32 without limitation the rights to use, copy, modify, merge, publish,
33 distribute, and/or sell copies of the Software, and to permit persons
34 to whom the Software is furnished to do so, provided that the above
35 copyright notice(s) and this permission notice appear in all copies of
36 the Software and that both the above copyright notice(s) and this
37 permission notice appear in supporting documentation.
38
39 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
40 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
41 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
42 OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
43 HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
44 INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
45 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
46 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
47 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
48
49 Except as contained in this notice, the name of a copyright holder
50 shall not be used in advertising or otherwise to promote the sale, use
51 or other dealings in this Software without prior written authorization
52 of the copyright holder.
53
54 X 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
89 typedef unsigned short unsign16;
90 typedef unsigned long unsign32;
91 typedef short sign16;
92 typedef 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 */
111 extern 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 */
141 extern int getdomainname(char *name, size_t len);
142 #endif
143 #endif
144
145 static int change_host(Display *dpy, char *name, Bool add);
146 static const char *get_hostname(XHostAddress *ha);
147 static 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 */
158 static signal_t nameserver_lost(int sig);
159
160 #define NAMESERVER_TIMEOUT 5    /* time to wait for nameserver */
161
162 static volatile int nameserver_timedout;
163
164 static char *ProgramName;
165
166 #ifdef NEEDSOCKETS
167 static int 
168 XFamily(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
196 static Display *dpy;
197
198 int
199 main(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
334 static int 
335 change_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
726 jmp_buf env;
727 #endif
728
729 static const char *
730 get_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*/
930 static signal_t 
931 nameserver_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  */
946 static int 
947 local_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__
970 void sethostent(int x)
971 {}
972
973 void endhostent()
974 {}
975 #endif
976