2 * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
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:
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
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.
25 Copyright 1985, 1986, 1987, 1998 The Open Group
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.
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.
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.
54 X Window System is a trademark of The Open Group.
62 #if defined(TCPCONN) || defined(STREAMSCONN)
74 #include <X11/Xproto.h>
75 #include <X11/Xfuncs.h>
83 #include <X11/Xauth.h>
84 #include <X11/Xmu/Error.h>
89 typedef unsigned short unsign16;
90 typedef unsigned long unsign32;
93 #include <interlan/socket.h>
94 #include <interlan/netdb.h>
95 #include <interlan/in.h>
98 #include <sys/socket.h>
103 #include <netinet/in.h>
105 #endif /* NEEDSOCKETS */
108 #include <arpa/inet.h>
110 /* bogus definition of inet_makeaddr() in BSD 4.2 and Ultrix */
111 extern unsigned long inet_makeaddr();
115 #include <netdnet/dn.h>
116 #include <netdnet/dnetdb.h>
122 #ifdef X_POSIX_C_SOURCE
123 #define _POSIX_C_SOURCE X_POSIX_C_SOURCE
125 #undef _POSIX_C_SOURCE
127 #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
130 #define _POSIX_SOURCE
136 #include <sys/param.h>
137 #define NGROUPS_MAX NGROUPS
140 /* Go figure, there's no getdomainname() prototype available */
141 extern int getdomainname(char *name, size_t len);
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);
149 #ifdef RETSIGTYPE /* autoconf AC_TYPE_SIGNAL */
150 # define signal_t RETSIGTYPE
152 #ifdef SIGNALRETURNSINT
155 #define signal_t void
157 #endif /* RETSIGTYPE */
158 static signal_t nameserver_lost(int sig);
160 #define NAMESERVER_TIMEOUT 5 /* time to wait for nameserver */
162 static volatile int nameserver_timedout;
164 static char *ProgramName;
171 static struct _familyMap {
175 { AF_DECnet, FamilyDECnet },
178 { AF_CHAOS, FamilyChaos },
181 { AF_INET, FamilyInternet },
182 #if defined(IPv6) && defined(AF_INET6)
183 { AF_INET6, FamilyInternet6 },
188 #define FAMILIES ((sizeof familyMap)/(sizeof familyMap[0]))
190 for (i = 0; i < FAMILIES; i++)
191 if (familyMap[i].af == af) return familyMap[i].xf;
194 #endif /* NEEDSOCKETS */
199 main(int argc, char *argv[])
203 const char *hostname;
206 Bool enabled = False;
210 struct dn_naddr *nlist, dnaddr, *dnaddrp, *dnet_addr();
214 ProgramName = argv[0];
216 if (argc == 2 && !strcmp(argv[1], "-help")) {
217 fprintf(stderr, "usage: %s [[+-]hostname ...]\n", argv[0]);
221 if ((dpy = XOpenDisplay(NULL)) == NULL) {
222 fprintf(stderr, "%s: unable to open display \"%s\"\n",
223 ProgramName, XDisplayName (NULL));
227 XSetErrorHandler(local_xerror);
232 setnodeent(1); /* keep the database accessed */
234 sethostent(1); /* don't close the data base each time */
235 list = XListHosts(dpy, &nhosts, &enabled);
237 printf ("access control enabled, only authorized clients can connect\n");
239 printf ("access control disabled, clients can connect from any host\n");
242 for (i = 0; i < nhosts; i++ ) {
243 hostname = get_hostname(&list[i]);
245 switch (list[i].family) {
249 case FamilyInternet6:
258 case FamilyKrb5Principal:
261 case FamilyLocalHost:
264 case FamilyServerInterpreted:
268 printf("<unknown family type %d>:", list[i].family);
271 printf ("%s", hostname);
273 printf ("<unknown address in family %d>",
276 if (nameserver_timedout) {
277 printf("\t(no nameserver response within %d seconds)\n",
279 nameserver_timedout = 0;
289 for (i = 1; i < argc; i++) {
293 if (!argv[i][1] && ((i+1) == argc)) {
294 printf ("access control enabled, only authorized clients can connect\n");
295 XEnableAccessControl(dpy);
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",
305 if (*arg == '+' && !argv[i][1] && ((i+1) == argc)) {
306 printf ("access control disabled, clients can connect from any host\n");
307 XDisableAccessControl(dpy);
310 arg = argv[i][1]? &argv[i][1] : argv[++i];
312 if (!change_host (dpy, arg, True)) {
313 fprintf (stderr, "%s: bad hostname \"%s\"\n",
320 XCloseDisplay (dpy); /* does an XSync first */
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
335 change_host(Display *dpy, char *name, Bool add)
339 int namelen, i, family = FamilyWild;
341 krb5_principal princ;
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 */
354 struct dn_naddr *dnaddrp;
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";
361 namelen = strlen(name);
362 if ((lname = (char *)malloc(namelen+1)) == NULL) {
363 fprintf (stderr, "%s: malloc bombed in change_host\n", ProgramName);
366 for (i = 0; i < namelen; i++) {
367 lname[i] = tolower(name[i]);
369 lname[namelen] = '\0';
370 if (!strncmp("inet:", lname, 5)) {
371 #if defined(TCPCONN) || defined(STREAMSCONN)
372 family = FamilyInternet;
375 fprintf (stderr, "%s: not compiled for TCP/IP\n", ProgramName);
380 else if (!strncmp("inet6:", lname, 6)) {
381 #if (defined(TCPCONN) || defined(STREAMSCONN)) && \
382 defined(IPv6) && defined(AF_INET6)
383 family = FamilyInternet6;
386 fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
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;
399 fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
404 #endif /* ACCEPT_INETV6 */
405 else if (!strncmp("dnet:", lname, 5)) {
407 family = FamilyDECnet;
410 fprintf (stderr, "%s: not compiled for DECnet\n", ProgramName);
415 else if (!strncmp("nis:", lname, 4)) {
417 family = FamilyNetname;
420 fprintf (stderr, "%s: not compiled for Secure RPC\n", ProgramName);
425 else if (!strncmp("krb:", lname, 4)) {
427 family = FamilyKrb5Principal;
430 fprintf (stderr, "%s: not compiled for Kerberos 5\n", ProgramName);
435 else if (!strncmp("local:", lname, 6)) {
436 family = FamilyLocalHost;
438 else if (!strncmp("si:", lname, 3)) {
439 family = FamilyServerInterpreted;
442 if (family == FamilyWild && (cp = strchr(lname, ':'))) {
444 fprintf (stderr, "%s: unknown address family \"%s\"\n",
451 if (family == FamilyServerInterpreted) {
452 XServerInterpretedAddress siaddr;
455 cp = strchr(name, ':');
456 if (cp == NULL || cp == name) {
458 "%s: type must be specified for server interpreted family \"%s\"\n",
463 siaddr.typelength = cp - name;
465 siaddr.valuelength = strlen(cp);
466 ha.family = FamilyServerInterpreted;
467 ha.address = (char *) &siaddr;
469 rc = XAddHost(dpy, &ha);
471 rc = XRemoveHost(dpy, &ha);
472 printf( "%s %s%s\n", name, rc == 1 ? "" : "failed when ",
473 add ? add_msg : remove_msg);
480 if (family == FamilyDECnet || ((family == FamilyWild) &&
481 (cp = strchr(name, ':')) && (*(cp + 1) == ':') &&
483 ha.family = FamilyDECnet;
484 if (dnaddrp = dnet_addr(name)) {
487 if ((np = getnodebyname (name)) == NULL) {
488 fprintf (stderr, "%s: unable to get node name for \"%s::\"\n",
492 dnaddr.a_len = np->n_length;
493 memmove( dnaddr.a_addr, np->n_addr, np->n_length);
495 ha.length = sizeof(struct dn_naddr);
496 ha.address = (char *)&dnaddr;
499 printf ("%s:: %s\n", name, add_msg);
501 XRemoveHost (dpy, &ha);
502 printf ("%s:: %s\n", name, remove_msg);
506 #endif /* DNETCONN */
508 if (family == FamilyKrb5Principal) {
509 krb5_error_code retval;
511 retval = krb5_parse_name(name, &princ);
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));
518 XauKrb5Encode(princ, &kbuf);
519 ha.length = kbuf.length;
520 ha.address = kbuf.data;
525 XRemoveHost(dpy, &ha);
526 krb5_free_principal(princ);
528 printf( "%s %s\n", name, add ? add_msg : remove_msg);
532 if (family == FamilyLocalHost) {
539 XRemoveHost(dpy, &ha);
540 printf( "non-network local connections %s\n", add ? add_msg : remove_msg);
544 * If it has an '@', it's a netname
546 if ((family == FamilyNetname && (cp = strchr(name, '@'))) ||
547 (cp = strchr(name, '@'))) {
548 char *netname = name;
550 static char username[MAXNETNAMELEN];
554 static char domainname[128];
557 pwd = getpwnam(name);
559 fprintf(stderr, "no such user \"%s\"\n", name);
562 getdomainname(domainname, sizeof(domainname));
563 if (!user2netname(username, pwd->pw_uid, domainname)) {
564 fprintf(stderr, "failed to get netname for \"%s\"\n", name);
570 ha.family = FamilyNetname;
571 ha.length = strlen(netname);
572 ha.address = netname;
576 XRemoveHost (dpy, &ha);
578 printf ("%s@ (%s) %s\n", name, netname, add ? add_msg : remove_msg);
580 printf ("%s %s\n", netname, add ? add_msg : remove_msg);
585 * First see if inet_addr() can grok the name; if so, then use it.
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 */
594 printf ("%s %s\n", name, add_msg);
596 XRemoveHost (dpy, &ha);
597 printf ("%s %s\n", name, remove_msg);
601 #if defined(IPv6) && defined(AF_INET6)
603 * Check to see if inet_pton() can grok it as an IPv6 address
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;
612 printf ("%s %s\n", name, add_msg);
614 XRemoveHost (dpy, &ha);
615 printf ("%s %s\n", name, remove_msg);
620 * Is it in the namespace?
622 * If no family was specified, use both Internet v4 & v6 addresses.
623 * Otherwise, use only addresses matching specified family.
625 struct addrinfo *addresses;
629 if (getaddrinfo(name, NULL, NULL, &addresses) != 0)
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;
641 sizeof (((struct sockaddr_in6 *) a->ai_addr)->sin6_addr);
643 ha.address = (char *)
644 &((struct sockaddr_in *) a->ai_addr)->sin_addr;
646 sizeof (((struct sockaddr_in *) a->ai_addr)->sin_addr);
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); */
655 XRemoveHost (dpy, &ha);
661 printf ("%s %s\n", name, add ? add_msg : remove_msg);
663 const char *familyMsg = "";
665 if (family == FamilyInternet6) {
666 familyMsg = "inet6 ";
667 } else if (family == FamilyInternet) {
671 fprintf(stderr, "%s: unable to get %saddress for \"%s\"\n",
672 ProgramName, familyMsg, name);
674 freeaddrinfo(addresses);
679 * Is it in the namespace?
681 else if (((hp = gethostbyname(name)) == (struct hostent *)NULL)
682 || hp->h_addrtype != AF_INET) {
685 ha.family = XFamily(hp->h_addrtype);
686 ha.length = hp->h_length;
687 #ifdef h_addr /* new 4.3bsd version of gethostent */
691 /* iterate over the hosts */
692 for (list = hp->h_addr_list; *list; list++) {
697 XRemoveHost (dpy, &ha);
702 ha.address = hp->h_addr;
706 XRemoveHost (dpy, &ha);
709 printf ("%s %s\n", name, add ? add_msg : remove_msg);
713 #else /* NEEDSOCKETS */
715 #endif /* NEEDSOCKETS */
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
730 get_hostname(XHostAddress *ha)
732 #if (defined(TCPCONN) || defined(STREAMSCONN)) && \
733 (!defined(IPv6) || !defined(AF_INET6))
734 static struct hostent *hp = NULL;
738 static char nodeaddr[5 + 2 * DN_MAXADDL];
739 #endif /* DNETCONN */
741 krb5_principal princ;
744 static char kname_out[255];
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];
758 memset(&saddr, 0, sizeof saddr);
759 if (ha->family == FamilyInternet) {
760 struct sockaddr_in *sin = (struct sockaddr_in *) &saddr;
762 sin->sin_len = sizeof(struct sockaddr_in);
764 sin->sin_family = AF_INET;
766 memcpy(&sin->sin_addr, ha->address, sizeof(sin->sin_addr));
767 saddrlen = sizeof(struct sockaddr_in);
769 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &saddr;
771 sin6->sin6_len = sizeof(struct sockaddr_in6);
773 sin6->sin6_family = AF_INET6;
775 memcpy(&sin6->sin6_addr, ha->address, sizeof(sin6->sin6_addr));
776 saddrlen = sizeof(struct sockaddr_in6);
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
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);
791 signal(SIGALRM, nameserver_lost);
793 alarm(NAMESERVER_TIMEOUT);
795 if (setjmp(env) == 0)
798 getnameinfo((struct sockaddr *) &saddr, saddrlen, inetname,
799 sizeof(inetname), NULL, 0, 0);
802 if (nameserver_timedout || inetname[0] == '\0')
803 inet_ntop(((struct sockaddr *)&saddr)->sa_family, ha->address,
804 inetname, sizeof(inetname));
808 if (ha->family == FamilyInternet) {
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;
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
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);
827 signal(SIGALRM, nameserver_lost);
831 if (setjmp(env) == 0) {
833 hp = gethostbyaddr (ha->address, ha->length, AF_INET);
840 else return (inet_ntoa(*((struct in_addr *)(ha->address))));
844 if (ha->family == FamilyNetname) {
845 static char netname[512];
850 gid_t gid, gidlist[NGROUPS_MAX];
853 if (ha->length < sizeof(netname) - 1)
856 len = sizeof(netname) - 1;
857 memmove( netname, ha->address, len);
860 if (netname2user(netname, &uid, &gid, &gidlen, gidlist)) {
865 sprintf(netname, "%s@ (%*.*s)", pwd->pw_name,
866 ha->length, ha->length, ha->address);
872 if (ha->family == FamilyDECnet) {
873 struct dn_naddr *addr_ptr = (struct dn_naddr *) ha->address;
875 if (np = getnodebyaddr(addr_ptr->a_addr, addr_ptr->a_len, AF_DECnet)) {
876 sprintf(nodeaddr, "%s", np->n_name);
878 sprintf(nodeaddr, "%s", dnet_htoa(ha->address));
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));
895 if (ha->family == FamilyLocalHost) {
898 if (ha->family == FamilyServerInterpreted) {
899 XServerInterpretedAddress *sip;
900 static char *addressString;
901 static size_t addressStringSize;
904 sip = (XServerInterpretedAddress *) ha->address;
905 neededSize = sip->typelength + sip->valuelength + 2;
907 if (addressStringSize < neededSize) {
908 if (addressString != NULL) {
911 addressStringSize = neededSize;
912 addressString = malloc(addressStringSize);
914 if (addressString != NULL) {
915 char *cp = addressString;
917 memcpy(cp, sip->type, sip->typelength);
918 cp += sip->typelength;
920 memcpy(cp, sip->value, sip->valuelength);
921 cp += sip->valuelength;
924 return addressString;
931 nameserver_lost(int sig)
933 nameserver_timedout = 1;
935 /* not needed with POSIX signals - stuck syscalls will not
936 be restarted after signal delivery */
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.
947 local_xerror(Display *dpy, XErrorEvent *rep)
949 if ((rep->error_code == BadAccess) && (rep->request_code == X_ChangeHosts)) {
951 "%s: must be on local machine to add or remove hosts.\n",
954 } else if ((rep->error_code == BadAccess) &&
955 (rep->request_code == X_SetAccessControl)) {
957 "%s: must be on local machine to enable or disable access control.\n",
960 } else if ((rep->error_code == BadValue) &&
961 (rep->request_code == X_ListHosts)) {
965 XmuPrintDefaultErrorMessage (dpy, rep, stderr);
970 void sethostent(int x)