source: trunk/athena/etc/xdm/xdm/access.c @ 6052

Revision 6052, 15.7 KB checked in by lwvanels, 33 years ago (diff)
Initial revision
Line 
1/*
2 * $XConsortium: access.c,v 1.12 92/03/20 13:33:50 gildea Exp $
3 *
4 * Copyright 1990 Massachusetts Institute of Technology
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of M.I.T. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission.  M.I.T. makes no representations about the
13 * suitability of this software for any purpose.  It is provided "as is"
14 * without express or implied warranty.
15 *
16 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Author:  Keith Packard, MIT X Consortium
24 */
25
26/*
27 * Access control for XDMCP - keep a database of allowable display addresses
28 * and (potentially) a list of hosts to send ForwardQuery packets to
29 */
30
31# include   "dm.h"
32
33#ifdef XDMCP
34
35# include   <X11/Xos.h>
36# include   <X11/Xdmcp.h>
37# include   <X11/X.h>
38# include   <stdio.h>
39# include   <netinet/in.h>
40# include   <netdb.h>
41# include   <sys/socket.h>
42
43#define ALIAS_CHARACTER     '%'
44#define NEGATE_CHARACTER    '!'
45#define CHOOSER_STRING      "CHOOSER"
46#define BROADCAST_STRING    "BROADCAST"
47
48#define HOST_ALIAS      0
49#define HOST_ADDRESS    1
50#define HOST_BROADCAST  2
51#define HOST_CHOOSER    3
52
53typedef struct _hostEntry {
54    struct _hostEntry   *next;
55    int     type;
56    union _hostOrAlias {
57        char    *aliasName;
58        ARRAY8  hostAddress;
59    } entry;
60} HostEntry;
61
62#define DISPLAY_ALIAS       0
63#define DISPLAY_PATTERN     1
64#define DISPLAY_ADDRESS     2
65
66typedef struct _displayEntry {
67    struct _displayEntry    *next;
68    int                     type;
69    int                     notAllowed;
70    int                     chooser;
71    union _displayType {
72        char                *aliasName;
73        char                *displayPattern;
74        struct _display {
75            ARRAY8          clientAddress;
76            CARD16          connectionType;
77        } displayAddress;
78    } entry;
79    HostEntry               *hosts;
80} DisplayEntry;
81
82static DisplayEntry     *database;
83
84static ARRAY8           localAddress;
85
86ARRAY8Ptr
87getLocalAddress ()
88{
89    static int  haveLocalAddress;
90   
91    if (!haveLocalAddress)
92    {
93        struct hostent  *hostent;
94
95        hostent = gethostbyname (localHostname());
96        XdmcpAllocARRAY8 (&localAddress, hostent->h_length);
97        bcopy (hostent->h_addr, localAddress.data, hostent->h_length);
98    }
99    return &localAddress;
100}
101
102static void
103FreeHostEntry (h)
104    HostEntry       *h;
105{
106    switch (h->type) {
107    case HOST_ALIAS:
108        free (h->entry.aliasName);
109        break;
110    case HOST_ADDRESS:
111        XdmcpDisposeARRAY8 (&h->entry.hostAddress);
112        break;
113    case HOST_CHOOSER:
114        break;
115    }
116    free ((char *) h);
117}
118
119static void
120FreeDisplayEntry (d)
121    DisplayEntry    *d;
122{
123    HostEntry   *h, *next;
124    switch (d->type) {
125    case DISPLAY_ALIAS:
126        free (d->entry.aliasName);
127        break;
128    case DISPLAY_PATTERN:
129        free (d->entry.displayPattern);
130        break;
131    case DISPLAY_ADDRESS:
132        XdmcpDisposeARRAY8 (&d->entry.displayAddress);
133        break;
134    }
135    for (h = d->hosts; h; h = next) {
136        next = h->next;
137        FreeHostEntry (h);
138    }
139    free ((char *) d);
140}
141
142static void
143FreeAccessDatabase ()
144{
145    DisplayEntry    *d, *next;
146
147    for (d = database; d; d = next)
148    {
149        next = d->next;
150        FreeDisplayEntry (d);
151    }
152    database = 0;
153}
154
155#define WORD_LEN    256
156static char     wordBuffer[WORD_LEN];
157static int      nextIsEOF;
158
159static char *
160ReadWord (file, EOFatEOL)
161    FILE    *file;
162    int     EOFatEOL;
163{
164    int     c;
165    char    *wordp;
166    int     quoted;
167
168    wordp = wordBuffer;
169    if (nextIsEOF)
170    {
171        nextIsEOF = FALSE;
172        return NULL;
173    }
174    quoted = FALSE;
175    for (;;) {
176        c = getc (file);
177        switch (c) {
178        case '#':
179            if (quoted)
180            {
181                *wordp++ = c;
182                break;
183            }
184            while ((c = getc (file)) != EOF && c != '\n')
185                ;
186        case '\n':
187        case EOF:
188            if (c == EOF || (EOFatEOL && !quoted))
189            {
190                ungetc (c, file);
191                if (wordp == wordBuffer)
192                    return NULL;
193                *wordp = '\0';
194                nextIsEOF = TRUE;
195                return wordBuffer;
196            }
197        case ' ':
198        case '\t':
199            if (wordp != wordBuffer)
200            {
201                ungetc (c, file);
202                *wordp = '\0';
203                return wordBuffer;
204            }
205            break;
206        case '\\':
207            if (!quoted)
208            {
209                quoted = TRUE;
210                continue;
211            }
212        default:
213            *wordp++ = c;
214            break;
215        }
216        quoted = FALSE;
217    }
218}
219
220static HostEntry *
221ReadHostEntry (file)
222    FILE    *file;
223{
224    char            *hostOrAlias;
225    HostEntry       *h;
226    struct hostent  *hostent;
227
228tryagain:
229    hostOrAlias = ReadWord (file, TRUE);
230    if (!hostOrAlias)
231        return NULL;
232    h = (HostEntry *) malloc (sizeof (DisplayEntry));
233    if (*hostOrAlias == ALIAS_CHARACTER)
234    {
235        h->type = HOST_ALIAS;
236        h->entry.aliasName = malloc (strlen (hostOrAlias) + 1);
237        if (!h->entry.aliasName) {
238            free ((char *) h);
239            return NULL;
240        }
241        strcpy (h->entry.aliasName, hostOrAlias);
242    }
243    else if (!strcmp (hostOrAlias, CHOOSER_STRING))
244    {
245        h->type = HOST_CHOOSER;
246    }
247    else if (!strcmp (hostOrAlias, BROADCAST_STRING))
248    {
249        h->type = HOST_BROADCAST;
250    }
251    else
252    {
253        h->type = HOST_ADDRESS;
254        hostent = gethostbyname (hostOrAlias);
255        if (!hostent)
256        {
257            Debug ("No such host %s\n", hostOrAlias);
258            LogError ("Access file \"%s\", host \"%s\" not found\n", accessFile, hostOrAlias);
259            free ((char *) h);
260            goto tryagain;
261        }
262        if (!XdmcpAllocARRAY8 (&h->entry.hostAddress, hostent->h_length))
263        {
264            LogOutOfMem ("ReadHostEntry\n");
265            free ((char *) h);
266            return NULL;
267        }
268        bcopy (hostent->h_addr, h->entry.hostAddress.data, hostent->h_length);
269    }
270    return h;
271}
272
273static int
274HasGlobCharacters (s)
275    char    *s;
276{
277    for (;;)
278        switch (*s++) {
279        case '?':
280        case '*':
281            return 1;
282        case '\0':
283            return 0;
284        }
285}
286
287static DisplayEntry *
288ReadDisplayEntry (file)
289    FILE    *file;
290{
291    char            *displayOrAlias;
292    DisplayEntry    *d;
293    struct _display *display;
294    HostEntry       *h, **prev;
295    struct hostent  *hostent;
296   
297    displayOrAlias = ReadWord (file, FALSE);
298    if (!displayOrAlias)
299        return NULL;
300    d = (DisplayEntry *) malloc (sizeof (DisplayEntry));
301    d->notAllowed = 0;
302    d->chooser = 0;
303    if (*displayOrAlias == ALIAS_CHARACTER)
304    {
305        d->type = DISPLAY_ALIAS;
306        d->entry.aliasName = malloc (strlen (displayOrAlias) + 1);
307        if (!d->entry.aliasName)
308        {
309            free ((char *) d);
310            return NULL;
311        }
312        strcpy (d->entry.aliasName, displayOrAlias);
313    }
314    else
315    {
316        if (*displayOrAlias == NEGATE_CHARACTER)
317        {
318            d->notAllowed = 1;
319            ++displayOrAlias;
320        }
321        if (HasGlobCharacters (displayOrAlias))
322        {
323            d->type = DISPLAY_PATTERN;
324            d->entry.displayPattern = malloc (strlen (displayOrAlias) + 1);
325            if (!d->entry.displayPattern)
326            {
327                free ((char *) d);
328                return NULL;
329            }
330            strcpy (d->entry.displayPattern, displayOrAlias);
331        }
332        else
333        {
334            if ((hostent = gethostbyname (displayOrAlias)) == NULL)
335            {
336                LogError ("Access file %s, display %s unknown\n", accessFile, displayOrAlias);
337                free ((char *) d);
338                return NULL;
339            }
340            d->type = DISPLAY_ADDRESS;
341            display = &d->entry.displayAddress;
342            if (!XdmcpAllocARRAY8 (&display->clientAddress, hostent->h_length))
343            {
344                free ((char *) d);
345                return NULL;
346            }
347            bcopy (hostent->h_addr, display->clientAddress.data, hostent->h_length);
348            switch (hostent->h_addrtype)
349            {
350#ifdef AF_UNIX
351            case AF_UNIX:
352                display->connectionType = FamilyLocal;
353                break;
354#endif
355#ifdef AF_INET
356            case AF_INET:
357                display->connectionType = FamilyInternet;
358                break;
359#endif
360#ifdef AF_DECnet
361            case AF_DECnet:
362                display->connectionType = FamilyDECnet;
363                break;
364#endif
365            default:
366                display->connectionType = FamilyLocal;
367                break;
368            }
369        }
370    }
371    prev = &d->hosts;
372    while (h = ReadHostEntry (file))
373    {
374        if (h->type == HOST_CHOOSER)
375        {
376            FreeHostEntry (h);
377            d->chooser = 1;
378        } else {
379            *prev = h;
380            prev = &h->next;
381        }
382    }
383    *prev = NULL;
384    return d;
385}
386
387static
388ReadAccessDatabase (file)
389    FILE    *file;
390{
391    DisplayEntry    *d, **prev;
392
393    prev = &database;
394    while (d = ReadDisplayEntry (file))
395    {
396        *prev = d;
397        prev = &d->next;
398    }
399    *prev = NULL;
400}
401
402ScanAccessDatabase ()
403{
404    FILE        *datafile;
405
406    FreeAccessDatabase ();
407    if (*accessFile)
408    {
409        datafile = fopen (accessFile, "r");
410        if (!datafile)
411        {
412            LogError ("Cannot open access control file %s, no XDMCP reqeusts will be granted\n", accessFile);
413            return 0;
414        }
415        ReadAccessDatabase (datafile);
416        fclose (datafile);
417    }
418    return 1;
419}
420
421/*
422 * calls the given function for each valid indirect entry.  Returns TRUE if
423 * the local host exists on any of the lists, else FALSE
424 */
425
426#define MAX_DEPTH   32
427
428static int indirectAlias ();
429
430static int
431scanHostlist (h, clientAddress, connectionType, function, closure, depth, broadcast)
432    HostEntry   *h;
433    ARRAY8Ptr   clientAddress;
434    CARD16      connectionType;
435    int         (*function)();
436    char        *closure;
437    int         depth;
438    int         broadcast;
439{
440    int haveLocalhost = 0;
441
442    for (; h; h = h->next)
443    {
444        switch (h->type) {
445        case HOST_ALIAS:
446            if (indirectAlias (h->entry.aliasName, clientAddress,
447                               connectionType, function, closure, depth,
448                               broadcast))
449                haveLocalhost = 1;
450            break;
451        case HOST_ADDRESS:
452            if (XdmcpARRAY8Equal (getLocalAddress(), &h->entry.hostAddress))
453                haveLocalhost = 1;
454            else if (function)
455                (*function) (connectionType, &h->entry.hostAddress, closure);
456            break;
457        case HOST_BROADCAST:
458            if (broadcast)
459            {
460                ARRAY8  temp;
461
462                if (function)
463                {
464                    temp.data = (BYTE *) BROADCAST_STRING;
465                    temp.length = strlen ((char *)temp.data);
466                    (*function) (connectionType, &temp, closure);
467                }
468            }
469            break;
470        }
471    }
472    return haveLocalhost;
473}
474
475/* returns non-0 iff string is matched by pattern */
476
477static int
478patternMatch (string, pattern)
479    char    *string, *pattern;
480{
481    int     p, s;
482
483    if (!string)
484        string = "";
485
486    for (;;)
487    {
488        s = *string++;
489        switch (p = *pattern++) {
490        case '*':
491            if (!*pattern)
492                return 1;
493            for (string--; *string; string++)
494                if (patternMatch (string, pattern))
495                    return 1;
496            return 0;
497        case '?':
498            if (s == '\0')
499                return 0;
500            break;
501        case '\0':
502            return s == '\0';
503        case '\\':
504            p = *pattern++;
505            /* fall through */
506        default:
507            if (p != s)
508                return 0;
509        }
510    }
511}
512
513static int
514indirectAlias (alias, clientAddress, connectionType, function, closure, depth,
515               broadcast)
516    char        *alias;
517    ARRAY8Ptr   clientAddress;
518    CARD16      connectionType;
519    int         (*function)();
520    char        *closure;
521    int         depth;
522    int         broadcast;
523{
524    DisplayEntry    *d;
525    int             haveLocalhost = 0;
526
527    if (depth == MAX_DEPTH)
528        return 0;
529    for (d = database; d; d = d->next)
530    {
531        if (d->type != DISPLAY_ALIAS || !patternMatch (alias, d->entry.aliasName))
532            continue;
533        if (scanHostlist (d->hosts, clientAddress, connectionType,
534                          function, closure, depth + 1, broadcast))
535        {
536            haveLocalhost = 1;
537        }
538    }
539    return haveLocalhost;
540}
541
542ARRAY8Ptr IndirectChoice ();
543
544ForEachMatchingIndirectHost (clientAddress, connectionType, function, closure)
545    ARRAY8Ptr   clientAddress;
546    CARD16      connectionType;
547    int         (*function)();
548    char        *closure;
549{
550    int             haveLocalhost = 0;
551    DisplayEntry    *d;
552    char            *clientName = 0, *NetworkAddressToHostname ();
553
554    for (d = database; d; d = d->next)
555    {
556        switch (d->type) {
557        case DISPLAY_ALIAS:
558            continue;
559        case DISPLAY_PATTERN:
560            if (!clientName)
561                clientName = NetworkAddressToHostname (connectionType,
562                                                       clientAddress);
563            if (!patternMatch (clientName, d->entry.displayPattern))
564                continue;
565            break;
566        case DISPLAY_ADDRESS:
567            if (d->entry.displayAddress.connectionType != connectionType ||
568                !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
569                                  clientAddress))
570            {
571                continue;
572            }
573            break;
574        }
575        if (!d->hosts)
576            continue;
577        if (d->notAllowed)
578            break;
579        if (d->chooser)
580        {
581            ARRAY8Ptr   choice;
582
583            choice = IndirectChoice (clientAddress, connectionType);
584            if (!choice || XdmcpARRAY8Equal (getLocalAddress(), choice))
585                haveLocalhost = 1;
586            else
587                (*function) (connectionType, choice, closure);
588        }
589        else if (scanHostlist (d->hosts, clientAddress, connectionType,
590                          function, closure, 0, FALSE))
591        {
592            haveLocalhost = 1;
593        }
594        break;
595    }
596    if (clientName)
597        free (clientName);
598    return haveLocalhost;
599}
600
601UseChooser (clientAddress, connectionType)
602    ARRAY8Ptr   clientAddress;
603    CARD16      connectionType;
604{
605    DisplayEntry    *d;
606    char            *clientName = 0, *NetworkAddressToHostname ();
607
608    for (d = database; d; d = d->next)
609    {
610        switch (d->type) {
611        case DISPLAY_ALIAS:
612            continue;
613        case DISPLAY_PATTERN:
614            if (!clientName)
615                clientName = NetworkAddressToHostname (connectionType,
616                                                       clientAddress);
617            if (!patternMatch (clientName, d->entry.displayPattern))
618                continue;
619            break;
620        case DISPLAY_ADDRESS:
621            if (d->entry.displayAddress.connectionType != connectionType ||
622                !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
623                                  clientAddress))
624            {
625                continue;
626            }
627            break;
628        }
629        if (!d->hosts)
630            continue;
631        if (d->notAllowed)
632            break;
633        if (d->chooser && !IndirectChoice (clientAddress, connectionType))
634            return 1;
635        break;
636    }
637    return 0;
638}
639
640ForEachChooserHost (clientAddress, connectionType, function, closure)
641    ARRAY8Ptr   clientAddress;
642    CARD16      connectionType;
643    int         (*function)();
644    char        *closure;
645{
646    int             haveLocalhost = 0;
647    DisplayEntry    *d;
648    char            *clientName = 0, *NetworkAddressToHostname ();
649
650    for (d = database; d; d = d->next)
651    {
652        switch (d->type) {
653        case DISPLAY_ALIAS:
654            continue;
655        case DISPLAY_PATTERN:
656            if (!clientName)
657                clientName = NetworkAddressToHostname (connectionType,
658                                                       clientAddress);
659            if (!patternMatch (clientName, d->entry.displayPattern))
660                continue;
661            break;
662        case DISPLAY_ADDRESS:
663            if (d->entry.displayAddress.connectionType != connectionType ||
664                !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
665                                  clientAddress))
666            {
667                continue;
668            }
669            break;
670        }
671        if (!d->hosts)
672            continue;
673        if (d->notAllowed)
674            break;
675        if (!d->chooser)
676            break;
677        if (scanHostlist (d->hosts, clientAddress, connectionType,
678                          function, closure, 0, TRUE))
679        {
680            haveLocalhost = 1;
681        }
682        break;
683    }
684    if (clientName)
685        free (clientName);
686    if (haveLocalhost)
687        (*function) (connectionType, getLocalAddress(), closure);
688}
689
690/*
691 * returns TRUE if the given client is acceptable to the local host.  The
692 * given display client is acceptable if it occurs without a host list.
693 */
694
695AcceptableDisplayAddress (clientAddress, connectionType, type)
696    ARRAY8Ptr   clientAddress;
697    CARD16      connectionType;
698    xdmOpCode   type;
699{
700    DisplayEntry    *d;
701    char            *clientName = 0, *NetworkAddressToHostname ();
702
703    if (!*accessFile)
704        return 1;
705    if (type == INDIRECT_QUERY)
706        return 1;
707    for (d = database; d; d = d->next)
708    {
709        if (d->hosts)
710            continue;
711        switch (d->type) {
712        case DISPLAY_ALIAS:
713            continue;
714        case DISPLAY_PATTERN:
715            if (!clientName)
716                clientName = NetworkAddressToHostname (connectionType,
717                                                       clientAddress);
718            if (!patternMatch (clientName, d->entry.displayPattern))
719                continue;
720            break;
721        case DISPLAY_ADDRESS:
722            if (d->entry.displayAddress.connectionType != connectionType ||
723                !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
724                                  clientAddress))
725            {
726                continue;
727            }
728            break;
729        }
730        break;
731    }
732    if (clientName)
733        free (clientName);
734    return (d != 0) && (d->notAllowed == 0);
735}
736
737#endif /* XDMCP */
Note: See TracBrowser for help on using the repository browser.