Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtlogin / access.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /*                                                                      *
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.                                *
28  */
29 /*
30  * $TOG: access.c /main/6 1998/04/06 13:20:57 mgreess $
31  *
32  * Copyright 1990 Massachusetts Institute of Technology
33  *
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.
43  *
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.
50  *
51  * Author:  Keith Packard, MIT X Consortium
52  */
53
54 /*
55  * Access control for XDMCP - keep a database of allowable display addresses
56  * and (potentially) a list of hosts to send ForwardQuery packets to
57  */
58
59 # include   "dm.h"
60 # include   "vgmsg.h"
61
62 # include   <X11/Xos.h>
63 # include   <X11/Xdmcp.h>
64 # include   <X11/X.h>
65 # include   <stdio.h>
66 # include   <netinet/in.h>
67 # include   <netdb.h>
68 # include   <sys/socket.h>
69 # include   <ctype.h>
70
71 #define ALIAS_CHARACTER     '%'
72 #define NEGATE_CHARACTER    '!'
73 #define CHOOSER_STRING      "CHOOSER"
74 #define BROADCAST_STRING    "BROADCAST"
75 #ifdef BYPASSLOGIN
76 #define BYPASS_STRING       "BYPASS_LOGIN"
77 #endif /* BYPASSLOGIN */
78
79 #define HOST_ALIAS      0
80 #define HOST_ADDRESS    1
81 #define HOST_BROADCAST  2
82 #define HOST_CHOOSER    3
83 #ifdef BYPASSLOGIN
84 #define HOST_BYPASS     4
85 #endif /* BYPASSLOGIN */
86
87 typedef struct _hostEntry {
88     struct _hostEntry   *next;
89     int     type;
90     union _hostOrAlias {
91         char    *aliasName;
92         ARRAY8  hostAddress;
93     } entry;
94 } HostEntry;
95
96 #define DISPLAY_ALIAS       0
97 #define DISPLAY_PATTERN     1
98 #define DISPLAY_ADDRESS     2
99
100 typedef struct _displayEntry {
101     struct _displayEntry    *next;
102     int                     type;
103     int                     notAllowed;
104     int                     chooser;
105 #ifdef BYPASSLOGIN
106     int                     bypass;
107 #endif /* BYPASSLOGIN */
108     union _displayType {
109         char                *aliasName;
110         char                *displayPattern;
111         struct _display {
112             ARRAY8          clientAddress;
113             CARD16          connectionType;
114         } displayAddress;
115     } entry;
116     HostEntry               *hosts;
117 } DisplayEntry;
118
119
120 /***************************************************************************
121  *
122  *  Local procedure declarations
123  *
124  ***************************************************************************/
125
126 static void FreeHostEntry( 
127                         HostEntry *h) ;
128 static void FreeDisplayEntry( 
129                         DisplayEntry *d) ;
130 static void FreeAccessDatabase( void ) ;
131 static char * ReadWord( 
132                         FILE *file,
133                         int EOFatEOL) ;
134 static HostEntry * ReadHostEntry( 
135                         FILE *file) ;
136 static int HasGlobCharacters( 
137                         char *s) ;
138 static DisplayEntry * ReadDisplayEntry( 
139                         FILE *file) ;
140 static void ReadAccessDatabase( 
141                         FILE *file) ;
142 static int scanHostlist( 
143                         HostEntry *h,
144                         ARRAY8Ptr clientAddress,
145 #if NeedWidePrototypes
146                         int connectionType,
147 #else
148                         CARD16 connectionType,
149 #endif /* NeedWidePrototypes */
150                         int (*function)(),
151                         char *closure,
152                         int depth,
153                         int broadcast) ;
154 static int patternMatch( 
155                         char *string,
156                         char *pattern) ;
157 static int indirectAlias( 
158                         char *alias,
159                         ARRAY8Ptr clientAddress,
160 #if NeedWidePrototypes
161                         int connectionType,
162 #else
163                         CARD16 connectionType,
164 #endif /* NeedWidePrototypes */
165                         int (*function)(),
166                         char *closure,
167                         int depth,
168                         int broadcast) ;
169
170
171
172
173
174
175 /***************************************************************************
176  *
177  *  Global variables
178  *
179  ***************************************************************************/
180
181 static DisplayEntry     *database = 0;
182
183 static ARRAY8           localAddress;
184
185
186
187 /***************************************************************************
188  ***************************************************************************/
189
190 static void
191 FreeHostEntry(
192         HostEntry *h )
193 {
194     switch (h->type) {
195 #ifdef BYPASSLOGIN
196     case HOST_BYPASS:
197 #endif /* BYPASSLOGIN */
198     case HOST_ALIAS:
199         free (h->entry.aliasName);
200         break;
201     case HOST_ADDRESS:
202         XdmcpDisposeARRAY8 (&h->entry.hostAddress);
203         break;
204     case HOST_CHOOSER:
205         break;
206     }
207     free ((char *) h);
208 }
209
210 static void
211 FreeDisplayEntry(
212         DisplayEntry *d )
213 {
214     HostEntry   *h, *next;
215     switch (d->type) {
216     case DISPLAY_ALIAS:
217         free (d->entry.aliasName);
218         break;
219     case DISPLAY_PATTERN:
220         free (d->entry.displayPattern);
221         break;
222     case DISPLAY_ADDRESS:
223         XdmcpDisposeARRAY8 (&d->entry.displayAddress);
224         break;
225     }
226     for (h = d->hosts; h; h = next) {
227         next = h->next;
228         FreeHostEntry (h);
229     }
230     free ((char *) d);
231 }
232
233 static void 
234 FreeAccessDatabase( void )
235 {
236     DisplayEntry    *d, *next;
237
238     for (d = database; d; d = next)
239     {
240         next = d->next;
241         FreeDisplayEntry (d);
242     }
243     database = 0;
244 }
245
246 #define WORD_LEN    256
247 static char     wordBuffer[WORD_LEN];
248 static int      nextIsEOF;
249
250 static char * 
251 ReadWord(
252         FILE *file,
253         int EOFatEOL )
254 {
255     int     c;
256     char    *wordp;
257     int     quoted;
258
259     wordp = wordBuffer;
260     if (nextIsEOF)
261     {
262         nextIsEOF = FALSE;
263         return NULL;
264     }
265     quoted = FALSE;
266     for (;;) {
267         c = getc (file);
268         switch (c) {
269         case '#':
270             if (quoted)
271             {
272                 *wordp++ = c;
273                 break;
274             }
275             while ((c = getc (file)) != EOF && c != '\n')
276                 ;
277         case '\n':
278         case EOF:
279             if (c == EOF || (EOFatEOL && !quoted))
280             {
281                 ungetc (c, file);
282                 if (wordp == wordBuffer)
283                     return NULL;
284                 *wordp = '\0';
285                 nextIsEOF = TRUE;
286                 return wordBuffer;
287             }
288         case ' ':
289         case '\t':
290             if (wordp != wordBuffer)
291             {
292                 ungetc (c, file);
293                 *wordp = '\0';
294                 return wordBuffer;
295             }
296             break;
297         case '\\':
298             if (!quoted)
299             {
300                 quoted = TRUE;
301                 continue;
302             }
303         default:
304             *wordp++ = c;
305             break;
306         }
307         quoted = FALSE;
308     }
309 }
310
311 static HostEntry * 
312 ReadHostEntry(
313         FILE *file )
314 {
315     char            *hostOrAlias;
316     HostEntry       *h;
317     struct hostent  *hostent;
318
319 tryagain:
320     hostOrAlias = ReadWord (file, TRUE);
321     if (!hostOrAlias)
322         return NULL;
323     h = (HostEntry *) malloc (sizeof (DisplayEntry));
324     if (*hostOrAlias == ALIAS_CHARACTER)
325     {
326         h->type = HOST_ALIAS;
327         h->entry.aliasName = malloc (strlen (hostOrAlias) + 1);
328         if (!h->entry.aliasName) {
329             free ((char *) h);
330             return NULL;
331         }
332         strcpy (h->entry.aliasName, hostOrAlias);
333     }
334     else if (!strcmp (hostOrAlias, CHOOSER_STRING))
335     {
336         h->type = HOST_CHOOSER;
337     }
338     else if (!strcmp (hostOrAlias, BROADCAST_STRING))
339     {
340         h->type = HOST_BROADCAST;
341     }
342 #ifdef BYPASSLOGIN
343     else if (!strcmp (hostOrAlias, BYPASS_STRING))
344     {
345         h->type = HOST_BYPASS;
346         hostOrAlias = ReadWord (file, TRUE);
347         if (!hostOrAlias)
348         {
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);
352             free ((char *) h);
353             goto tryagain;
354         }
355         if (!strcmp (hostOrAlias, "root"))
356         {
357             LogError ((unsigned char *)
358                       "Access file \"%s\", root bypass disallowed\n",
359                       accessFile);
360             free ((char *) h);
361             return NULL;
362         }
363         h->entry.aliasName = malloc (strlen (hostOrAlias) + 1);
364         if (!h->entry.aliasName) {
365             free ((char *) h);
366             return NULL;
367         }
368         strcpy (h->entry.aliasName, hostOrAlias);
369     }
370 #endif  /* BYPASSLOGIN */
371     else
372     {
373         h->type = HOST_ADDRESS;
374         hostent = gethostbyname (hostOrAlias);
375         if (!hostent)
376         {
377             Debug ("No such host %s\n", hostOrAlias);
378             LogError(
379                 ReadCatalog(MC_LOG_SET,MC_LOG_ACC_FILE,MC_DEF_LOG_ACC_FILE),
380                 accessFile,hostOrAlias);
381             free ((char *) h);
382             goto tryagain;
383         }
384         if (!XdmcpAllocARRAY8 (&h->entry.hostAddress, hostent->h_length))
385         {
386             LogOutOfMem(
387                 ReadCatalog(MC_LOG_SET,MC_LOG_HOST_ENT,MC_DEF_LOG_HOST_ENT));
388             free ((char *) h);
389             return NULL;
390         }
391         bcopy (hostent->h_addr, (char *) h->entry.hostAddress.data, hostent->h_length);
392     }
393     return h;
394 }
395
396 static int 
397 HasGlobCharacters(
398         char *s )
399 {
400     for (;;)
401         switch (*s++) {
402         case '?':
403         case '*':
404             return 1;
405         case '\0':
406             return 0;
407         }
408 }
409
410 static DisplayEntry * 
411 ReadDisplayEntry(
412         FILE *file )
413 {
414     char            *displayOrAlias;
415     DisplayEntry    *d;
416     struct _display *display;
417     HostEntry       *h, **prev;
418     struct hostent  *hostent;
419     
420     displayOrAlias = ReadWord (file, FALSE);
421     if (!displayOrAlias)
422         return NULL;
423     d = (DisplayEntry *) malloc (sizeof (DisplayEntry));
424     d->notAllowed = 0;
425     d->chooser = 0;
426 #ifdef BYPASSLOGIN
427     d->bypass = 0;
428 #endif /* BYPASSLOGIN */
429     if (*displayOrAlias == ALIAS_CHARACTER)
430     {
431         d->type = DISPLAY_ALIAS;
432         d->entry.aliasName = malloc (strlen (displayOrAlias) + 1);
433         if (!d->entry.aliasName)
434         {
435             free ((char *) d);
436             return NULL;
437         }
438         strcpy (d->entry.aliasName, displayOrAlias);
439     }
440     else
441     {
442         if (*displayOrAlias == NEGATE_CHARACTER)
443         {
444             d->notAllowed = 1;
445             ++displayOrAlias;
446         }
447         if (HasGlobCharacters (displayOrAlias))
448         {
449             d->type = DISPLAY_PATTERN;
450             d->entry.displayPattern = malloc (strlen (displayOrAlias) + 1);
451             if (!d->entry.displayPattern)
452             {
453                 free ((char *) d);
454                 return NULL;
455             }
456             strcpy (d->entry.displayPattern, displayOrAlias);
457         }
458         else
459         {
460             if ((hostent = gethostbyname (displayOrAlias)) == NULL)
461             {
462                 LogError(
463                   ReadCatalog(MC_LOG_SET,MC_LOG_ACC_DPY,MC_DEF_LOG_ACC_DPY),
464                   accessFile,displayOrAlias);
465                 free ((char *) d);
466                 return NULL;
467             }
468             d->type = DISPLAY_ADDRESS;
469             display = &d->entry.displayAddress;
470             if (!XdmcpAllocARRAY8 (&display->clientAddress, hostent->h_length))
471             {
472                 free ((char *) d);
473                 return NULL;
474             }
475             bcopy (hostent->h_addr, (char *) display->clientAddress.data, hostent->h_length);
476             switch (hostent->h_addrtype)
477             {
478 #ifdef AF_UNIX
479             case AF_UNIX:
480                 display->connectionType = FamilyLocal;
481                 break;
482 #endif
483 #ifdef AF_INET
484             case AF_INET:
485                 display->connectionType = FamilyInternet;
486                 break;
487 #endif
488 #ifdef AF_DECnet
489             case AF_DECnet:
490                 display->connectionType = FamilyDECnet;
491                 break;
492 #endif
493             default:
494                 display->connectionType = FamilyLocal;
495                 break;
496             }
497         }
498     }
499     prev = &d->hosts;
500     while (h = ReadHostEntry (file))
501     {
502         if (h->type == HOST_CHOOSER)
503         {
504             FreeHostEntry (h);
505             d->chooser = 1;
506         } else {
507             *prev = h;
508             prev = &h->next;
509         }
510 #ifdef BYPASSLOGIN
511         if (h->type == HOST_BYPASS)
512         {
513             d->bypass = 1;
514         }
515 #endif /* BYPASSLOGIN */
516     }
517     *prev = NULL;
518     return d;
519 }
520
521 static void
522 ReadAccessDatabase(
523         FILE *file )
524 {
525     DisplayEntry    *d, **prev;
526
527     prev = &database;
528     while (d = ReadDisplayEntry (file))
529     {
530         *prev = d;
531         prev = &d->next;
532     }
533     *prev = NULL;
534 }
535
536 int 
537 ScanAccessDatabase( void )
538 {
539     FILE        *datafile;
540
541     FreeAccessDatabase ();
542     if (accessFile && strlen(accessFile) > 0)
543     {
544         datafile = fopen (accessFile, "r");
545         if (!datafile)
546         {
547             LogError(ReadCatalog(MC_LOG_SET,MC_LOG_ACC_CTL,MC_DEF_LOG_ACC_CTL),
548                 accessFile);
549             return 0;
550         }
551         ReadAccessDatabase (datafile);
552         fclose (datafile);
553     }
554     return 1;
555 }
556
557
558 static int 
559 patternMatch(
560         char *string,
561         char *pattern )
562 {
563     int     p, s;
564
565     if (!string)
566         string = "";
567
568     for (;;)
569     {
570         s = *string++;
571         switch (p = *pattern++) {
572         case '*':
573             if (!*pattern)
574                 return TRUE;
575             for (string--; *string; string++)
576                 if (patternMatch (string, pattern))
577                     return 1;
578             return 0;
579         case '?':
580             if (s == 0)
581                 return 0;
582             break;
583         case '\0':
584             return s == 0;
585         case '\\':
586             p = *pattern++;
587         default:
588             if (p != s)
589                 return 0;
590         }
591     }
592 }
593
594
595 ARRAY8Ptr
596 getLocalAddress( void )
597 {
598     static int  haveLocalAddress;
599     
600     if (!haveLocalAddress)
601     {
602         struct hostent  *hostent;
603
604         hostent = gethostbyname (localHostname());
605         XdmcpAllocARRAY8 (&localAddress, hostent->h_length);
606         bcopy (hostent->h_addr, (char *) localAddress.data, hostent->h_length);
607     }
608     return &localAddress;
609 }
610
611
612 /*
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
615  */
616
617 #define MAX_DEPTH   32
618
619 static int 
620 scanHostlist(
621         HostEntry *h,
622         ARRAY8Ptr clientAddress,
623 #if NeedWidePrototypes
624         int connectionType,
625 #else
626         CARD16 connectionType,
627 #endif /* NeedWidePrototypes */
628         int (*function)(),
629         char *closure,
630         int depth,
631         int broadcast )
632 {
633     int haveLocalhost = 0;
634
635     for (; h; h = h->next)
636     {
637         switch (h->type) {
638         case HOST_ALIAS:
639             if (indirectAlias (h->entry.aliasName, clientAddress,
640                                connectionType, function, closure, depth,
641                                broadcast))
642                 haveLocalhost = 1;
643             break;
644         case HOST_ADDRESS:
645             if (XdmcpARRAY8Equal (getLocalAddress(), &h->entry.hostAddress))
646                 haveLocalhost = 1;
647             else if (function)
648                 (*function) (connectionType, &h->entry.hostAddress, closure);
649             break;
650         case HOST_BROADCAST:
651             if (broadcast)
652             {
653                 ARRAY8  temp;
654
655                 if (function)
656                 {
657                     temp.data = (BYTE *) BROADCAST_STRING;
658                     temp.length = strlen ((char *)temp.data);
659                     (*function) (connectionType, &temp, closure);
660                 }
661             }
662             break;
663         }
664     }
665     return haveLocalhost;
666 }
667
668
669 static int 
670 indirectAlias(
671         char *alias,
672         ARRAY8Ptr clientAddress,
673 #if NeedWidePrototypes
674         int connectionType,
675 #else
676         CARD16 connectionType,
677 #endif /* NeedWidePrototypes */
678         int (*function)(),
679         char *closure,
680         int depth,
681         int broadcast )
682 {
683     DisplayEntry    *d;
684     int             haveLocalhost = 0;
685
686     if (depth == MAX_DEPTH)
687         return 0;
688     for (d = database; d; d = d->next)
689     {
690         if (d->type != DISPLAY_ALIAS || !patternMatch (alias, d->entry.aliasName))
691             continue;
692         if (scanHostlist (d->hosts, clientAddress, connectionType,
693                           function, closure, depth + 1, broadcast))
694         {
695             haveLocalhost = 1;
696         }
697     }
698     return haveLocalhost;
699 }
700
701
702 ARRAY8Ptr IndirectChoice ();
703
704 int 
705 ForEachMatchingIndirectHost(
706         ARRAY8Ptr clientAddress,
707 #if NeedWidePrototypes
708         int connectionType,
709 #else
710         CARD16 connectionType,
711 #endif /* NeedWidePrototypes */
712         int (*function)(),
713         char *closure )
714 {
715     int             haveLocalhost = 0;
716     DisplayEntry    *d;
717     char            *clientName = NULL;
718
719     for (d = database; d; d = d->next)
720     {
721         switch (d->type) {
722         case DISPLAY_ALIAS:
723             continue;
724         case DISPLAY_PATTERN:
725             if (!clientName)
726                 clientName = NetworkAddressToHostname (connectionType,
727                                                        clientAddress);
728             if (!patternMatch (clientName, d->entry.displayPattern))
729                 continue;
730             break;
731         case DISPLAY_ADDRESS:
732             if (d->entry.displayAddress.connectionType != connectionType ||
733                 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
734                                   clientAddress))
735             {
736                 continue;
737             }
738             break;
739         }
740         if (!d->hosts)
741             continue;
742         if (d->notAllowed)
743             break;
744 #ifdef BYPASSLOGIN
745         if (d->bypass)
746             break;
747 #endif /* BYPASSLOGIN */
748         if (d->chooser)
749         {
750             ARRAY8Ptr   choice;
751
752             choice = IndirectChoice (clientAddress, connectionType);
753             if (!choice || XdmcpARRAY8Equal (getLocalAddress(), choice))
754                 haveLocalhost = 1;
755             else
756                 (*function) (connectionType, choice, closure);
757         }
758         else if (scanHostlist (d->hosts, clientAddress, connectionType,
759                           function, closure, 0, FALSE))
760         {
761             haveLocalhost = 1;
762         }
763         break;
764     }
765     if (clientName)
766         free (clientName);
767     return haveLocalhost;
768 }
769
770 int 
771 UseChooser(
772         ARRAY8Ptr clientAddress,
773 #if NeedWidePrototypes
774         int connectionType )
775 #else
776         CARD16 connectionType )
777 #endif /* NeedWidePrototypes */
778 {
779     DisplayEntry    *d;
780     char            *clientName = NULL;
781
782     for (d = database; d; d = d->next)
783     {
784         switch (d->type) {
785         case DISPLAY_ALIAS:
786             continue;
787         case DISPLAY_PATTERN:
788             if (!clientName)
789                 clientName = NetworkAddressToHostname (connectionType,
790                                                        clientAddress);
791             if (!patternMatch (clientName, d->entry.displayPattern))
792                 continue;
793             break;
794         case DISPLAY_ADDRESS:
795             if (d->entry.displayAddress.connectionType != connectionType ||
796                 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
797                                   clientAddress))
798             {
799                 continue;
800             }
801             break;
802         }
803         if (!d->hosts)
804             continue;
805         if (d->notAllowed)
806             break;
807 #ifdef BYPASSLOGIN
808         if (d->bypass)
809             break;
810 #endif /* BYPASSLOGIN */
811         if (d->chooser && !IndirectChoice (clientAddress, connectionType)) {
812             if (clientName)
813                 free (clientName);
814             return 1;
815         }
816         break;
817     }
818     if (clientName)
819         free (clientName);
820     return 0;
821 }
822
823 void 
824 ForEachChooserHost(
825         ARRAY8Ptr clientAddress,
826 #if NeedWidePrototypes
827         int connectionType,
828 #else
829         CARD16 connectionType,
830 #endif /* NeedWidePrototypes */
831         int (*function)(),
832         char *closure )
833 {
834     int             haveLocalhost = 0;
835     DisplayEntry    *d;
836     char            *clientName = NULL;
837
838     for (d = database; d; d = d->next)
839     {
840         switch (d->type) {
841         case DISPLAY_ALIAS:
842             continue;
843         case DISPLAY_PATTERN:
844             if (!clientName)
845                 clientName = NetworkAddressToHostname (connectionType,
846                                                        clientAddress);
847             if (!patternMatch (clientName, d->entry.displayPattern))
848                 continue;
849             break;
850         case DISPLAY_ADDRESS:
851             if (d->entry.displayAddress.connectionType != connectionType ||
852                 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
853                                   clientAddress))
854             {
855                 continue;
856             }
857             break;
858         }
859         if (!d->hosts)
860             continue;
861         if (d->notAllowed)
862             break;
863 #ifdef BYPASSLOGIN
864         if (d->bypass)
865             break;
866 #endif /* BYPASSLOGIN */
867         if (!d->chooser)
868             break;
869         if (scanHostlist (d->hosts, clientAddress, connectionType,
870                           function, closure, 0, TRUE))
871         {
872             haveLocalhost = 1;
873         }
874         break;
875     }
876     if (clientName)
877         free (clientName);
878     if (haveLocalhost)
879         (*function) (connectionType, getLocalAddress(), closure);
880 }
881
882 /*
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.
885  */
886
887 int 
888 AcceptableDisplayAddress(
889         ARRAY8Ptr clientAddress,
890 #if NeedWidePrototypes
891         int connectionType,
892 #else
893         CARD16 connectionType,
894 #endif /* NeedWidePrototypes */
895         xdmOpCode type )
896 {
897     DisplayEntry    *d;
898     char            *clientName = NULL;
899
900     if (!accessFile || strlen(accessFile) == 0)
901         return 1;
902     if (type == INDIRECT_QUERY)
903         return 1;
904     for (d = database; d; d = d->next)
905     {
906         if (d->hosts)
907             continue;
908         switch (d->type) {
909         case DISPLAY_ALIAS:
910             continue;
911         case DISPLAY_PATTERN:
912             if (!clientName)
913                 clientName = NetworkAddressToHostname (connectionType,
914                                                        clientAddress);
915             if (!patternMatch (clientName, d->entry.displayPattern))
916                 continue;
917             break;
918         case DISPLAY_ADDRESS:
919             if (d->entry.displayAddress.connectionType != connectionType ||
920                 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
921                                   clientAddress))
922             {
923                 continue;
924             }
925             break;
926         }
927         break;
928     }
929     if (clientName)
930         free (clientName);
931     return (d != 0) && (d->notAllowed == 0);
932 }
933
934 #ifdef BYPASSLOGIN
935
936 char *
937 BypassLogin (char *displayName)
938 {
939     DisplayEntry    *d;
940     HostEntry       *h;
941     ARRAY8      connectionAddress;
942     CARD16      connectionType;
943     CARD16      displayNumber;
944     
945     if (!NameToNetworkAddress (displayName, &connectionType, &connectionAddress,
946                                &displayNumber))
947         return NULL;
948     
949     for (d = database; d; d = d->next)
950     {
951         switch (d->type) {
952         case DISPLAY_ALIAS:
953             continue;
954         case DISPLAY_PATTERN:
955             if (!patternMatch (displayName, d->entry.displayPattern))
956                 continue;
957             break;
958         case DISPLAY_ADDRESS:
959             if (d->entry.displayAddress.connectionType != connectionType ||
960                 !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
961                                    &connectionAddress))
962             {
963                 continue;
964             }
965             break;
966         }
967         if (!d->hosts)
968             continue;
969         if (d->notAllowed)
970             continue;
971         if (d->chooser)
972             continue;
973         if (d->bypass)
974         {
975             h = d->hosts;
976             if (h->entry.aliasName != NULL)
977                 return h->entry.aliasName;
978         }
979     }
980     return NULL;
981 }
982
983 HostnameToNetworkAddress (char *name,
984 #if NeedWidePrototypes
985                           int connectionType,
986 #else
987                           CARD16 connectionType,
988 #endif /* NeedWidePrototypes */
989                           ARRAY8Ptr connectionAddress )
990 {
991     switch (connectionType) {
992     case FamilyInternet:
993     {
994         struct hostent  *hostent;
995         hostent = gethostbyname (name);
996         if (!hostent) return FALSE;
997         if (!XdmcpAllocARRAY8 (connectionAddress, hostent->h_length))
998             return FALSE;
999         bcopy (hostent->h_addr, connectionAddress->data,
1000                hostent->h_length);
1001         return TRUE;
1002     }
1003 #ifdef DNET
1004     case FamilyDECnet:
1005         return FALSE;
1006 #endif
1007     }
1008     return FALSE;
1009 }
1010
1011
1012 /*
1013  * converts a display name into a network address, using
1014  * the same rules as XOpenDisplay (algorithm cribbed from there)
1015  */
1016
1017 NameToNetworkAddress(char        *name,
1018                      CARD16Ptr   connectionTypep,
1019                      ARRAY8Ptr   connectionAddress,
1020                      CARD16Ptr   displayNumber )
1021 {
1022     char    *colon, *display_number;
1023     char    hostname[1024];
1024     int     dnet = FALSE;
1025     CARD16  number;
1026     CARD16  connectionType;
1027     
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';
1034     } else {
1035         strcpy (hostname, localHostname ());
1036     }
1037
1038     if (colon[1] == ':') {
1039         dnet = TRUE;
1040         colon++;
1041     }
1042
1043 #ifndef DNETCONN
1044     if (dnet)
1045         return FALSE;
1046 #endif
1047
1048     display_number = colon + 1;
1049     while (*display_number && *display_number != '.') {
1050         if (!isascii (*display_number) || !isdigit(*display_number))
1051             return FALSE;
1052         display_number++;
1053     }
1054     if (display_number == colon + 1) return FALSE;
1055     number = atoi (colon + 1);
1056
1057 #ifdef DNETCONN
1058     if (dnet)
1059         connectionType = FamilyDECnet;
1060     else
1061 #endif
1062         connectionType = FamilyInternet;
1063
1064     if (!HostnameToNetworkAddress (hostname, connectionType,
1065                                    connectionAddress)) return FALSE;
1066     *displayNumber = number;
1067     *connectionTypep = connectionType;
1068     return TRUE;
1069 }
1070
1071 #endif /* BYPASSLOGIN */