diff options
Diffstat (limited to 'os/access.c')
-rw-r--r-- | os/access.c | 1232 |
1 files changed, 1232 insertions, 0 deletions
diff --git a/os/access.c b/os/access.c new file mode 100644 index 000000000..abca79e9d --- /dev/null +++ b/os/access.c @@ -0,0 +1,1232 @@ +/* $Xorg: access.c,v 1.5 2001/02/09 02:05:23 xorgcvs Exp $ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +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 +OPEN GROUP 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 Open Group 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 Open Group. + + +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 <X11/Xwinsock.h> +#endif + +#include <stdio.h> +#include <X11/Xtrans.h> +#include <X11/Xauth.h> +#include "X.h" +#include "Xproto.h" +#include "misc.h" +#include "site.h" +#include <errno.h> + +#ifndef WIN32 +#ifdef ESIX +#include <lan/socket.h> +#else +#include <sys/socket.h> +#endif +#include <sys/ioctl.h> +#include <ctype.h> + +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(ISC) +#include <netinet/in.h> +#endif /* TCPCONN || STREAMSCONN || ISC */ +#ifdef DNETCONN +#include <netdnet/dn.h> +#include <netdnet/dnetdb.h> +#endif + +#ifdef hpux +# include <sys/utsname.h> +# ifdef HAS_IFREQ +# include <net/if.h> +# endif +#else +#if defined(SVR4) || (defined(SYSV) && defined(i386)) +# include <sys/utsname.h> +#endif +#if defined(SYSV) && defined(i386) +# include <sys/stream.h> +#endif +#ifdef ESIX +# include <lan/if.h> +#else +# include <net/if.h> +#endif +#endif /* hpux */ + +#ifdef SVR4 +#include <sys/sockio.h> +#endif + +#ifdef ESIX +#include <lan/netdb.h> +#else +#include <netdb.h> +#endif + +#endif /* WIN32 */ + +#define X_INCLUDE_NETDB_H +#include <X11/Xos_r.h> + +#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));\ + if((h))\ + (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; +} + + +/* + * 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 <sys/un.h> +#include <stropts.h> +#include <tiuser.h> + +#include <sys/stream.h> +#include <net/if.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/in.h> +#include <netinet/in_var.h> + +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"); + + /* 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"); + } + + 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"); + } + + 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(UNIXCONN) + return; +#else + register int n; + int len; + caddr_t addr; + int family; + register HOST *host; + +#if defined(__386BSD__) || defined(__NetBSD__) || defined(__FreeBSD__) \ + || defined(WIN32) + char name[100]; +#else + struct utsname name; +#endif + register struct hostent *hp; + + union { + struct sockaddr sa; + struct sockaddr_in in; + } saddr; + + struct sockaddr_in *inetaddr; + struct sockaddr_in broad_addr; + _Xgethostbynameparams hparams; + +#if defined(__386BSD__) || defined(__NetBSD__) || defined(__FreeBSD__) \ + || defined(WIN32) + if (gethostname (name, sizeof name) < 0) + hp = NULL; + else + hp = _XGethostbyname(name, hparams); +#else + /* 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 = _XGethostbyname(name.nodename, hparams); +#endif + 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 && !UNIXCONN */ +} + +#else +void +DefineSelf (fd) + int fd; +{ + char buf[2048]; + 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 (ioctl (fd, (int) SIOCGIFCONF, (pointer) &ifc) < 0) + Error ("Getting interface configuration"); + for (ifr = ifc.ifc_req +#ifdef BSD44SOCKETS + ; (char *)ifr < ifc.ifc_buf + ifc.ifc_len; + ifr = (struct ifreq *)((char *)ifr + sizeof (struct ifreq) + + (ifr->ifr_addr.sa_len > sizeof (ifr->ifr_addr) ? + ifr->ifr_addr.sa_len - sizeof (ifr->ifr_addr) : 0)) +#else + , n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0; ifr++ +#endif + ) + { + len = sizeof(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; + 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 (ioctl (fd, SIOCGIFFLAGS, (char *) &broad_req) != -1 && + (broad_req.ifr_flags & IFF_BROADCAST) && + (broad_req.ifr_flags & IFF_UP) + ) + { + broad_req = *ifr; + if (ioctl (fd, SIOCGIFBRDADDR, &broad_req) != -1) + broad_addr = broad_req.ifr_addr; + else + continue; + } + else + continue; + } +#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); +} + +static char* etcx_hosts = NULL; + +/* Reset access control list to initial hosts */ +void +ResetHosts (display) + char *display; +{ + register HOST *host; + char lhostname[120], ohostname[120]; + char *hostname = ohostname; + int fnamelen; + char* etcstr = "/etc/X"; + char* dothoststr = ".hosts"; + FILE *fd; + char *ptr; + int i, hostlen; + union { + struct sockaddr sa; +#if defined(TCPCONN) || defined(STREAMSCONN) + struct sockaddr_in in; +#endif /* TCPCONN || STREAMSCONN */ +#ifdef DNETCONN + struct sockaddr_dn dn; +#endif + } saddr; +#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); + } + if (etcx_hosts == NULL) { + fnamelen = strlen (display); + fnamelen += strlen (etcstr); + fnamelen += strlen (dothoststr); + etcx_hosts = (char*) xalloc (fnamelen + 1); /* A memory leak? No! */ + /* eventually could use snprintf, when more systems have it */ + sprintf (etcx_hosts, "%s%s%s", etcstr, display, dothoststr); +#ifndef WIN32 +#ifdef PATH_MAX + if (fnamelen > PATH_MAX) { + /* punish stupid hackers */ + strcpy (etcx_hosts, "/dev/zero"); + } +#endif +#endif + } + if (fd = fopen (etcx_hosts, "r")) + { + while (fgets (ohostname, sizeof (ohostname), fd)) + { + if (*ohostname == '#') + continue; + if (ptr = strchr(ohostname, '\n')) + *ptr = 0; + 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) + 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) + { + _Xgethostbynameparams hparams; + + /* host name */ + if (family == FamilyInternet && + (hp = _XGethostbyname(hostname, hparams)) || + (hp = _XGethostbyname(hostname, hparams))) + { + 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 +ForEachHostInFamily (family, func, closure) + int family; + Bool (*func)(); + pointer closure; +{ + 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) + case FamilyInternet: + if (length == sizeof (struct in_addr)) + 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) + register struct sockaddr *saddr; + 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) + register struct sockaddr *saddr; + int *len; + pointer *addr; +{ + if (*len == 0) + return (FamilyLocal); + switch (saddr->sa_family) + { + case AF_UNSPEC: +#if defined(UNIXCONN) || defined(LOCALCONN) + case AF_UNIX: +#endif + return FamilyLocal; +#if defined(TCPCONN) || defined(STREAMSCONN) + 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; + } +} + +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; +} + |