summaryrefslogtreecommitdiff
path: root/os/access.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/access.c')
-rw-r--r--os/access.c1232
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,
+ &notused, &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;
+}
+