1233 lines
28 KiB
C
1233 lines
28 KiB
C
/* $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;
|
|
}
|
|
|