xhost.c revision aadd013e
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
163aadd013eSmrg#if defined(__CYGWIN__) || defined(WIN32)
164aadd013eSmrgvoid sethostent(int x)
165aadd013eSmrg{}
166aadd013eSmrg
167aadd013eSmrgvoid endhostent()
168aadd013eSmrg{}
169aadd013eSmrg#endif
170aadd013eSmrg
17164ce7165Smrgint
17264ce7165Smrgmain(int argc, char *argv[])
17364ce7165Smrg{
17464ce7165Smrg    register char *arg;
17564ce7165Smrg    int i, nhosts = 0;
1763544ea2eSmrg    const char *hostname;
17764ce7165Smrg    int nfailed = 0;
17864ce7165Smrg    XHostAddress *list;
17964ce7165Smrg    Bool enabled = False;
18081440437Smrg    Display *dpy;
18164ce7165Smrg
18264ce7165Smrg    ProgramName = argv[0];
18364ce7165Smrg
1843544ea2eSmrg    if (argc == 2 && !strcmp(argv[1], "-help")) {
1853544ea2eSmrg	fprintf(stderr, "usage: %s [[+-]hostname ...]\n", argv[0]);
1863544ea2eSmrg	exit(1);
1873544ea2eSmrg    }
1883544ea2eSmrg
18964ce7165Smrg    if ((dpy = XOpenDisplay(NULL)) == NULL) {
19064ce7165Smrg	fprintf(stderr, "%s:  unable to open display \"%s\"\n",
19164ce7165Smrg		ProgramName, XDisplayName (NULL));
19264ce7165Smrg	exit(1);
19364ce7165Smrg    }
19464ce7165Smrg
19564ce7165Smrg    XSetErrorHandler(local_xerror);
19664ce7165Smrg
19764ce7165Smrg
19864ce7165Smrg    if (argc == 1) {
19964ce7165Smrg	sethostent(1);		/* don't close the data base each time */
20064ce7165Smrg	list = XListHosts(dpy, &nhosts, &enabled);
20164ce7165Smrg	if (enabled)
20264ce7165Smrg	    printf ("access control enabled, only authorized clients can connect\n");
20364ce7165Smrg	else
20464ce7165Smrg	    printf ("access control disabled, clients can connect from any host\n");
20564ce7165Smrg
20664ce7165Smrg	if (nhosts != 0) {
20764ce7165Smrg	    for (i = 0; i < nhosts; i++ )  {
20864ce7165Smrg		hostname = get_hostname(&list[i]);
20964ce7165Smrg		if (hostname) {
21064ce7165Smrg		    switch (list[i].family) {
21164ce7165Smrg		    case FamilyInternet:
21264ce7165Smrg			printf("INET:");
21364ce7165Smrg			break;
21464ce7165Smrg		    case FamilyInternet6:
21564ce7165Smrg			printf("INET6:");
21664ce7165Smrg			break;
21764ce7165Smrg		    case FamilyDECnet:
21864ce7165Smrg			printf("DNET:");
21964ce7165Smrg			break;
22064ce7165Smrg		    case FamilyNetname:
22164ce7165Smrg			printf("NIS:");
22264ce7165Smrg			break;
22364ce7165Smrg		    case FamilyKrb5Principal:
22464ce7165Smrg			printf("KRB:");
22564ce7165Smrg			break;
22664ce7165Smrg		    case FamilyLocalHost:
22764ce7165Smrg			printf("LOCAL:");
22864ce7165Smrg			break;
22964ce7165Smrg		    case FamilyServerInterpreted:
23064ce7165Smrg			printf("SI:");
23164ce7165Smrg			break;
23264ce7165Smrg		    default:
23364ce7165Smrg			printf("<unknown family type %d>:", list[i].family);
23464ce7165Smrg			break;
23564ce7165Smrg		    }
23664ce7165Smrg		    printf ("%s", hostname);
23764ce7165Smrg		} else {
23864ce7165Smrg		    printf ("<unknown address in family %d>",
23964ce7165Smrg			    list[i].family);
24064ce7165Smrg		}
24164ce7165Smrg		if (nameserver_timedout) {
24264ce7165Smrg		    printf("\t(no nameserver response within %d seconds)\n",
24364ce7165Smrg			   NAMESERVER_TIMEOUT);
24464ce7165Smrg		    nameserver_timedout = 0;
24564ce7165Smrg		} else
24664ce7165Smrg		    printf("\n");
24764ce7165Smrg	    }
24864ce7165Smrg	    free(list);
24964ce7165Smrg	    endhostent();
25064ce7165Smrg	}
25164ce7165Smrg	exit(0);
25264ce7165Smrg    }
25364ce7165Smrg
25464ce7165Smrg    for (i = 1; i < argc; i++) {
25564ce7165Smrg	arg = argv[i];
25664ce7165Smrg	if (*arg == '-') {
25764ce7165Smrg
25864ce7165Smrg	    if (!argv[i][1] && ((i+1) == argc)) {
25964ce7165Smrg		printf ("access control enabled, only authorized clients can connect\n");
26064ce7165Smrg		XEnableAccessControl(dpy);
26164ce7165Smrg	    } else {
26264ce7165Smrg		arg = argv[i][1]? &argv[i][1] : argv[++i];
26364ce7165Smrg		if (!change_host (dpy, arg, False)) {
26464ce7165Smrg		    fprintf (stderr, "%s:  bad hostname \"%s\"\n",
26564ce7165Smrg			     ProgramName, arg);
26664ce7165Smrg		    nfailed++;
26764ce7165Smrg		}
26864ce7165Smrg	    }
26964ce7165Smrg	} else {
27064ce7165Smrg	    if (*arg == '+' && !argv[i][1] && ((i+1) == argc)) {
27164ce7165Smrg		printf ("access control disabled, clients can connect from any host\n");
27264ce7165Smrg		XDisableAccessControl(dpy);
27364ce7165Smrg	    } else {
27464ce7165Smrg		if (*arg == '+') {
27564ce7165Smrg		    arg = argv[i][1]? &argv[i][1] : argv[++i];
27664ce7165Smrg		}
27764ce7165Smrg		if (!change_host (dpy, arg, True)) {
27864ce7165Smrg		    fprintf (stderr, "%s:  bad hostname \"%s\"\n",
27964ce7165Smrg			     ProgramName, arg);
28064ce7165Smrg		    nfailed++;
28164ce7165Smrg		}
28264ce7165Smrg	    }
28364ce7165Smrg	}
28464ce7165Smrg    }
28564ce7165Smrg    XCloseDisplay (dpy);	/* does an XSync first */
28664ce7165Smrg    exit(nfailed);
28764ce7165Smrg}
28864ce7165Smrg
28964ce7165Smrg
29064ce7165Smrg
29164ce7165Smrg/*
29264ce7165Smrg * change_host - edit the list of hosts that may connect to the server;
29364ce7165Smrg * it parses DECnet names (expo::), Internet addresses (18.30.0.212), or
29464ce7165Smrg * Internet names (expo.lcs.mit.edu); if 4.3bsd macro h_addr is defined
29564ce7165Smrg * (from <netdb.h>), it will add or remove all addresses with the given
29664ce7165Smrg * address.
29764ce7165Smrg */
29864ce7165Smrg
29964ce7165Smrgstatic int
30064ce7165Smrgchange_host(Display *dpy, char *name, Bool add)
30164ce7165Smrg{
30264ce7165Smrg    XHostAddress ha;
30364ce7165Smrg    char *lname;
30481440437Smrg    size_t namelen, i;
30581440437Smrg    int family = FamilyWild;
30664ce7165Smrg#ifdef K5AUTH
30764ce7165Smrg    krb5_principal princ;
30864ce7165Smrg    krb5_data kbuf;
30964ce7165Smrg#endif
31064ce7165Smrg#ifdef NEEDSOCKETS
31164ce7165Smrg    static struct in_addr addr;	/* so we can point at it */
31264ce7165Smrg#if defined(IPv6) && defined(AF_INET6)
31364ce7165Smrg    static struct in6_addr addr6; /* so we can point at it */
31464ce7165Smrg#else
31564ce7165Smrg    struct hostent *hp;
31664ce7165Smrg#endif
31764ce7165Smrg#endif
31864ce7165Smrg    char *cp;
3193544ea2eSmrg    static const char *add_msg = "being added to access control list";
3203544ea2eSmrg    static const char *remove_msg = "being removed from access control list";
32164ce7165Smrg
32264ce7165Smrg    namelen = strlen(name);
32364ce7165Smrg    if ((lname = (char *)malloc(namelen+1)) == NULL) {
32464ce7165Smrg	fprintf (stderr, "%s: malloc bombed in change_host\n", ProgramName);
32564ce7165Smrg	exit (1);
32664ce7165Smrg    }
32764ce7165Smrg    for (i = 0; i < namelen; i++) {
32864ce7165Smrg	lname[i] = tolower(name[i]);
32964ce7165Smrg    }
33064ce7165Smrg    lname[namelen] = '\0';
33164ce7165Smrg    if (!strncmp("inet:", lname, 5)) {
33281440437Smrg#ifdef TCPCONN
33364ce7165Smrg	family = FamilyInternet;
33464ce7165Smrg	name += 5;
33564ce7165Smrg#else
33664ce7165Smrg	fprintf (stderr, "%s: not compiled for TCP/IP\n", ProgramName);
33764ce7165Smrg	free(lname);
33864ce7165Smrg	return 0;
33964ce7165Smrg#endif
34064ce7165Smrg    }
34164ce7165Smrg    else if (!strncmp("inet6:", lname, 6)) {
34281440437Smrg#if defined(TCPCONN) && defined(IPv6) && defined(AF_INET6)
34364ce7165Smrg	family = FamilyInternet6;
34464ce7165Smrg	name += 6;
34564ce7165Smrg#else
34664ce7165Smrg	fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
34764ce7165Smrg	free(lname);
34864ce7165Smrg	return 0;
34964ce7165Smrg#endif
35064ce7165Smrg    }
35164ce7165Smrg#ifdef ACCEPT_INETV6 /* Allow inetv6 as an alias for inet6 for compatibility
35264ce7165Smrg			with original X11 over IPv6 draft. */
35364ce7165Smrg    else if (!strncmp("inetv6:", lname, 7)) {
35481440437Smrg#if defined(TCPCONN) && defined(IPv6) && defined(AF_INET6)
35564ce7165Smrg	family = FamilyInternet6;
35664ce7165Smrg	name += 7;
35764ce7165Smrg#else
35864ce7165Smrg	fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
35964ce7165Smrg	free(lname);
36064ce7165Smrg	return 0;
36164ce7165Smrg#endif
36264ce7165Smrg    }
36364ce7165Smrg#endif /* ACCEPT_INETV6 */
36464ce7165Smrg    else if (!strncmp("dnet:", lname, 5)) {
36564ce7165Smrg	fprintf (stderr, "%s: not compiled for DECnet\n", ProgramName);
36664ce7165Smrg	free(lname);
36764ce7165Smrg	return 0;
36864ce7165Smrg    }
36964ce7165Smrg    else if (!strncmp("nis:", lname, 4)) {
37064ce7165Smrg#ifdef SECURE_RPC
37164ce7165Smrg	family = FamilyNetname;
37264ce7165Smrg	name += 4;
37364ce7165Smrg#else
37464ce7165Smrg	fprintf (stderr, "%s: not compiled for Secure RPC\n", ProgramName);
37564ce7165Smrg	free(lname);
37664ce7165Smrg	return 0;
37764ce7165Smrg#endif
37864ce7165Smrg    }
37964ce7165Smrg    else if (!strncmp("krb:", lname, 4)) {
38064ce7165Smrg#ifdef K5AUTH
38164ce7165Smrg	family = FamilyKrb5Principal;
38264ce7165Smrg	name +=4;
38364ce7165Smrg#else
38464ce7165Smrg	fprintf (stderr, "%s: not compiled for Kerberos 5\n", ProgramName);
38564ce7165Smrg	free(lname);
38664ce7165Smrg	return 0;
38764ce7165Smrg#endif
38864ce7165Smrg    }
38964ce7165Smrg    else if (!strncmp("local:", lname, 6)) {
39064ce7165Smrg	family = FamilyLocalHost;
39164ce7165Smrg    }
39264ce7165Smrg    else if (!strncmp("si:", lname, 3)) {
39364ce7165Smrg	family = FamilyServerInterpreted;
39464ce7165Smrg	name += 3;
39564ce7165Smrg    }
39664ce7165Smrg    if (family == FamilyWild && (cp = strchr(lname, ':'))) {
39764ce7165Smrg	*cp = '\0';
39864ce7165Smrg	fprintf (stderr, "%s: unknown address family \"%s\"\n",
39964ce7165Smrg		 ProgramName, lname);
40064ce7165Smrg	free(lname);
40164ce7165Smrg	return 0;
40264ce7165Smrg    }
40364ce7165Smrg    free(lname);
40464ce7165Smrg
40564ce7165Smrg    if (family == FamilyServerInterpreted) {
40664ce7165Smrg	XServerInterpretedAddress siaddr;
4073544ea2eSmrg	int rc;
40864ce7165Smrg
40964ce7165Smrg	cp = strchr(name, ':');
41064ce7165Smrg	if (cp == NULL || cp == name) {
41164ce7165Smrg	    fprintf(stderr,
41264ce7165Smrg	   "%s: type must be specified for server interpreted family \"%s\"\n",
41364ce7165Smrg	      ProgramName, name);
41464ce7165Smrg	    return 0;
41564ce7165Smrg	}
4163544ea2eSmrg	siaddr.type = name;
4173544ea2eSmrg	siaddr.typelength = cp - name;
4183544ea2eSmrg	siaddr.value = ++cp;
4193544ea2eSmrg	siaddr.valuelength = strlen(cp);
42064ce7165Smrg	ha.family = FamilyServerInterpreted;
42164ce7165Smrg	ha.address = (char *) &siaddr;
42264ce7165Smrg	if (add)
4233544ea2eSmrg	    rc = XAddHost(dpy, &ha);
42464ce7165Smrg	else
4253544ea2eSmrg	    rc = XRemoveHost(dpy, &ha);
4263544ea2eSmrg	printf( "%s %s%s\n", name, rc == 1 ? "" : "failed when ",
4273544ea2eSmrg		add ? add_msg : remove_msg);
4283544ea2eSmrg	if (rc != 1)
4293544ea2eSmrg	    return 0;
43064ce7165Smrg	return 1;
43164ce7165Smrg    }
43264ce7165Smrg
43364ce7165Smrg#ifdef K5AUTH
43464ce7165Smrg    if (family == FamilyKrb5Principal) {
43564ce7165Smrg	krb5_error_code retval;
43664ce7165Smrg
43764ce7165Smrg	retval = krb5_parse_name(name, &princ);
43864ce7165Smrg	if (retval) {
43964ce7165Smrg	    krb5_init_ets();	/* init krb errs for error_message() */
44064ce7165Smrg	    fprintf(stderr, "%s: cannot parse Kerberos name: %s\n",
44164ce7165Smrg		    ProgramName, error_message(retval));
44264ce7165Smrg	    return 0;
44364ce7165Smrg	}
44464ce7165Smrg	XauKrb5Encode(princ, &kbuf);
44564ce7165Smrg	ha.length = kbuf.length;
44664ce7165Smrg	ha.address = kbuf.data;
44764ce7165Smrg	ha.family = family;
44864ce7165Smrg	if (add)
44964ce7165Smrg	    XAddHost(dpy, &ha);
45064ce7165Smrg	else
45164ce7165Smrg	    XRemoveHost(dpy, &ha);
45264ce7165Smrg	krb5_free_principal(princ);
45364ce7165Smrg	free(kbuf.data);
45464ce7165Smrg	printf( "%s %s\n", name, add ? add_msg : remove_msg);
45564ce7165Smrg	return 1;
45664ce7165Smrg    }
45764ce7165Smrg#endif
45864ce7165Smrg    if (family == FamilyLocalHost) {
45981440437Smrg	char empty[] = "";
46064ce7165Smrg	ha.length = 0;
46181440437Smrg	ha.address = empty;
46264ce7165Smrg	ha.family = family;
46364ce7165Smrg	if (add)
46464ce7165Smrg	    XAddHost(dpy, &ha);
46564ce7165Smrg	else
46664ce7165Smrg	    XRemoveHost(dpy, &ha);
46764ce7165Smrg	printf( "non-network local connections %s\n", add ? add_msg : remove_msg);
46864ce7165Smrg	return 1;
46964ce7165Smrg    }
47064ce7165Smrg    /*
47164ce7165Smrg     * If it has an '@', it's a netname
47264ce7165Smrg     */
47364ce7165Smrg    if ((family == FamilyNetname && (cp = strchr(name, '@'))) ||
47464ce7165Smrg	(cp = strchr(name, '@'))) {
47564ce7165Smrg        char *netname = name;
47664ce7165Smrg#ifdef SECURE_RPC
47764ce7165Smrg	static char username[MAXNETNAMELEN];
47864ce7165Smrg
47964ce7165Smrg	if (!cp[1]) {
48064ce7165Smrg	    struct passwd *pwd;
48164ce7165Smrg	    static char domainname[128];
48264ce7165Smrg
48364ce7165Smrg	    *cp = '\0';
48464ce7165Smrg	    pwd = getpwnam(name);
48564ce7165Smrg	    if (!pwd) {
48664ce7165Smrg		fprintf(stderr, "no such user \"%s\"\n", name);
48764ce7165Smrg		return 0;
48864ce7165Smrg	    }
48964ce7165Smrg	    getdomainname(domainname, sizeof(domainname));
49064ce7165Smrg	    if (!user2netname(username, pwd->pw_uid, domainname)) {
49164ce7165Smrg		fprintf(stderr, "failed to get netname for \"%s\"\n", name);
49264ce7165Smrg		return 0;
49364ce7165Smrg	    }
49464ce7165Smrg	    netname = username;
49564ce7165Smrg	}
49664ce7165Smrg#endif
49764ce7165Smrg	ha.family = FamilyNetname;
49864ce7165Smrg	ha.length = strlen(netname);
49964ce7165Smrg	ha.address = netname;
50064ce7165Smrg	if (add)
50164ce7165Smrg	    XAddHost (dpy, &ha);
50264ce7165Smrg	else
50364ce7165Smrg	    XRemoveHost (dpy, &ha);
50464ce7165Smrg	if (netname != name)
50564ce7165Smrg	    printf ("%s@ (%s) %s\n", name, netname, add ? add_msg : remove_msg);
50664ce7165Smrg	else
50764ce7165Smrg	    printf ("%s %s\n", netname, add ? add_msg : remove_msg);
50864ce7165Smrg        return 1;
50964ce7165Smrg    }
51064ce7165Smrg#ifdef NEEDSOCKETS
51164ce7165Smrg    /*
512aadd013eSmrg     * First see if inet_aton/inet_addr can grok the name; if so, then use it.
51364ce7165Smrg     */
51464ce7165Smrg    if (((family == FamilyWild) || (family == FamilyInternet)) &&
515aadd013eSmrg#ifdef HAVE_INET_ATON
516aadd013eSmrg	(inet_aton (name, &addr) != 0)
517aadd013eSmrg#else
518aadd013eSmrg	((addr.s_addr = inet_addr(name)) != -1)
519aadd013eSmrg#endif
520aadd013eSmrg        ) {
52164ce7165Smrg	ha.family = FamilyInternet;
522aadd013eSmrg	ha.length = sizeof(addr.s_addr);
523aadd013eSmrg	ha.address = (char *) &addr.s_addr;
52464ce7165Smrg	if (add) {
52564ce7165Smrg	    XAddHost (dpy, &ha);
52664ce7165Smrg	    printf ("%s %s\n", name, add_msg);
52764ce7165Smrg	} else {
52864ce7165Smrg	    XRemoveHost (dpy, &ha);
52964ce7165Smrg	    printf ("%s %s\n", name, remove_msg);
53064ce7165Smrg	}
53164ce7165Smrg	return 1;
53264ce7165Smrg    }
53364ce7165Smrg#if defined(IPv6) && defined(AF_INET6)
53464ce7165Smrg    /*
53564ce7165Smrg     * Check to see if inet_pton() can grok it as an IPv6 address
53664ce7165Smrg     */
53764ce7165Smrg    else if (((family == FamilyWild) || (family == FamilyInternet6)) &&
53864ce7165Smrg	     (inet_pton(AF_INET6, name, &addr6.s6_addr) == 1)) {
53964ce7165Smrg	ha.family = FamilyInternet6;
54064ce7165Smrg	ha.length = sizeof(addr6.s6_addr);
54164ce7165Smrg	ha.address = (char *) &addr6.s6_addr;
54264ce7165Smrg	if (add) {
54364ce7165Smrg	    XAddHost (dpy, &ha);
54464ce7165Smrg	    printf ("%s %s\n", name, add_msg);
54564ce7165Smrg	} else {
54664ce7165Smrg	    XRemoveHost (dpy, &ha);
54764ce7165Smrg	    printf ("%s %s\n", name, remove_msg);
54864ce7165Smrg	}
54964ce7165Smrg	return 1;
55064ce7165Smrg    } else {
55164ce7165Smrg    /*
55264ce7165Smrg     * Is it in the namespace?
55364ce7165Smrg     *
55464ce7165Smrg     * If no family was specified, use both Internet v4 & v6 addresses.
55564ce7165Smrg     * Otherwise, use only addresses matching specified family.
55664ce7165Smrg     */
55764ce7165Smrg	struct addrinfo *addresses;
55864ce7165Smrg	struct addrinfo *a;
55964ce7165Smrg	Bool didit = False;
56064ce7165Smrg
56164ce7165Smrg	if (getaddrinfo(name, NULL, NULL, &addresses) != 0)
56264ce7165Smrg	    return 0;
56364ce7165Smrg
56464ce7165Smrg	for (a = addresses; a != NULL; a = a->ai_next) {
56564ce7165Smrg	    if ( ((a->ai_family == AF_INET) && (family != FamilyInternet6))
56664ce7165Smrg	      || ((a->ai_family == AF_INET6) && (family != FamilyInternet)) ) {
56764ce7165Smrg		char ad[INET6_ADDRSTRLEN];
56864ce7165Smrg		ha.family = XFamily(a->ai_family);
56964ce7165Smrg		if (a->ai_family == AF_INET6) {
57064ce7165Smrg		    ha.address = (char *)
57164ce7165Smrg		      &((struct sockaddr_in6 *) a->ai_addr)->sin6_addr;
57264ce7165Smrg		    ha.length =
57364ce7165Smrg		      sizeof (((struct sockaddr_in6 *) a->ai_addr)->sin6_addr);
57464ce7165Smrg		} else {
57564ce7165Smrg		    ha.address = (char *)
57664ce7165Smrg		      &((struct sockaddr_in *) a->ai_addr)->sin_addr;
57764ce7165Smrg		    ha.length =
57864ce7165Smrg		      sizeof (((struct sockaddr_in *) a->ai_addr)->sin_addr);
57964ce7165Smrg		}
58064ce7165Smrg		inet_ntop(a->ai_family, ha.address, ad, sizeof(ad));
58164ce7165Smrg	/* printf("Family: %d\nLength: %d\n", a->ai_family, ha.length); */
58264ce7165Smrg		/* printf("Address: %s\n", ad); */
58364ce7165Smrg
58464ce7165Smrg		if (add) {
58564ce7165Smrg		    XAddHost (dpy, &ha);
58664ce7165Smrg		} else {
58764ce7165Smrg		    XRemoveHost (dpy, &ha);
58864ce7165Smrg		}
58964ce7165Smrg		didit = True;
59064ce7165Smrg	    }
59164ce7165Smrg	}
59264ce7165Smrg	if (didit == True) {
59364ce7165Smrg	    printf ("%s %s\n", name, add ? add_msg : remove_msg);
59464ce7165Smrg	} else {
59564ce7165Smrg	    const char *familyMsg = "";
59664ce7165Smrg
59764ce7165Smrg	    if (family == FamilyInternet6) {
59864ce7165Smrg		familyMsg = "inet6 ";
59964ce7165Smrg	    } else if (family == FamilyInternet) {
60064ce7165Smrg		familyMsg = "inet ";
60164ce7165Smrg	    }
60264ce7165Smrg
60364ce7165Smrg	    fprintf(stderr, "%s: unable to get %saddress for \"%s\"\n",
60464ce7165Smrg		ProgramName, familyMsg, name);
60564ce7165Smrg	}
60664ce7165Smrg	freeaddrinfo(addresses);
60764ce7165Smrg	return 1;
60864ce7165Smrg    }
60964ce7165Smrg#else /* !IPv6 */
61064ce7165Smrg    /*
61164ce7165Smrg     * Is it in the namespace?
61264ce7165Smrg     */
61364ce7165Smrg    else if (((hp = gethostbyname(name)) == (struct hostent *)NULL)
61464ce7165Smrg	     || hp->h_addrtype != AF_INET) {
61564ce7165Smrg	return 0;
61664ce7165Smrg    } else {
61764ce7165Smrg	ha.family = XFamily(hp->h_addrtype);
61864ce7165Smrg	ha.length = hp->h_length;
61964ce7165Smrg#ifdef h_addr			/* new 4.3bsd version of gethostent */
62064ce7165Smrg    {
62164ce7165Smrg	char **list;
62264ce7165Smrg
62364ce7165Smrg	/* iterate over the hosts */
62464ce7165Smrg	for (list = hp->h_addr_list; *list; list++) {
62564ce7165Smrg	    ha.address = *list;
62664ce7165Smrg	    if (add) {
62764ce7165Smrg		XAddHost (dpy, &ha);
62864ce7165Smrg	    } else {
62964ce7165Smrg		XRemoveHost (dpy, &ha);
63064ce7165Smrg	    }
63164ce7165Smrg	}
63264ce7165Smrg    }
63364ce7165Smrg#else
63464ce7165Smrg	ha.address = hp->h_addr;
63564ce7165Smrg	if (add) {
63664ce7165Smrg	    XAddHost (dpy, &ha);
63764ce7165Smrg	} else {
63864ce7165Smrg	    XRemoveHost (dpy, &ha);
63964ce7165Smrg	}
64064ce7165Smrg#endif
64164ce7165Smrg	printf ("%s %s\n", name, add ? add_msg : remove_msg);
64264ce7165Smrg	return 1;
64364ce7165Smrg    }
64464ce7165Smrg#endif /* IPv6 */
64564ce7165Smrg#else /* NEEDSOCKETS */
64664ce7165Smrg    return 0;
64764ce7165Smrg#endif /* NEEDSOCKETS */
64864ce7165Smrg}
64964ce7165Smrg
65064ce7165Smrg
65164ce7165Smrg/*
65264ce7165Smrg * get_hostname - Given an internet address, return a name (CHARON.MIT.EDU)
65364ce7165Smrg * or a string representing the address (18.58.0.13) if the name cannot
65464ce7165Smrg * be found.
65564ce7165Smrg */
65664ce7165Smrg
65764ce7165Smrg
6583544ea2eSmrgstatic const char *
65964ce7165Smrgget_hostname(XHostAddress *ha)
66064ce7165Smrg{
66181440437Smrg#if defined(TCPCONN) && (!defined(IPv6) || !defined(AF_INET6))
66264ce7165Smrg    static struct hostent *hp = NULL;
66364ce7165Smrg#endif
66464ce7165Smrg#ifdef K5AUTH
66564ce7165Smrg    krb5_principal princ;
66664ce7165Smrg    krb5_data kbuf;
66764ce7165Smrg    char *kname;
66864ce7165Smrg    static char kname_out[255];
66964ce7165Smrg#endif
67081440437Smrg#ifdef SIGALRM
67164ce7165Smrg    struct sigaction sa;
67264ce7165Smrg#endif
67364ce7165Smrg
67481440437Smrg#ifdef TCPCONN
67564ce7165Smrg#if defined(IPv6) && defined(AF_INET6)
67664ce7165Smrg    if ((ha->family == FamilyInternet) || (ha->family == FamilyInternet6)) {
67764ce7165Smrg	struct sockaddr_storage saddr;
67864ce7165Smrg	static char inetname[NI_MAXHOST];
67981440437Smrg	unsigned int saddrlen;
68064ce7165Smrg
68164ce7165Smrg	inetname[0] = '\0';
68264ce7165Smrg	memset(&saddr, 0, sizeof saddr);
68364ce7165Smrg	if (ha->family == FamilyInternet) {
68464ce7165Smrg	    struct sockaddr_in *sin = (struct sockaddr_in *) &saddr;
68564ce7165Smrg#ifdef BSD44SOCKETS
68664ce7165Smrg	    sin->sin_len = sizeof(struct sockaddr_in);
68764ce7165Smrg#endif
68864ce7165Smrg	    sin->sin_family = AF_INET;
68964ce7165Smrg	    sin->sin_port = 0;
690aadd013eSmrg	    if (sizeof(sin->sin_addr) > ha->length)
691aadd013eSmrg		return "";
69264ce7165Smrg	    memcpy(&sin->sin_addr, ha->address, sizeof(sin->sin_addr));
69364ce7165Smrg	    saddrlen = sizeof(struct sockaddr_in);
69464ce7165Smrg	} else {
69564ce7165Smrg	    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &saddr;
69664ce7165Smrg#ifdef SIN6_LEN
69764ce7165Smrg	    sin6->sin6_len = sizeof(struct sockaddr_in6);
69864ce7165Smrg#endif
69964ce7165Smrg	    sin6->sin6_family = AF_INET6;
70064ce7165Smrg	    sin6->sin6_port = 0;
701aadd013eSmrg	    if (sizeof(sin6->sin6_addr) > ha->length)
702aadd013eSmrg		return "";
70364ce7165Smrg	    memcpy(&sin6->sin6_addr, ha->address, sizeof(sin6->sin6_addr));
70464ce7165Smrg	    saddrlen = sizeof(struct sockaddr_in6);
70564ce7165Smrg	}
70664ce7165Smrg
70764ce7165Smrg	/* gethostbyaddr can take a LONG time if the host does not exist.
70864ce7165Smrg	   Assume that if it does not respond in NAMESERVER_TIMEOUT seconds
70964ce7165Smrg	   that something is wrong and do not make the user wait.
71064ce7165Smrg	   gethostbyaddr will continue after a signal, so we have to
71164ce7165Smrg	   jump out of it.
71264ce7165Smrg	   */
71381440437Smrg#ifdef SIGALRM
71464ce7165Smrg	memset(&sa, 0, sizeof sa);
71564ce7165Smrg	sa.sa_handler = nameserver_lost;
71664ce7165Smrg	sa.sa_flags = 0;	/* don't restart syscalls */
71764ce7165Smrg	sigaction(SIGALRM, &sa, NULL);
71864ce7165Smrg	alarm(NAMESERVER_TIMEOUT);
71964ce7165Smrg#endif
72081440437Smrg	getnameinfo((struct sockaddr *) &saddr, saddrlen, inetname,
72181440437Smrg		    sizeof(inetname), NULL, 0, 0);
72281440437Smrg#ifdef SIGALRM
72364ce7165Smrg	alarm(0);
72481440437Smrg#endif
72564ce7165Smrg	if (nameserver_timedout || inetname[0] == '\0')
72664ce7165Smrg	    inet_ntop(((struct sockaddr *)&saddr)->sa_family, ha->address,
72764ce7165Smrg		inetname, sizeof(inetname));
72864ce7165Smrg	return inetname;
72964ce7165Smrg    }
73064ce7165Smrg#else
73164ce7165Smrg    if (ha->family == FamilyInternet) {
73264ce7165Smrg	/* gethostbyaddr can take a LONG time if the host does not exist.
73364ce7165Smrg	   Assume that if it does not respond in NAMESERVER_TIMEOUT seconds
73464ce7165Smrg	   that something is wrong and do not make the user wait.
73564ce7165Smrg	   gethostbyaddr will continue after a signal, so we have to
73664ce7165Smrg	   jump out of it.
73764ce7165Smrg	   */
73881440437Smrg#ifdef SIGALRM
73964ce7165Smrg	memset(&sa, 0, sizeof sa);
74064ce7165Smrg	sa.sa_handler = nameserver_lost;
74164ce7165Smrg	sa.sa_flags = 0;	/* don't restart syscalls */
74264ce7165Smrg	sigaction(SIGALRM, &sa, NULL);
74364ce7165Smrg	alarm(4);
74464ce7165Smrg#endif
74581440437Smrg	hp = gethostbyaddr (ha->address, ha->length, AF_INET);
74681440437Smrg#ifdef SIGALRM
74764ce7165Smrg	alarm(0);
74881440437Smrg#endif
74964ce7165Smrg	if (hp)
75064ce7165Smrg	    return (hp->h_name);
75164ce7165Smrg	else return (inet_ntoa(*((struct in_addr *)(ha->address))));
75264ce7165Smrg    }
75364ce7165Smrg#endif /* IPv6 */
75464ce7165Smrg#endif
75564ce7165Smrg    if (ha->family == FamilyNetname) {
75664ce7165Smrg	static char netname[512];
75764ce7165Smrg	int len;
75864ce7165Smrg#ifdef SECURE_RPC
75964ce7165Smrg	int gidlen;
76064ce7165Smrg	uid_t uid;
76164ce7165Smrg	gid_t gid, gidlist[NGROUPS_MAX];
76264ce7165Smrg#endif
76364ce7165Smrg
76464ce7165Smrg	if (ha->length < sizeof(netname) - 1)
76564ce7165Smrg	    len = ha->length;
76664ce7165Smrg	else
76764ce7165Smrg	    len = sizeof(netname) - 1;
76864ce7165Smrg	memmove( netname, ha->address, len);
76964ce7165Smrg	netname[len] = '\0';
77064ce7165Smrg#ifdef SECURE_RPC
77164ce7165Smrg	if (netname2user(netname, &uid, &gid, &gidlen, gidlist)) {
77264ce7165Smrg	    struct passwd *pwd;
77364ce7165Smrg
77464ce7165Smrg	    pwd = getpwuid(uid);
77564ce7165Smrg	    if (pwd)
77681440437Smrg		snprintf(netname, sizeof(netname), "%s@ (%*.*s)",
77781440437Smrg			 pwd->pw_name, ha->length, ha->length, ha->address);
77864ce7165Smrg	}
77964ce7165Smrg#endif
78064ce7165Smrg	return (netname);
78164ce7165Smrg    }
78264ce7165Smrg#ifdef K5AUTH
78364ce7165Smrg    if (ha->family == FamilyKrb5Principal) {
78464ce7165Smrg	kbuf.data = ha->address;
78564ce7165Smrg	kbuf.length = ha->length;
78664ce7165Smrg	XauKrb5Decode(kbuf, &princ);
78764ce7165Smrg	krb5_unparse_name(princ, &kname);
78864ce7165Smrg	krb5_free_principal(princ);
78964ce7165Smrg	strncpy(kname_out, kname, sizeof (kname_out));
79064ce7165Smrg	free(kname);
79164ce7165Smrg	return kname_out;
79264ce7165Smrg    }
79364ce7165Smrg#endif
79464ce7165Smrg    if (ha->family == FamilyLocalHost) {
79564ce7165Smrg	return "";
79664ce7165Smrg    }
79764ce7165Smrg    if (ha->family == FamilyServerInterpreted) {
79864ce7165Smrg	XServerInterpretedAddress *sip;
79964ce7165Smrg	static char *addressString;
80064ce7165Smrg	static size_t addressStringSize;
80164ce7165Smrg	size_t neededSize;
80264ce7165Smrg
80364ce7165Smrg	sip = (XServerInterpretedAddress *) ha->address;
80464ce7165Smrg	neededSize = sip->typelength + sip->valuelength + 2;
80564ce7165Smrg
80664ce7165Smrg	if (addressStringSize < neededSize) {
80764ce7165Smrg	    if (addressString != NULL) {
80864ce7165Smrg		free(addressString);
80964ce7165Smrg	    }
81064ce7165Smrg	    addressStringSize = neededSize;
81164ce7165Smrg	    addressString = malloc(addressStringSize);
81264ce7165Smrg	}
81364ce7165Smrg	if (addressString != NULL) {
81464ce7165Smrg	    char *cp = addressString;
81564ce7165Smrg
81664ce7165Smrg	    memcpy(cp, sip->type, sip->typelength);
81764ce7165Smrg	    cp += sip->typelength;
81864ce7165Smrg	    *cp++ = ':';
81964ce7165Smrg	    memcpy(cp, sip->value, sip->valuelength);
82064ce7165Smrg	    cp += sip->valuelength;
82164ce7165Smrg	    *cp = '\0';
82264ce7165Smrg	}
82364ce7165Smrg	return addressString;
82464ce7165Smrg    }
82564ce7165Smrg    return (NULL);
82664ce7165Smrg}
82764ce7165Smrg
82864ce7165Smrg/*ARGUSED*/
82981440437Smrgstatic void
83081440437Smrgnameserver_lost(_X_UNUSED int sig)
83164ce7165Smrg{
83264ce7165Smrg    nameserver_timedout = 1;
83364ce7165Smrg}
83464ce7165Smrg
83564ce7165Smrg/*
83664ce7165Smrg * local_xerror - local non-fatal error handling routine. If the error was
83764ce7165Smrg * that an X_GetHosts request for an unknown address format was received, just
83864ce7165Smrg * return, otherwise print the normal error message and continue.
83964ce7165Smrg */
84064ce7165Smrgstatic int
84164ce7165Smrglocal_xerror(Display *dpy, XErrorEvent *rep)
84264ce7165Smrg{
84364ce7165Smrg    if ((rep->error_code == BadAccess) && (rep->request_code == X_ChangeHosts)) {
84464ce7165Smrg	fprintf (stderr,
84564ce7165Smrg		 "%s:  must be on local machine to add or remove hosts.\n",
84664ce7165Smrg		 ProgramName);
84764ce7165Smrg	return 1;
84864ce7165Smrg    } else if ((rep->error_code == BadAccess) &&
84964ce7165Smrg	       (rep->request_code == X_SetAccessControl)) {
85064ce7165Smrg	fprintf (stderr,
85164ce7165Smrg	"%s:  must be on local machine to enable or disable access control.\n",
85264ce7165Smrg		 ProgramName);
85364ce7165Smrg	return 1;
85464ce7165Smrg    } else if ((rep->error_code == BadValue) &&
85564ce7165Smrg	       (rep->request_code == X_ListHosts)) {
85664ce7165Smrg	return 1;
85764ce7165Smrg    }
85864ce7165Smrg
85964ce7165Smrg    XmuPrintDefaultErrorMessage (dpy, rep, stderr);
86064ce7165Smrg    return 0;
86164ce7165Smrg}
862