X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=Xserver%2Fprograms%2FXserver%2Fos%2Faccess.c;fp=Xserver%2Fprograms%2FXserver%2Fos%2Faccess.c;h=05b6b8680612fa6c2d20ca9a38aecf066a54ba4e;hb=b6e6afccf37f4ad0515ef2a698f714fdf1bf23b3;hp=0000000000000000000000000000000000000000;hpb=e3340a110a3b01756b8e67531395a33b40a17d37;p=rdpsrv diff --git a/Xserver/programs/Xserver/os/access.c b/Xserver/programs/Xserver/os/access.c new file mode 100644 index 0000000..05b6b86 --- /dev/null +++ b/Xserver/programs/Xserver/os/access.c @@ -0,0 +1,1398 @@ +/* $XConsortium: access.c /main/68 1996/12/15 22:57:09 rws $ */ +/* $XFree86: xc/programs/Xserver/os/access.c,v 3.18.2.4 1998/02/21 06:07:16 robin Exp $ */ +/*********************************************************** + +Copyright (c) 1987 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from the X Consortium. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifdef WIN32 +#include +#endif + +#include +#include +#include +#include "X.h" +#include "Xproto.h" +#include "misc.h" +#include "site.h" +#include +#include +#ifndef WIN32 +#if !defined(AMOEBA) && !defined(MINIX) +#ifdef ESIX +#include +#else +#ifndef Lynx +#include +#else +#include +#endif +#endif +#include +#else +#ifdef AMOEBA +#define port am_port_t +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#undef port +#endif +#endif /* AMOEBA || MINIX */ +#include + +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(ISC) || defined(SCO) +#include +#endif /* TCPCONN || STREAMSCONN || ISC || SCO */ +#ifdef DNETCONN +#include +#include +#endif + +#if !defined(AMOEBA) +#ifdef hpux +# include +# ifdef HAS_IFREQ +# include +# endif +#else +#if defined(SVR4) || (defined(SYSV) && defined(i386)) || defined(MINIX) +# include +#endif +#if defined(SYSV) && defined(i386) +# include +# ifdef ISC +# include +# include +# endif /* ISC */ +#endif +#ifdef ESIX +# include +#else +#ifndef MINIX +# include +#endif +#endif +#endif /* hpux */ +#endif /* !AMOEBA */ + +#ifdef SVR4 +#ifndef SCO +#include +#endif +#include +#endif + +#ifdef ESIX +#include +#else +#if !defined(AMOEBA) && !defined(MINIX) +#include +#else +#ifdef AMOEBA +#include +#endif +#ifdef MINIX +#include +#include +#define INADDR_BROADCAST 0xFFFFFFFF +#endif +#endif /* AMOEBA || MINIX */ +#endif /* ESIX */ + +#ifdef CSRG_BASED +#include +#if (BSD >= 199103) +#define VARIABLE_IFREQ +#endif +#endif + +#if defined(Lynx) && defined(BSD44SOCKETS) +#define VARIABLE_IFREQ +#endif + +#endif /* WIN32 */ + +#ifndef PATH_MAX +#ifndef Lynx +#include +#else +#include +#endif +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif +#endif + +#include "dixstruct.h" +#include "osdep.h" + +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include "extensions/security.h" +#endif + +Bool defeatAccessControl = FALSE; + +#define acmp(a1, a2, len) memcmp((char *)(a1), (char *)(a2), len) +#define acopy(a1, a2, len) memmove((char *)(a2), (char *)(a1), len) +#define addrEqual(fam, address, length, host) \ + ((fam) == (host)->family &&\ + (length) == (host)->len &&\ + !acmp (address, (host)->addr, length)) + +static int ConvertAddr( +#if NeedFunctionPrototypes + struct sockaddr */*saddr*/, + int */*len*/, + pointer */*addr*/ +#endif +); + +static int CheckAddr( +#if NeedFunctionPrototypes + int /*family*/, + pointer /*pAddr*/, + unsigned /*length*/ +#endif +); + +static Bool NewHost( +#if NeedFunctionPrototypes + int /*family*/, + pointer /*addr*/, + int /*len*/ +#endif +); + +typedef struct _host { + short family; + short len; + unsigned char *addr; + struct _host *next; +} HOST; + +#define MakeHost(h,l) (h)=(HOST *) xalloc(sizeof *(h)+(l));\ + (h)->addr=(unsigned char *) ((h) + 1); +#define FreeHost(h) xfree(h) +static HOST *selfhosts = NULL; +static HOST *validhosts = NULL; +static int AccessEnabled = DEFAULT_ACCESS_CONTROL; +static int LocalHostEnabled = FALSE; +static int UsingXdmcp = FALSE; + + +/* + * called when authorization is not enabled to add the + * local host to the access list + */ + +void +EnableLocalHost () +{ + if (!UsingXdmcp) + { + LocalHostEnabled = TRUE; + AddLocalHosts (); + } +} + +/* + * called when authorization is enabled to keep us secure + */ +void +DisableLocalHost () +{ + HOST *self; + + LocalHostEnabled = FALSE; + for (self = selfhosts; self; self = self->next) + (void) RemoveHost ((ClientPtr)NULL, self->family, self->len, (pointer)self->addr); +} + +/* + * called at init time when XDMCP will be used; xdmcp always + * adds local hosts manually when needed + */ + +void +AccessUsingXdmcp () +{ + UsingXdmcp = TRUE; + LocalHostEnabled = FALSE; +} + + +#if ((defined(SVR4) && !defined(SCO325) && !defined(sun) && !defined(NCR)) || defined(ISC)) && defined(SIOCGIFCONF) + +/* Deal with different SIOCGIFCONF ioctl semantics on these OSs */ + +static int +ifioctl (fd, cmd, arg) + int fd; + int cmd; + char *arg; +{ + struct strioctl ioc; + int ret; + + bzero((char *) &ioc, sizeof(ioc)); + ioc.ic_cmd = cmd; + ioc.ic_timout = 0; + if (cmd == SIOCGIFCONF) + { + ioc.ic_len = ((struct ifconf *) arg)->ifc_len; + ioc.ic_dp = ((struct ifconf *) arg)->ifc_buf; +#ifdef ISC + /* SIOCGIFCONF is somewhat brain damaged on ISC. The argument + * buffer must contain the ifconf structure as header. Ifc_req + * is also not a pointer but a one element array of ifreq + * structures. On return this array is extended by enough + * ifreq fields to hold all interfaces. The return buffer length + * is placed in the buffer header. + */ + ((struct ifconf *) ioc.ic_dp)->ifc_len = + ioc.ic_len - sizeof(struct ifconf); +#endif + } + else + { + ioc.ic_len = sizeof(struct ifreq); + ioc.ic_dp = arg; + } + ret = ioctl(fd, I_STR, (char *) &ioc); + if (ret >= 0 && cmd == SIOCGIFCONF) +#ifdef SVR4 + ((struct ifconf *) arg)->ifc_len = ioc.ic_len; +#endif +#ifdef ISC + { + ((struct ifconf *) arg)->ifc_len = + ((struct ifconf *)ioc.ic_dp)->ifc_len; + ((struct ifconf *) arg)->ifc_buf = + (caddr_t)((struct ifconf *)ioc.ic_dp)->ifc_req; + } +#endif + return(ret); +} +#else /* ((SVR4 && !sun) || ISC) && SIOCGIFCONF */ +#define ifioctl ioctl +#endif /* ((SVR4 && !sun) || ISC) && SIOCGIFCONF */ + +/* + * DefineSelf (fd): + * + * Define this host for access control. Find all the hosts the OS knows about + * for this fd and add them to the selfhosts list. + */ + +#ifdef WINTCP /* NCR Wollongong based TCP */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +void +DefineSelf (fd) + int fd; +{ + /* + * The Wolongong drivers used by NCR SVR4/MP-RAS don't understand the + * socket IO calls that most other drivers seem to like. Because of + * this, this routine must be special cased for NCR. Eventually, + * this will be cleared up. + */ + + struct ipb ifnet; + struct in_ifaddr ifaddr; + struct strioctl str; + unsigned char *addr; + register HOST *host; + int family, len; + + if ((fd = open ("/dev/ip", O_RDWR, 0 )) < 0) + Error ("Getting interface configuration (1)"); + + /* Indicate that we want to start at the begining */ + ifnet.ib_next = (struct ipb *) 1; + + while (ifnet.ib_next) + { + str.ic_cmd = IPIOC_GETIPB; + str.ic_timout = 0; + str.ic_len = sizeof (struct ipb); + str.ic_dp = (char *) &ifnet; + + if (ioctl (fd, (int) I_STR, (char *) &str) < 0) + { + close (fd); + Error ("Getting interface configuration (2)"); + } + + ifaddr.ia_next = (struct in_ifaddr *) ifnet.if_addrlist; + str.ic_cmd = IPIOC_GETINADDR; + str.ic_timout = 0; + str.ic_len = sizeof (struct in_ifaddr); + str.ic_dp = (char *) &ifaddr; + + if (ioctl (fd, (int) I_STR, (char *) &str) < 0) + { + close (fd); + Error ("Getting interface configuration (3)"); + } + + len = sizeof(struct sockaddr_in); + family = ConvertAddr (IA_SIN(&ifaddr), &len, (pointer *)&addr); + if (family == -1 || family == FamilyLocal) + continue; + for (host = selfhosts; + host && !addrEqual (family, addr, len, host); + host = host->next) + ; + if (host) + continue; + MakeHost(host,len) + if (host) + { + host->family = family; + host->len = len; + acopy(addr, host->addr, len); + host->next = selfhosts; + selfhosts = host; + } +#ifdef XDMCP + { + struct sockaddr broad_addr; + + /* + * If this isn't an Internet Address, don't register it. + */ + if (family != FamilyInternet) + continue; + + /* + * ignore 'localhost' entries as they're not useful + * on the other end of the wire + */ + if (len == 4 && + addr[0] == 127 && addr[1] == 0 && + addr[2] == 0 && addr[3] == 1) + continue; + + XdmcpRegisterConnection (family, (char *)addr, len); + + +#define IA_BROADADDR(ia) ((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_broadaddr)) + + XdmcpRegisterBroadcastAddress ( + (struct sockaddr_in *) IA_BROADADDR(&ifaddr)); + +#undef IA_BROADADDR + } +#endif /* XDMCP */ + } + + close(fd); + + /* + * add something of FamilyLocalHost + */ + for (host = selfhosts; + host && !addrEqual(FamilyLocalHost, "", 0, host); + host = host->next); + if (!host) + { + MakeHost(host, 0); + if (host) + { + host->family = FamilyLocalHost; + host->len = 0; + acopy("", host->addr, 0); + host->next = selfhosts; + selfhosts = host; + } + } +} + +#else /* WINTCP */ + +#if !defined(SIOCGIFCONF) || (defined (hpux) && ! defined (HAS_IFREQ)) +void +DefineSelf (fd) + int fd; +{ +#if !defined(TCPCONN) && !defined(STREAMSCONN) && !defined(UNIXCONN) && !defined(MNX_TCPCONN) + return; +#else + register int n; + int len; + caddr_t addr; + int family; + register HOST *host; + + struct utsname name; + register struct hostent *hp; + + union { + struct sockaddr sa; + struct sockaddr_in in; + } saddr; + + struct sockaddr_in *inetaddr; + struct sockaddr_in broad_addr; + + /* Why not use gethostname()? Well, at least on my system, I've had to + * make an ugly kernel patch to get a name longer than 8 characters, and + * uname() lets me access to the whole string (it smashes release, you + * see), whereas gethostname() kindly truncates it for me. + */ + uname(&name); + hp = gethostbyname (name.nodename); + if (hp != NULL) + { + saddr.sa.sa_family = hp->h_addrtype; + inetaddr = (struct sockaddr_in *) (&(saddr.sa)); + acopy ( hp->h_addr, &(inetaddr->sin_addr), hp->h_length); + len = sizeof(saddr.sa); + family = ConvertAddr ( &(saddr.sa), &len, (pointer *)&addr); + if ( family != -1 && family != FamilyLocal ) + { + for (host = selfhosts; + host && !addrEqual (family, addr, len, host); + host = host->next) ; + if (!host) + { + /* add this host to the host list. */ + MakeHost(host,len) + if (host) + { + host->family = family; + host->len = len; + acopy ( addr, host->addr, len); + host->next = selfhosts; + selfhosts = host; + } +#ifdef XDMCP + /* + * If this is an Internet Address, but not the localhost + * address (127.0.0.1), register it. + */ + if (family == FamilyInternet && + !(len == 4 && addr[0] == 127 && addr[1] == 0 && + addr[2] == 0 && addr[3] == 1) + ) + { + XdmcpRegisterConnection (family, (char *)addr, len); + broad_addr = *inetaddr; + ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr = + htonl (INADDR_BROADCAST); + XdmcpRegisterBroadcastAddress ((struct sockaddr_in *) + &broad_addr); + } +#endif /* XDMCP */ + } + } + } + /* + * now add a host of family FamilyLocalHost... + */ + for (host = selfhosts; + host && !addrEqual(FamilyLocalHost, "", 0, host); + host = host->next); + if (!host) + { + MakeHost(host, 0); + if (host) + { + host->family = FamilyLocalHost; + host->len = 0; + acopy("", host->addr, 0); + host->next = selfhosts; + selfhosts = host; + } + } +#endif /* !TCPCONN && !STREAMSCONN && !UNIXCONN && !MNX_TCPCONN */ +} + +#else + +#ifdef VARIABLE_IFREQ +#define ifr_size(p) (sizeof (struct ifreq) + \ + (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \ + p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0)) +#define ifraddr_size(a) (a.sa_len) +#else +#define ifr_size(p) (sizeof (struct ifreq)) +#define ifraddr_size(a) (sizeof (a)) +#endif + +void +DefineSelf (fd) + int fd; +{ + char buf[2048], *cp, *cplim; + struct ifconf ifc; + register int n; + int len; + unsigned char * addr; + int family; + register HOST *host; + register struct ifreq *ifr; + +#ifdef DNETCONN + struct dn_naddr *dnaddr = getnodeadd(); + /* + * AF_DECnet may not be listed in the interface list. Instead use + * the supported library call to find out the local address (if any). + */ + if (dnaddr) + { + addr = (unsigned char *) dnaddr; + len = dnaddr->a_len + sizeof(dnaddr->a_len); + family = FamilyDECnet; + for (host = selfhosts; + host && !addrEqual (family, addr, len, host); + host = host->next) + ; + if (!host) + { + MakeHost(host,len) + if (host) + { + host->family = family; + host->len = len; + acopy(addr, host->addr, len); + host->next = selfhosts; + selfhosts = host; + } + } + } +#endif + ifc.ifc_len = sizeof (buf); + ifc.ifc_buf = buf; + if (ifioctl (fd, (int) SIOCGIFCONF, (pointer) &ifc) < 0) + Error ("Getting interface configuration (4)"); + +#ifdef ISC +#define IFC_IFC_REQ (struct ifreq *) ifc.ifc_buf +#else +#define IFC_IFC_REQ ifc.ifc_req +#endif + + cplim = (char *) IFC_IFC_REQ + ifc.ifc_len; + + for (cp = (char *) IFC_IFC_REQ; cp < cplim; cp += ifr_size (ifr)) + { + ifr = (struct ifreq *) cp; + len = ifraddr_size (ifr->ifr_addr); +#ifdef DNETCONN + /* + * DECnet was handled up above. + */ + if (ifr->ifr_addr.sa_family == AF_DECnet) + continue; +#endif /* DNETCONN */ + family = ConvertAddr (&ifr->ifr_addr, &len, (pointer *)&addr); + if (family == -1 || family == FamilyLocal) + continue; +#ifdef DEF_SELF_DEBUG + if (family == FamilyInternet) + ErrorF("Xserver: DefineSelf(): ifname = %s, addr = %d.%d.%d.%d\n", + ifr->ifr_name, addr[0], addr[1], addr[2], addr[3]); +#endif + for (host = selfhosts; + host && !addrEqual (family, addr, len, host); + host = host->next) + ; + if (host) + continue; + MakeHost(host,len) + if (host) + { + host->family = family; + host->len = len; + acopy(addr, host->addr, len); + host->next = selfhosts; + selfhosts = host; + } +#ifdef XDMCP + { + struct sockaddr broad_addr; + + /* + * If this isn't an Internet Address, don't register it. + */ + if (family != FamilyInternet) + continue; + + /* + * ignore 'localhost' entries as they're not useful + * on the other end of the wire + */ + if (len == 4 && + addr[0] == 127 && addr[1] == 0 && + addr[2] == 0 && addr[3] == 1) + continue; + + XdmcpRegisterConnection (family, (char *)addr, len); + broad_addr = ifr->ifr_addr; + ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr = + htonl (INADDR_BROADCAST); +#ifdef SIOCGIFBRDADDR + { + struct ifreq broad_req; + + broad_req = *ifr; + if (ifioctl (fd, SIOCGIFFLAGS, (char *) &broad_req) != -1 && + (broad_req.ifr_flags & IFF_BROADCAST) && + (broad_req.ifr_flags & IFF_UP) + ) + { + broad_req = *ifr; + if (ifioctl (fd, SIOCGIFBRDADDR, &broad_req) != -1) + broad_addr = broad_req.ifr_addr; + else + continue; + } + else + continue; + } +#endif +#ifdef DEF_SELF_DEBUG + ErrorF("Xserver: DefineSelf(): ifname = %s, baddr = %s\n", + ifr->ifr_name, + inet_ntoa(((struct sockaddr_in *) &broad_addr)->sin_addr)); +#endif + XdmcpRegisterBroadcastAddress ((struct sockaddr_in *) &broad_addr); + } +#endif + } + /* + * add something of FamilyLocalHost + */ + for (host = selfhosts; + host && !addrEqual(FamilyLocalHost, "", 0, host); + host = host->next); + if (!host) + { + MakeHost(host, 0); + if (host) + { + host->family = FamilyLocalHost; + host->len = 0; + acopy("", host->addr, 0); + host->next = selfhosts; + selfhosts = host; + } + } +} +#endif /* hpux && !HAS_IFREQ */ +#endif /* WINTCP */ + +#ifdef XDMCP +void +AugmentSelf(from, len) + pointer from; + int len; +{ + int family; + pointer addr; + register HOST *host; + + family = ConvertAddr(from, &len, (pointer *)&addr); + if (family == -1 || family == FamilyLocal) + return; + for (host = selfhosts; host; host = host->next) + { + if (addrEqual(family, addr, len, host)) + return; + } + MakeHost(host,len) + if (!host) + return; + host->family = family; + host->len = len; + acopy(addr, host->addr, len); + host->next = selfhosts; + selfhosts = host; +} +#endif + +void +AddLocalHosts () +{ + HOST *self; + + for (self = selfhosts; self; self = self->next) + (void) NewHost (self->family, self->addr, self->len); +} + +/* Reset access control list to initial hosts */ +void +ResetHosts (display) + char *display; +{ + register HOST *host; + char lhostname[120], ohostname[120]; + char *hostname = ohostname; + char fname[PATH_MAX + 1]; + int fnamelen; + FILE *fd; + char *ptr; + int i, hostlen; +#ifndef AMOEBA + union { + struct sockaddr sa; +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_TCPCONN) + struct sockaddr_in in; +#endif /* TCPCONN || STREAMSCONN */ +#ifdef DNETCONN + struct sockaddr_dn dn; +#endif + } saddr; +#endif /* AMOEBA */ +#ifdef DNETCONN + struct nodeent *np; + struct dn_naddr dnaddr, *dnaddrp, *dnet_addr(); +#endif +#ifdef K5AUTH + krb5_principal princ; + krb5_data kbuf; +#endif + int family; + pointer addr; + int len; + register struct hostent *hp; + + AccessEnabled = defeatAccessControl ? FALSE : DEFAULT_ACCESS_CONTROL; + LocalHostEnabled = FALSE; + while (host = validhosts) + { + validhosts = host->next; + FreeHost (host); + } +#ifndef __EMX__ +#define ETC_HOST_PREFIX "/etc/X" +#define ETC_HOST_SUFFIX ".hosts" +#else +#define ETC_HOST_PREFIX "/XFree86/lib/X11/X" +#define ETC_HOST_SUFFIX ".hosts" +#endif /* __EMX__ */ + fnamelen = strlen(ETC_HOST_PREFIX) + strlen(ETC_HOST_SUFFIX) + + strlen(display) + 1; + if (fnamelen > sizeof(fname)) + FatalError("Display name `%s' is too long\n"); + sprintf(fname, ETC_HOST_PREFIX "%s" ETC_HOST_SUFFIX, display); +#ifdef __EMX__ + strcpy(fname, (char*)__XOS2RedirRoot(fname)); +#endif /* __EMX__ */ + + if (fd = fopen (fname, "r")) + { + while (fgets (ohostname, sizeof (ohostname), fd)) + { + if (*ohostname == '#') + continue; + if (ptr = strchr(ohostname, '\n')) + *ptr = 0; +#ifdef __EMX__ + if (ptr = strchr(ohostname, '\r')) + *ptr = 0; +#endif + hostlen = strlen(ohostname) + 1; + for (i = 0; i < hostlen; i++) + lhostname[i] = tolower(ohostname[i]); + hostname = ohostname; + if (!strncmp("local:", lhostname, 6)) + { + family = FamilyLocalHost; + NewHost(family, "", 0); + } +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_TCPCONN) + else if (!strncmp("inet:", lhostname, 5)) + { + family = FamilyInternet; + hostname = ohostname + 5; + } +#endif +#ifdef DNETCONN + else if (!strncmp("dnet:", lhostname, 5)) + { + family = FamilyDECnet; + hostname = ohostname + 5; + } +#endif +#ifdef SECURE_RPC + else if (!strncmp("nis:", lhostname, 4)) + { + family = FamilyNetname; + hostname = ohostname + 4; + } +#endif +#ifdef K5AUTH + else if (!strncmp("krb:", lhostname, 4)) + { + family = FamilyKrb5Principal; + hostname = ohostname + 4; + } +#endif +#ifdef DNETCONN + if ((family == FamilyDECnet) || + (ptr = strchr(hostname, ':')) && (*(ptr + 1) == ':') && + !(*ptr = '\0')) /* bash trailing colons if necessary */ + { + /* node name (DECnet names end in "::") */ + dnaddrp = dnet_addr(hostname); + if (!dnaddrp && (np = getnodebyname (hostname))) + { + /* node was specified by name */ + saddr.sa.sa_family = np->n_addrtype; + len = sizeof(saddr.sa); + if (ConvertAddr (&saddr.sa, &len, (pointer *)&addr) == FamilyDECnet) + { + bzero ((char *) &dnaddr, sizeof (dnaddr)); + dnaddr.a_len = np->n_length; + acopy (np->n_addr, dnaddr.a_addr, np->n_length); + dnaddrp = &dnaddr; + } + } + if (dnaddrp) + (void) NewHost(FamilyDECnet, (pointer)dnaddrp, + (int)(dnaddrp->a_len + sizeof(dnaddrp->a_len))); + } + else +#endif /* DNETCONN */ +#ifdef K5AUTH + if (family == FamilyKrb5Principal) + { + krb5_parse_name(hostname, &princ); + XauKrb5Encode(princ, &kbuf); + (void) NewHost(FamilyKrb5Principal, kbuf.data, kbuf.length); + krb5_free_principal(princ); + } + else +#endif +#ifdef SECURE_RPC + if ((family == FamilyNetname) || (strchr(hostname, '@'))) + { + SecureRPCInit (); + (void) NewHost (FamilyNetname, hostname, strlen (hostname)); + } + else +#endif /* SECURE_RPC */ +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_TCPCONN) + { + /* host name */ + if (family == FamilyInternet && (hp = gethostbyname (hostname)) || + (hp = gethostbyname (hostname))) + { + saddr.sa.sa_family = hp->h_addrtype; + len = sizeof(saddr.sa); + if ((family = ConvertAddr (&saddr.sa, &len, (pointer *)&addr)) != -1) + { +#ifdef h_addr /* new 4.3bsd version of gethostent */ + char **list; + + /* iterate over the addresses */ + for (list = hp->h_addr_list; *list; list++) + (void) NewHost (family, (pointer)*list, len); +#else + (void) NewHost (family, (pointer)hp->h_addr, len); +#endif + } + } + } +#endif /* TCPCONN || STREAMSCONN */ + family = FamilyWild; + } + fclose (fd); + } +} + +/* Is client on the local host */ +Bool LocalClient(client) + ClientPtr client; +{ + int alen, family, notused; + Xtransaddr *from = NULL; + pointer addr; + register HOST *host; + +#ifdef XCSECURITY + /* untrusted clients can't change host access */ + if (client->trustLevel != XSecurityClientTrusted) + { + SecurityAudit("client %d attempted to change host access\n", + client->index); + return FALSE; + } +#endif +#ifdef LBX + if (!((OsCommPtr)client->osPrivate)->trans_conn) + return FALSE; +#endif + if (!_XSERVTransGetPeerAddr (((OsCommPtr)client->osPrivate)->trans_conn, + ¬used, &alen, &from)) + { + family = ConvertAddr ((struct sockaddr *) from, + &alen, (pointer *)&addr); + if (family == -1) + { + xfree ((char *) from); + return FALSE; + } + if (family == FamilyLocal) + { + xfree ((char *) from); + return TRUE; + } + for (host = selfhosts; host; host = host->next) + { + if (addrEqual (family, addr, alen, host)) + return TRUE; + } + xfree ((char *) from); + } + return FALSE; +} + +static Bool +AuthorizedClient(client) + ClientPtr client; +{ + if (!client || defeatAccessControl) + return TRUE; + return LocalClient(client); +} + +/* Add a host to the access control list. This is the external interface + * called from the dispatcher */ + +int +AddHost (client, family, length, pAddr) + ClientPtr client; + int family; + unsigned length; /* of bytes in pAddr */ + pointer pAddr; +{ + int len; + + if (!AuthorizedClient(client)) + return(BadAccess); + switch (family) { + case FamilyLocalHost: + len = length; + LocalHostEnabled = TRUE; + break; +#ifdef K5AUTH + case FamilyKrb5Principal: + len = length; + break; +#endif +#ifdef SECURE_RPC + case FamilyNetname: + len = length; + SecureRPCInit (); + break; +#endif + case FamilyInternet: + case FamilyDECnet: + case FamilyChaos: + if ((len = CheckAddr (family, pAddr, length)) < 0) + { + client->errorValue = length; + return (BadValue); + } + break; + case FamilyLocal: + default: + client->errorValue = family; + return (BadValue); + } + if (NewHost (family, pAddr, len)) + return Success; + return BadAlloc; +} + +Bool +#if NeedFunctionPrototypes +ForEachHostInFamily ( + int family, + Bool (*func)( +#if NeedNestedPrototypes + unsigned char * /* addr */, + short /* len */, + pointer /* closure */ +#endif + ), + pointer closure) +#else +ForEachHostInFamily (family, func, closure) + int family; + Bool (*func)(); + pointer closure; +#endif +{ + HOST *host; + + for (host = validhosts; host; host = host->next) + if (family == host->family && func (host->addr, host->len, closure)) + return TRUE; + return FALSE; +} + +/* Add a host to the access control list. This is the internal interface + * called when starting or resetting the server */ +static Bool +NewHost (family, addr, len) + int family; + pointer addr; + int len; +{ + register HOST *host; + + for (host = validhosts; host; host = host->next) + { + if (addrEqual (family, addr, len, host)) + return TRUE; + } + MakeHost(host,len) + if (!host) + return FALSE; + host->family = family; + host->len = len; + acopy(addr, host->addr, len); + host->next = validhosts; + validhosts = host; + return TRUE; +} + +/* Remove a host from the access control list */ + +int +RemoveHost (client, family, length, pAddr) + ClientPtr client; + int family; + unsigned length; /* of bytes in pAddr */ + pointer pAddr; +{ + int len; + register HOST *host, **prev; + + if (!AuthorizedClient(client)) + return(BadAccess); + switch (family) { + case FamilyLocalHost: + len = length; + LocalHostEnabled = FALSE; + break; +#ifdef K5AUTH + case FamilyKrb5Principal: + len = length; + break; +#endif +#ifdef SECURE_RPC + case FamilyNetname: + len = length; + break; +#endif + case FamilyInternet: + case FamilyDECnet: + case FamilyChaos: + if ((len = CheckAddr (family, pAddr, length)) < 0) + { + client->errorValue = length; + return(BadValue); + } + break; + case FamilyLocal: + default: + client->errorValue = family; + return(BadValue); + } + for (prev = &validhosts; + (host = *prev) && (!addrEqual (family, pAddr, len, host)); + prev = &host->next) + ; + if (host) + { + *prev = host->next; + FreeHost (host); + } + return (Success); +} + +/* Get all hosts in the access control list */ +int +GetHosts (data, pnHosts, pLen, pEnabled) + pointer *data; + int *pnHosts; + int *pLen; + BOOL *pEnabled; +{ + int len; + register int n = 0; + register unsigned char *ptr; + register HOST *host; + int nHosts = 0; + + *pEnabled = AccessEnabled ? EnableAccess : DisableAccess; + for (host = validhosts; host; host = host->next) + { + nHosts++; + n += (((host->len + 3) >> 2) << 2) + sizeof(xHostEntry); + } + if (n) + { + *data = ptr = (pointer) xalloc (n); + if (!ptr) + { + return(BadAlloc); + } + for (host = validhosts; host; host = host->next) + { + len = host->len; + ((xHostEntry *)ptr)->family = host->family; + ((xHostEntry *)ptr)->length = len; + ptr += sizeof(xHostEntry); + acopy (host->addr, ptr, len); + ptr += ((len + 3) >> 2) << 2; + } + } else { + *data = NULL; + } + *pnHosts = nHosts; + *pLen = n; + return(Success); +} + +/* Check for valid address family and length, and return address length. */ + +/*ARGSUSED*/ +static int +CheckAddr (family, pAddr, length) + int family; + pointer pAddr; + unsigned length; +{ + int len; + + switch (family) + { +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(AMTCPCONN) || defined(MNX_TCPCONN) + case FamilyInternet: +#if !defined(AMOEBA) + if (length == sizeof (struct in_addr)) +#else + if (length == sizeof(ipaddr_t)) +#endif + len = length; + else + len = -1; + break; +#endif +#ifdef DNETCONN + case FamilyDECnet: + { + struct dn_naddr *dnaddr = (struct dn_naddr *) pAddr; + + if ((length < sizeof(dnaddr->a_len)) || + (length < dnaddr->a_len + sizeof(dnaddr->a_len))) + len = -1; + else + len = dnaddr->a_len + sizeof(dnaddr->a_len); + if (len > sizeof(struct dn_naddr)) + len = -1; + } + break; +#endif + default: + len = -1; + } + return (len); +} + +/* Check if a host is not in the access control list. + * Returns 1 if host is invalid, 0 if we've found it. */ + +InvalidHost (saddr, len) +#ifndef AMOEBA_ORIG + register struct sockaddr *saddr; +#else + register ipaddr_t *saddr; +#endif + int len; +{ + int family; + pointer addr; + register HOST *selfhost, *host; + + if (!AccessEnabled) /* just let them in */ + return(0); + family = ConvertAddr (saddr, &len, (pointer *)&addr); + if (family == -1) + return 1; + if (family == FamilyLocal) + { + if (!LocalHostEnabled) + { + /* + * check to see if any local address is enabled. This + * implicitly enables local connections. + */ + for (selfhost = selfhosts; selfhost; selfhost=selfhost->next) + { + for (host = validhosts; host; host=host->next) + { + if (addrEqual (selfhost->family, selfhost->addr, + selfhost->len, host)) + return 0; + } + } + return 1; + } else + return 0; + } + for (host = validhosts; host; host = host->next) + { + if (addrEqual (family, addr, len, host)) + return (0); + } + return (1); +} + +static int +ConvertAddr (saddr, len, addr) +#ifndef AMOEBA_ORIG + register struct sockaddr *saddr; +#else + register ipaddr_t *saddr; +#endif + int *len; + pointer *addr; +{ +#ifndef AMOEBA + if (*len == 0) + return (FamilyLocal); + switch (saddr->sa_family) + { + case AF_UNSPEC: +#if defined(UNIXCONN) || defined(LOCALCONN) || defined(OS2PIPECONN) + case AF_UNIX: +#endif + return FamilyLocal; +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_TCPCONN) + case AF_INET: + *len = sizeof (struct in_addr); + *addr = (pointer) &(((struct sockaddr_in *) saddr)->sin_addr); + return FamilyInternet; +#endif +#ifdef DNETCONN + case AF_DECnet: + { + struct sockaddr_dn *sdn = (struct sockaddr_dn *) saddr; + *len = sdn->sdn_nodeaddrl + sizeof(sdn->sdn_nodeaddrl); + *addr = (pointer) &(sdn->sdn_add); + } + return FamilyDECnet; +#endif +#ifdef CHAOSCONN + case AF_CHAOS: + { + not implemented + } + return FamilyChaos; +#endif + default: + return -1; + } +#else /* AMOEBA */ + if (*len == 0) return -1; + *len = sizeof (ipaddr_t); + *addr = (pointer) saddr; + return FamilyInternet; +#endif /* AMOEBA */ +} + +int +ChangeAccessControl(client, fEnabled) + ClientPtr client; + int fEnabled; +{ + if (!AuthorizedClient(client)) + return BadAccess; + AccessEnabled = fEnabled; + return Success; +} + +/* returns FALSE if xhost + in effect, else TRUE */ +int +GetAccessControl() +{ + return AccessEnabled; +} +