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