not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kdm / backend / access.c
blobc557d42ea1d637d3b89285703b5af89082fa0ab2
1 /*
3 Copyright 1990, 1998 The Open Group
4 Copyright 2001,2004 Oswald Buddenhagen <ossi@kde.org>
5 Copyright 2002 Sun Microsystems, Inc. All rights reserved.
7 Permission to use, copy, modify, distribute, and sell this software and its
8 documentation for any purpose is hereby granted without fee, provided that
9 the above copyright notice appear in all copies and that both that
10 copyright notice and this permission notice appear in supporting
11 documentation.
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
24 Except as contained in this notice, the name of a copyright holder shall
25 not be used in advertising or otherwise to promote the sale, use or
26 other dealings in this Software without prior written authorization
27 from the copyright holder.
32 * xdm - display manager daemon
33 * Author: Keith Packard, MIT X Consortium
35 * Access control for XDMCP - keep a database of allowable display addresses
36 * and (potentially) a list of hosts to send ForwardQuery packets to
39 #include "dm.h"
40 #include "dm_error.h"
41 #include "dm_socket.h"
43 #include <stdio.h>
44 #include <ctype.h>
46 #include <netdb.h>
47 #if defined(IPv6) && defined(AF_INET6)
48 # include <arpa/inet.h>
49 #endif
51 typedef struct {
52 short int type;
53 union {
54 char *aliasPattern;
55 char *hostPattern;
56 struct _displayAddress {
57 CARD16 connectionType;
58 ARRAY8 hostAddress;
59 } displayAddress;
60 } entry;
61 } HostEntry;
63 typedef struct {
64 short int iface;
65 short int mcasts;
66 short int nmcasts;
67 } ListenEntry;
69 typedef struct {
70 char *name;
71 short int hosts;
72 short int nhosts;
73 } AliasEntry;
75 typedef struct {
76 short int entries;
77 short int nentries;
78 short int hosts;
79 short int nhosts;
80 short int flags;
81 } AclEntry;
83 typedef struct {
84 HostEntry *hostList;
85 ListenEntry *listenList;
86 AliasEntry *aliasList;
87 AclEntry *acList;
88 short int nHosts, nListens, nAliases, nAcls;
89 CfgDep dep;
90 } AccArr;
92 static AccArr accData[1];
95 static ARRAY8 localAddress;
97 ARRAY8Ptr
98 getLocalAddress( void )
100 static int haveLocalAddress;
102 if (!haveLocalAddress) {
103 #if defined(IPv6) && defined(AF_INET6)
104 struct addrinfo *ai;
106 if (getaddrinfo( localHostname(), NULL, NULL, &ai )) {
107 XdmcpAllocARRAY8( &localAddress, 4 );
108 localAddress.data[0] = 127;
109 localAddress.data[1] = 0;
110 localAddress.data[2] = 0;
111 localAddress.data[3] = 1;
112 } else {
113 if (ai->ai_family == AF_INET) {
114 XdmcpAllocARRAY8( &localAddress, sizeof(struct in_addr) );
115 memcpy( localAddress.data,
116 &((struct sockaddr_in *)ai->ai_addr)->sin_addr,
117 sizeof(struct in_addr) );
118 } else /* if (ai->ai_family == AF_INET6) */ {
119 XdmcpAllocARRAY8( &localAddress, sizeof(struct in6_addr) );
120 memcpy( localAddress.data,
121 &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr,
122 sizeof(struct in6_addr) );
124 freeaddrinfo( ai );
125 #else
126 struct hostent *hostent;
128 if ((hostent = gethostbyname( localHostname() ))) {
129 XdmcpAllocARRAY8( &localAddress, hostent->h_length );
130 memmove( localAddress.data, hostent->h_addr, hostent->h_length );
131 #endif
132 haveLocalAddress = True;
135 return &localAddress;
139 void
140 scanAccessDatabase( int force )
142 struct _displayAddress *da;
143 char *cptr;
144 int nChars, i;
146 debug( "scanAccessDatabase\n" );
147 if (Setjmp( cnftalk.errjmp ))
148 return; /* may memleak */
149 if (startConfig( GC_gXaccess, &accData->dep, force ) <= 0)
150 return;
151 if (accData->hostList)
152 free( accData->hostList );
153 accData->nHosts = gRecvInt();
154 accData->nListens = gRecvInt();
155 accData->nAliases = gRecvInt();
156 accData->nAcls = gRecvInt();
157 nChars = gRecvInt();
158 if (!(accData->hostList = (HostEntry *)
159 Malloc( accData->nHosts * sizeof(HostEntry) +
160 accData->nListens * sizeof(ListenEntry) +
161 accData->nAliases * sizeof(AliasEntry) +
162 accData->nAcls * sizeof(AclEntry) +
163 nChars )))
165 closeGetter();
166 return;
168 accData->listenList = (ListenEntry *)(accData->hostList + accData->nHosts);
169 accData->aliasList = (AliasEntry *)(accData->listenList + accData->nListens);
170 accData->acList = (AclEntry *)(accData->aliasList + accData->nAliases);
171 cptr = (char *)(accData->acList + accData->nAcls);
172 for (i = 0; i < accData->nHosts; i++) {
173 switch ((accData->hostList[i].type = gRecvInt())) {
174 case HOST_ALIAS:
175 accData->hostList[i].entry.aliasPattern = cptr;
176 cptr += gRecvStrBuf( cptr );
177 break;
178 case HOST_PATTERN:
179 accData->hostList[i].entry.hostPattern = cptr;
180 cptr += gRecvStrBuf( cptr );
181 break;
182 case HOST_ADDRESS:
183 da = &accData->hostList[i].entry.displayAddress;
184 da->hostAddress.data = (unsigned char *)cptr;
185 cptr += (da->hostAddress.length = gRecvArrBuf( cptr ));
186 switch (gRecvInt())
188 #ifdef AF_INET
189 case AF_INET:
190 da->connectionType = FamilyInternet;
191 break;
192 #endif
193 #if defined(IPv6) && defined(AF_INET6)
194 case AF_INET6:
195 da->connectionType = FamilyInternet6;
196 break;
197 #endif
198 #ifdef AF_DECnet
199 case AF_DECnet:
200 da->connectionType = FamilyDECnet;
201 break;
202 #endif
203 /*#ifdef AF_UNIX
204 case AF_UNIX:
205 #endif*/
206 default:
207 da->connectionType = FamilyLocal;
208 break;
210 break;
211 case HOST_BROADCAST:
212 break;
213 default:
214 logError( "Received unknown host type %d from config reader\n", accData->hostList[i].type );
215 return;
218 for (i = 0; i < accData->nListens; i++) {
219 accData->listenList[i].iface = gRecvInt();
220 accData->listenList[i].mcasts = gRecvInt();
221 accData->listenList[i].nmcasts = gRecvInt();
223 for (i = 0; i < accData->nAliases; i++) {
224 accData->aliasList[i].name = cptr;
225 cptr += gRecvStrBuf( cptr );
226 accData->aliasList[i].hosts = gRecvInt();
227 accData->aliasList[i].nhosts = gRecvInt();
229 for (i = 0; i < accData->nAcls; i++) {
230 accData->acList[i].entries = gRecvInt();
231 accData->acList[i].nentries = gRecvInt();
232 accData->acList[i].hosts = gRecvInt();
233 accData->acList[i].nhosts = gRecvInt();
234 accData->acList[i].flags = gRecvInt();
239 /* Returns True if string is matched by pattern. Does case folding.
241 static int
242 patternMatch( const char *string, const char *pattern )
244 int p, s;
246 if (!string)
247 string = "";
249 for (;;) {
250 s = *string++;
251 switch (p = *pattern++) {
252 case '*':
253 if (!*pattern)
254 return True;
255 for (string--; *string; string++)
256 if (patternMatch( string, pattern ))
257 return True;
258 return False;
259 case '?':
260 if (s == '\0')
261 return False;
262 break;
263 case '\0':
264 return s == '\0';
265 case '\\':
266 p = *pattern++;
267 /* fall through */
268 default:
269 if (tolower( p ) != tolower( s ))
270 return False;
276 #define MAX_DEPTH 32
278 static void
279 scanHostlist( int fh, int nh,
280 ARRAY8Ptr clientAddress, CARD16 connectionType,
281 ChooserFunc function, char *closure,
282 int broadcast, int *haveLocalhost )
284 HostEntry *h;
285 AliasEntry *a;
286 int na;
288 for (h = accData->hostList + fh; nh; nh--, h++) {
289 switch (h->type) {
290 case HOST_ALIAS:
291 for (a = accData->aliasList, na = accData->nAliases; na; na--, a++)
292 if (patternMatch( a->name, h->entry.aliasPattern )) /* XXX originally swapped, no wildcards in alias name matching */
293 scanHostlist( a->hosts, a->nhosts,
294 clientAddress, connectionType,
295 function, closure, broadcast,
296 haveLocalhost );
297 break;
298 case HOST_ADDRESS:
299 if (haveLocalhost &&
300 XdmcpARRAY8Equal( getLocalAddress(), &h->entry.displayAddress.hostAddress ))
301 *haveLocalhost = True;
302 else if (function)
303 (*function)( connectionType, &h->entry.displayAddress.hostAddress, closure );
304 break;
305 case HOST_BROADCAST:
306 if (broadcast && function)
307 (*function)( FamilyBroadcast, 0, closure );
308 break;
309 default:
310 break;
315 static int
316 scanEntrylist( int fh, int nh,
317 ARRAY8Ptr clientAddress, CARD16 connectionType,
318 char **clientName )
320 HostEntry *h;
321 AliasEntry *a;
322 int na;
324 for (h = accData->hostList + fh; nh; nh--, h++) {
325 switch (h->type) {
326 case HOST_ALIAS:
327 for (a = accData->aliasList, na = accData->nAliases; na; na--, a++)
328 if (patternMatch( a->name, h->entry.aliasPattern ))
329 if (scanEntrylist( a->hosts, a->nhosts,
330 clientAddress, connectionType,
331 clientName ))
332 return True;
333 break;
334 case HOST_PATTERN:
335 if (!*clientName)
336 *clientName = networkAddressToHostname( connectionType,
337 clientAddress );
338 if (patternMatch( *clientName, h->entry.hostPattern ))
339 return True;
340 break;
341 case HOST_ADDRESS:
342 if (h->entry.displayAddress.connectionType == connectionType &&
343 XdmcpARRAY8Equal( &h->entry.displayAddress.hostAddress,
344 clientAddress ))
345 return True;
346 break;
347 default:
348 break;
351 return False;
354 static AclEntry *
355 matchAclEntry( ARRAY8Ptr clientAddress, CARD16 connectionType, int direct )
357 AclEntry *e, *re;
358 char *clientName = 0;
359 int ne;
361 for (e = accData->acList, ne = accData->nAcls, re = 0; ne; ne--, e++)
362 if (!e->nhosts == direct)
363 if (scanEntrylist( e->entries, e->nentries,
364 clientAddress, connectionType,
365 &clientName ))
367 re = e;
368 break;
370 if (clientName)
371 free( clientName );
372 return re;
376 * calls the given function for each valid indirect entry. Returns True if
377 * the local host exists on any of the lists, else False
380 forEachMatchingIndirectHost( ARRAY8Ptr clientAddress, ARRAY8Ptr clientPort,
381 CARD16 connectionType,
382 ChooserFunc function, char *closure )
384 AclEntry *e;
385 int haveLocalhost = False;
387 e = matchAclEntry( clientAddress, connectionType, False );
388 if (e && !(e->flags & a_notAllowed)) {
389 if (e->flags & a_useChooser) {
390 ARRAY8Ptr choice;
392 choice = indirectChoice( clientAddress, clientPort, connectionType );
393 if (!choice || XdmcpARRAY8Equal( getLocalAddress(), choice ))
394 /* If nothing was chosen yet, we want to pop up the chooser.
395 * If we were chosen, we want to pop up the greeter. */
396 haveLocalhost = True;
397 else
398 /* If something else was chosen, we forward the query to
399 * the chosen host. */
400 (*function)( connectionType, choice, closure );
401 } else
402 /* Just forward the query to each listed host. */
403 scanHostlist( e->hosts, e->nhosts, clientAddress, connectionType,
404 function, closure, False, &haveLocalhost );
406 return haveLocalhost;
410 useChooser( ARRAY8Ptr clientAddress, CARD16 connectionType )
412 AclEntry *e;
414 e = matchAclEntry( clientAddress, connectionType, False );
415 return e && !(e->flags & a_notAllowed) && (e->flags & a_useChooser);
418 void
419 forEachChooserHost( ARRAY8Ptr clientAddress, CARD16 connectionType,
420 ChooserFunc function, char *closure )
422 AclEntry *e;
424 e = matchAclEntry( clientAddress, connectionType, False );
425 if (e && !(e->flags & a_notAllowed) && (e->flags & a_useChooser))
426 scanHostlist( e->hosts, e->nhosts, clientAddress, connectionType,
427 function, closure, True, 0 );
431 * returns True if the given client is acceptable to the local host. The
432 * given display client is acceptable if it occurs without a host list.
435 acceptableDisplayAddress( ARRAY8Ptr clientAddress, CARD16 connectionType,
436 xdmOpCode type )
438 AclEntry *e;
440 if (type == INDIRECT_QUERY)
441 return True;
443 e = matchAclEntry( clientAddress, connectionType, True );
444 return e && !(e->flags & a_notAllowed) &&
445 (type != BROADCAST_QUERY || !(e->flags & a_notBroadcast));
448 void
449 forEachListenAddr( ListenFunc listenfunction, ListenFunc mcastfunction,
450 void **closure )
452 int i, j, ifc, mc, nmc;
454 for (i = 0; i < accData->nListens; i++) {
455 ifc = accData->listenList[i].iface;
456 (*listenfunction)( ifc < 0 ? 0 :
457 &accData->hostList[ifc].entry.displayAddress.hostAddress,
458 closure );
459 mc = accData->listenList[i].mcasts;
460 nmc = accData->listenList[i].nmcasts;
461 for (j = 0; j < nmc; j++, mc++)
462 (*mcastfunction)( &accData->hostList[mc].entry.displayAddress.hostAddress,
463 closure );