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 $ */
5
Copyright 1985, 1986, 1987, 1998 The Open Group
6
Copyright 2004 Sun Microsystems, Inc.
10
Permission is hereby granted, free of charge, to any person obtaining a
11
copy of this software and associated documentation files (the
12
"Software"), to deal in the Software without restriction, including
13
without limitation the rights to use, copy, modify, merge, publish,
14
distribute, and/or sell copies of the Software, and to permit persons
15
to whom the Software is furnished to do so, provided that the above
16
copyright notice(s) and this permission notice appear in all copies of
17
the Software and that both the above copyright notice(s) and this
18
permission notice appear in supporting documentation.
20
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
23
OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
24
HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
25
INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
26
FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
27
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
28
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30
Except as contained in this notice, the name of a copyright holder
31
shall not be used in advertising or otherwise to promote the sale, use
32
or other dealings in this Software without prior written authorization
33
of the copyright holder.
35
X Window System is a trademark of The Open Group.
38
/* $XFree86: xc/programs/xhost/xhost.c,v 3.26 2003/07/27 14:05:45 herrb Exp $ */
44
#if defined(TCPCONN) || defined(STREAMSCONN)
56
#include <X11/Xproto.h>
57
#include <X11/Xfuncs.h>
65
#include <X11/Xauth.h>
66
#include <X11/Xmu/Error.h>
71
typedef unsigned short unsign16;
72
typedef unsigned long unsign32;
75
#include <interlan/socket.h>
76
#include <interlan/netdb.h>
77
#include <interlan/in.h>
80
#include <sys/socket.h>
85
#include <netinet/in.h>
87
#endif /* NEEDSOCKETS */
90
#include <arpa/inet.h>
92
/* bogus definition of inet_makeaddr() in BSD 4.2 and Ultrix */
93
extern unsigned long inet_makeaddr();
97
#include <netdnet/dn.h>
98
#include <netdnet/dnetdb.h>
104
#ifdef X_POSIX_C_SOURCE
105
#define _POSIX_C_SOURCE X_POSIX_C_SOURCE
107
#undef _POSIX_C_SOURCE
109
#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
112
#define _POSIX_SOURCE
118
#include <sys/param.h>
119
#define NGROUPS_MAX NGROUPS
122
/* Go figure, there's no getdomainname() prototype available */
123
extern int getdomainname(char *name, size_t len);
127
static int change_host(Display *dpy, char *name, Bool add);
128
static char *get_hostname(XHostAddress *ha);
129
static int local_xerror(Display *dpy, XErrorEvent *rep);
131
#ifdef RETSIGTYPE /* autoconf AC_TYPE_SIGNAL */
132
# define signal_t RETSIGTYPE
134
#ifdef SIGNALRETURNSINT
137
#define signal_t void
139
#endif /* RETSIGTYPE */
140
static signal_t nameserver_lost(int sig);
142
#define NAMESERVER_TIMEOUT 5 /* time to wait for nameserver */
144
volatile int nameserver_timedout;
153
static struct _familyMap {
157
{ AF_DECnet, FamilyDECnet },
160
{ AF_CHAOS, FamilyChaos },
163
{ AF_INET, FamilyInternet },
164
#if defined(IPv6) && defined(AF_INET6)
165
{ AF_INET6, FamilyInternet6 },
170
#define FAMILIES ((sizeof familyMap)/(sizeof familyMap[0]))
172
for (i = 0; i < FAMILIES; i++)
173
if (familyMap[i].af == af) return familyMap[i].xf;
176
#endif /* NEEDSOCKETS */
181
main(int argc, char *argv[])
188
Bool enabled = False;
192
struct dn_naddr *nlist, dnaddr, *dnaddrp, *dnet_addr();
196
ProgramName = argv[0];
198
if ((dpy = XOpenDisplay(NULL)) == NULL) {
199
fprintf(stderr, "%s: unable to open display \"%s\"\n",
200
ProgramName, XDisplayName (NULL));
204
XSetErrorHandler(local_xerror);
209
setnodeent(1); /* keep the database accessed */
211
sethostent(1); /* don't close the data base each time */
212
list = XListHosts(dpy, &nhosts, &enabled);
214
printf ("access control enabled, only authorized clients can connect\n");
216
printf ("access control disabled, clients can connect from any host\n");
219
for (i = 0; i < nhosts; i++ ) {
220
hostname = get_hostname(&list[i]);
222
switch (list[i].family) {
226
case FamilyInternet6:
235
case FamilyKrb5Principal:
238
case FamilyLocalHost:
241
case FamilyServerInterpreted:
245
printf("<unknown family type %d>:", list[i].family);
248
printf ("%s", hostname);
250
printf ("<unknown address in family %d>",
253
if (nameserver_timedout) {
254
printf("\t(no nameserver response within %d seconds)\n",
256
nameserver_timedout = 0;
266
if (argc == 2 && !strcmp(argv[1], "-help")) {
267
fprintf(stderr, "usage: %s [[+-]hostname ...]\n", argv[0]);
271
for (i = 1; i < argc; i++) {
275
if (!argv[i][1] && ((i+1) == argc)) {
276
printf ("access control enabled, only authorized clients can connect\n");
277
XEnableAccessControl(dpy);
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",
287
if (*arg == '+' && !argv[i][1] && ((i+1) == argc)) {
288
printf ("access control disabled, clients can connect from any host\n");
289
XDisableAccessControl(dpy);
292
arg = argv[i][1]? &argv[i][1] : argv[++i];
294
if (!change_host (dpy, arg, True)) {
295
fprintf (stderr, "%s: bad hostname \"%s\"\n",
302
XCloseDisplay (dpy); /* does an XSync first */
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
317
change_host(Display *dpy, char *name, Bool add)
321
int namelen, i, family = FamilyWild;
323
krb5_principal princ;
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 */
336
struct dn_naddr *dnaddrp;
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";
343
namelen = strlen(name);
344
if ((lname = (char *)malloc(namelen+1)) == NULL) {
345
fprintf (stderr, "%s: malloc bombed in change_host\n", ProgramName);
348
for (i = 0; i < namelen; i++) {
349
lname[i] = tolower(name[i]);
351
lname[namelen] = '\0';
352
if (!strncmp("inet:", lname, 5)) {
353
#if defined(TCPCONN) || defined(STREAMSCONN)
354
family = FamilyInternet;
357
fprintf (stderr, "%s: not compiled for TCP/IP\n", ProgramName);
362
else if (!strncmp("inet6:", lname, 6)) {
363
#if (defined(TCPCONN) || defined(STREAMSCONN)) && \
364
defined(IPv6) && defined(AF_INET6)
365
family = FamilyInternet6;
368
fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
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;
381
fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
386
#endif /* ACCEPT_INETV6 */
387
else if (!strncmp("dnet:", lname, 5)) {
389
family = FamilyDECnet;
392
fprintf (stderr, "%s: not compiled for DECnet\n", ProgramName);
397
else if (!strncmp("nis:", lname, 4)) {
399
family = FamilyNetname;
402
fprintf (stderr, "%s: not compiled for Secure RPC\n", ProgramName);
407
else if (!strncmp("krb:", lname, 4)) {
409
family = FamilyKrb5Principal;
412
fprintf (stderr, "%s: not compiled for Kerberos 5\n", ProgramName);
417
else if (!strncmp("local:", lname, 6)) {
418
family = FamilyLocalHost;
420
else if (!strncmp("si:", lname, 3)) {
421
family = FamilyServerInterpreted;
424
if (family == FamilyWild && (cp = strchr(lname, ':'))) {
426
fprintf (stderr, "%s: unknown address family \"%s\"\n",
433
if (family == FamilyServerInterpreted) {
434
XServerInterpretedAddress siaddr;
437
cp = strchr(name, ':');
438
if (cp == NULL || cp == name) {
440
"%s: type must be specified for server interpreted family \"%s\"\n",
444
ha.family = FamilyServerInterpreted;
445
ha.address = (char *) &siaddr;
446
namelen = strlen(name);
447
siaddr.type = malloc(namelen);
448
if (siaddr.type == NULL) {
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);
459
XRemoveHost(dpy, &ha);
461
printf( "%s %s\n", name, add ? add_msg : remove_msg);
466
if (family == FamilyDECnet || ((family == FamilyWild) &&
467
(cp = strchr(name, ':')) && (*(cp + 1) == ':') &&
469
ha.family = FamilyDECnet;
470
if (dnaddrp = dnet_addr(name)) {
473
if ((np = getnodebyname (name)) == NULL) {
474
fprintf (stderr, "%s: unable to get node name for \"%s::\"\n",
478
dnaddr.a_len = np->n_length;
479
memmove( dnaddr.a_addr, np->n_addr, np->n_length);
481
ha.length = sizeof(struct dn_naddr);
482
ha.address = (char *)&dnaddr;
485
printf ("%s:: %s\n", name, add_msg);
487
XRemoveHost (dpy, &ha);
488
printf ("%s:: %s\n", name, remove_msg);
492
#endif /* DNETCONN */
494
if (family == FamilyKrb5Principal) {
495
krb5_error_code retval;
497
retval = krb5_parse_name(name, &princ);
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));
504
XauKrb5Encode(princ, &kbuf);
505
ha.length = kbuf.length;
506
ha.address = kbuf.data;
511
XRemoveHost(dpy, &ha);
512
krb5_free_principal(princ);
514
printf( "%s %s\n", name, add ? add_msg : remove_msg);
518
if (family == FamilyLocalHost) {
525
XRemoveHost(dpy, &ha);
526
printf( "non-network local connections %s\n", add ? add_msg : remove_msg);
530
* If it has an '@', it's a netname
532
if ((family == FamilyNetname && (cp = strchr(name, '@'))) ||
533
(cp = strchr(name, '@'))) {
534
char *netname = name;
536
static char username[MAXNETNAMELEN];
540
static char domainname[128];
543
pwd = getpwnam(name);
545
fprintf(stderr, "no such user \"%s\"\n", name);
548
getdomainname(domainname, sizeof(domainname));
549
if (!user2netname(username, pwd->pw_uid, domainname)) {
550
fprintf(stderr, "failed to get netname for \"%s\"\n", name);
556
ha.family = FamilyNetname;
557
ha.length = strlen(netname);
558
ha.address = netname;
562
XRemoveHost (dpy, &ha);
564
printf ("%s@ (%s) %s\n", name, netname, add ? add_msg : remove_msg);
566
printf ("%s %s\n", netname, add ? add_msg : remove_msg);
571
* First see if inet_addr() can grok the name; if so, then use it.
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 */
580
printf ("%s %s\n", name, add_msg);
582
XRemoveHost (dpy, &ha);
583
printf ("%s %s\n", name, remove_msg);
587
#if defined(IPv6) && defined(AF_INET6)
589
* Check to see if inet_pton() can grok it as an IPv6 address
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;
598
printf ("%s %s\n", name, add_msg);
600
XRemoveHost (dpy, &ha);
601
printf ("%s %s\n", name, remove_msg);
606
* Is it in the namespace?
608
* If no family was specified, use both Internet v4 & v6 addresses.
609
* Otherwise, use only addresses matching specified family.
611
struct addrinfo *addresses;
615
if (getaddrinfo(name, NULL, NULL, &addresses) != 0)
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;
627
sizeof (((struct sockaddr_in6 *) a->ai_addr)->sin6_addr);
629
ha.address = (char *)
630
&((struct sockaddr_in *) a->ai_addr)->sin_addr;
632
sizeof (((struct sockaddr_in *) a->ai_addr)->sin_addr);
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); */
641
XRemoveHost (dpy, &ha);
647
printf ("%s %s\n", name, add ? add_msg : remove_msg);
649
const char *familyMsg = "";
651
if (family == FamilyInternet6) {
652
familyMsg = "inet6 ";
653
} else if (family == FamilyInternet) {
657
fprintf(stderr, "%s: unable to get %saddress for \"%s\"\n",
658
ProgramName, familyMsg, name);
660
freeaddrinfo(addresses);
665
* Is it in the namespace?
667
else if (((hp = gethostbyname(name)) == (struct hostent *)NULL)
668
|| hp->h_addrtype != AF_INET) {
671
ha.family = XFamily(hp->h_addrtype);
672
ha.length = hp->h_length;
673
#ifdef h_addr /* new 4.3bsd version of gethostent */
677
/* iterate over the hosts */
678
for (list = hp->h_addr_list; *list; list++) {
683
XRemoveHost (dpy, &ha);
688
ha.address = hp->h_addr;
692
XRemoveHost (dpy, &ha);
695
printf ("%s %s\n", name, add ? add_msg : remove_msg);
699
#else /* NEEDSOCKETS */
701
#endif /* NEEDSOCKETS */
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
716
get_hostname(XHostAddress *ha)
718
#if (defined(TCPCONN) || defined(STREAMSCONN)) && \
719
(!defined(IPv6) || !defined(AF_INET6))
720
static struct hostent *hp = NULL;
724
static char nodeaddr[5 + 2 * DN_MAXADDL];
725
#endif /* DNETCONN */
727
krb5_principal princ;
730
static char kname_out[255];
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];
744
memset(&saddr, 0, sizeof saddr);
745
if (ha->family == FamilyInternet) {
746
struct sockaddr_in *sin = (struct sockaddr_in *) &saddr;
748
sin->sin_len = sizeof(struct sockaddr_in);
750
sin->sin_family = AF_INET;
752
memcpy(&sin->sin_addr, ha->address, sizeof(sin->sin_addr));
753
saddrlen = sizeof(struct sockaddr_in);
755
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &saddr;
757
sin6->sin6_len = sizeof(struct sockaddr_in6);
759
sin6->sin6_family = AF_INET6;
761
memcpy(&sin6->sin6_addr, ha->address, sizeof(sin6->sin6_addr));
762
saddrlen = sizeof(struct sockaddr_in6);
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
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);
777
signal(SIGALRM, nameserver_lost);
779
alarm(NAMESERVER_TIMEOUT);
781
if (setjmp(env) == 0)
784
getnameinfo((struct sockaddr *) &saddr, saddrlen, inetname,
785
sizeof(inetname), NULL, 0, 0);
788
if (nameserver_timedout || inetname[0] == '\0')
789
inet_ntop(((struct sockaddr *)&saddr)->sa_family, ha->address,
790
inetname, sizeof(inetname));
794
if (ha->family == FamilyInternet) {
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;
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
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);
813
signal(SIGALRM, nameserver_lost);
817
if (setjmp(env) == 0) {
819
hp = gethostbyaddr (ha->address, ha->length, AF_INET);
826
else return (inet_ntoa(*((struct in_addr *)(ha->address))));
830
if (ha->family == FamilyNetname) {
831
static char netname[512];
836
gid_t gid, gidlist[NGROUPS_MAX];
839
if (ha->length < sizeof(netname) - 1)
842
len = sizeof(netname) - 1;
843
memmove( netname, ha->address, len);
846
if (netname2user(netname, &uid, &gid, &gidlen, gidlist)) {
851
sprintf(netname, "%s@ (%*.*s)", pwd->pw_name,
852
ha->length, ha->length, ha->address);
858
if (ha->family == FamilyDECnet) {
859
struct dn_naddr *addr_ptr = (struct dn_naddr *) ha->address;
861
if (np = getnodebyaddr(addr_ptr->a_addr, addr_ptr->a_len, AF_DECnet)) {
862
sprintf(nodeaddr, "%s", np->n_name);
864
sprintf(nodeaddr, "%s", dnet_htoa(ha->address));
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));
881
if (ha->family == FamilyLocalHost) {
884
if (ha->family == FamilyServerInterpreted) {
885
XServerInterpretedAddress *sip;
886
static char *addressString;
887
static size_t addressStringSize;
890
sip = (XServerInterpretedAddress *) ha->address;
891
neededSize = sip->typelength + sip->valuelength + 2;
893
if (addressStringSize < neededSize) {
894
if (addressString != NULL) {
897
addressStringSize = neededSize;
898
addressString = malloc(addressStringSize);
900
if (addressString != NULL) {
901
char *cp = addressString;
903
memcpy(cp, sip->type, sip->typelength);
904
cp += sip->typelength;
906
memcpy(cp, sip->value, sip->valuelength);
907
cp += sip->valuelength;
910
return addressString;
917
nameserver_lost(int sig)
919
nameserver_timedout = 1;
921
/* not needed with POSIX signals - stuck syscalls will not
922
be restarted after signal delivery */
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.
933
local_xerror(Display *dpy, XErrorEvent *rep)
935
if ((rep->error_code == BadAccess) && (rep->request_code == X_ChangeHosts)) {
937
"%s: must be on local machine to add or remove hosts.\n",
940
} else if ((rep->error_code == BadAccess) &&
941
(rep->request_code == X_SetAccessControl)) {
943
"%s: must be on local machine to enable or disable access control.\n",
946
} else if ((rep->error_code == BadValue) &&
947
(rep->request_code == X_ListHosts)) {
951
XmuPrintDefaultErrorMessage (dpy, rep, stderr);
956
void sethostent(int x)