2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
25 * (c) Copyright 1993, 1994 International Business Machines Corp. *
26 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
27 * (c) Copyright 1993, 1994 Novell, Inc. *
30 * $TOG: access.c /main/6 1998/04/06 13:20:57 mgreess $
32 * Copyright 1990 Massachusetts Institute of Technology
34 * Permission to use, copy, modify, distribute, and sell this software and its
35 * documentation for any purpose is hereby granted without fee, provided that
36 * the above copyright notice appear in all copies and that both that
37 * copyright notice and this permission notice appear in supporting
38 * documentation, and that the name of M.I.T. not be used in advertising or
39 * publicity pertaining to distribution of the software without specific,
40 * written prior permission. M.I.T. makes no representations about the
41 * suitability of this software for any purpose. It is provided "as is"
42 * without express or implied warranty.
44 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
46 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
47 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
48 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
49 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
51 * Author: Keith Packard, MIT X Consortium
55 * Access control for XDMCP - keep a database of allowable display addresses
56 * and (potentially) a list of hosts to send ForwardQuery packets to
63 # include <X11/Xdmcp.h>
66 # include <netinet/in.h>
68 # include <sys/socket.h>
71 #define ALIAS_CHARACTER '%'
72 #define NEGATE_CHARACTER '!'
73 #define CHOOSER_STRING "CHOOSER"
74 #define BROADCAST_STRING "BROADCAST"
76 #define BYPASS_STRING "BYPASS_LOGIN"
77 #endif /* BYPASSLOGIN */
80 #define HOST_ADDRESS 1
81 #define HOST_BROADCAST 2
82 #define HOST_CHOOSER 3
85 #endif /* BYPASSLOGIN */
87 typedef struct _hostEntry {
88 struct _hostEntry *next;
96 #define DISPLAY_ALIAS 0
97 #define DISPLAY_PATTERN 1
98 #define DISPLAY_ADDRESS 2
100 typedef struct _displayEntry {
101 struct _displayEntry *next;
107 #endif /* BYPASSLOGIN */
110 char *displayPattern;
112 ARRAY8 clientAddress;
113 CARD16 connectionType;
120 /***************************************************************************
122 * Local procedure declarations
124 ***************************************************************************/
126 static void FreeHostEntry(
128 static void FreeDisplayEntry(
130 static void FreeAccessDatabase( void ) ;
131 static char * ReadWord(
134 static HostEntry * ReadHostEntry(
136 static int HasGlobCharacters(
138 static DisplayEntry * ReadDisplayEntry(
140 static void ReadAccessDatabase(
142 static int scanHostlist(
144 ARRAY8Ptr clientAddress,
145 #if NeedWidePrototypes
148 CARD16 connectionType,
149 #endif /* NeedWidePrototypes */
154 static int patternMatch(
157 static int indirectAlias(
159 ARRAY8Ptr clientAddress,
160 #if NeedWidePrototypes
163 CARD16 connectionType,
164 #endif /* NeedWidePrototypes */
175 /***************************************************************************
179 ***************************************************************************/
181 static DisplayEntry *database = 0;
183 static ARRAY8 localAddress;
187 /***************************************************************************
188 ***************************************************************************/
197 #endif /* BYPASSLOGIN */
199 free (h->entry.aliasName);
202 XdmcpDisposeARRAY8 (&h->entry.hostAddress);
217 free (d->entry.aliasName);
219 case DISPLAY_PATTERN:
220 free (d->entry.displayPattern);
222 case DISPLAY_ADDRESS:
223 XdmcpDisposeARRAY8 (&d->entry.displayAddress);
226 for (h = d->hosts; h; h = next) {
234 FreeAccessDatabase( void )
236 DisplayEntry *d, *next;
238 for (d = database; d; d = next)
241 FreeDisplayEntry (d);
247 static char wordBuffer[WORD_LEN];
248 static int nextIsEOF;
275 while ((c = getc (file)) != EOF && c != '\n')
279 if (c == EOF || (EOFatEOL && !quoted))
282 if (wordp == wordBuffer)
290 if (wordp != wordBuffer)
317 struct hostent *hostent;
320 hostOrAlias = ReadWord (file, TRUE);
323 h = (HostEntry *) malloc (sizeof (DisplayEntry));
324 if (*hostOrAlias == ALIAS_CHARACTER)
326 h->type = HOST_ALIAS;
327 h->entry.aliasName = malloc (strlen (hostOrAlias) + 1);
328 if (!h->entry.aliasName) {
332 strcpy (h->entry.aliasName, hostOrAlias);
334 else if (!strcmp (hostOrAlias, CHOOSER_STRING))
336 h->type = HOST_CHOOSER;
338 else if (!strcmp (hostOrAlias, BROADCAST_STRING))
340 h->type = HOST_BROADCAST;
343 else if (!strcmp (hostOrAlias, BYPASS_STRING))
345 h->type = HOST_BYPASS;
346 hostOrAlias = ReadWord (file, TRUE);
349 Debug ("No username specified for login bypass.\n");
350 LogError ((unsigned char *) "Access file \"%s\", No username "
351 "specified for login bypass\n", accessFile);
355 if (!strcmp (hostOrAlias, "root"))
357 LogError ((unsigned char *)
358 "Access file \"%s\", root bypass disallowed\n",
363 h->entry.aliasName = malloc (strlen (hostOrAlias) + 1);
364 if (!h->entry.aliasName) {
368 strcpy (h->entry.aliasName, hostOrAlias);
370 #endif /* BYPASSLOGIN */
373 h->type = HOST_ADDRESS;
374 hostent = gethostbyname (hostOrAlias);
377 Debug ("No such host %s\n", hostOrAlias);
379 ReadCatalog(MC_LOG_SET,MC_LOG_ACC_FILE,MC_DEF_LOG_ACC_FILE),
380 accessFile,hostOrAlias);
384 if (!XdmcpAllocARRAY8 (&h->entry.hostAddress, hostent->h_length))
387 ReadCatalog(MC_LOG_SET,MC_LOG_HOST_ENT,MC_DEF_LOG_HOST_ENT));
391 bcopy (hostent->h_addr, (char *) h->entry.hostAddress.data, hostent->h_length);
410 static DisplayEntry *
414 char *displayOrAlias;
416 struct _display *display;
417 HostEntry *h, **prev;
418 struct hostent *hostent;
420 displayOrAlias = ReadWord (file, FALSE);
423 d = (DisplayEntry *) malloc (sizeof (DisplayEntry));
428 #endif /* BYPASSLOGIN */
429 if (*displayOrAlias == ALIAS_CHARACTER)
431 d->type = DISPLAY_ALIAS;
432 d->entry.aliasName = malloc (strlen (displayOrAlias) + 1);
433 if (!d->entry.aliasName)
438 strcpy (d->entry.aliasName, displayOrAlias);
442 if (*displayOrAlias == NEGATE_CHARACTER)
447 if (HasGlobCharacters (displayOrAlias))
449 d->type = DISPLAY_PATTERN;
450 d->entry.displayPattern = malloc (strlen (displayOrAlias) + 1);
451 if (!d->entry.displayPattern)
456 strcpy (d->entry.displayPattern, displayOrAlias);
460 if ((hostent = gethostbyname (displayOrAlias)) == NULL)
463 ReadCatalog(MC_LOG_SET,MC_LOG_ACC_DPY,MC_DEF_LOG_ACC_DPY),
464 accessFile,displayOrAlias);
468 d->type = DISPLAY_ADDRESS;
469 display = &d->entry.displayAddress;
470 if (!XdmcpAllocARRAY8 (&display->clientAddress, hostent->h_length))
475 bcopy (hostent->h_addr, (char *) display->clientAddress.data, hostent->h_length);
476 switch (hostent->h_addrtype)
480 display->connectionType = FamilyLocal;
485 display->connectionType = FamilyInternet;
490 display->connectionType = FamilyDECnet;
494 display->connectionType = FamilyLocal;
500 while (h = ReadHostEntry (file))
502 if (h->type == HOST_CHOOSER)
511 if (h->type == HOST_BYPASS)
515 #endif /* BYPASSLOGIN */
525 DisplayEntry *d, **prev;
528 while (d = ReadDisplayEntry (file))
537 ScanAccessDatabase( void )
541 FreeAccessDatabase ();
542 if (accessFile && strlen(accessFile) > 0)
544 datafile = fopen (accessFile, "r");
547 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_ACC_CTL,MC_DEF_LOG_ACC_CTL),
551 ReadAccessDatabase (datafile);
571 switch (p = *pattern++) {
575 for (string--; *string; string++)
576 if (patternMatch (string, pattern))
596 getLocalAddress( void )
598 static int haveLocalAddress;
600 if (!haveLocalAddress)
602 struct hostent *hostent;
604 hostent = gethostbyname (localHostname());
605 XdmcpAllocARRAY8 (&localAddress, hostent->h_length);
606 bcopy (hostent->h_addr, (char *) localAddress.data, hostent->h_length);
608 return &localAddress;
613 * calls the given function for each valid indirect entry. Returns TRUE if
614 * the local host exists on any of the lists, else FALSE
622 ARRAY8Ptr clientAddress,
623 #if NeedWidePrototypes
626 CARD16 connectionType,
627 #endif /* NeedWidePrototypes */
633 int haveLocalhost = 0;
635 for (; h; h = h->next)
639 if (indirectAlias (h->entry.aliasName, clientAddress,
640 connectionType, function, closure, depth,
645 if (XdmcpARRAY8Equal (getLocalAddress(), &h->entry.hostAddress))
648 (*function) (connectionType, &h->entry.hostAddress, closure);
657 temp.data = (BYTE *) BROADCAST_STRING;
658 temp.length = strlen ((char *)temp.data);
659 (*function) (connectionType, &temp, closure);
665 return haveLocalhost;
672 ARRAY8Ptr clientAddress,
673 #if NeedWidePrototypes
676 CARD16 connectionType,
677 #endif /* NeedWidePrototypes */
684 int haveLocalhost = 0;
686 if (depth == MAX_DEPTH)
688 for (d = database; d; d = d->next)
690 if (d->type != DISPLAY_ALIAS || !patternMatch (alias, d->entry.aliasName))
692 if (scanHostlist (d->hosts, clientAddress, connectionType,
693 function, closure, depth + 1, broadcast))
698 return haveLocalhost;
702 ARRAY8Ptr IndirectChoice ();
705 ForEachMatchingIndirectHost(
706 ARRAY8Ptr clientAddress,
707 #if NeedWidePrototypes
710 CARD16 connectionType,
711 #endif /* NeedWidePrototypes */
715 int haveLocalhost = 0;
717 char *clientName = NULL;
719 for (d = database; d; d = d->next)
724 case DISPLAY_PATTERN:
726 clientName = NetworkAddressToHostname (connectionType,
728 if (!patternMatch (clientName, d->entry.displayPattern))
731 case DISPLAY_ADDRESS:
732 if (d->entry.displayAddress.connectionType != connectionType ||
733 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
747 #endif /* BYPASSLOGIN */
752 choice = IndirectChoice (clientAddress, connectionType);
753 if (!choice || XdmcpARRAY8Equal (getLocalAddress(), choice))
756 (*function) (connectionType, choice, closure);
758 else if (scanHostlist (d->hosts, clientAddress, connectionType,
759 function, closure, 0, FALSE))
767 return haveLocalhost;
772 ARRAY8Ptr clientAddress,
773 #if NeedWidePrototypes
776 CARD16 connectionType )
777 #endif /* NeedWidePrototypes */
780 char *clientName = NULL;
782 for (d = database; d; d = d->next)
787 case DISPLAY_PATTERN:
789 clientName = NetworkAddressToHostname (connectionType,
791 if (!patternMatch (clientName, d->entry.displayPattern))
794 case DISPLAY_ADDRESS:
795 if (d->entry.displayAddress.connectionType != connectionType ||
796 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
810 #endif /* BYPASSLOGIN */
811 if (d->chooser && !IndirectChoice (clientAddress, connectionType)) {
825 ARRAY8Ptr clientAddress,
826 #if NeedWidePrototypes
829 CARD16 connectionType,
830 #endif /* NeedWidePrototypes */
834 int haveLocalhost = 0;
836 char *clientName = NULL;
838 for (d = database; d; d = d->next)
843 case DISPLAY_PATTERN:
845 clientName = NetworkAddressToHostname (connectionType,
847 if (!patternMatch (clientName, d->entry.displayPattern))
850 case DISPLAY_ADDRESS:
851 if (d->entry.displayAddress.connectionType != connectionType ||
852 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
866 #endif /* BYPASSLOGIN */
869 if (scanHostlist (d->hosts, clientAddress, connectionType,
870 function, closure, 0, TRUE))
879 (*function) (connectionType, getLocalAddress(), closure);
883 * returns TRUE if the given client is acceptable to the local host. The
884 * given display client is acceptable if it occurs without a host list.
888 AcceptableDisplayAddress(
889 ARRAY8Ptr clientAddress,
890 #if NeedWidePrototypes
893 CARD16 connectionType,
894 #endif /* NeedWidePrototypes */
898 char *clientName = NULL;
900 if (!accessFile || strlen(accessFile) == 0)
902 if (type == INDIRECT_QUERY)
904 for (d = database; d; d = d->next)
911 case DISPLAY_PATTERN:
913 clientName = NetworkAddressToHostname (connectionType,
915 if (!patternMatch (clientName, d->entry.displayPattern))
918 case DISPLAY_ADDRESS:
919 if (d->entry.displayAddress.connectionType != connectionType ||
920 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
931 return (d != 0) && (d->notAllowed == 0);
937 BypassLogin (char *displayName)
941 ARRAY8 connectionAddress;
942 CARD16 connectionType;
943 CARD16 displayNumber;
945 if (!NameToNetworkAddress (displayName, &connectionType, &connectionAddress,
949 for (d = database; d; d = d->next)
954 case DISPLAY_PATTERN:
955 if (!patternMatch (displayName, d->entry.displayPattern))
958 case DISPLAY_ADDRESS:
959 if (d->entry.displayAddress.connectionType != connectionType ||
960 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
976 if (h->entry.aliasName != NULL)
977 return h->entry.aliasName;
983 HostnameToNetworkAddress (char *name,
984 #if NeedWidePrototypes
987 CARD16 connectionType,
988 #endif /* NeedWidePrototypes */
989 ARRAY8Ptr connectionAddress )
991 switch (connectionType) {
994 struct hostent *hostent;
995 hostent = gethostbyname (name);
996 if (!hostent) return FALSE;
997 if (!XdmcpAllocARRAY8 (connectionAddress, hostent->h_length))
999 bcopy (hostent->h_addr, connectionAddress->data,
1013 * converts a display name into a network address, using
1014 * the same rules as XOpenDisplay (algorithm cribbed from there)
1017 NameToNetworkAddress(char *name,
1018 CARD16Ptr connectionTypep,
1019 ARRAY8Ptr connectionAddress,
1020 CARD16Ptr displayNumber )
1022 char *colon, *display_number;
1023 char hostname[1024];
1026 CARD16 connectionType;
1028 colon = index (name, ':');
1029 if (!colon) return FALSE;
1030 if (colon != name) {
1031 if (colon - name > sizeof (hostname)) return FALSE;
1032 strncpy (hostname, name, colon - name);
1033 hostname[colon - name] = '\0';
1035 strcpy (hostname, localHostname ());
1038 if (colon[1] == ':') {
1048 display_number = colon + 1;
1049 while (*display_number && *display_number != '.') {
1050 if (!isascii (*display_number) || !isdigit(*display_number))
1054 if (display_number == colon + 1) return FALSE;
1055 number = atoi (colon + 1);
1059 connectionType = FamilyDECnet;
1062 connectionType = FamilyInternet;
1064 if (!HostnameToNetworkAddress (hostname, connectionType,
1065 connectionAddress)) return FALSE;
1066 *displayNumber = number;
1067 *connectionTypep = connectionType;
1071 #endif /* BYPASSLOGIN */