1072 lines
24 KiB
C
1072 lines
24 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* *
|
|
* (c) Copyright 1993, 1994 Hewlett-Packard Company *
|
|
* (c) Copyright 1993, 1994 International Business Machines Corp. *
|
|
* (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
|
|
* (c) Copyright 1993, 1994 Novell, Inc. *
|
|
*/
|
|
/*
|
|
* $TOG: access.c /main/6 1998/04/06 13:20:57 mgreess $
|
|
*
|
|
* Copyright 1990 Massachusetts Institute of Technology
|
|
*
|
|
* 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, and that the name of M.I.T. not be used in advertising or
|
|
* publicity pertaining to distribution of the software without specific,
|
|
* written prior permission. M.I.T. makes no representations about the
|
|
* suitability of this software for any purpose. It is provided "as is"
|
|
* without express or implied warranty.
|
|
*
|
|
* M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
|
|
* 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.
|
|
*
|
|
* Author: Keith Packard, MIT X Consortium
|
|
*/
|
|
|
|
/*
|
|
* Access control for XDMCP - keep a database of allowable display addresses
|
|
* and (potentially) a list of hosts to send ForwardQuery packets to
|
|
*/
|
|
|
|
# include "dm.h"
|
|
# include "vgmsg.h"
|
|
|
|
# include <X11/Xos.h>
|
|
# include <X11/Xdmcp.h>
|
|
# include <X11/X.h>
|
|
# include <stdio.h>
|
|
# include <netinet/in.h>
|
|
# include <netdb.h>
|
|
# include <sys/socket.h>
|
|
# include <ctype.h>
|
|
|
|
#define ALIAS_CHARACTER '%'
|
|
#define NEGATE_CHARACTER '!'
|
|
#define CHOOSER_STRING "CHOOSER"
|
|
#define BROADCAST_STRING "BROADCAST"
|
|
#ifdef BYPASSLOGIN
|
|
#define BYPASS_STRING "BYPASS_LOGIN"
|
|
#endif /* BYPASSLOGIN */
|
|
|
|
#define HOST_ALIAS 0
|
|
#define HOST_ADDRESS 1
|
|
#define HOST_BROADCAST 2
|
|
#define HOST_CHOOSER 3
|
|
#ifdef BYPASSLOGIN
|
|
#define HOST_BYPASS 4
|
|
#endif /* BYPASSLOGIN */
|
|
|
|
typedef struct _hostEntry {
|
|
struct _hostEntry *next;
|
|
int type;
|
|
union _hostOrAlias {
|
|
char *aliasName;
|
|
ARRAY8 hostAddress;
|
|
} entry;
|
|
} HostEntry;
|
|
|
|
#define DISPLAY_ALIAS 0
|
|
#define DISPLAY_PATTERN 1
|
|
#define DISPLAY_ADDRESS 2
|
|
|
|
typedef struct _displayEntry {
|
|
struct _displayEntry *next;
|
|
int type;
|
|
int notAllowed;
|
|
int chooser;
|
|
#ifdef BYPASSLOGIN
|
|
int bypass;
|
|
#endif /* BYPASSLOGIN */
|
|
union _displayType {
|
|
char *aliasName;
|
|
char *displayPattern;
|
|
struct _display {
|
|
ARRAY8 clientAddress;
|
|
CARD16 connectionType;
|
|
} displayAddress;
|
|
} entry;
|
|
HostEntry *hosts;
|
|
} DisplayEntry;
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* Local procedure declarations
|
|
*
|
|
***************************************************************************/
|
|
|
|
static void FreeHostEntry(
|
|
HostEntry *h) ;
|
|
static void FreeDisplayEntry(
|
|
DisplayEntry *d) ;
|
|
static void FreeAccessDatabase( void ) ;
|
|
static char * ReadWord(
|
|
FILE *file,
|
|
int EOFatEOL) ;
|
|
static HostEntry * ReadHostEntry(
|
|
FILE *file) ;
|
|
static int HasGlobCharacters(
|
|
char *s) ;
|
|
static DisplayEntry * ReadDisplayEntry(
|
|
FILE *file) ;
|
|
static void ReadAccessDatabase(
|
|
FILE *file) ;
|
|
static int scanHostlist(
|
|
HostEntry *h,
|
|
ARRAY8Ptr clientAddress,
|
|
#if NeedWidePrototypes
|
|
int connectionType,
|
|
#else
|
|
CARD16 connectionType,
|
|
#endif /* NeedWidePrototypes */
|
|
int (*function)(),
|
|
char *closure,
|
|
int depth,
|
|
int broadcast) ;
|
|
static int patternMatch(
|
|
char *string,
|
|
char *pattern) ;
|
|
static int indirectAlias(
|
|
char *alias,
|
|
ARRAY8Ptr clientAddress,
|
|
#if NeedWidePrototypes
|
|
int connectionType,
|
|
#else
|
|
CARD16 connectionType,
|
|
#endif /* NeedWidePrototypes */
|
|
int (*function)(),
|
|
char *closure,
|
|
int depth,
|
|
int broadcast) ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* Global variables
|
|
*
|
|
***************************************************************************/
|
|
|
|
static DisplayEntry *database = 0;
|
|
|
|
static ARRAY8 localAddress;
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
***************************************************************************/
|
|
|
|
static void
|
|
FreeHostEntry(
|
|
HostEntry *h )
|
|
{
|
|
switch (h->type) {
|
|
#ifdef BYPASSLOGIN
|
|
case HOST_BYPASS:
|
|
#endif /* BYPASSLOGIN */
|
|
case HOST_ALIAS:
|
|
free (h->entry.aliasName);
|
|
break;
|
|
case HOST_ADDRESS:
|
|
XdmcpDisposeARRAY8 (&h->entry.hostAddress);
|
|
break;
|
|
case HOST_CHOOSER:
|
|
break;
|
|
}
|
|
free ((char *) h);
|
|
}
|
|
|
|
static void
|
|
FreeDisplayEntry(
|
|
DisplayEntry *d )
|
|
{
|
|
HostEntry *h, *next;
|
|
switch (d->type) {
|
|
case DISPLAY_ALIAS:
|
|
free (d->entry.aliasName);
|
|
break;
|
|
case DISPLAY_PATTERN:
|
|
free (d->entry.displayPattern);
|
|
break;
|
|
case DISPLAY_ADDRESS:
|
|
XdmcpDisposeARRAY8 (&d->entry.displayAddress.clientAddress);
|
|
break;
|
|
}
|
|
for (h = d->hosts; h; h = next) {
|
|
next = h->next;
|
|
FreeHostEntry (h);
|
|
}
|
|
free ((char *) d);
|
|
}
|
|
|
|
static void
|
|
FreeAccessDatabase( void )
|
|
{
|
|
DisplayEntry *d, *next;
|
|
|
|
for (d = database; d; d = next)
|
|
{
|
|
next = d->next;
|
|
FreeDisplayEntry (d);
|
|
}
|
|
database = 0;
|
|
}
|
|
|
|
#define WORD_LEN 256
|
|
static char wordBuffer[WORD_LEN];
|
|
static int nextIsEOF;
|
|
|
|
static char *
|
|
ReadWord(
|
|
FILE *file,
|
|
int EOFatEOL )
|
|
{
|
|
int c;
|
|
char *wordp;
|
|
int quoted;
|
|
|
|
wordp = wordBuffer;
|
|
if (nextIsEOF)
|
|
{
|
|
nextIsEOF = FALSE;
|
|
return NULL;
|
|
}
|
|
quoted = FALSE;
|
|
for (;;) {
|
|
c = getc (file);
|
|
switch (c) {
|
|
case '#':
|
|
if (quoted)
|
|
{
|
|
*wordp++ = c;
|
|
break;
|
|
}
|
|
while ((c = getc (file)) != EOF && c != '\n')
|
|
;
|
|
case '\n':
|
|
case EOF:
|
|
if (c == EOF || (EOFatEOL && !quoted))
|
|
{
|
|
ungetc (c, file);
|
|
if (wordp == wordBuffer)
|
|
return NULL;
|
|
*wordp = '\0';
|
|
nextIsEOF = TRUE;
|
|
return wordBuffer;
|
|
}
|
|
case ' ':
|
|
case '\t':
|
|
if (wordp != wordBuffer)
|
|
{
|
|
ungetc (c, file);
|
|
*wordp = '\0';
|
|
return wordBuffer;
|
|
}
|
|
break;
|
|
case '\\':
|
|
if (!quoted)
|
|
{
|
|
quoted = TRUE;
|
|
continue;
|
|
}
|
|
default:
|
|
*wordp++ = c;
|
|
break;
|
|
}
|
|
quoted = FALSE;
|
|
}
|
|
}
|
|
|
|
static HostEntry *
|
|
ReadHostEntry(
|
|
FILE *file )
|
|
{
|
|
char *hostOrAlias;
|
|
HostEntry *h;
|
|
struct hostent *hostent;
|
|
|
|
tryagain:
|
|
hostOrAlias = ReadWord (file, TRUE);
|
|
if (!hostOrAlias)
|
|
return NULL;
|
|
h = (HostEntry *) malloc (sizeof (DisplayEntry));
|
|
if (*hostOrAlias == ALIAS_CHARACTER)
|
|
{
|
|
h->type = HOST_ALIAS;
|
|
h->entry.aliasName = malloc (strlen (hostOrAlias) + 1);
|
|
if (!h->entry.aliasName) {
|
|
free ((char *) h);
|
|
return NULL;
|
|
}
|
|
strcpy (h->entry.aliasName, hostOrAlias);
|
|
}
|
|
else if (!strcmp (hostOrAlias, CHOOSER_STRING))
|
|
{
|
|
h->type = HOST_CHOOSER;
|
|
}
|
|
else if (!strcmp (hostOrAlias, BROADCAST_STRING))
|
|
{
|
|
h->type = HOST_BROADCAST;
|
|
}
|
|
#ifdef BYPASSLOGIN
|
|
else if (!strcmp (hostOrAlias, BYPASS_STRING))
|
|
{
|
|
h->type = HOST_BYPASS;
|
|
hostOrAlias = ReadWord (file, TRUE);
|
|
if (!hostOrAlias)
|
|
{
|
|
Debug ("No username specified for login bypass.\n");
|
|
LogError ((unsigned char *) "Access file \"%s\", No username "
|
|
"specified for login bypass\n", accessFile);
|
|
free ((char *) h);
|
|
goto tryagain;
|
|
}
|
|
if (!strcmp (hostOrAlias, "root"))
|
|
{
|
|
LogError ((unsigned char *)
|
|
"Access file \"%s\", root bypass disallowed\n",
|
|
accessFile);
|
|
free ((char *) h);
|
|
return NULL;
|
|
}
|
|
h->entry.aliasName = malloc (strlen (hostOrAlias) + 1);
|
|
if (!h->entry.aliasName) {
|
|
free ((char *) h);
|
|
return NULL;
|
|
}
|
|
strcpy (h->entry.aliasName, hostOrAlias);
|
|
}
|
|
#endif /* BYPASSLOGIN */
|
|
else
|
|
{
|
|
h->type = HOST_ADDRESS;
|
|
hostent = gethostbyname (hostOrAlias);
|
|
if (!hostent)
|
|
{
|
|
Debug ("No such host %s\n", hostOrAlias);
|
|
LogError(
|
|
ReadCatalog(MC_LOG_SET,MC_LOG_ACC_FILE,MC_DEF_LOG_ACC_FILE),
|
|
accessFile,hostOrAlias);
|
|
free ((char *) h);
|
|
goto tryagain;
|
|
}
|
|
if (!XdmcpAllocARRAY8 (&h->entry.hostAddress, hostent->h_length))
|
|
{
|
|
LogOutOfMem(
|
|
ReadCatalog(MC_LOG_SET,MC_LOG_HOST_ENT,MC_DEF_LOG_HOST_ENT));
|
|
free ((char *) h);
|
|
return NULL;
|
|
}
|
|
bcopy (hostent->h_addr, (char *) h->entry.hostAddress.data, hostent->h_length);
|
|
}
|
|
return h;
|
|
}
|
|
|
|
static int
|
|
HasGlobCharacters(
|
|
char *s )
|
|
{
|
|
for (;;)
|
|
switch (*s++) {
|
|
case '?':
|
|
case '*':
|
|
return 1;
|
|
case '\0':
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static DisplayEntry *
|
|
ReadDisplayEntry(
|
|
FILE *file )
|
|
{
|
|
char *displayOrAlias;
|
|
DisplayEntry *d;
|
|
struct _display *display;
|
|
HostEntry *h, **prev;
|
|
struct hostent *hostent;
|
|
|
|
displayOrAlias = ReadWord (file, FALSE);
|
|
if (!displayOrAlias)
|
|
return NULL;
|
|
d = (DisplayEntry *) malloc (sizeof (DisplayEntry));
|
|
d->notAllowed = 0;
|
|
d->chooser = 0;
|
|
#ifdef BYPASSLOGIN
|
|
d->bypass = 0;
|
|
#endif /* BYPASSLOGIN */
|
|
if (*displayOrAlias == ALIAS_CHARACTER)
|
|
{
|
|
d->type = DISPLAY_ALIAS;
|
|
d->entry.aliasName = malloc (strlen (displayOrAlias) + 1);
|
|
if (!d->entry.aliasName)
|
|
{
|
|
free ((char *) d);
|
|
return NULL;
|
|
}
|
|
strcpy (d->entry.aliasName, displayOrAlias);
|
|
}
|
|
else
|
|
{
|
|
if (*displayOrAlias == NEGATE_CHARACTER)
|
|
{
|
|
d->notAllowed = 1;
|
|
++displayOrAlias;
|
|
}
|
|
if (HasGlobCharacters (displayOrAlias))
|
|
{
|
|
d->type = DISPLAY_PATTERN;
|
|
d->entry.displayPattern = malloc (strlen (displayOrAlias) + 1);
|
|
if (!d->entry.displayPattern)
|
|
{
|
|
free ((char *) d);
|
|
return NULL;
|
|
}
|
|
strcpy (d->entry.displayPattern, displayOrAlias);
|
|
}
|
|
else
|
|
{
|
|
if ((hostent = gethostbyname (displayOrAlias)) == NULL)
|
|
{
|
|
LogError(
|
|
ReadCatalog(MC_LOG_SET,MC_LOG_ACC_DPY,MC_DEF_LOG_ACC_DPY),
|
|
accessFile,displayOrAlias);
|
|
free ((char *) d);
|
|
return NULL;
|
|
}
|
|
d->type = DISPLAY_ADDRESS;
|
|
display = &d->entry.displayAddress;
|
|
if (!XdmcpAllocARRAY8 (&display->clientAddress, hostent->h_length))
|
|
{
|
|
free ((char *) d);
|
|
return NULL;
|
|
}
|
|
bcopy (hostent->h_addr, (char *) display->clientAddress.data, hostent->h_length);
|
|
switch (hostent->h_addrtype)
|
|
{
|
|
#ifdef AF_UNIX
|
|
case AF_UNIX:
|
|
display->connectionType = FamilyLocal;
|
|
break;
|
|
#endif
|
|
#ifdef AF_INET
|
|
case AF_INET:
|
|
display->connectionType = FamilyInternet;
|
|
break;
|
|
#endif
|
|
#ifdef AF_DECnet
|
|
case AF_DECnet:
|
|
display->connectionType = FamilyDECnet;
|
|
break;
|
|
#endif
|
|
default:
|
|
display->connectionType = FamilyLocal;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
prev = &d->hosts;
|
|
while (h = ReadHostEntry (file))
|
|
{
|
|
if (h->type == HOST_CHOOSER)
|
|
{
|
|
FreeHostEntry (h);
|
|
d->chooser = 1;
|
|
} else {
|
|
*prev = h;
|
|
prev = &h->next;
|
|
}
|
|
#ifdef BYPASSLOGIN
|
|
if (h->type == HOST_BYPASS)
|
|
{
|
|
d->bypass = 1;
|
|
}
|
|
#endif /* BYPASSLOGIN */
|
|
}
|
|
*prev = NULL;
|
|
return d;
|
|
}
|
|
|
|
static void
|
|
ReadAccessDatabase(
|
|
FILE *file )
|
|
{
|
|
DisplayEntry *d, **prev;
|
|
|
|
prev = &database;
|
|
while (d = ReadDisplayEntry (file))
|
|
{
|
|
*prev = d;
|
|
prev = &d->next;
|
|
}
|
|
*prev = NULL;
|
|
}
|
|
|
|
int
|
|
ScanAccessDatabase( void )
|
|
{
|
|
FILE *datafile;
|
|
|
|
FreeAccessDatabase ();
|
|
if (accessFile && strlen(accessFile) > 0)
|
|
{
|
|
datafile = fopen (accessFile, "r");
|
|
if (!datafile)
|
|
{
|
|
LogError(ReadCatalog(MC_LOG_SET,MC_LOG_ACC_CTL,MC_DEF_LOG_ACC_CTL),
|
|
accessFile);
|
|
return 0;
|
|
}
|
|
ReadAccessDatabase (datafile);
|
|
fclose (datafile);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int
|
|
patternMatch(
|
|
char *string,
|
|
char *pattern )
|
|
{
|
|
int p, s;
|
|
|
|
if (!string)
|
|
string = "";
|
|
|
|
for (;;)
|
|
{
|
|
s = *string++;
|
|
switch (p = *pattern++) {
|
|
case '*':
|
|
if (!*pattern)
|
|
return TRUE;
|
|
for (string--; *string; string++)
|
|
if (patternMatch (string, pattern))
|
|
return 1;
|
|
return 0;
|
|
case '?':
|
|
if (s == 0)
|
|
return 0;
|
|
break;
|
|
case '\0':
|
|
return s == 0;
|
|
case '\\':
|
|
p = *pattern++;
|
|
default:
|
|
if (p != s)
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ARRAY8Ptr
|
|
getLocalAddress( void )
|
|
{
|
|
static int haveLocalAddress;
|
|
|
|
if (!haveLocalAddress)
|
|
{
|
|
struct hostent *hostent;
|
|
|
|
hostent = gethostbyname (localHostname());
|
|
XdmcpAllocARRAY8 (&localAddress, hostent->h_length);
|
|
bcopy (hostent->h_addr, (char *) localAddress.data, hostent->h_length);
|
|
}
|
|
return &localAddress;
|
|
}
|
|
|
|
|
|
/*
|
|
* calls the given function for each valid indirect entry. Returns TRUE if
|
|
* the local host exists on any of the lists, else FALSE
|
|
*/
|
|
|
|
#define MAX_DEPTH 32
|
|
|
|
static int
|
|
scanHostlist(
|
|
HostEntry *h,
|
|
ARRAY8Ptr clientAddress,
|
|
#if NeedWidePrototypes
|
|
int connectionType,
|
|
#else
|
|
CARD16 connectionType,
|
|
#endif /* NeedWidePrototypes */
|
|
int (*function)(),
|
|
char *closure,
|
|
int depth,
|
|
int broadcast )
|
|
{
|
|
int haveLocalhost = 0;
|
|
|
|
for (; h; h = h->next)
|
|
{
|
|
switch (h->type) {
|
|
case HOST_ALIAS:
|
|
if (indirectAlias (h->entry.aliasName, clientAddress,
|
|
connectionType, function, closure, depth,
|
|
broadcast))
|
|
haveLocalhost = 1;
|
|
break;
|
|
case HOST_ADDRESS:
|
|
if (XdmcpARRAY8Equal (getLocalAddress(), &h->entry.hostAddress))
|
|
haveLocalhost = 1;
|
|
else if (function)
|
|
(*function) (connectionType, &h->entry.hostAddress, closure);
|
|
break;
|
|
case HOST_BROADCAST:
|
|
if (broadcast)
|
|
{
|
|
ARRAY8 temp;
|
|
|
|
if (function)
|
|
{
|
|
temp.data = (BYTE *) BROADCAST_STRING;
|
|
temp.length = strlen ((char *)temp.data);
|
|
(*function) (connectionType, &temp, closure);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return haveLocalhost;
|
|
}
|
|
|
|
|
|
static int
|
|
indirectAlias(
|
|
char *alias,
|
|
ARRAY8Ptr clientAddress,
|
|
#if NeedWidePrototypes
|
|
int connectionType,
|
|
#else
|
|
CARD16 connectionType,
|
|
#endif /* NeedWidePrototypes */
|
|
int (*function)(),
|
|
char *closure,
|
|
int depth,
|
|
int broadcast )
|
|
{
|
|
DisplayEntry *d;
|
|
int haveLocalhost = 0;
|
|
|
|
if (depth == MAX_DEPTH)
|
|
return 0;
|
|
for (d = database; d; d = d->next)
|
|
{
|
|
if (d->type != DISPLAY_ALIAS || !patternMatch (alias, d->entry.aliasName))
|
|
continue;
|
|
if (scanHostlist (d->hosts, clientAddress, connectionType,
|
|
function, closure, depth + 1, broadcast))
|
|
{
|
|
haveLocalhost = 1;
|
|
}
|
|
}
|
|
return haveLocalhost;
|
|
}
|
|
|
|
|
|
ARRAY8Ptr IndirectChoice ();
|
|
|
|
int
|
|
ForEachMatchingIndirectHost(
|
|
ARRAY8Ptr clientAddress,
|
|
#if NeedWidePrototypes
|
|
int connectionType,
|
|
#else
|
|
CARD16 connectionType,
|
|
#endif /* NeedWidePrototypes */
|
|
int (*function)(CARD16, struct _ARRAY8 *, char *),
|
|
char *closure )
|
|
{
|
|
int haveLocalhost = 0;
|
|
DisplayEntry *d;
|
|
char *clientName = NULL;
|
|
|
|
for (d = database; d; d = d->next)
|
|
{
|
|
switch (d->type) {
|
|
case DISPLAY_ALIAS:
|
|
continue;
|
|
case DISPLAY_PATTERN:
|
|
if (!clientName)
|
|
clientName = NetworkAddressToHostname (connectionType,
|
|
clientAddress);
|
|
if (!patternMatch (clientName, d->entry.displayPattern))
|
|
continue;
|
|
break;
|
|
case DISPLAY_ADDRESS:
|
|
if (d->entry.displayAddress.connectionType != connectionType ||
|
|
!XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
|
|
clientAddress))
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (!d->hosts)
|
|
continue;
|
|
if (d->notAllowed)
|
|
break;
|
|
#ifdef BYPASSLOGIN
|
|
if (d->bypass)
|
|
break;
|
|
#endif /* BYPASSLOGIN */
|
|
if (d->chooser)
|
|
{
|
|
ARRAY8Ptr choice;
|
|
|
|
choice = IndirectChoice (clientAddress, connectionType);
|
|
if (!choice || XdmcpARRAY8Equal (getLocalAddress(), choice))
|
|
haveLocalhost = 1;
|
|
else
|
|
(*function) (connectionType, choice, closure);
|
|
}
|
|
else if (scanHostlist (d->hosts, clientAddress, connectionType,
|
|
function, closure, 0, FALSE))
|
|
{
|
|
haveLocalhost = 1;
|
|
}
|
|
break;
|
|
}
|
|
if (clientName)
|
|
free (clientName);
|
|
return haveLocalhost;
|
|
}
|
|
|
|
int
|
|
UseChooser(
|
|
ARRAY8Ptr clientAddress,
|
|
#if NeedWidePrototypes
|
|
int connectionType )
|
|
#else
|
|
CARD16 connectionType )
|
|
#endif /* NeedWidePrototypes */
|
|
{
|
|
DisplayEntry *d;
|
|
char *clientName = NULL;
|
|
|
|
for (d = database; d; d = d->next)
|
|
{
|
|
switch (d->type) {
|
|
case DISPLAY_ALIAS:
|
|
continue;
|
|
case DISPLAY_PATTERN:
|
|
if (!clientName)
|
|
clientName = NetworkAddressToHostname (connectionType,
|
|
clientAddress);
|
|
if (!patternMatch (clientName, d->entry.displayPattern))
|
|
continue;
|
|
break;
|
|
case DISPLAY_ADDRESS:
|
|
if (d->entry.displayAddress.connectionType != connectionType ||
|
|
!XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
|
|
clientAddress))
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (!d->hosts)
|
|
continue;
|
|
if (d->notAllowed)
|
|
break;
|
|
#ifdef BYPASSLOGIN
|
|
if (d->bypass)
|
|
break;
|
|
#endif /* BYPASSLOGIN */
|
|
if (d->chooser && !IndirectChoice (clientAddress, connectionType)) {
|
|
if (clientName)
|
|
free (clientName);
|
|
return 1;
|
|
}
|
|
break;
|
|
}
|
|
if (clientName)
|
|
free (clientName);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
ForEachChooserHost(
|
|
ARRAY8Ptr clientAddress,
|
|
#if NeedWidePrototypes
|
|
int connectionType,
|
|
#else
|
|
CARD16 connectionType,
|
|
#endif /* NeedWidePrototypes */
|
|
int (*function)(),
|
|
char *closure )
|
|
{
|
|
int haveLocalhost = 0;
|
|
DisplayEntry *d;
|
|
char *clientName = NULL;
|
|
|
|
for (d = database; d; d = d->next)
|
|
{
|
|
switch (d->type) {
|
|
case DISPLAY_ALIAS:
|
|
continue;
|
|
case DISPLAY_PATTERN:
|
|
if (!clientName)
|
|
clientName = NetworkAddressToHostname (connectionType,
|
|
clientAddress);
|
|
if (!patternMatch (clientName, d->entry.displayPattern))
|
|
continue;
|
|
break;
|
|
case DISPLAY_ADDRESS:
|
|
if (d->entry.displayAddress.connectionType != connectionType ||
|
|
!XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
|
|
clientAddress))
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (!d->hosts)
|
|
continue;
|
|
if (d->notAllowed)
|
|
break;
|
|
#ifdef BYPASSLOGIN
|
|
if (d->bypass)
|
|
break;
|
|
#endif /* BYPASSLOGIN */
|
|
if (!d->chooser)
|
|
break;
|
|
if (scanHostlist (d->hosts, clientAddress, connectionType,
|
|
function, closure, 0, TRUE))
|
|
{
|
|
haveLocalhost = 1;
|
|
}
|
|
break;
|
|
}
|
|
if (clientName)
|
|
free (clientName);
|
|
if (haveLocalhost)
|
|
(*function) (connectionType, getLocalAddress(), closure);
|
|
}
|
|
|
|
/*
|
|
* returns TRUE if the given client is acceptable to the local host. The
|
|
* given display client is acceptable if it occurs without a host list.
|
|
*/
|
|
|
|
int
|
|
AcceptableDisplayAddress(
|
|
ARRAY8Ptr clientAddress,
|
|
#if NeedWidePrototypes
|
|
int connectionType,
|
|
#else
|
|
CARD16 connectionType,
|
|
#endif /* NeedWidePrototypes */
|
|
xdmOpCode type )
|
|
{
|
|
DisplayEntry *d;
|
|
char *clientName = NULL;
|
|
|
|
if (!accessFile || strlen(accessFile) == 0)
|
|
return 1;
|
|
if (type == INDIRECT_QUERY)
|
|
return 1;
|
|
for (d = database; d; d = d->next)
|
|
{
|
|
if (d->hosts)
|
|
continue;
|
|
switch (d->type) {
|
|
case DISPLAY_ALIAS:
|
|
continue;
|
|
case DISPLAY_PATTERN:
|
|
if (!clientName)
|
|
clientName = NetworkAddressToHostname (connectionType,
|
|
clientAddress);
|
|
if (!patternMatch (clientName, d->entry.displayPattern))
|
|
continue;
|
|
break;
|
|
case DISPLAY_ADDRESS:
|
|
if (d->entry.displayAddress.connectionType != connectionType ||
|
|
!XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
|
|
clientAddress))
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
if (clientName)
|
|
free (clientName);
|
|
return (d != 0) && (d->notAllowed == 0);
|
|
}
|
|
|
|
#ifdef BYPASSLOGIN
|
|
|
|
char *
|
|
BypassLogin (char *displayName)
|
|
{
|
|
DisplayEntry *d;
|
|
HostEntry *h;
|
|
ARRAY8 connectionAddress;
|
|
CARD16 connectionType;
|
|
CARD16 displayNumber;
|
|
|
|
if (!NameToNetworkAddress (displayName, &connectionType, &connectionAddress,
|
|
&displayNumber))
|
|
return NULL;
|
|
|
|
for (d = database; d; d = d->next)
|
|
{
|
|
switch (d->type) {
|
|
case DISPLAY_ALIAS:
|
|
continue;
|
|
case DISPLAY_PATTERN:
|
|
if (!patternMatch (displayName, d->entry.displayPattern))
|
|
continue;
|
|
break;
|
|
case DISPLAY_ADDRESS:
|
|
if (d->entry.displayAddress.connectionType != connectionType ||
|
|
!XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
|
|
&connectionAddress))
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (!d->hosts)
|
|
continue;
|
|
if (d->notAllowed)
|
|
continue;
|
|
if (d->chooser)
|
|
continue;
|
|
if (d->bypass)
|
|
{
|
|
h = d->hosts;
|
|
if (h->entry.aliasName != NULL)
|
|
return h->entry.aliasName;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
HostnameToNetworkAddress (char *name,
|
|
#if NeedWidePrototypes
|
|
int connectionType,
|
|
#else
|
|
CARD16 connectionType,
|
|
#endif /* NeedWidePrototypes */
|
|
ARRAY8Ptr connectionAddress )
|
|
{
|
|
switch (connectionType) {
|
|
case FamilyInternet:
|
|
{
|
|
struct hostent *hostent;
|
|
hostent = gethostbyname (name);
|
|
if (!hostent) return FALSE;
|
|
if (!XdmcpAllocARRAY8 (connectionAddress, hostent->h_length))
|
|
return FALSE;
|
|
bcopy (hostent->h_addr, connectionAddress->data,
|
|
hostent->h_length);
|
|
return TRUE;
|
|
}
|
|
#ifdef DNET
|
|
case FamilyDECnet:
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* converts a display name into a network address, using
|
|
* the same rules as XOpenDisplay (algorithm cribbed from there)
|
|
*/
|
|
|
|
NameToNetworkAddress(char *name,
|
|
CARD16Ptr connectionTypep,
|
|
ARRAY8Ptr connectionAddress,
|
|
CARD16Ptr displayNumber )
|
|
{
|
|
char *colon, *display_number;
|
|
char hostname[1024];
|
|
int dnet = FALSE;
|
|
CARD16 number;
|
|
CARD16 connectionType;
|
|
|
|
colon = index (name, ':');
|
|
if (!colon) return FALSE;
|
|
if (colon != name) {
|
|
if (colon - name > sizeof (hostname)) return FALSE;
|
|
strncpy (hostname, name, colon - name);
|
|
hostname[colon - name] = '\0';
|
|
} else {
|
|
strcpy (hostname, localHostname ());
|
|
}
|
|
|
|
if (colon[1] == ':') {
|
|
dnet = TRUE;
|
|
colon++;
|
|
}
|
|
|
|
#ifndef DNETCONN
|
|
if (dnet)
|
|
return FALSE;
|
|
#endif
|
|
|
|
display_number = colon + 1;
|
|
while (*display_number && *display_number != '.') {
|
|
if (!isascii (*display_number) || !isdigit(*display_number))
|
|
return FALSE;
|
|
display_number++;
|
|
}
|
|
if (display_number == colon + 1) return FALSE;
|
|
number = atoi (colon + 1);
|
|
|
|
#ifdef DNETCONN
|
|
if (dnet)
|
|
connectionType = FamilyDECnet;
|
|
else
|
|
#endif
|
|
connectionType = FamilyInternet;
|
|
|
|
if (!HostnameToNetworkAddress (hostname, connectionType,
|
|
connectionAddress)) return FALSE;
|
|
*displayNumber = number;
|
|
*connectionTypep = connectionType;
|
|
return TRUE;
|
|
}
|
|
|
|
#endif /* BYPASSLOGIN */
|