xhost.c revision 81440437
1169a0819Smrg/*
2169a0819Smrg * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
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
12264ce7165Smrgstatic int change_host(Display *dpy, char *name, Bool add);
1233544ea2eSmrgstatic const char *get_hostname(XHostAddress *ha);
12464ce7165Smrgstatic int local_xerror(Display *dpy, XErrorEvent *rep);
12581440437Smrgstatic void nameserver_lost(int sig);
12664ce7165Smrg
12764ce7165Smrg#define NAMESERVER_TIMEOUT 5	/* time to wait for nameserver */
12864ce7165Smrg
129fb23d3a8Smrgstatic volatile int nameserver_timedout;
130fb23d3a8Smrg
131fb23d3a8Smrgstatic char *ProgramName;
13264ce7165Smrg
13364ce7165Smrg#ifdef NEEDSOCKETS
13464ce7165Smrgstatic int
13564ce7165SmrgXFamily(int af)
13664ce7165Smrg{
13781440437Smrg    unsigned int i;
13864ce7165Smrg    static struct _familyMap {
13964ce7165Smrg	int af, xf;
14064ce7165Smrg    } familyMap[] = {
14164ce7165Smrg#ifdef	AF_DECnet
14264ce7165Smrg        { AF_DECnet, FamilyDECnet },
14364ce7165Smrg#endif
14464ce7165Smrg#ifdef	AF_CHAOS
14564ce7165Smrg        { AF_CHAOS, FamilyChaos },
14664ce7165Smrg#endif
14764ce7165Smrg#ifdef	AF_INET
14864ce7165Smrg        { AF_INET, FamilyInternet },
14964ce7165Smrg#if defined(IPv6) && defined(AF_INET6)
15064ce7165Smrg        { AF_INET6, FamilyInternet6 },
15164ce7165Smrg#endif
15264ce7165Smrg#endif
15364ce7165Smrg};
15464ce7165Smrg
15564ce7165Smrg#define FAMILIES ((sizeof familyMap)/(sizeof familyMap[0]))
15664ce7165Smrg
15764ce7165Smrg    for (i = 0; i < FAMILIES; i++)
15864ce7165Smrg	if (familyMap[i].af == af) return familyMap[i].xf;
15964ce7165Smrg    return -1;
16064ce7165Smrg}
16164ce7165Smrg#endif /* NEEDSOCKETS */
16264ce7165Smrg
16364ce7165Smrgint
16464ce7165Smrgmain(int argc, char *argv[])
16564ce7165Smrg{
16664ce7165Smrg    register char *arg;
16764ce7165Smrg    int i, nhosts = 0;
1683544ea2eSmrg    const char *hostname;
16964ce7165Smrg    int nfailed = 0;
17064ce7165Smrg    XHostAddress *list;
17164ce7165Smrg    Bool enabled = False;
17281440437Smrg    Display *dpy;
17364ce7165Smrg
17464ce7165Smrg    ProgramName = argv[0];
17564ce7165Smrg
1763544ea2eSmrg    if (argc == 2 && !strcmp(argv[1], "-help")) {
1773544ea2eSmrg	fprintf(stderr, "usage: %s [[+-]hostname ...]\n", argv[0]);
1783544ea2eSmrg	exit(1);
1793544ea2eSmrg    }
1803544ea2eSmrg
18164ce7165Smrg    if ((dpy = XOpenDisplay(NULL)) == NULL) {
18264ce7165Smrg	fprintf(stderr, "%s:  unable to open display \"%s\"\n",
18364ce7165Smrg		ProgramName, XDisplayName (NULL));
18464ce7165Smrg	exit(1);
18564ce7165Smrg    }
18664ce7165Smrg
18764ce7165Smrg    XSetErrorHandler(local_xerror);
18864ce7165Smrg
18964ce7165Smrg
19064ce7165Smrg    if (argc == 1) {
19164ce7165Smrg	sethostent(1);		/* don't close the data base each time */
19264ce7165Smrg	list = XListHosts(dpy, &nhosts, &enabled);
19364ce7165Smrg	if (enabled)
19464ce7165Smrg	    printf ("access control enabled, only authorized clients can connect\n");
19564ce7165Smrg	else
19664ce7165Smrg	    printf ("access control disabled, clients can connect from any host\n");
19764ce7165Smrg
19864ce7165Smrg	if (nhosts != 0) {
19964ce7165Smrg	    for (i = 0; i < nhosts; i++ )  {
20064ce7165Smrg		hostname = get_hostname(&list[i]);
20164ce7165Smrg		if (hostname) {
20264ce7165Smrg		    switch (list[i].family) {
20364ce7165Smrg		    case FamilyInternet:
20464ce7165Smrg			printf("INET:");
20564ce7165Smrg			break;
20664ce7165Smrg		    case FamilyInternet6:
20764ce7165Smrg			printf("INET6:");
20864ce7165Smrg			break;
20964ce7165Smrg		    case FamilyDECnet:
21064ce7165Smrg			printf("DNET:");
21164ce7165Smrg			break;
21264ce7165Smrg		    case FamilyNetname:
21364ce7165Smrg			printf("NIS:");
21464ce7165Smrg			break;
21564ce7165Smrg		    case FamilyKrb5Principal:
21664ce7165Smrg			printf("KRB:");
21764ce7165Smrg			break;
21864ce7165Smrg		    case FamilyLocalHost:
21964ce7165Smrg			printf("LOCAL:");
22064ce7165Smrg			break;
22164ce7165Smrg		    case FamilyServerInterpreted:
22264ce7165Smrg			printf("SI:");
22364ce7165Smrg			break;
22464ce7165Smrg		    default:
22564ce7165Smrg			printf("<unknown family type %d>:", list[i].family);
22664ce7165Smrg			break;
22764ce7165Smrg		    }
22864ce7165Smrg		    printf ("%s", hostname);
22964ce7165Smrg		} else {
23064ce7165Smrg		    printf ("<unknown address in family %d>",
23164ce7165Smrg			    list[i].family);
23264ce7165Smrg		}
23364ce7165Smrg		if (nameserver_timedout) {
23464ce7165Smrg		    printf("\t(no nameserver response within %d seconds)\n",
23564ce7165Smrg			   NAMESERVER_TIMEOUT);
23664ce7165Smrg		    nameserver_timedout = 0;
23764ce7165Smrg		} else
23864ce7165Smrg		    printf("\n");
23964ce7165Smrg	    }
24064ce7165Smrg	    free(list);
24164ce7165Smrg	    endhostent();
24264ce7165Smrg	}
24364ce7165Smrg	exit(0);
24464ce7165Smrg    }
24564ce7165Smrg
24664ce7165Smrg    for (i = 1; i < argc; i++) {
24764ce7165Smrg	arg = argv[i];
24864ce7165Smrg	if (*arg == '-') {
24964ce7165Smrg
25064ce7165Smrg	    if (!argv[i][1] && ((i+1) == argc)) {
25164ce7165Smrg		printf ("access control enabled, only authorized clients can connect\n");
25264ce7165Smrg		XEnableAccessControl(dpy);
25364ce7165Smrg	    } else {
25464ce7165Smrg		arg = argv[i][1]? &argv[i][1] : argv[++i];
25564ce7165Smrg		if (!change_host (dpy, arg, False)) {
25664ce7165Smrg		    fprintf (stderr, "%s:  bad hostname \"%s\"\n",
25764ce7165Smrg			     ProgramName, arg);
25864ce7165Smrg		    nfailed++;
25964ce7165Smrg		}
26064ce7165Smrg	    }
26164ce7165Smrg	} else {
26264ce7165Smrg	    if (*arg == '+' && !argv[i][1] && ((i+1) == argc)) {
26364ce7165Smrg		printf ("access control disabled, clients can connect from any host\n");
26464ce7165Smrg		XDisableAccessControl(dpy);
26564ce7165Smrg	    } else {
26664ce7165Smrg		if (*arg == '+') {
26764ce7165Smrg		    arg = argv[i][1]? &argv[i][1] : argv[++i];
26864ce7165Smrg		}
26964ce7165Smrg		if (!change_host (dpy, arg, True)) {
27064ce7165Smrg		    fprintf (stderr, "%s:  bad hostname \"%s\"\n",
27164ce7165Smrg			     ProgramName, arg);
27264ce7165Smrg		    nfailed++;
27364ce7165Smrg		}
27464ce7165Smrg	    }
27564ce7165Smrg	}
27664ce7165Smrg    }
27764ce7165Smrg    XCloseDisplay (dpy);	/* does an XSync first */
27864ce7165Smrg    exit(nfailed);
27964ce7165Smrg}
28064ce7165Smrg
28164ce7165Smrg
28264ce7165Smrg
28364ce7165Smrg/*
28464ce7165Smrg * change_host - edit the list of hosts that may connect to the server;
28564ce7165Smrg * it parses DECnet names (expo::), Internet addresses (18.30.0.212), or
28664ce7165Smrg * Internet names (expo.lcs.mit.edu); if 4.3bsd macro h_addr is defined
28764ce7165Smrg * (from <netdb.h>), it will add or remove all addresses with the given
28864ce7165Smrg * address.
28964ce7165Smrg */
29064ce7165Smrg
29164ce7165Smrgstatic int
29264ce7165Smrgchange_host(Display *dpy, char *name, Bool add)
29364ce7165Smrg{
29464ce7165Smrg    XHostAddress ha;
29564ce7165Smrg    char *lname;
29681440437Smrg    size_t namelen, i;
29781440437Smrg    int family = FamilyWild;
29864ce7165Smrg#ifdef K5AUTH
29964ce7165Smrg    krb5_principal princ;
30064ce7165Smrg    krb5_data kbuf;
30164ce7165Smrg#endif
30264ce7165Smrg#ifdef NEEDSOCKETS
30364ce7165Smrg    static struct in_addr addr;	/* so we can point at it */
30464ce7165Smrg#if defined(IPv6) && defined(AF_INET6)
30564ce7165Smrg    static struct in6_addr addr6; /* so we can point at it */
30664ce7165Smrg#else
30764ce7165Smrg    struct hostent *hp;
30864ce7165Smrg#endif
30964ce7165Smrg#endif
31064ce7165Smrg    char *cp;
3113544ea2eSmrg    static const char *add_msg = "being added to access control list";
3123544ea2eSmrg    static const char *remove_msg = "being removed from access control list";
31364ce7165Smrg
31464ce7165Smrg    namelen = strlen(name);
31564ce7165Smrg    if ((lname = (char *)malloc(namelen+1)) == NULL) {
31664ce7165Smrg	fprintf (stderr, "%s: malloc bombed in change_host\n", ProgramName);
31764ce7165Smrg	exit (1);
31864ce7165Smrg    }
31964ce7165Smrg    for (i = 0; i < namelen; i++) {
32064ce7165Smrg	lname[i] = tolower(name[i]);
32164ce7165Smrg    }
32264ce7165Smrg    lname[namelen] = '\0';
32364ce7165Smrg    if (!strncmp("inet:", lname, 5)) {
32481440437Smrg#ifdef TCPCONN
32564ce7165Smrg	family = FamilyInternet;
32664ce7165Smrg	name += 5;
32764ce7165Smrg#else
32864ce7165Smrg	fprintf (stderr, "%s: not compiled for TCP/IP\n", ProgramName);
32964ce7165Smrg	free(lname);
33064ce7165Smrg	return 0;
33164ce7165Smrg#endif
33264ce7165Smrg    }
33364ce7165Smrg    else if (!strncmp("inet6:", lname, 6)) {
33481440437Smrg#if defined(TCPCONN) && defined(IPv6) && defined(AF_INET6)
33564ce7165Smrg	family = FamilyInternet6;
33664ce7165Smrg	name += 6;
33764ce7165Smrg#else
33864ce7165Smrg	fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
33964ce7165Smrg	free(lname);
34064ce7165Smrg	return 0;
34164ce7165Smrg#endif
34264ce7165Smrg    }
34364ce7165Smrg#ifdef ACCEPT_INETV6 /* Allow inetv6 as an alias for inet6 for compatibility
34464ce7165Smrg			with original X11 over IPv6 draft. */
34564ce7165Smrg    else if (!strncmp("inetv6:", lname, 7)) {
34681440437Smrg#if defined(TCPCONN) && defined(IPv6) && defined(AF_INET6)
34764ce7165Smrg	family = FamilyInternet6;
34864ce7165Smrg	name += 7;
34964ce7165Smrg#else
35064ce7165Smrg	fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
35164ce7165Smrg	free(lname);
35264ce7165Smrg	return 0;
35364ce7165Smrg#endif
35464ce7165Smrg    }
35564ce7165Smrg#endif /* ACCEPT_INETV6 */
35664ce7165Smrg    else if (!strncmp("dnet:", lname, 5)) {
35764ce7165Smrg	fprintf (stderr, "%s: not compiled for DECnet\n", ProgramName);
35864ce7165Smrg	free(lname);
35964ce7165Smrg	return 0;
36064ce7165Smrg    }
36164ce7165Smrg    else if (!strncmp("nis:", lname, 4)) {
36264ce7165Smrg#ifdef SECURE_RPC
36364ce7165Smrg	family = FamilyNetname;
36464ce7165Smrg	name += 4;
36564ce7165Smrg#else
36664ce7165Smrg	fprintf (stderr, "%s: not compiled for Secure RPC\n", ProgramName);
36764ce7165Smrg	free(lname);
36864ce7165Smrg	return 0;
36964ce7165Smrg#endif
37064ce7165Smrg    }
37164ce7165Smrg    else if (!strncmp("krb:", lname, 4)) {
37264ce7165Smrg#ifdef K5AUTH
37364ce7165Smrg	family = FamilyKrb5Principal;
37464ce7165Smrg	name +=4;
37564ce7165Smrg#else
37664ce7165Smrg	fprintf (stderr, "%s: not compiled for Kerberos 5\n", ProgramName);
37764ce7165Smrg	free(lname);
37864ce7165Smrg	return 0;
37964ce7165Smrg#endif
38064ce7165Smrg    }
38164ce7165Smrg    else if (!strncmp("local:", lname, 6)) {
38264ce7165Smrg	family = FamilyLocalHost;
38364ce7165Smrg    }
38464ce7165Smrg    else if (!strncmp("si:", lname, 3)) {
38564ce7165Smrg	family = FamilyServerInterpreted;
38664ce7165Smrg	name += 3;
38764ce7165Smrg    }
38864ce7165Smrg    if (family == FamilyWild && (cp = strchr(lname, ':'))) {
38964ce7165Smrg	*cp = '\0';
39064ce7165Smrg	fprintf (stderr, "%s: unknown address family \"%s\"\n",
39164ce7165Smrg		 ProgramName, lname);
39264ce7165Smrg	free(lname);
39364ce7165Smrg	return 0;
39464ce7165Smrg    }
39564ce7165Smrg    free(lname);
39664ce7165Smrg
39764ce7165Smrg    if (family == FamilyServerInterpreted) {
39864ce7165Smrg	XServerInterpretedAddress siaddr;
3993544ea2eSmrg	int rc;
40064ce7165Smrg
40164ce7165Smrg	cp = strchr(name, ':');
40264ce7165Smrg	if (cp == NULL || cp == name) {
40364ce7165Smrg	    fprintf(stderr,
40464ce7165Smrg	   "%s: type must be specified for server interpreted family \"%s\"\n",
40564ce7165Smrg	      ProgramName, name);
40664ce7165Smrg	    return 0;
40764ce7165Smrg	}
4083544ea2eSmrg	siaddr.type = name;
4093544ea2eSmrg	siaddr.typelength = cp - name;
4103544ea2eSmrg	siaddr.value = ++cp;
4113544ea2eSmrg	siaddr.valuelength = strlen(cp);
41264ce7165Smrg	ha.family = FamilyServerInterpreted;
41364ce7165Smrg	ha.address = (char *) &siaddr;
41464ce7165Smrg	if (add)
4153544ea2eSmrg	    rc = XAddHost(dpy, &ha);
41664ce7165Smrg	else
4173544ea2eSmrg	    rc = XRemoveHost(dpy, &ha);
4183544ea2eSmrg	printf( "%s %s%s\n", name, rc == 1 ? "" : "failed when ",
4193544ea2eSmrg		add ? add_msg : remove_msg);
4203544ea2eSmrg	if (rc != 1)
4213544ea2eSmrg	    return 0;
42264ce7165Smrg	return 1;
42364ce7165Smrg    }
42464ce7165Smrg
42564ce7165Smrg#ifdef K5AUTH
42664ce7165Smrg    if (family == FamilyKrb5Principal) {
42764ce7165Smrg	krb5_error_code retval;
42864ce7165Smrg
42964ce7165Smrg	retval = krb5_parse_name(name, &princ);
43064ce7165Smrg	if (retval) {
43164ce7165Smrg	    krb5_init_ets();	/* init krb errs for error_message() */
43264ce7165Smrg	    fprintf(stderr, "%s: cannot parse Kerberos name: %s\n",
43364ce7165Smrg		    ProgramName, error_message(retval));
43464ce7165Smrg	    return 0;
43564ce7165Smrg	}
43664ce7165Smrg	XauKrb5Encode(princ, &kbuf);
43764ce7165Smrg	ha.length = kbuf.length;
43864ce7165Smrg	ha.address = kbuf.data;
43964ce7165Smrg	ha.family = family;
44064ce7165Smrg	if (add)
44164ce7165Smrg	    XAddHost(dpy, &ha);
44264ce7165Smrg	else
44364ce7165Smrg	    XRemoveHost(dpy, &ha);
44464ce7165Smrg	krb5_free_principal(princ);
44564ce7165Smrg	free(kbuf.data);
44664ce7165Smrg	printf( "%s %s\n", name, add ? add_msg : remove_msg);
44764ce7165Smrg	return 1;
44864ce7165Smrg    }
44964ce7165Smrg#endif
45064ce7165Smrg    if (family == FamilyLocalHost) {
45181440437Smrg	char empty[] = "";
45264ce7165Smrg	ha.length = 0;
45381440437Smrg	ha.address = empty;
45464ce7165Smrg	ha.family = family;
45564ce7165Smrg	if (add)
45664ce7165Smrg	    XAddHost(dpy, &ha);
45764ce7165Smrg	else
45864ce7165Smrg	    XRemoveHost(dpy, &ha);
45964ce7165Smrg	printf( "non-network local connections %s\n", add ? add_msg : remove_msg);
46064ce7165Smrg	return 1;
46164ce7165Smrg    }
46264ce7165Smrg    /*
46364ce7165Smrg     * If it has an '@', it's a netname
46464ce7165Smrg     */
46564ce7165Smrg    if ((family == FamilyNetname && (cp = strchr(name, '@'))) ||
46664ce7165Smrg	(cp = strchr(name, '@'))) {
46764ce7165Smrg        char *netname = name;
46864ce7165Smrg#ifdef SECURE_RPC
46964ce7165Smrg	static char username[MAXNETNAMELEN];
47064ce7165Smrg
47164ce7165Smrg	if (!cp[1]) {
47264ce7165Smrg	    struct passwd *pwd;
47364ce7165Smrg	    static char domainname[128];
47464ce7165Smrg
47564ce7165Smrg	    *cp = '\0';
47664ce7165Smrg	    pwd = getpwnam(name);
47764ce7165Smrg	    if (!pwd) {
47864ce7165Smrg		fprintf(stderr, "no such user \"%s\"\n", name);
47964ce7165Smrg		return 0;
48064ce7165Smrg	    }
48164ce7165Smrg	    getdomainname(domainname, sizeof(domainname));
48264ce7165Smrg	    if (!user2netname(username, pwd->pw_uid, domainname)) {
48364ce7165Smrg		fprintf(stderr, "failed to get netname for \"%s\"\n", name);
48464ce7165Smrg		return 0;
48564ce7165Smrg	    }
48664ce7165Smrg	    netname = username;
48764ce7165Smrg	}
48864ce7165Smrg#endif
48964ce7165Smrg	ha.family = FamilyNetname;
49064ce7165Smrg	ha.length = strlen(netname);
49164ce7165Smrg	ha.address = netname;
49264ce7165Smrg	if (add)
49364ce7165Smrg	    XAddHost (dpy, &ha);
49464ce7165Smrg	else
49564ce7165Smrg	    XRemoveHost (dpy, &ha);
49664ce7165Smrg	if (netname != name)
49764ce7165Smrg	    printf ("%s@ (%s) %s\n", name, netname, add ? add_msg : remove_msg);
49864ce7165Smrg	else
49964ce7165Smrg	    printf ("%s %s\n", netname, add ? add_msg : remove_msg);
50064ce7165Smrg        return 1;
50164ce7165Smrg    }
50264ce7165Smrg#ifdef NEEDSOCKETS
50364ce7165Smrg    /*
50464ce7165Smrg     * First see if inet_addr() can grok the name; if so, then use it.
50564ce7165Smrg     */
50664ce7165Smrg    if (((family == FamilyWild) || (family == FamilyInternet)) &&
50764ce7165Smrg	((addr.s_addr = inet_addr(name)) != -1)) {
50864ce7165Smrg	ha.family = FamilyInternet;
50964ce7165Smrg	ha.length = 4;		/* but for Cray would be sizeof(addr.s_addr) */
51064ce7165Smrg	ha.address = (char *)&addr; /* but for Cray would be &addr.s_addr */
51164ce7165Smrg	if (add) {
51264ce7165Smrg	    XAddHost (dpy, &ha);
51364ce7165Smrg	    printf ("%s %s\n", name, add_msg);
51464ce7165Smrg	} else {
51564ce7165Smrg	    XRemoveHost (dpy, &ha);
51664ce7165Smrg	    printf ("%s %s\n", name, remove_msg);
51764ce7165Smrg	}
51864ce7165Smrg	return 1;
51964ce7165Smrg    }
52064ce7165Smrg#if defined(IPv6) && defined(AF_INET6)
52164ce7165Smrg    /*
52264ce7165Smrg     * Check to see if inet_pton() can grok it as an IPv6 address
52364ce7165Smrg     */
52464ce7165Smrg    else if (((family == FamilyWild) || (family == FamilyInternet6)) &&
52564ce7165Smrg	     (inet_pton(AF_INET6, name, &addr6.s6_addr) == 1)) {
52664ce7165Smrg	ha.family = FamilyInternet6;
52764ce7165Smrg	ha.length = sizeof(addr6.s6_addr);
52864ce7165Smrg	ha.address = (char *) &addr6.s6_addr;
52964ce7165Smrg	if (add) {
53064ce7165Smrg	    XAddHost (dpy, &ha);
53164ce7165Smrg	    printf ("%s %s\n", name, add_msg);
53264ce7165Smrg	} else {
53364ce7165Smrg	    XRemoveHost (dpy, &ha);
53464ce7165Smrg	    printf ("%s %s\n", name, remove_msg);
53564ce7165Smrg	}
53664ce7165Smrg	return 1;
53764ce7165Smrg    } else {
53864ce7165Smrg    /*
53964ce7165Smrg     * Is it in the namespace?
54064ce7165Smrg     *
54164ce7165Smrg     * If no family was specified, use both Internet v4 & v6 addresses.
54264ce7165Smrg     * Otherwise, use only addresses matching specified family.
54364ce7165Smrg     */
54464ce7165Smrg	struct addrinfo *addresses;
54564ce7165Smrg	struct addrinfo *a;
54664ce7165Smrg	Bool didit = False;
54764ce7165Smrg
54864ce7165Smrg	if (getaddrinfo(name, NULL, NULL, &addresses) != 0)
54964ce7165Smrg	    return 0;
55064ce7165Smrg
55164ce7165Smrg	for (a = addresses; a != NULL; a = a->ai_next) {
55264ce7165Smrg	    if ( ((a->ai_family == AF_INET) && (family != FamilyInternet6))
55364ce7165Smrg	      || ((a->ai_family == AF_INET6) && (family != FamilyInternet)) ) {
55464ce7165Smrg		char ad[INET6_ADDRSTRLEN];
55564ce7165Smrg		ha.family = XFamily(a->ai_family);
55664ce7165Smrg		if (a->ai_family == AF_INET6) {
55764ce7165Smrg		    ha.address = (char *)
55864ce7165Smrg		      &((struct sockaddr_in6 *) a->ai_addr)->sin6_addr;
55964ce7165Smrg		    ha.length =
56064ce7165Smrg		      sizeof (((struct sockaddr_in6 *) a->ai_addr)->sin6_addr);
56164ce7165Smrg		} else {
56264ce7165Smrg		    ha.address = (char *)
56364ce7165Smrg		      &((struct sockaddr_in *) a->ai_addr)->sin_addr;
56464ce7165Smrg		    ha.length =
56564ce7165Smrg		      sizeof (((struct sockaddr_in *) a->ai_addr)->sin_addr);
56664ce7165Smrg		}
56764ce7165Smrg		inet_ntop(a->ai_family, ha.address, ad, sizeof(ad));
56864ce7165Smrg	/* printf("Family: %d\nLength: %d\n", a->ai_family, ha.length); */
56964ce7165Smrg		/* printf("Address: %s\n", ad); */
57064ce7165Smrg
57164ce7165Smrg		if (add) {
57264ce7165Smrg		    XAddHost (dpy, &ha);
57364ce7165Smrg		} else {
57464ce7165Smrg		    XRemoveHost (dpy, &ha);
57564ce7165Smrg		}
57664ce7165Smrg		didit = True;
57764ce7165Smrg	    }
57864ce7165Smrg	}
57964ce7165Smrg	if (didit == True) {
58064ce7165Smrg	    printf ("%s %s\n", name, add ? add_msg : remove_msg);
58164ce7165Smrg	} else {
58264ce7165Smrg	    const char *familyMsg = "";
58364ce7165Smrg
58464ce7165Smrg	    if (family == FamilyInternet6) {
58564ce7165Smrg		familyMsg = "inet6 ";
58664ce7165Smrg	    } else if (family == FamilyInternet) {
58764ce7165Smrg		familyMsg = "inet ";
58864ce7165Smrg	    }
58964ce7165Smrg
59064ce7165Smrg	    fprintf(stderr, "%s: unable to get %saddress for \"%s\"\n",
59164ce7165Smrg		ProgramName, familyMsg, name);
59264ce7165Smrg	}
59364ce7165Smrg	freeaddrinfo(addresses);
59464ce7165Smrg	return 1;
59564ce7165Smrg    }
59664ce7165Smrg#else /* !IPv6 */
59764ce7165Smrg    /*
59864ce7165Smrg     * Is it in the namespace?
59964ce7165Smrg     */
60064ce7165Smrg    else if (((hp = gethostbyname(name)) == (struct hostent *)NULL)
60164ce7165Smrg	     || hp->h_addrtype != AF_INET) {
60264ce7165Smrg	return 0;
60364ce7165Smrg    } else {
60464ce7165Smrg	ha.family = XFamily(hp->h_addrtype);
60564ce7165Smrg	ha.length = hp->h_length;
60664ce7165Smrg#ifdef h_addr			/* new 4.3bsd version of gethostent */
60764ce7165Smrg    {
60864ce7165Smrg	char **list;
60964ce7165Smrg
61064ce7165Smrg	/* iterate over the hosts */
61164ce7165Smrg	for (list = hp->h_addr_list; *list; list++) {
61264ce7165Smrg	    ha.address = *list;
61364ce7165Smrg	    if (add) {
61464ce7165Smrg		XAddHost (dpy, &ha);
61564ce7165Smrg	    } else {
61664ce7165Smrg		XRemoveHost (dpy, &ha);
61764ce7165Smrg	    }
61864ce7165Smrg	}
61964ce7165Smrg    }
62064ce7165Smrg#else
62164ce7165Smrg	ha.address = hp->h_addr;
62264ce7165Smrg	if (add) {
62364ce7165Smrg	    XAddHost (dpy, &ha);
62464ce7165Smrg	} else {
62564ce7165Smrg	    XRemoveHost (dpy, &ha);
62664ce7165Smrg	}
62764ce7165Smrg#endif
62864ce7165Smrg	printf ("%s %s\n", name, add ? add_msg : remove_msg);
62964ce7165Smrg	return 1;
63064ce7165Smrg    }
63164ce7165Smrg#endif /* IPv6 */
63264ce7165Smrg#else /* NEEDSOCKETS */
63364ce7165Smrg    return 0;
63464ce7165Smrg#endif /* NEEDSOCKETS */
63564ce7165Smrg}
63664ce7165Smrg
63764ce7165Smrg
63864ce7165Smrg/*
63964ce7165Smrg * get_hostname - Given an internet address, return a name (CHARON.MIT.EDU)
64064ce7165Smrg * or a string representing the address (18.58.0.13) if the name cannot
64164ce7165Smrg * be found.
64264ce7165Smrg */
64364ce7165Smrg
64464ce7165Smrg
6453544ea2eSmrgstatic const char *
64664ce7165Smrgget_hostname(XHostAddress *ha)
64764ce7165Smrg{
64881440437Smrg#if defined(TCPCONN) && (!defined(IPv6) || !defined(AF_INET6))
64964ce7165Smrg    static struct hostent *hp = NULL;
65064ce7165Smrg#endif
65164ce7165Smrg#ifdef K5AUTH
65264ce7165Smrg    krb5_principal princ;
65364ce7165Smrg    krb5_data kbuf;
65464ce7165Smrg    char *kname;
65564ce7165Smrg    static char kname_out[255];
65664ce7165Smrg#endif
65781440437Smrg#ifdef SIGALRM
65864ce7165Smrg    struct sigaction sa;
65964ce7165Smrg#endif
66064ce7165Smrg
66181440437Smrg#ifdef TCPCONN
66264ce7165Smrg#if defined(IPv6) && defined(AF_INET6)
66364ce7165Smrg    if ((ha->family == FamilyInternet) || (ha->family == FamilyInternet6)) {
66464ce7165Smrg	struct sockaddr_storage saddr;
66564ce7165Smrg	static char inetname[NI_MAXHOST];
66681440437Smrg	unsigned int saddrlen;
66764ce7165Smrg
66864ce7165Smrg	inetname[0] = '\0';
66964ce7165Smrg	memset(&saddr, 0, sizeof saddr);
67064ce7165Smrg	if (ha->family == FamilyInternet) {
67164ce7165Smrg	    struct sockaddr_in *sin = (struct sockaddr_in *) &saddr;
67264ce7165Smrg#ifdef BSD44SOCKETS
67364ce7165Smrg	    sin->sin_len = sizeof(struct sockaddr_in);
67464ce7165Smrg#endif
67564ce7165Smrg	    sin->sin_family = AF_INET;
67664ce7165Smrg	    sin->sin_port = 0;
67764ce7165Smrg	    memcpy(&sin->sin_addr, ha->address, sizeof(sin->sin_addr));
67864ce7165Smrg	    saddrlen = sizeof(struct sockaddr_in);
67964ce7165Smrg	} else {
68064ce7165Smrg	    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &saddr;
68164ce7165Smrg#ifdef SIN6_LEN
68264ce7165Smrg	    sin6->sin6_len = sizeof(struct sockaddr_in6);
68364ce7165Smrg#endif
68464ce7165Smrg	    sin6->sin6_family = AF_INET6;
68564ce7165Smrg	    sin6->sin6_port = 0;
68664ce7165Smrg	    memcpy(&sin6->sin6_addr, ha->address, sizeof(sin6->sin6_addr));
68764ce7165Smrg	    saddrlen = sizeof(struct sockaddr_in6);
68864ce7165Smrg	}
68964ce7165Smrg
69064ce7165Smrg	/* gethostbyaddr can take a LONG time if the host does not exist.
69164ce7165Smrg	   Assume that if it does not respond in NAMESERVER_TIMEOUT seconds
69264ce7165Smrg	   that something is wrong and do not make the user wait.
69364ce7165Smrg	   gethostbyaddr will continue after a signal, so we have to
69464ce7165Smrg	   jump out of it.
69564ce7165Smrg	   */
69681440437Smrg#ifdef SIGALRM
69764ce7165Smrg	memset(&sa, 0, sizeof sa);
69864ce7165Smrg	sa.sa_handler = nameserver_lost;
69964ce7165Smrg	sa.sa_flags = 0;	/* don't restart syscalls */
70064ce7165Smrg	sigaction(SIGALRM, &sa, NULL);
70164ce7165Smrg	alarm(NAMESERVER_TIMEOUT);
70264ce7165Smrg#endif
70381440437Smrg	getnameinfo((struct sockaddr *) &saddr, saddrlen, inetname,
70481440437Smrg		    sizeof(inetname), NULL, 0, 0);
70581440437Smrg#ifdef SIGALRM
70664ce7165Smrg	alarm(0);
70781440437Smrg#endif
70864ce7165Smrg	if (nameserver_timedout || inetname[0] == '\0')
70964ce7165Smrg	    inet_ntop(((struct sockaddr *)&saddr)->sa_family, ha->address,
71064ce7165Smrg		inetname, sizeof(inetname));
71164ce7165Smrg	return inetname;
71264ce7165Smrg    }
71364ce7165Smrg#else
71464ce7165Smrg    if (ha->family == FamilyInternet) {
71564ce7165Smrg	/* gethostbyaddr can take a LONG time if the host does not exist.
71664ce7165Smrg	   Assume that if it does not respond in NAMESERVER_TIMEOUT seconds
71764ce7165Smrg	   that something is wrong and do not make the user wait.
71864ce7165Smrg	   gethostbyaddr will continue after a signal, so we have to
71964ce7165Smrg	   jump out of it.
72064ce7165Smrg	   */
72181440437Smrg#ifdef SIGALRM
72264ce7165Smrg	memset(&sa, 0, sizeof sa);
72364ce7165Smrg	sa.sa_handler = nameserver_lost;
72464ce7165Smrg	sa.sa_flags = 0;	/* don't restart syscalls */
72564ce7165Smrg	sigaction(SIGALRM, &sa, NULL);
72664ce7165Smrg	alarm(4);
72764ce7165Smrg#endif
72881440437Smrg	hp = gethostbyaddr (ha->address, ha->length, AF_INET);
72981440437Smrg#ifdef SIGALRM
73064ce7165Smrg	alarm(0);
73181440437Smrg#endif
73264ce7165Smrg	if (hp)
73364ce7165Smrg	    return (hp->h_name);
73464ce7165Smrg	else return (inet_ntoa(*((struct in_addr *)(ha->address))));
73564ce7165Smrg    }
73664ce7165Smrg#endif /* IPv6 */
73764ce7165Smrg#endif
73864ce7165Smrg    if (ha->family == FamilyNetname) {
73964ce7165Smrg	static char netname[512];
74064ce7165Smrg	int len;
74164ce7165Smrg#ifdef SECURE_RPC
74264ce7165Smrg	int gidlen;
74364ce7165Smrg	uid_t uid;
74464ce7165Smrg	gid_t gid, gidlist[NGROUPS_MAX];
74564ce7165Smrg#endif
74664ce7165Smrg
74764ce7165Smrg	if (ha->length < sizeof(netname) - 1)
74864ce7165Smrg	    len = ha->length;
74964ce7165Smrg	else
75064ce7165Smrg	    len = sizeof(netname) - 1;
75164ce7165Smrg	memmove( netname, ha->address, len);
75264ce7165Smrg	netname[len] = '\0';
75364ce7165Smrg#ifdef SECURE_RPC
75464ce7165Smrg	if (netname2user(netname, &uid, &gid, &gidlen, gidlist)) {
75564ce7165Smrg	    struct passwd *pwd;
75664ce7165Smrg
75764ce7165Smrg	    pwd = getpwuid(uid);
75864ce7165Smrg	    if (pwd)
75981440437Smrg		snprintf(netname, sizeof(netname), "%s@ (%*.*s)",
76081440437Smrg			 pwd->pw_name, ha->length, ha->length, ha->address);
76164ce7165Smrg	}
76264ce7165Smrg#endif
76364ce7165Smrg	return (netname);
76464ce7165Smrg    }
76564ce7165Smrg#ifdef K5AUTH
76664ce7165Smrg    if (ha->family == FamilyKrb5Principal) {
76764ce7165Smrg	kbuf.data = ha->address;
76864ce7165Smrg	kbuf.length = ha->length;
76964ce7165Smrg	XauKrb5Decode(kbuf, &princ);
77064ce7165Smrg	krb5_unparse_name(princ, &kname);
77164ce7165Smrg	krb5_free_principal(princ);
77264ce7165Smrg	strncpy(kname_out, kname, sizeof (kname_out));
77364ce7165Smrg	free(kname);
77464ce7165Smrg	return kname_out;
77564ce7165Smrg    }
77664ce7165Smrg#endif
77764ce7165Smrg    if (ha->family == FamilyLocalHost) {
77864ce7165Smrg	return "";
77964ce7165Smrg    }
78064ce7165Smrg    if (ha->family == FamilyServerInterpreted) {
78164ce7165Smrg	XServerInterpretedAddress *sip;
78264ce7165Smrg	static char *addressString;
78364ce7165Smrg	static size_t addressStringSize;
78464ce7165Smrg	size_t neededSize;
78564ce7165Smrg
78664ce7165Smrg	sip = (XServerInterpretedAddress *) ha->address;
78764ce7165Smrg	neededSize = sip->typelength + sip->valuelength + 2;
78864ce7165Smrg
78964ce7165Smrg	if (addressStringSize < neededSize) {
79064ce7165Smrg	    if (addressString != NULL) {
79164ce7165Smrg		free(addressString);
79264ce7165Smrg	    }
79364ce7165Smrg	    addressStringSize = neededSize;
79464ce7165Smrg	    addressString = malloc(addressStringSize);
79564ce7165Smrg	}
79664ce7165Smrg	if (addressString != NULL) {
79764ce7165Smrg	    char *cp = addressString;
79864ce7165Smrg
79964ce7165Smrg	    memcpy(cp, sip->type, sip->typelength);
80064ce7165Smrg	    cp += sip->typelength;
80164ce7165Smrg	    *cp++ = ':';
80264ce7165Smrg	    memcpy(cp, sip->value, sip->valuelength);
80364ce7165Smrg	    cp += sip->valuelength;
80464ce7165Smrg	    *cp = '\0';
80564ce7165Smrg	}
80664ce7165Smrg	return addressString;
80764ce7165Smrg    }
80864ce7165Smrg    return (NULL);
80964ce7165Smrg}
81064ce7165Smrg
81164ce7165Smrg/*ARGUSED*/
81281440437Smrgstatic void
81381440437Smrgnameserver_lost(_X_UNUSED int sig)
81464ce7165Smrg{
81564ce7165Smrg    nameserver_timedout = 1;
81664ce7165Smrg}
81764ce7165Smrg
81864ce7165Smrg/*
81964ce7165Smrg * local_xerror - local non-fatal error handling routine. If the error was
82064ce7165Smrg * that an X_GetHosts request for an unknown address format was received, just
82164ce7165Smrg * return, otherwise print the normal error message and continue.
82264ce7165Smrg */
82364ce7165Smrgstatic int
82464ce7165Smrglocal_xerror(Display *dpy, XErrorEvent *rep)
82564ce7165Smrg{
82664ce7165Smrg    if ((rep->error_code == BadAccess) && (rep->request_code == X_ChangeHosts)) {
82764ce7165Smrg	fprintf (stderr,
82864ce7165Smrg		 "%s:  must be on local machine to add or remove hosts.\n",
82964ce7165Smrg		 ProgramName);
83064ce7165Smrg	return 1;
83164ce7165Smrg    } else if ((rep->error_code == BadAccess) &&
83264ce7165Smrg	       (rep->request_code == X_SetAccessControl)) {
83364ce7165Smrg	fprintf (stderr,
83464ce7165Smrg	"%s:  must be on local machine to enable or disable access control.\n",
83564ce7165Smrg		 ProgramName);
83664ce7165Smrg	return 1;
83764ce7165Smrg    } else if ((rep->error_code == BadValue) &&
83864ce7165Smrg	       (rep->request_code == X_ListHosts)) {
83964ce7165Smrg	return 1;
84064ce7165Smrg    }
84164ce7165Smrg
84264ce7165Smrg    XmuPrintDefaultErrorMessage (dpy, rep, stderr);
84364ce7165Smrg    return 0;
84464ce7165Smrg}
84564ce7165Smrg
84681440437Smrg#if defined(__CYGWIN__) || defined(WIN32)
84764ce7165Smrgvoid sethostent(int x)
84864ce7165Smrg{}
84964ce7165Smrg
85064ce7165Smrgvoid endhostent()
85164ce7165Smrg{}
85264ce7165Smrg#endif
85364ce7165Smrg
854