summaryrefslogtreecommitdiffstats
path: root/kdm/backend/access.c
diff options
context:
space:
mode:
Diffstat (limited to 'kdm/backend/access.c')
-rw-r--r--kdm/backend/access.c468
1 files changed, 468 insertions, 0 deletions
diff --git a/kdm/backend/access.c b/kdm/backend/access.c
new file mode 100644
index 000000000..82736be57
--- /dev/null
+++ b/kdm/backend/access.c
@@ -0,0 +1,468 @@
+/*
+
+Copyright 1990, 1998 The Open Group
+Copyright 2001,2004 Oswald Buddenhagen <[email protected]>
+Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+
+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 COPYRIGHT HOLDERS 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 a copyright holder 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 copyright holder.
+
+*/
+
+/*
+ * xdm - display manager daemon
+ * 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 <config.h>
+
+#ifdef XDMCP
+
+#include "dm.h"
+#include "dm_error.h"
+#include "dm_socket.h"
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <netdb.h>
+#if defined(IPv6) && defined(AF_INET6)
+# include <arpa/inet.h>
+#endif
+
+typedef struct {
+ short int type;
+ union {
+ char *aliasPattern;
+ char *hostPattern;
+ struct _displayAddress {
+ CARD16 connectionType;
+ ARRAY8 hostAddress;
+ } displayAddress;
+ } entry;
+} HostEntry;
+
+typedef struct {
+ short int iface;
+ short int mcasts;
+ short int nmcasts;
+} ListenEntry;
+
+typedef struct {
+ char *name;
+ short int hosts;
+ short int nhosts;
+} AliasEntry;
+
+typedef struct {
+ short int entries;
+ short int nentries;
+ short int hosts;
+ short int nhosts;
+ short int flags;
+} AclEntry;
+
+typedef struct {
+ HostEntry *hostList;
+ ListenEntry *listenList;
+ AliasEntry *aliasList;
+ AclEntry *acList;
+ short int nHosts, nListens, nAliases, nAcls;
+ CfgDep dep;
+} AccArr;
+
+static AccArr accData[1];
+
+
+static ARRAY8 localAddress;
+
+ARRAY8Ptr
+getLocalAddress( void )
+{
+ static int haveLocalAddress;
+
+ if (!haveLocalAddress) {
+#if defined(IPv6) && defined(AF_INET6)
+ struct addrinfo *ai;
+
+ if (getaddrinfo( localHostname(), NULL, NULL, &ai )) {
+ XdmcpAllocARRAY8( &localAddress, 4 );
+ localAddress.data[0] = 127;
+ localAddress.data[1] = 0;
+ localAddress.data[2] = 0;
+ localAddress.data[3] = 1;
+ } else {
+ if (ai->ai_family == AF_INET) {
+ XdmcpAllocARRAY8( &localAddress, sizeof(struct in_addr) );
+ memcpy( localAddress.data,
+ &((struct sockaddr_in *)ai->ai_addr)->sin_addr,
+ sizeof(struct in_addr) );
+ } else /* if (ai->ai_family == AF_INET6) */ {
+ XdmcpAllocARRAY8( &localAddress, sizeof(struct in6_addr) );
+ memcpy( localAddress.data,
+ &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr,
+ sizeof(struct in6_addr) );
+ }
+ freeaddrinfo( ai );
+#else
+ struct hostent *hostent;
+
+ if ((hostent = gethostbyname( localHostname() ))) {
+ XdmcpAllocARRAY8( &localAddress, hostent->h_length );
+ memmove( localAddress.data, hostent->h_addr, hostent->h_length );
+#endif
+ haveLocalAddress = 1;
+ }
+ }
+ return &localAddress;
+}
+
+
+void
+ScanAccessDatabase( int force )
+{
+ struct _displayAddress *da;
+ char *cptr;
+ int nChars, i;
+
+ Debug( "ScanAccessDatabase\n" );
+ if (Setjmp( cnftalk.errjmp ))
+ return; /* may memleak */
+ if (startConfig( GC_gXaccess, &accData->dep, force ) <= 0)
+ return;
+ if (accData->hostList)
+ free( accData->hostList );
+ accData->nHosts = GRecvInt();
+ accData->nListens = GRecvInt();
+ accData->nAliases = GRecvInt();
+ accData->nAcls = GRecvInt();
+ nChars = GRecvInt();
+ if (!(accData->hostList = (HostEntry *)
+ Malloc( accData->nHosts * sizeof(HostEntry) +
+ accData->nListens * sizeof(ListenEntry) +
+ accData->nAliases * sizeof(AliasEntry) +
+ accData->nAcls * sizeof(AclEntry) +
+ nChars )))
+ {
+ CloseGetter();
+ return;
+ }
+ accData->listenList = (ListenEntry *)(accData->hostList + accData->nHosts);
+ accData->aliasList = (AliasEntry *)(accData->listenList + accData->nListens);
+ accData->acList = (AclEntry *)(accData->aliasList + accData->nAliases);
+ cptr = (char *)(accData->acList + accData->nAcls);
+ for (i = 0; i < accData->nHosts; i++) {
+ switch ((accData->hostList[i].type = GRecvInt())) {
+ case HOST_ALIAS:
+ accData->hostList[i].entry.aliasPattern = cptr;
+ cptr += GRecvStrBuf( cptr );
+ break;
+ case HOST_PATTERN:
+ accData->hostList[i].entry.hostPattern = cptr;
+ cptr += GRecvStrBuf( cptr );
+ break;
+ case HOST_ADDRESS:
+ da = &accData->hostList[i].entry.displayAddress;
+ da->hostAddress.data = (unsigned char *)cptr;
+ cptr += (da->hostAddress.length = GRecvArrBuf( cptr ));
+ switch (GRecvInt())
+ {
+#ifdef AF_INET
+ case AF_INET:
+ da->connectionType = FamilyInternet;
+ break;
+#endif
+#if defined(IPv6) && defined(AF_INET6)
+ case AF_INET6:
+ da->connectionType = FamilyInternet6;
+ break;
+#endif
+#ifdef AF_DECnet
+ case AF_DECnet:
+ da->connectionType = FamilyDECnet;
+ break;
+#endif
+/*#ifdef AF_UNIX
+ case AF_UNIX:
+#endif*/
+ default:
+ da->connectionType = FamilyLocal;
+ break;
+ }
+ break;
+ case HOST_BROADCAST:
+ break;
+ default:
+ LogError( "Received unknown host type %d from config reader\n", accData->hostList[i].type );
+ return;
+ }
+ }
+ for (i = 0; i < accData->nListens; i++) {
+ accData->listenList[i].iface = GRecvInt();
+ accData->listenList[i].mcasts = GRecvInt();
+ accData->listenList[i].nmcasts = GRecvInt();
+ }
+ for (i = 0; i < accData->nAliases; i++) {
+ accData->aliasList[i].name = cptr;
+ cptr += GRecvStrBuf( cptr );
+ accData->aliasList[i].hosts = GRecvInt();
+ accData->aliasList[i].nhosts = GRecvInt();
+ }
+ for (i = 0; i < accData->nAcls; i++) {
+ accData->acList[i].entries = GRecvInt();
+ accData->acList[i].nentries = GRecvInt();
+ accData->acList[i].hosts = GRecvInt();
+ accData->acList[i].nhosts = GRecvInt();
+ accData->acList[i].flags = GRecvInt();
+ }
+}
+
+
+/* Returns non-0 if string is matched by pattern. Does case folding.
+ */
+static int
+patternMatch( const char *string, const char *pattern )
+{
+ int p, s;
+
+ if (!string)
+ string = "";
+
+ for (;;) {
+ s = *string++;
+ switch (p = *pattern++) {
+ case '*':
+ if (!*pattern)
+ return 1;
+ 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++;
+ /* fall through */
+ default:
+ if (tolower( p ) != tolower( s ))
+ return 0;
+ }
+ }
+}
+
+
+#define MAX_DEPTH 32
+
+static void
+scanHostlist( int fh, int nh,
+ ARRAY8Ptr clientAddress, CARD16 connectionType,
+ ChooserFunc function, char *closure,
+ int broadcast, int *haveLocalhost )
+{
+ HostEntry *h;
+ AliasEntry *a;
+ int na;
+
+ for (h = accData->hostList + fh; nh; nh--, h++) {
+ switch (h->type) {
+ case HOST_ALIAS:
+ for (a = accData->aliasList, na = accData->nAliases; na; na--, a++)
+ if (patternMatch( a->name, h->entry.aliasPattern )) /* XXX originally swapped, no wildcards in alias name matching */
+ scanHostlist( a->hosts, a->nhosts,
+ clientAddress, connectionType,
+ function, closure, broadcast,
+ haveLocalhost );
+ break;
+ case HOST_ADDRESS:
+ if (XdmcpARRAY8Equal( getLocalAddress(), &h->entry.displayAddress.hostAddress ))
+ *haveLocalhost = 1;
+ else if (function)
+ (*function)( connectionType, &h->entry.displayAddress.hostAddress, closure );
+ break;
+ case HOST_BROADCAST:
+ if (broadcast && function)
+ (*function)( FamilyBroadcast, 0, closure );
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static int
+scanEntrylist( int fh, int nh,
+ ARRAY8Ptr clientAddress, CARD16 connectionType,
+ char **clientName )
+{
+ HostEntry *h;
+ AliasEntry *a;
+ int na;
+
+ for (h = accData->hostList + fh; nh; nh--, h++) {
+ switch (h->type) {
+ case HOST_ALIAS:
+ for (a = accData->aliasList, na = accData->nAliases; na; na--, a++)
+ if (patternMatch( a->name, h->entry.aliasPattern ))
+ if (scanEntrylist( a->hosts, a->nhosts,
+ clientAddress, connectionType,
+ clientName ))
+ return 1;
+ break;
+ case HOST_PATTERN:
+ if (!*clientName)
+ *clientName = NetworkAddressToHostname( connectionType,
+ clientAddress );
+ if (patternMatch( *clientName, h->entry.hostPattern ))
+ return 1;
+ break;
+ case HOST_ADDRESS:
+ if (h->entry.displayAddress.connectionType == connectionType &&
+ XdmcpARRAY8Equal( &h->entry.displayAddress.hostAddress,
+ clientAddress ))
+ return 1;
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+static AclEntry *
+matchAclEntry( ARRAY8Ptr clientAddress, CARD16 connectionType, int direct )
+{
+ AclEntry *e, *re;
+ char *clientName = 0;
+ int ne;
+
+ for (e = accData->acList, ne = accData->nAcls, re = 0; ne; ne--, e++)
+ if (!e->nhosts == direct)
+ if (scanEntrylist( e->entries, e->nentries,
+ clientAddress, connectionType,
+ &clientName ))
+ {
+ re = e;
+ break;
+ }
+ if (clientName)
+ free( clientName );
+ return re;
+}
+
+/*
+ * calls the given function for each valid indirect entry. Returns TRUE if
+ * the local host exists on any of the lists, else FALSE
+ */
+int
+ForEachMatchingIndirectHost( ARRAY8Ptr clientAddress,
+ CARD16 connectionType,
+ ChooserFunc function, char *closure )
+{
+ AclEntry *e;
+ int haveLocalhost = 0;
+
+ e = matchAclEntry( clientAddress, connectionType, 0 );
+ if (e && !(e->flags & a_notAllowed)) {
+ if (e->flags & a_useChooser) {
+ ARRAY8Ptr choice;
+
+ choice = IndirectChoice( clientAddress, connectionType );
+ if (!choice || XdmcpARRAY8Equal( getLocalAddress(), choice ))
+ haveLocalhost = 1;
+ else
+ (*function)( connectionType, choice, closure );
+ } else
+ scanHostlist( e->hosts, e->nhosts, clientAddress, connectionType,
+ function, closure, FALSE, &haveLocalhost );
+ }
+ return haveLocalhost;
+}
+
+int
+UseChooser( ARRAY8Ptr clientAddress, CARD16 connectionType )
+{
+ AclEntry *e;
+
+ e = matchAclEntry( clientAddress, connectionType, 0 );
+ return e && !(e->flags & a_notAllowed) && (e->flags & a_useChooser) &&
+ !IndirectChoice( clientAddress, connectionType );
+}
+
+void
+ForEachChooserHost( ARRAY8Ptr clientAddress, CARD16 connectionType,
+ ChooserFunc function, char *closure )
+{
+ AclEntry *e;
+ int haveLocalhost = 0;
+
+ e = matchAclEntry( clientAddress, connectionType, 0 );
+ if (e && !(e->flags & a_notAllowed) && (e->flags & a_useChooser))
+ scanHostlist( e->hosts, e->nhosts, clientAddress, connectionType,
+ function, closure, TRUE, &haveLocalhost );
+ 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, CARD16 connectionType,
+ xdmOpCode type )
+{
+ AclEntry *e;
+
+ if (type == INDIRECT_QUERY)
+ return 1;
+
+ e = matchAclEntry( clientAddress, connectionType, 1 );
+ return e && !(e->flags & a_notAllowed) &&
+ (type != BROADCAST_QUERY || !(e->flags & a_notBroadcast));
+}
+
+void
+ForEachListenAddr( ListenFunc listenfunction, ListenFunc mcastfunction,
+ void **closure )
+{
+ int i, j, ifc, mc, nmc;
+
+ for (i = 0; i < accData->nListens; i++) {
+ ifc = accData->listenList[i].iface;
+ (*listenfunction)( ifc < 0 ? 0 :
+ &accData->hostList[ifc].entry.displayAddress.hostAddress,
+ closure );
+ mc = accData->listenList[i].mcasts;
+ nmc = accData->listenList[i].nmcasts;
+ for (j = 0; j < nmc; j++, mc++)
+ (*mcastfunction)( &accData->hostList[mc].entry.displayAddress.hostAddress,
+ closure );
+ }
+}
+#endif /* XDMCP */