2 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
3 * (c) Copyright 1993, 1994 International Business Machines Corp. *
4 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
5 * (c) Copyright 1993, 1994 Novell, Inc. *
8 * $TOG: access.c /main/6 1998/04/06 13:20:57 mgreess $
10 * Copyright 1990 Massachusetts Institute of Technology
12 * Permission to use, copy, modify, distribute, and sell this software and its
13 * documentation for any purpose is hereby granted without fee, provided that
14 * the above copyright notice appear in all copies and that both that
15 * copyright notice and this permission notice appear in supporting
16 * documentation, and that the name of M.I.T. not be used in advertising or
17 * publicity pertaining to distribution of the software without specific,
18 * written prior permission. M.I.T. makes no representations about the
19 * suitability of this software for any purpose. It is provided "as is"
20 * without express or implied warranty.
22 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
24 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
25 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
26 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
27 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29 * Author: Keith Packard, MIT X Consortium
33 * Access control for XDMCP - keep a database of allowable display addresses
34 * and (potentially) a list of hosts to send ForwardQuery packets to
41 # include <X11/Xdmcp.h>
44 # include <netinet/in.h>
46 # include <sys/socket.h>
49 #define ALIAS_CHARACTER '%'
50 #define NEGATE_CHARACTER '!'
51 #define CHOOSER_STRING "CHOOSER"
52 #define BROADCAST_STRING "BROADCAST"
54 #define BYPASS_STRING "BYPASS_LOGIN"
55 #endif /* BYPASSLOGIN */
58 #define HOST_ADDRESS 1
59 #define HOST_BROADCAST 2
60 #define HOST_CHOOSER 3
63 #endif /* BYPASSLOGIN */
65 typedef struct _hostEntry {
66 struct _hostEntry *next;
74 #define DISPLAY_ALIAS 0
75 #define DISPLAY_PATTERN 1
76 #define DISPLAY_ADDRESS 2
78 typedef struct _displayEntry {
79 struct _displayEntry *next;
85 #endif /* BYPASSLOGIN */
91 CARD16 connectionType;
98 /***************************************************************************
100 * Local procedure declarations
102 ***************************************************************************/
104 static void FreeHostEntry(
106 static void FreeDisplayEntry(
108 static void FreeAccessDatabase( void ) ;
109 static char * ReadWord(
112 static HostEntry * ReadHostEntry(
114 static int HasGlobCharacters(
116 static DisplayEntry * ReadDisplayEntry(
118 static void ReadAccessDatabase(
120 static int scanHostlist(
122 ARRAY8Ptr clientAddress,
123 #if NeedWidePrototypes
126 CARD16 connectionType,
127 #endif /* NeedWidePrototypes */
132 static int patternMatch(
135 static int indirectAlias(
137 ARRAY8Ptr clientAddress,
138 #if NeedWidePrototypes
141 CARD16 connectionType,
142 #endif /* NeedWidePrototypes */
153 /***************************************************************************
157 ***************************************************************************/
159 static DisplayEntry *database = 0;
161 static ARRAY8 localAddress;
165 /***************************************************************************
166 ***************************************************************************/
175 #endif /* BYPASSLOGIN */
177 free (h->entry.aliasName);
180 XdmcpDisposeARRAY8 (&h->entry.hostAddress);
195 free (d->entry.aliasName);
197 case DISPLAY_PATTERN:
198 free (d->entry.displayPattern);
200 case DISPLAY_ADDRESS:
201 XdmcpDisposeARRAY8 (&d->entry.displayAddress);
204 for (h = d->hosts; h; h = next) {
212 FreeAccessDatabase( void )
214 DisplayEntry *d, *next;
216 for (d = database; d; d = next)
219 FreeDisplayEntry (d);
225 static char wordBuffer[WORD_LEN];
226 static int nextIsEOF;
253 while ((c = getc (file)) != EOF && c != '\n')
257 if (c == EOF || (EOFatEOL && !quoted))
260 if (wordp == wordBuffer)
268 if (wordp != wordBuffer)
295 struct hostent *hostent;
298 hostOrAlias = ReadWord (file, TRUE);
301 h = (HostEntry *) malloc (sizeof (DisplayEntry));
302 if (*hostOrAlias == ALIAS_CHARACTER)
304 h->type = HOST_ALIAS;
305 h->entry.aliasName = malloc (strlen (hostOrAlias) + 1);
306 if (!h->entry.aliasName) {
310 strcpy (h->entry.aliasName, hostOrAlias);
312 else if (!strcmp (hostOrAlias, CHOOSER_STRING))
314 h->type = HOST_CHOOSER;
316 else if (!strcmp (hostOrAlias, BROADCAST_STRING))
318 h->type = HOST_BROADCAST;
321 else if (!strcmp (hostOrAlias, BYPASS_STRING))
323 h->type = HOST_BYPASS;
324 hostOrAlias = ReadWord (file, TRUE);
327 Debug ("No username specified for login bypass.\n");
328 LogError ((unsigned char *) "Access file \"%s\", No username "
329 "specified for login bypass\n", accessFile);
333 if (!strcmp (hostOrAlias, "root"))
335 LogError ((unsigned char *)
336 "Access file \"%s\", root bypass disallowed\n",
341 h->entry.aliasName = malloc (strlen (hostOrAlias) + 1);
342 if (!h->entry.aliasName) {
346 strcpy (h->entry.aliasName, hostOrAlias);
348 #endif /* BYPASSLOGIN */
351 h->type = HOST_ADDRESS;
352 hostent = gethostbyname (hostOrAlias);
355 Debug ("No such host %s\n", hostOrAlias);
357 ReadCatalog(MC_LOG_SET,MC_LOG_ACC_FILE,MC_DEF_LOG_ACC_FILE),
358 accessFile,hostOrAlias);
362 if (!XdmcpAllocARRAY8 (&h->entry.hostAddress, hostent->h_length))
365 ReadCatalog(MC_LOG_SET,MC_LOG_HOST_ENT,MC_DEF_LOG_HOST_ENT));
369 bcopy (hostent->h_addr, (char *) h->entry.hostAddress.data, hostent->h_length);
388 static DisplayEntry *
392 char *displayOrAlias;
394 struct _display *display;
395 HostEntry *h, **prev;
396 struct hostent *hostent;
398 displayOrAlias = ReadWord (file, FALSE);
401 d = (DisplayEntry *) malloc (sizeof (DisplayEntry));
406 #endif /* BYPASSLOGIN */
407 if (*displayOrAlias == ALIAS_CHARACTER)
409 d->type = DISPLAY_ALIAS;
410 d->entry.aliasName = malloc (strlen (displayOrAlias) + 1);
411 if (!d->entry.aliasName)
416 strcpy (d->entry.aliasName, displayOrAlias);
420 if (*displayOrAlias == NEGATE_CHARACTER)
425 if (HasGlobCharacters (displayOrAlias))
427 d->type = DISPLAY_PATTERN;
428 d->entry.displayPattern = malloc (strlen (displayOrAlias) + 1);
429 if (!d->entry.displayPattern)
434 strcpy (d->entry.displayPattern, displayOrAlias);
438 if ((hostent = gethostbyname (displayOrAlias)) == NULL)
441 ReadCatalog(MC_LOG_SET,MC_LOG_ACC_DPY,MC_DEF_LOG_ACC_DPY),
442 accessFile,displayOrAlias);
446 d->type = DISPLAY_ADDRESS;
447 display = &d->entry.displayAddress;
448 if (!XdmcpAllocARRAY8 (&display->clientAddress, hostent->h_length))
453 bcopy (hostent->h_addr, (char *) display->clientAddress.data, hostent->h_length);
454 switch (hostent->h_addrtype)
458 display->connectionType = FamilyLocal;
463 display->connectionType = FamilyInternet;
468 display->connectionType = FamilyDECnet;
472 display->connectionType = FamilyLocal;
478 while (h = ReadHostEntry (file))
480 if (h->type == HOST_CHOOSER)
489 if (h->type == HOST_BYPASS)
493 #endif /* BYPASSLOGIN */
503 DisplayEntry *d, **prev;
506 while (d = ReadDisplayEntry (file))
515 ScanAccessDatabase( void )
519 FreeAccessDatabase ();
520 if (accessFile && strlen(accessFile) > 0)
522 datafile = fopen (accessFile, "r");
525 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_ACC_CTL,MC_DEF_LOG_ACC_CTL),
529 ReadAccessDatabase (datafile);
549 switch (p = *pattern++) {
553 for (string--; *string; string++)
554 if (patternMatch (string, pattern))
574 getLocalAddress( void )
576 static int haveLocalAddress;
578 if (!haveLocalAddress)
580 struct hostent *hostent;
582 hostent = gethostbyname (localHostname());
583 XdmcpAllocARRAY8 (&localAddress, hostent->h_length);
584 bcopy (hostent->h_addr, (char *) localAddress.data, hostent->h_length);
586 return &localAddress;
591 * calls the given function for each valid indirect entry. Returns TRUE if
592 * the local host exists on any of the lists, else FALSE
600 ARRAY8Ptr clientAddress,
601 #if NeedWidePrototypes
604 CARD16 connectionType,
605 #endif /* NeedWidePrototypes */
611 int haveLocalhost = 0;
613 for (; h; h = h->next)
617 if (indirectAlias (h->entry.aliasName, clientAddress,
618 connectionType, function, closure, depth,
623 if (XdmcpARRAY8Equal (getLocalAddress(), &h->entry.hostAddress))
626 (*function) (connectionType, &h->entry.hostAddress, closure);
635 temp.data = (BYTE *) BROADCAST_STRING;
636 temp.length = strlen ((char *)temp.data);
637 (*function) (connectionType, &temp, closure);
643 return haveLocalhost;
650 ARRAY8Ptr clientAddress,
651 #if NeedWidePrototypes
654 CARD16 connectionType,
655 #endif /* NeedWidePrototypes */
662 int haveLocalhost = 0;
664 if (depth == MAX_DEPTH)
666 for (d = database; d; d = d->next)
668 if (d->type != DISPLAY_ALIAS || !patternMatch (alias, d->entry.aliasName))
670 if (scanHostlist (d->hosts, clientAddress, connectionType,
671 function, closure, depth + 1, broadcast))
676 return haveLocalhost;
680 ARRAY8Ptr IndirectChoice ();
683 ForEachMatchingIndirectHost(
684 ARRAY8Ptr clientAddress,
685 #if NeedWidePrototypes
688 CARD16 connectionType,
689 #endif /* NeedWidePrototypes */
693 int haveLocalhost = 0;
695 char *clientName = NULL;
697 for (d = database; d; d = d->next)
702 case DISPLAY_PATTERN:
704 clientName = NetworkAddressToHostname (connectionType,
706 if (!patternMatch (clientName, d->entry.displayPattern))
709 case DISPLAY_ADDRESS:
710 if (d->entry.displayAddress.connectionType != connectionType ||
711 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
725 #endif /* BYPASSLOGIN */
730 choice = IndirectChoice (clientAddress, connectionType);
731 if (!choice || XdmcpARRAY8Equal (getLocalAddress(), choice))
734 (*function) (connectionType, choice, closure);
736 else if (scanHostlist (d->hosts, clientAddress, connectionType,
737 function, closure, 0, FALSE))
745 return haveLocalhost;
750 ARRAY8Ptr clientAddress,
751 #if NeedWidePrototypes
754 CARD16 connectionType )
755 #endif /* NeedWidePrototypes */
758 char *clientName = NULL;
760 for (d = database; d; d = d->next)
765 case DISPLAY_PATTERN:
767 clientName = NetworkAddressToHostname (connectionType,
769 if (!patternMatch (clientName, d->entry.displayPattern))
772 case DISPLAY_ADDRESS:
773 if (d->entry.displayAddress.connectionType != connectionType ||
774 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
788 #endif /* BYPASSLOGIN */
789 if (d->chooser && !IndirectChoice (clientAddress, connectionType)) {
803 ARRAY8Ptr clientAddress,
804 #if NeedWidePrototypes
807 CARD16 connectionType,
808 #endif /* NeedWidePrototypes */
812 int haveLocalhost = 0;
814 char *clientName = NULL;
816 for (d = database; d; d = d->next)
821 case DISPLAY_PATTERN:
823 clientName = NetworkAddressToHostname (connectionType,
825 if (!patternMatch (clientName, d->entry.displayPattern))
828 case DISPLAY_ADDRESS:
829 if (d->entry.displayAddress.connectionType != connectionType ||
830 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
844 #endif /* BYPASSLOGIN */
847 if (scanHostlist (d->hosts, clientAddress, connectionType,
848 function, closure, 0, TRUE))
857 (*function) (connectionType, getLocalAddress(), closure);
861 * returns TRUE if the given client is acceptable to the local host. The
862 * given display client is acceptable if it occurs without a host list.
866 AcceptableDisplayAddress(
867 ARRAY8Ptr clientAddress,
868 #if NeedWidePrototypes
871 CARD16 connectionType,
872 #endif /* NeedWidePrototypes */
876 char *clientName = NULL;
878 if (!accessFile || strlen(accessFile) == 0)
880 if (type == INDIRECT_QUERY)
882 for (d = database; d; d = d->next)
889 case DISPLAY_PATTERN:
891 clientName = NetworkAddressToHostname (connectionType,
893 if (!patternMatch (clientName, d->entry.displayPattern))
896 case DISPLAY_ADDRESS:
897 if (d->entry.displayAddress.connectionType != connectionType ||
898 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
909 return (d != 0) && (d->notAllowed == 0);
915 BypassLogin (char *displayName)
919 ARRAY8 connectionAddress;
920 CARD16 connectionType;
921 CARD16 displayNumber;
923 if (!NameToNetworkAddress (displayName, &connectionType, &connectionAddress,
927 for (d = database; d; d = d->next)
932 case DISPLAY_PATTERN:
933 if (!patternMatch (displayName, d->entry.displayPattern))
936 case DISPLAY_ADDRESS:
937 if (d->entry.displayAddress.connectionType != connectionType ||
938 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
954 if (h->entry.aliasName != NULL)
955 return h->entry.aliasName;
961 HostnameToNetworkAddress (char *name,
962 #if NeedWidePrototypes
965 CARD16 connectionType,
966 #endif /* NeedWidePrototypes */
967 ARRAY8Ptr connectionAddress )
969 switch (connectionType) {
972 struct hostent *hostent;
973 hostent = gethostbyname (name);
974 if (!hostent) return FALSE;
975 if (!XdmcpAllocARRAY8 (connectionAddress, hostent->h_length))
977 bcopy (hostent->h_addr, connectionAddress->data,
991 * converts a display name into a network address, using
992 * the same rules as XOpenDisplay (algorithm cribbed from there)
995 NameToNetworkAddress(char *name,
996 CARD16Ptr connectionTypep,
997 ARRAY8Ptr connectionAddress,
998 CARD16Ptr displayNumber )
1000 char *colon, *display_number;
1001 char hostname[1024];
1004 CARD16 connectionType;
1006 colon = index (name, ':');
1007 if (!colon) return FALSE;
1008 if (colon != name) {
1009 if (colon - name > sizeof (hostname)) return FALSE;
1010 strncpy (hostname, name, colon - name);
1011 hostname[colon - name] = '\0';
1013 strcpy (hostname, localHostname ());
1016 if (colon[1] == ':') {
1026 display_number = colon + 1;
1027 while (*display_number && *display_number != '.') {
1028 if (!isascii (*display_number) || !isdigit(*display_number))
1032 if (display_number == colon + 1) return FALSE;
1033 number = atoi (colon + 1);
1037 connectionType = FamilyDECnet;
1040 connectionType = FamilyInternet;
1042 if (!HostnameToNetworkAddress (hostname, connectionType,
1043 connectionAddress)) return FALSE;
1044 *displayNumber = number;
1045 *connectionTypep = connectionType;
1049 #endif /* BYPASSLOGIN */