1169a0819Smrg/* 2b71ad168Smrg * Copyright (c) 2000, 2004, 2022, Oracle and/or its affiliates. 3169a0819Smrg * 4169a0819Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5169a0819Smrg * copy of this software and associated documentation files (the "Software"), 6169a0819Smrg * to deal in the Software without restriction, including without limitation 7169a0819Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8169a0819Smrg * and/or sell copies of the Software, and to permit persons to whom the 9169a0819Smrg * Software is furnished to do so, subject to the following conditions: 10169a0819Smrg * 11169a0819Smrg * The above copyright notice and this permission notice (including the next 12169a0819Smrg * paragraph) shall be included in all copies or substantial portions of the 13169a0819Smrg * Software. 14169a0819Smrg * 15169a0819Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16169a0819Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17169a0819Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18169a0819Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19169a0819Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20169a0819Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21169a0819Smrg * DEALINGS IN THE SOFTWARE. 22169a0819Smrg */ 2364ce7165Smrg/* 2464ce7165Smrg 2564ce7165SmrgCopyright 1985, 1986, 1987, 1998 The Open Group 2664ce7165Smrg 2764ce7165SmrgAll rights reserved. 2864ce7165Smrg 2964ce7165SmrgPermission is hereby granted, free of charge, to any person obtaining a 3064ce7165Smrgcopy of this software and associated documentation files (the 3164ce7165Smrg"Software"), to deal in the Software without restriction, including 3264ce7165Smrgwithout limitation the rights to use, copy, modify, merge, publish, 3364ce7165Smrgdistribute, and/or sell copies of the Software, and to permit persons 3464ce7165Smrgto whom the Software is furnished to do so, provided that the above 3564ce7165Smrgcopyright notice(s) and this permission notice appear in all copies of 3664ce7165Smrgthe Software and that both the above copyright notice(s) and this 3764ce7165Smrgpermission notice appear in supporting documentation. 3864ce7165Smrg 3964ce7165SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 4064ce7165SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 4164ce7165SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 4264ce7165SmrgOF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 4364ce7165SmrgHOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 4464ce7165SmrgINDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING 4564ce7165SmrgFROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 4664ce7165SmrgNEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 4764ce7165SmrgWITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 4864ce7165Smrg 4964ce7165SmrgExcept as contained in this notice, the name of a copyright holder 5064ce7165Smrgshall not be used in advertising or otherwise to promote the sale, use 5164ce7165Smrgor other dealings in this Software without prior written authorization 5264ce7165Smrgof the copyright holder. 5364ce7165Smrg 5464ce7165SmrgX Window System is a trademark of The Open Group. 5564ce7165Smrg 5664ce7165Smrg*/ 5764ce7165Smrg 5864ce7165Smrg#ifdef HAVE_CONFIG_H 5964ce7165Smrg#include "config.h" 6064ce7165Smrg#endif 6164ce7165Smrg 6281440437Smrg#ifdef TCPCONN 6364ce7165Smrg#define NEEDSOCKETS 6464ce7165Smrg#endif 6564ce7165Smrg#ifdef UNIXCONN 6664ce7165Smrg#define NEEDSOCKETS 6764ce7165Smrg#endif 6864ce7165Smrg 6964ce7165Smrg#include <X11/Xlib.h> 7064ce7165Smrg#include <X11/Xos.h> 7164ce7165Smrg#include <X11/Xproto.h> 7264ce7165Smrg#include <X11/Xfuncs.h> 7364ce7165Smrg#include <stdio.h> 7464ce7165Smrg#include <stdlib.h> 7564ce7165Smrg#include <signal.h> 7664ce7165Smrg#include <ctype.h> 7764ce7165Smrg#include <X11/Xauth.h> 7864ce7165Smrg#include <X11/Xmu/Error.h> 7964ce7165Smrg#include <stdlib.h> 8064ce7165Smrg 8164ce7165Smrg#ifdef NEEDSOCKETS 8281440437Smrg#ifdef WIN32 8381440437Smrg#include <X11/Xwinsock.h> 8464ce7165Smrg#else 8564ce7165Smrg#include <sys/socket.h> 8664ce7165Smrg#include <netdb.h> 8764ce7165Smrg#include <netinet/in.h> 8864ce7165Smrg#endif 8964ce7165Smrg#endif /* NEEDSOCKETS */ 9064ce7165Smrg 9181440437Smrg#ifndef WIN32 9264ce7165Smrg#include <arpa/inet.h> 9364ce7165Smrg#endif 9464ce7165Smrg 9564ce7165Smrg 9664ce7165Smrg#ifdef SECURE_RPC 9764ce7165Smrg#include <pwd.h> 9864ce7165Smrg#include <rpc/rpc.h> 9964ce7165Smrg#ifdef X_POSIX_C_SOURCE 10064ce7165Smrg#define _POSIX_C_SOURCE X_POSIX_C_SOURCE 10164ce7165Smrg#include <limits.h> 10264ce7165Smrg#undef _POSIX_C_SOURCE 10364ce7165Smrg#else 10481440437Smrg#ifdef _POSIX_SOURCE 10564ce7165Smrg#include <limits.h> 10664ce7165Smrg#else 10764ce7165Smrg#define _POSIX_SOURCE 10864ce7165Smrg#include <limits.h> 10964ce7165Smrg#undef _POSIX_SOURCE 11064ce7165Smrg#endif 11164ce7165Smrg#endif 11264ce7165Smrg#ifndef NGROUPS_MAX 11364ce7165Smrg#include <sys/param.h> 11464ce7165Smrg#define NGROUPS_MAX NGROUPS 11564ce7165Smrg#endif 11664ce7165Smrg#ifdef sun 11764ce7165Smrg/* Go figure, there's no getdomainname() prototype available */ 11864ce7165Smrgextern int getdomainname(char *name, size_t len); 11964ce7165Smrg#endif 12064ce7165Smrg#endif 12164ce7165Smrg 122b71ad168Smrg#ifdef USE_GETTEXT 123b71ad168Smrg# include <locale.h> /* setlocale() */ 124b71ad168Smrg# include <libintl.h> /* gettext(), textdomain(), etc. */ 125b71ad168Smrg#else 126b71ad168Smrg# define gettext(a) (a) 127b71ad168Smrg#endif 128b71ad168Smrg 12964ce7165Smrgstatic int change_host(Display *dpy, char *name, Bool add); 1303544ea2eSmrgstatic const char *get_hostname(XHostAddress *ha); 13164ce7165Smrgstatic int local_xerror(Display *dpy, XErrorEvent *rep); 13281440437Smrgstatic void nameserver_lost(int sig); 13364ce7165Smrg 13464ce7165Smrg#define NAMESERVER_TIMEOUT 5 /* time to wait for nameserver */ 13564ce7165Smrg 136fb23d3a8Smrgstatic volatile int nameserver_timedout; 137fb23d3a8Smrg 138fb23d3a8Smrgstatic char *ProgramName; 13964ce7165Smrg 14064ce7165Smrg#ifdef NEEDSOCKETS 14164ce7165Smrgstatic int 14264ce7165SmrgXFamily(int af) 14364ce7165Smrg{ 14481440437Smrg unsigned int i; 14564ce7165Smrg static struct _familyMap { 14664ce7165Smrg int af, xf; 14764ce7165Smrg } familyMap[] = { 14864ce7165Smrg#ifdef AF_DECnet 14964ce7165Smrg { AF_DECnet, FamilyDECnet }, 15064ce7165Smrg#endif 15164ce7165Smrg#ifdef AF_CHAOS 15264ce7165Smrg { AF_CHAOS, FamilyChaos }, 15364ce7165Smrg#endif 15464ce7165Smrg#ifdef AF_INET 15564ce7165Smrg { AF_INET, FamilyInternet }, 15664ce7165Smrg#if defined(IPv6) && defined(AF_INET6) 15764ce7165Smrg { AF_INET6, FamilyInternet6 }, 15864ce7165Smrg#endif 15964ce7165Smrg#endif 16064ce7165Smrg}; 16164ce7165Smrg 16264ce7165Smrg#define FAMILIES ((sizeof familyMap)/(sizeof familyMap[0])) 16364ce7165Smrg 16464ce7165Smrg for (i = 0; i < FAMILIES; i++) 16564ce7165Smrg if (familyMap[i].af == af) return familyMap[i].xf; 16664ce7165Smrg return -1; 16764ce7165Smrg} 16864ce7165Smrg#endif /* NEEDSOCKETS */ 16964ce7165Smrg 170aadd013eSmrg#if defined(__CYGWIN__) || defined(WIN32) 171aadd013eSmrgvoid sethostent(int x) 172aadd013eSmrg{} 173aadd013eSmrg 174aadd013eSmrgvoid endhostent() 175aadd013eSmrg{} 176aadd013eSmrg#endif 177aadd013eSmrg 17864ce7165Smrgint 17964ce7165Smrgmain(int argc, char *argv[]) 18064ce7165Smrg{ 18164ce7165Smrg register char *arg; 18264ce7165Smrg int i, nhosts = 0; 1833544ea2eSmrg const char *hostname; 18464ce7165Smrg int nfailed = 0; 18564ce7165Smrg XHostAddress *list; 18664ce7165Smrg Bool enabled = False; 18781440437Smrg Display *dpy; 18864ce7165Smrg 189b71ad168Smrg#ifdef USE_GETTEXT 190b71ad168Smrg const char *domaindir; 191b71ad168Smrg 192b71ad168Smrg setlocale(LC_ALL, ""); 193b71ad168Smrg textdomain("xhost"); 194b71ad168Smrg 195b71ad168Smrg /* mainly for debugging */ 196b71ad168Smrg if ((domaindir = getenv("TEXTDOMAINDIR")) == NULL) { 197b71ad168Smrg domaindir = LOCALEDIR; 198b71ad168Smrg } 199b71ad168Smrg bindtextdomain("xhost", domaindir); 200b71ad168Smrg#endif 201b71ad168Smrg 20264ce7165Smrg ProgramName = argv[0]; 20364ce7165Smrg 2043544ea2eSmrg if (argc == 2 && !strcmp(argv[1], "-help")) { 205b71ad168Smrg fprintf(stderr, gettext("usage: %s [[+-]hostname ...]\n"), argv[0]); 2063544ea2eSmrg exit(1); 2073544ea2eSmrg } 2083544ea2eSmrg 20964ce7165Smrg if ((dpy = XOpenDisplay(NULL)) == NULL) { 210b71ad168Smrg fprintf(stderr, 211b71ad168Smrg gettext("%s: unable to open display \"%s\"\n"), 21264ce7165Smrg ProgramName, XDisplayName (NULL)); 21364ce7165Smrg exit(1); 21464ce7165Smrg } 21564ce7165Smrg 21664ce7165Smrg XSetErrorHandler(local_xerror); 21764ce7165Smrg 21864ce7165Smrg 21964ce7165Smrg if (argc == 1) { 22064ce7165Smrg sethostent(1); /* don't close the data base each time */ 22164ce7165Smrg list = XListHosts(dpy, &nhosts, &enabled); 22264ce7165Smrg if (enabled) 223b71ad168Smrg printf (gettext("access control enabled, only authorized clients can connect\n")); 22464ce7165Smrg else 225b71ad168Smrg printf (gettext("access control disabled, clients can connect from any host\n")); 22664ce7165Smrg 22764ce7165Smrg if (nhosts != 0) { 22864ce7165Smrg for (i = 0; i < nhosts; i++ ) { 22964ce7165Smrg hostname = get_hostname(&list[i]); 23064ce7165Smrg if (hostname) { 23164ce7165Smrg switch (list[i].family) { 23264ce7165Smrg case FamilyInternet: 23364ce7165Smrg printf("INET:"); 23464ce7165Smrg break; 23564ce7165Smrg case FamilyInternet6: 23664ce7165Smrg printf("INET6:"); 23764ce7165Smrg break; 23864ce7165Smrg case FamilyDECnet: 23964ce7165Smrg printf("DNET:"); 24064ce7165Smrg break; 24164ce7165Smrg case FamilyNetname: 24264ce7165Smrg printf("NIS:"); 24364ce7165Smrg break; 24464ce7165Smrg case FamilyKrb5Principal: 24564ce7165Smrg printf("KRB:"); 24664ce7165Smrg break; 24764ce7165Smrg case FamilyLocalHost: 24864ce7165Smrg printf("LOCAL:"); 24964ce7165Smrg break; 25064ce7165Smrg case FamilyServerInterpreted: 25164ce7165Smrg printf("SI:"); 25264ce7165Smrg break; 25364ce7165Smrg default: 254b71ad168Smrg printf(gettext("<unknown family type %d>:"), list[i].family); 25564ce7165Smrg break; 25664ce7165Smrg } 25764ce7165Smrg printf ("%s", hostname); 25864ce7165Smrg } else { 259b71ad168Smrg printf (gettext("<unknown address in family %d>"), 26064ce7165Smrg list[i].family); 26164ce7165Smrg } 26264ce7165Smrg if (nameserver_timedout) { 263b71ad168Smrg printf(gettext("\t(no nameserver response within %d seconds)\n"), 26464ce7165Smrg NAMESERVER_TIMEOUT); 26564ce7165Smrg nameserver_timedout = 0; 26664ce7165Smrg } else 26764ce7165Smrg printf("\n"); 26864ce7165Smrg } 26964ce7165Smrg free(list); 27064ce7165Smrg endhostent(); 27164ce7165Smrg } 27264ce7165Smrg exit(0); 27364ce7165Smrg } 27464ce7165Smrg 27564ce7165Smrg for (i = 1; i < argc; i++) { 27664ce7165Smrg arg = argv[i]; 27764ce7165Smrg if (*arg == '-') { 27864ce7165Smrg 27964ce7165Smrg if (!argv[i][1] && ((i+1) == argc)) { 280b71ad168Smrg printf (gettext("access control enabled, only authorized clients can connect\n")); 28164ce7165Smrg XEnableAccessControl(dpy); 28264ce7165Smrg } else { 28364ce7165Smrg arg = argv[i][1]? &argv[i][1] : argv[++i]; 28464ce7165Smrg if (!change_host (dpy, arg, False)) { 285b71ad168Smrg fprintf (stderr, gettext("%s: bad hostname \"%s\"\n"), 28664ce7165Smrg ProgramName, arg); 28764ce7165Smrg nfailed++; 28864ce7165Smrg } 28964ce7165Smrg } 29064ce7165Smrg } else { 29164ce7165Smrg if (*arg == '+' && !argv[i][1] && ((i+1) == argc)) { 292b71ad168Smrg printf (gettext("access control disabled, clients can connect from any host\n")); 29364ce7165Smrg XDisableAccessControl(dpy); 29464ce7165Smrg } else { 29564ce7165Smrg if (*arg == '+') { 29664ce7165Smrg arg = argv[i][1]? &argv[i][1] : argv[++i]; 29764ce7165Smrg } 29864ce7165Smrg if (!change_host (dpy, arg, True)) { 299b71ad168Smrg fprintf (stderr, gettext("%s: bad hostname \"%s\"\n"), 30064ce7165Smrg ProgramName, arg); 30164ce7165Smrg nfailed++; 30264ce7165Smrg } 30364ce7165Smrg } 30464ce7165Smrg } 30564ce7165Smrg } 30664ce7165Smrg XCloseDisplay (dpy); /* does an XSync first */ 30764ce7165Smrg exit(nfailed); 30864ce7165Smrg} 30964ce7165Smrg 31064ce7165Smrg 31164ce7165Smrg 31264ce7165Smrg/* 31364ce7165Smrg * change_host - edit the list of hosts that may connect to the server; 31464ce7165Smrg * it parses DECnet names (expo::), Internet addresses (18.30.0.212), or 31564ce7165Smrg * Internet names (expo.lcs.mit.edu); if 4.3bsd macro h_addr is defined 31664ce7165Smrg * (from <netdb.h>), it will add or remove all addresses with the given 31764ce7165Smrg * address. 31864ce7165Smrg */ 31964ce7165Smrg 32064ce7165Smrgstatic int 32164ce7165Smrgchange_host(Display *dpy, char *name, Bool add) 32264ce7165Smrg{ 32364ce7165Smrg XHostAddress ha; 32464ce7165Smrg char *lname; 32581440437Smrg size_t namelen, i; 32681440437Smrg int family = FamilyWild; 32764ce7165Smrg#ifdef K5AUTH 32864ce7165Smrg krb5_principal princ; 32964ce7165Smrg krb5_data kbuf; 33064ce7165Smrg#endif 33164ce7165Smrg#ifdef NEEDSOCKETS 33264ce7165Smrg static struct in_addr addr; /* so we can point at it */ 33364ce7165Smrg#if defined(IPv6) && defined(AF_INET6) 33464ce7165Smrg static struct in6_addr addr6; /* so we can point at it */ 33564ce7165Smrg#else 33664ce7165Smrg struct hostent *hp; 33764ce7165Smrg#endif 33864ce7165Smrg#endif 33964ce7165Smrg char *cp; 340b71ad168Smrg const char *add_msg = gettext("being added to access control list"); 341b71ad168Smrg const char *remove_msg = gettext("being removed from access control list"); 34264ce7165Smrg 34364ce7165Smrg namelen = strlen(name); 34464ce7165Smrg if ((lname = (char *)malloc(namelen+1)) == NULL) { 345b71ad168Smrg fprintf (stderr, gettext("%s: malloc bombed in change_host\n"), 346b71ad168Smrg ProgramName); 34764ce7165Smrg exit (1); 34864ce7165Smrg } 34964ce7165Smrg for (i = 0; i < namelen; i++) { 35064ce7165Smrg lname[i] = tolower(name[i]); 35164ce7165Smrg } 35264ce7165Smrg lname[namelen] = '\0'; 35364ce7165Smrg if (!strncmp("inet:", lname, 5)) { 35481440437Smrg#ifdef TCPCONN 35564ce7165Smrg family = FamilyInternet; 35664ce7165Smrg name += 5; 35764ce7165Smrg#else 358b71ad168Smrg fprintf (stderr, gettext("%s: not compiled for TCP/IP\n"), ProgramName); 35964ce7165Smrg free(lname); 36064ce7165Smrg return 0; 36164ce7165Smrg#endif 36264ce7165Smrg } 36364ce7165Smrg else if (!strncmp("inet6:", lname, 6)) { 36481440437Smrg#if defined(TCPCONN) && defined(IPv6) && defined(AF_INET6) 36564ce7165Smrg family = FamilyInternet6; 36664ce7165Smrg name += 6; 36764ce7165Smrg#else 368b71ad168Smrg fprintf (stderr, gettext("%s: not compiled for IPv6\n"), ProgramName); 36964ce7165Smrg free(lname); 37064ce7165Smrg return 0; 37164ce7165Smrg#endif 37264ce7165Smrg } 37364ce7165Smrg#ifdef ACCEPT_INETV6 /* Allow inetv6 as an alias for inet6 for compatibility 37464ce7165Smrg with original X11 over IPv6 draft. */ 37564ce7165Smrg else if (!strncmp("inetv6:", lname, 7)) { 37681440437Smrg#if defined(TCPCONN) && defined(IPv6) && defined(AF_INET6) 37764ce7165Smrg family = FamilyInternet6; 37864ce7165Smrg name += 7; 37964ce7165Smrg#else 380b71ad168Smrg fprintf (stderr, gettext("%s: not compiled for IPv6\n"), ProgramName); 38164ce7165Smrg free(lname); 38264ce7165Smrg return 0; 38364ce7165Smrg#endif 38464ce7165Smrg } 38564ce7165Smrg#endif /* ACCEPT_INETV6 */ 38664ce7165Smrg else if (!strncmp("dnet:", lname, 5)) { 387b71ad168Smrg fprintf (stderr, gettext("%s: not compiled for DECnet\n"), ProgramName); 38864ce7165Smrg free(lname); 38964ce7165Smrg return 0; 39064ce7165Smrg } 39164ce7165Smrg else if (!strncmp("nis:", lname, 4)) { 39264ce7165Smrg#ifdef SECURE_RPC 39364ce7165Smrg family = FamilyNetname; 39464ce7165Smrg name += 4; 39564ce7165Smrg#else 396b71ad168Smrg fprintf (stderr, gettext("%s: not compiled for Secure RPC\n"), ProgramName); 39764ce7165Smrg free(lname); 39864ce7165Smrg return 0; 39964ce7165Smrg#endif 40064ce7165Smrg } 40164ce7165Smrg else if (!strncmp("krb:", lname, 4)) { 40264ce7165Smrg#ifdef K5AUTH 40364ce7165Smrg family = FamilyKrb5Principal; 40464ce7165Smrg name +=4; 40564ce7165Smrg#else 406b71ad168Smrg fprintf (stderr, gettext("%s: not compiled for Kerberos 5\n"), ProgramName); 40764ce7165Smrg free(lname); 40864ce7165Smrg return 0; 40964ce7165Smrg#endif 41064ce7165Smrg } 41164ce7165Smrg else if (!strncmp("local:", lname, 6)) { 41264ce7165Smrg family = FamilyLocalHost; 41364ce7165Smrg } 41464ce7165Smrg else if (!strncmp("si:", lname, 3)) { 41564ce7165Smrg family = FamilyServerInterpreted; 41664ce7165Smrg name += 3; 41764ce7165Smrg } 41864ce7165Smrg if (family == FamilyWild && (cp = strchr(lname, ':'))) { 419b71ad168Smrg#ifdef IPv6 420b71ad168Smrg /* 421b71ad168Smrg * Check to see if inet_pton() can grok it as an IPv6 address 422b71ad168Smrg */ 423b71ad168Smrg if (inet_pton(AF_INET6, lname, &addr6.s6_addr) == 1) { 424b71ad168Smrg family = FamilyInternet6; 425b71ad168Smrg } else 426b71ad168Smrg#endif 427b71ad168Smrg { 428b71ad168Smrg *cp = '\0'; 429b71ad168Smrg fprintf (stderr, gettext("%s: unknown address family \"%s\"\n"), 430b71ad168Smrg ProgramName, lname); 431b71ad168Smrg free(lname); 432b71ad168Smrg return 0; 433b71ad168Smrg } 43464ce7165Smrg } 43564ce7165Smrg free(lname); 43664ce7165Smrg 43764ce7165Smrg if (family == FamilyServerInterpreted) { 43864ce7165Smrg XServerInterpretedAddress siaddr; 4393544ea2eSmrg int rc; 44064ce7165Smrg 44164ce7165Smrg cp = strchr(name, ':'); 44264ce7165Smrg if (cp == NULL || cp == name) { 443b71ad168Smrg fprintf(stderr, gettext( 444b71ad168Smrg "%s: type must be specified for server interpreted family \"%s\"\n"), 44564ce7165Smrg ProgramName, name); 44664ce7165Smrg return 0; 44764ce7165Smrg } 4483544ea2eSmrg siaddr.type = name; 4493544ea2eSmrg siaddr.typelength = cp - name; 4503544ea2eSmrg siaddr.value = ++cp; 4513544ea2eSmrg siaddr.valuelength = strlen(cp); 45264ce7165Smrg ha.family = FamilyServerInterpreted; 45364ce7165Smrg ha.address = (char *) &siaddr; 45464ce7165Smrg if (add) 4553544ea2eSmrg rc = XAddHost(dpy, &ha); 45664ce7165Smrg else 4573544ea2eSmrg rc = XRemoveHost(dpy, &ha); 4583544ea2eSmrg printf( "%s %s%s\n", name, rc == 1 ? "" : "failed when ", 4593544ea2eSmrg add ? add_msg : remove_msg); 4603544ea2eSmrg if (rc != 1) 4613544ea2eSmrg return 0; 46264ce7165Smrg return 1; 46364ce7165Smrg } 46464ce7165Smrg 46564ce7165Smrg#ifdef K5AUTH 46664ce7165Smrg if (family == FamilyKrb5Principal) { 46764ce7165Smrg krb5_error_code retval; 46864ce7165Smrg 46964ce7165Smrg retval = krb5_parse_name(name, &princ); 47064ce7165Smrg if (retval) { 47164ce7165Smrg krb5_init_ets(); /* init krb errs for error_message() */ 472b71ad168Smrg fprintf(stderr, gettext("%s: cannot parse Kerberos name: %s\n"), 47364ce7165Smrg ProgramName, error_message(retval)); 47464ce7165Smrg return 0; 47564ce7165Smrg } 47664ce7165Smrg XauKrb5Encode(princ, &kbuf); 47764ce7165Smrg ha.length = kbuf.length; 47864ce7165Smrg ha.address = kbuf.data; 47964ce7165Smrg ha.family = family; 48064ce7165Smrg if (add) 48164ce7165Smrg XAddHost(dpy, &ha); 48264ce7165Smrg else 48364ce7165Smrg XRemoveHost(dpy, &ha); 48464ce7165Smrg krb5_free_principal(princ); 48564ce7165Smrg free(kbuf.data); 48664ce7165Smrg printf( "%s %s\n", name, add ? add_msg : remove_msg); 48764ce7165Smrg return 1; 48864ce7165Smrg } 48964ce7165Smrg#endif 49064ce7165Smrg if (family == FamilyLocalHost) { 49181440437Smrg char empty[] = ""; 49264ce7165Smrg ha.length = 0; 49381440437Smrg ha.address = empty; 49464ce7165Smrg ha.family = family; 49564ce7165Smrg if (add) 49664ce7165Smrg XAddHost(dpy, &ha); 49764ce7165Smrg else 49864ce7165Smrg XRemoveHost(dpy, &ha); 499b71ad168Smrg printf( gettext("non-network local connections %s\n"), add ? add_msg : remove_msg); 50064ce7165Smrg return 1; 50164ce7165Smrg } 50264ce7165Smrg /* 50364ce7165Smrg * If it has an '@', it's a netname 50464ce7165Smrg */ 50564ce7165Smrg if ((family == FamilyNetname && (cp = strchr(name, '@'))) || 50664ce7165Smrg (cp = strchr(name, '@'))) { 50764ce7165Smrg char *netname = name; 50864ce7165Smrg#ifdef SECURE_RPC 50964ce7165Smrg static char username[MAXNETNAMELEN]; 51064ce7165Smrg 51164ce7165Smrg if (!cp[1]) { 51264ce7165Smrg struct passwd *pwd; 51364ce7165Smrg static char domainname[128]; 51464ce7165Smrg 51564ce7165Smrg *cp = '\0'; 51664ce7165Smrg pwd = getpwnam(name); 51764ce7165Smrg if (!pwd) { 518b71ad168Smrg fprintf(stderr, gettext("no such user \"%s\"\n"), name); 51964ce7165Smrg return 0; 52064ce7165Smrg } 52164ce7165Smrg getdomainname(domainname, sizeof(domainname)); 52264ce7165Smrg if (!user2netname(username, pwd->pw_uid, domainname)) { 523b71ad168Smrg fprintf(stderr, gettext("failed to get netname for \"%s\"\n"), name); 52464ce7165Smrg return 0; 52564ce7165Smrg } 52664ce7165Smrg netname = username; 52764ce7165Smrg } 52864ce7165Smrg#endif 52964ce7165Smrg ha.family = FamilyNetname; 53064ce7165Smrg ha.length = strlen(netname); 53164ce7165Smrg ha.address = netname; 53264ce7165Smrg if (add) 53364ce7165Smrg XAddHost (dpy, &ha); 53464ce7165Smrg else 53564ce7165Smrg XRemoveHost (dpy, &ha); 53664ce7165Smrg if (netname != name) 53764ce7165Smrg printf ("%s@ (%s) %s\n", name, netname, add ? add_msg : remove_msg); 53864ce7165Smrg else 53964ce7165Smrg printf ("%s %s\n", netname, add ? add_msg : remove_msg); 54064ce7165Smrg return 1; 54164ce7165Smrg } 54264ce7165Smrg#ifdef NEEDSOCKETS 54364ce7165Smrg /* 544aadd013eSmrg * First see if inet_aton/inet_addr can grok the name; if so, then use it. 54564ce7165Smrg */ 54664ce7165Smrg if (((family == FamilyWild) || (family == FamilyInternet)) && 547aadd013eSmrg#ifdef HAVE_INET_ATON 548aadd013eSmrg (inet_aton (name, &addr) != 0) 549aadd013eSmrg#else 550aadd013eSmrg ((addr.s_addr = inet_addr(name)) != -1) 551aadd013eSmrg#endif 552aadd013eSmrg ) { 55364ce7165Smrg ha.family = FamilyInternet; 554aadd013eSmrg ha.length = sizeof(addr.s_addr); 555aadd013eSmrg ha.address = (char *) &addr.s_addr; 55664ce7165Smrg if (add) { 55764ce7165Smrg XAddHost (dpy, &ha); 55864ce7165Smrg printf ("%s %s\n", name, add_msg); 55964ce7165Smrg } else { 56064ce7165Smrg XRemoveHost (dpy, &ha); 56164ce7165Smrg printf ("%s %s\n", name, remove_msg); 56264ce7165Smrg } 56364ce7165Smrg return 1; 56464ce7165Smrg } 56564ce7165Smrg#if defined(IPv6) && defined(AF_INET6) 56664ce7165Smrg /* 56764ce7165Smrg * Check to see if inet_pton() can grok it as an IPv6 address 56864ce7165Smrg */ 56964ce7165Smrg else if (((family == FamilyWild) || (family == FamilyInternet6)) && 57064ce7165Smrg (inet_pton(AF_INET6, name, &addr6.s6_addr) == 1)) { 57164ce7165Smrg ha.family = FamilyInternet6; 57264ce7165Smrg ha.length = sizeof(addr6.s6_addr); 57364ce7165Smrg ha.address = (char *) &addr6.s6_addr; 57464ce7165Smrg if (add) { 57564ce7165Smrg XAddHost (dpy, &ha); 57664ce7165Smrg printf ("%s %s\n", name, add_msg); 57764ce7165Smrg } else { 57864ce7165Smrg XRemoveHost (dpy, &ha); 57964ce7165Smrg printf ("%s %s\n", name, remove_msg); 58064ce7165Smrg } 58164ce7165Smrg return 1; 58264ce7165Smrg } else { 58364ce7165Smrg /* 58464ce7165Smrg * Is it in the namespace? 58564ce7165Smrg * 58664ce7165Smrg * If no family was specified, use both Internet v4 & v6 addresses. 58764ce7165Smrg * Otherwise, use only addresses matching specified family. 58864ce7165Smrg */ 58964ce7165Smrg struct addrinfo *addresses; 59064ce7165Smrg struct addrinfo *a; 59164ce7165Smrg Bool didit = False; 59264ce7165Smrg 59364ce7165Smrg if (getaddrinfo(name, NULL, NULL, &addresses) != 0) 59464ce7165Smrg return 0; 59564ce7165Smrg 59664ce7165Smrg for (a = addresses; a != NULL; a = a->ai_next) { 59764ce7165Smrg if ( ((a->ai_family == AF_INET) && (family != FamilyInternet6)) 59864ce7165Smrg || ((a->ai_family == AF_INET6) && (family != FamilyInternet)) ) { 59964ce7165Smrg char ad[INET6_ADDRSTRLEN]; 60064ce7165Smrg ha.family = XFamily(a->ai_family); 60164ce7165Smrg if (a->ai_family == AF_INET6) { 60264ce7165Smrg ha.address = (char *) 60364ce7165Smrg &((struct sockaddr_in6 *) a->ai_addr)->sin6_addr; 60464ce7165Smrg ha.length = 60564ce7165Smrg sizeof (((struct sockaddr_in6 *) a->ai_addr)->sin6_addr); 60664ce7165Smrg } else { 60764ce7165Smrg ha.address = (char *) 60864ce7165Smrg &((struct sockaddr_in *) a->ai_addr)->sin_addr; 60964ce7165Smrg ha.length = 61064ce7165Smrg sizeof (((struct sockaddr_in *) a->ai_addr)->sin_addr); 61164ce7165Smrg } 61264ce7165Smrg inet_ntop(a->ai_family, ha.address, ad, sizeof(ad)); 61364ce7165Smrg /* printf("Family: %d\nLength: %d\n", a->ai_family, ha.length); */ 61464ce7165Smrg /* printf("Address: %s\n", ad); */ 61564ce7165Smrg 61664ce7165Smrg if (add) { 61764ce7165Smrg XAddHost (dpy, &ha); 61864ce7165Smrg } else { 61964ce7165Smrg XRemoveHost (dpy, &ha); 62064ce7165Smrg } 62164ce7165Smrg didit = True; 62264ce7165Smrg } 62364ce7165Smrg } 62464ce7165Smrg if (didit == True) { 62564ce7165Smrg printf ("%s %s\n", name, add ? add_msg : remove_msg); 62664ce7165Smrg } else { 62764ce7165Smrg const char *familyMsg = ""; 62864ce7165Smrg 62964ce7165Smrg if (family == FamilyInternet6) { 63064ce7165Smrg familyMsg = "inet6 "; 63164ce7165Smrg } else if (family == FamilyInternet) { 63264ce7165Smrg familyMsg = "inet "; 63364ce7165Smrg } 63464ce7165Smrg 635b71ad168Smrg fprintf(stderr, gettext("%s: unable to get %saddress for \"%s\"\n"), 63664ce7165Smrg ProgramName, familyMsg, name); 63764ce7165Smrg } 63864ce7165Smrg freeaddrinfo(addresses); 63964ce7165Smrg return 1; 64064ce7165Smrg } 64164ce7165Smrg#else /* !IPv6 */ 64264ce7165Smrg /* 64364ce7165Smrg * Is it in the namespace? 64464ce7165Smrg */ 64564ce7165Smrg else if (((hp = gethostbyname(name)) == (struct hostent *)NULL) 64664ce7165Smrg || hp->h_addrtype != AF_INET) { 64764ce7165Smrg return 0; 64864ce7165Smrg } else { 64964ce7165Smrg ha.family = XFamily(hp->h_addrtype); 65064ce7165Smrg ha.length = hp->h_length; 65164ce7165Smrg#ifdef h_addr /* new 4.3bsd version of gethostent */ 65264ce7165Smrg { 65364ce7165Smrg char **list; 65464ce7165Smrg 65564ce7165Smrg /* iterate over the hosts */ 65664ce7165Smrg for (list = hp->h_addr_list; *list; list++) { 65764ce7165Smrg ha.address = *list; 65864ce7165Smrg if (add) { 65964ce7165Smrg XAddHost (dpy, &ha); 66064ce7165Smrg } else { 66164ce7165Smrg XRemoveHost (dpy, &ha); 66264ce7165Smrg } 66364ce7165Smrg } 66464ce7165Smrg } 66564ce7165Smrg#else 66664ce7165Smrg ha.address = hp->h_addr; 66764ce7165Smrg if (add) { 66864ce7165Smrg XAddHost (dpy, &ha); 66964ce7165Smrg } else { 67064ce7165Smrg XRemoveHost (dpy, &ha); 67164ce7165Smrg } 67264ce7165Smrg#endif 67364ce7165Smrg printf ("%s %s\n", name, add ? add_msg : remove_msg); 67464ce7165Smrg return 1; 67564ce7165Smrg } 67664ce7165Smrg#endif /* IPv6 */ 67764ce7165Smrg#else /* NEEDSOCKETS */ 67864ce7165Smrg return 0; 67964ce7165Smrg#endif /* NEEDSOCKETS */ 68064ce7165Smrg} 68164ce7165Smrg 68264ce7165Smrg 68364ce7165Smrg/* 68464ce7165Smrg * get_hostname - Given an internet address, return a name (CHARON.MIT.EDU) 68564ce7165Smrg * or a string representing the address (18.58.0.13) if the name cannot 68664ce7165Smrg * be found. 68764ce7165Smrg */ 68864ce7165Smrg 68964ce7165Smrg 6903544ea2eSmrgstatic const char * 69164ce7165Smrgget_hostname(XHostAddress *ha) 69264ce7165Smrg{ 69381440437Smrg#if defined(TCPCONN) && (!defined(IPv6) || !defined(AF_INET6)) 69464ce7165Smrg static struct hostent *hp = NULL; 69564ce7165Smrg#endif 69664ce7165Smrg#ifdef K5AUTH 69764ce7165Smrg krb5_principal princ; 69864ce7165Smrg krb5_data kbuf; 69964ce7165Smrg char *kname; 70064ce7165Smrg static char kname_out[255]; 70164ce7165Smrg#endif 70281440437Smrg#ifdef SIGALRM 70364ce7165Smrg struct sigaction sa; 70464ce7165Smrg#endif 70564ce7165Smrg 70681440437Smrg#ifdef TCPCONN 70764ce7165Smrg#if defined(IPv6) && defined(AF_INET6) 70864ce7165Smrg if ((ha->family == FamilyInternet) || (ha->family == FamilyInternet6)) { 70964ce7165Smrg struct sockaddr_storage saddr; 71064ce7165Smrg static char inetname[NI_MAXHOST]; 71181440437Smrg unsigned int saddrlen; 71264ce7165Smrg 71364ce7165Smrg inetname[0] = '\0'; 71464ce7165Smrg memset(&saddr, 0, sizeof saddr); 71564ce7165Smrg if (ha->family == FamilyInternet) { 71664ce7165Smrg struct sockaddr_in *sin = (struct sockaddr_in *) &saddr; 71764ce7165Smrg#ifdef BSD44SOCKETS 71864ce7165Smrg sin->sin_len = sizeof(struct sockaddr_in); 71964ce7165Smrg#endif 72064ce7165Smrg sin->sin_family = AF_INET; 72164ce7165Smrg sin->sin_port = 0; 722aadd013eSmrg if (sizeof(sin->sin_addr) > ha->length) 723aadd013eSmrg return ""; 72464ce7165Smrg memcpy(&sin->sin_addr, ha->address, sizeof(sin->sin_addr)); 72564ce7165Smrg saddrlen = sizeof(struct sockaddr_in); 72664ce7165Smrg } else { 72764ce7165Smrg struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &saddr; 72864ce7165Smrg#ifdef SIN6_LEN 72964ce7165Smrg sin6->sin6_len = sizeof(struct sockaddr_in6); 73064ce7165Smrg#endif 73164ce7165Smrg sin6->sin6_family = AF_INET6; 73264ce7165Smrg sin6->sin6_port = 0; 733aadd013eSmrg if (sizeof(sin6->sin6_addr) > ha->length) 734aadd013eSmrg return ""; 73564ce7165Smrg memcpy(&sin6->sin6_addr, ha->address, sizeof(sin6->sin6_addr)); 73664ce7165Smrg saddrlen = sizeof(struct sockaddr_in6); 73764ce7165Smrg } 73864ce7165Smrg 73964ce7165Smrg /* gethostbyaddr can take a LONG time if the host does not exist. 74064ce7165Smrg Assume that if it does not respond in NAMESERVER_TIMEOUT seconds 74164ce7165Smrg that something is wrong and do not make the user wait. 74264ce7165Smrg gethostbyaddr will continue after a signal, so we have to 74364ce7165Smrg jump out of it. 74464ce7165Smrg */ 74581440437Smrg#ifdef SIGALRM 74664ce7165Smrg memset(&sa, 0, sizeof sa); 74764ce7165Smrg sa.sa_handler = nameserver_lost; 74864ce7165Smrg sa.sa_flags = 0; /* don't restart syscalls */ 74964ce7165Smrg sigaction(SIGALRM, &sa, NULL); 75064ce7165Smrg alarm(NAMESERVER_TIMEOUT); 75164ce7165Smrg#endif 75281440437Smrg getnameinfo((struct sockaddr *) &saddr, saddrlen, inetname, 75381440437Smrg sizeof(inetname), NULL, 0, 0); 75481440437Smrg#ifdef SIGALRM 75564ce7165Smrg alarm(0); 75681440437Smrg#endif 75764ce7165Smrg if (nameserver_timedout || inetname[0] == '\0') 75864ce7165Smrg inet_ntop(((struct sockaddr *)&saddr)->sa_family, ha->address, 75964ce7165Smrg inetname, sizeof(inetname)); 76064ce7165Smrg return inetname; 76164ce7165Smrg } 76264ce7165Smrg#else 76364ce7165Smrg if (ha->family == FamilyInternet) { 76464ce7165Smrg /* gethostbyaddr can take a LONG time if the host does not exist. 76564ce7165Smrg Assume that if it does not respond in NAMESERVER_TIMEOUT seconds 76664ce7165Smrg that something is wrong and do not make the user wait. 76764ce7165Smrg gethostbyaddr will continue after a signal, so we have to 76864ce7165Smrg jump out of it. 76964ce7165Smrg */ 77081440437Smrg#ifdef SIGALRM 77164ce7165Smrg memset(&sa, 0, sizeof sa); 77264ce7165Smrg sa.sa_handler = nameserver_lost; 77364ce7165Smrg sa.sa_flags = 0; /* don't restart syscalls */ 77464ce7165Smrg sigaction(SIGALRM, &sa, NULL); 77564ce7165Smrg alarm(4); 77664ce7165Smrg#endif 77781440437Smrg hp = gethostbyaddr (ha->address, ha->length, AF_INET); 77881440437Smrg#ifdef SIGALRM 77964ce7165Smrg alarm(0); 78081440437Smrg#endif 78164ce7165Smrg if (hp) 78264ce7165Smrg return (hp->h_name); 78364ce7165Smrg else return (inet_ntoa(*((struct in_addr *)(ha->address)))); 78464ce7165Smrg } 78564ce7165Smrg#endif /* IPv6 */ 78664ce7165Smrg#endif 78764ce7165Smrg if (ha->family == FamilyNetname) { 78864ce7165Smrg static char netname[512]; 78964ce7165Smrg int len; 79064ce7165Smrg#ifdef SECURE_RPC 79164ce7165Smrg int gidlen; 79264ce7165Smrg uid_t uid; 79364ce7165Smrg gid_t gid, gidlist[NGROUPS_MAX]; 79464ce7165Smrg#endif 79564ce7165Smrg 79664ce7165Smrg if (ha->length < sizeof(netname) - 1) 79764ce7165Smrg len = ha->length; 79864ce7165Smrg else 79964ce7165Smrg len = sizeof(netname) - 1; 80064ce7165Smrg memmove( netname, ha->address, len); 80164ce7165Smrg netname[len] = '\0'; 80264ce7165Smrg#ifdef SECURE_RPC 80364ce7165Smrg if (netname2user(netname, &uid, &gid, &gidlen, gidlist)) { 80464ce7165Smrg struct passwd *pwd; 80564ce7165Smrg 80664ce7165Smrg pwd = getpwuid(uid); 80764ce7165Smrg if (pwd) 80881440437Smrg snprintf(netname, sizeof(netname), "%s@ (%*.*s)", 80981440437Smrg pwd->pw_name, ha->length, ha->length, ha->address); 81064ce7165Smrg } 81164ce7165Smrg#endif 81264ce7165Smrg return (netname); 81364ce7165Smrg } 81464ce7165Smrg#ifdef K5AUTH 81564ce7165Smrg if (ha->family == FamilyKrb5Principal) { 81664ce7165Smrg kbuf.data = ha->address; 81764ce7165Smrg kbuf.length = ha->length; 81864ce7165Smrg XauKrb5Decode(kbuf, &princ); 81964ce7165Smrg krb5_unparse_name(princ, &kname); 82064ce7165Smrg krb5_free_principal(princ); 82164ce7165Smrg strncpy(kname_out, kname, sizeof (kname_out)); 82264ce7165Smrg free(kname); 82364ce7165Smrg return kname_out; 82464ce7165Smrg } 82564ce7165Smrg#endif 82664ce7165Smrg if (ha->family == FamilyLocalHost) { 82764ce7165Smrg return ""; 82864ce7165Smrg } 82964ce7165Smrg if (ha->family == FamilyServerInterpreted) { 83064ce7165Smrg XServerInterpretedAddress *sip; 83164ce7165Smrg static char *addressString; 83264ce7165Smrg static size_t addressStringSize; 83364ce7165Smrg size_t neededSize; 83464ce7165Smrg 83564ce7165Smrg sip = (XServerInterpretedAddress *) ha->address; 83664ce7165Smrg neededSize = sip->typelength + sip->valuelength + 2; 83764ce7165Smrg 83864ce7165Smrg if (addressStringSize < neededSize) { 83964ce7165Smrg if (addressString != NULL) { 84064ce7165Smrg free(addressString); 84164ce7165Smrg } 84264ce7165Smrg addressStringSize = neededSize; 84364ce7165Smrg addressString = malloc(addressStringSize); 84464ce7165Smrg } 84564ce7165Smrg if (addressString != NULL) { 84664ce7165Smrg char *cp = addressString; 84764ce7165Smrg 84864ce7165Smrg memcpy(cp, sip->type, sip->typelength); 84964ce7165Smrg cp += sip->typelength; 85064ce7165Smrg *cp++ = ':'; 85164ce7165Smrg memcpy(cp, sip->value, sip->valuelength); 85264ce7165Smrg cp += sip->valuelength; 85364ce7165Smrg *cp = '\0'; 85464ce7165Smrg } 85564ce7165Smrg return addressString; 85664ce7165Smrg } 85764ce7165Smrg return (NULL); 85864ce7165Smrg} 85964ce7165Smrg 86064ce7165Smrg/*ARGUSED*/ 86181440437Smrgstatic void 86281440437Smrgnameserver_lost(_X_UNUSED int sig) 86364ce7165Smrg{ 86464ce7165Smrg nameserver_timedout = 1; 86564ce7165Smrg} 86664ce7165Smrg 86764ce7165Smrg/* 86864ce7165Smrg * local_xerror - local non-fatal error handling routine. If the error was 86964ce7165Smrg * that an X_GetHosts request for an unknown address format was received, just 87064ce7165Smrg * return, otherwise print the normal error message and continue. 87164ce7165Smrg */ 87264ce7165Smrgstatic int 87364ce7165Smrglocal_xerror(Display *dpy, XErrorEvent *rep) 87464ce7165Smrg{ 87564ce7165Smrg if ((rep->error_code == BadAccess) && (rep->request_code == X_ChangeHosts)) { 87664ce7165Smrg fprintf (stderr, 877b71ad168Smrg gettext("%s: must be on local machine to add or remove hosts.\n"), 87864ce7165Smrg ProgramName); 87964ce7165Smrg return 1; 88064ce7165Smrg } else if ((rep->error_code == BadAccess) && 88164ce7165Smrg (rep->request_code == X_SetAccessControl)) { 88264ce7165Smrg fprintf (stderr, 883b71ad168Smrg gettext("%s: must be on local machine to enable or disable access control.\n"), 88464ce7165Smrg ProgramName); 88564ce7165Smrg return 1; 88664ce7165Smrg } else if ((rep->error_code == BadValue) && 88764ce7165Smrg (rep->request_code == X_ListHosts)) { 88864ce7165Smrg return 1; 88964ce7165Smrg } 89064ce7165Smrg 89164ce7165Smrg XmuPrintDefaultErrorMessage (dpy, rep, stderr); 89264ce7165Smrg return 0; 89364ce7165Smrg} 894