not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kdm / backend / xdmcp.c
blob9a29b02a43f4b9fb4dc0e56b4d7d6367a94ecab4
1 /*
3 Copyright 1988, 1998 The Open Group
4 Copyright 2002 Sun Microsystems, Inc. All rights reserved.
5 Copyright 2001-2004 Oswald Buddenhagen <ossi@kde.org>
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 * xdmcp.c - Support for XDMCP
38 #include "dm.h"
39 #include "dm_error.h"
40 #include "dm_auth.h"
41 #include "dm_socket.h"
43 #include <sys/types.h>
44 #include <ctype.h>
46 #include <netdb.h>
47 #if defined(IPv6) && defined(AF_INET6)
48 # include <arpa/inet.h>
49 #endif
52 char *
53 networkAddressToHostname( CARD16 connectionType, ARRAY8Ptr connectionAddress )
55 switch (connectionType) {
56 case FamilyInternet:
57 #if defined(IPv6) && defined(AF_INET6)
58 case FamilyInternet6:
59 #endif
61 struct hostent *he;
62 char *myDot, *name, *lname;
63 int af_type;
64 #if defined(IPv6) && defined(AF_INET6)
65 char dotted[INET6_ADDRSTRLEN];
67 if (connectionType == FamilyInternet6)
68 af_type = AF_INET6;
69 else
70 #endif
71 af_type = AF_INET;
73 he = gethostbyaddr( (char *)connectionAddress->data,
74 connectionAddress->length, af_type );
75 if (he) {
76 #if defined(IPv6) && defined(AF_INET6)
77 struct addrinfo *ai, *nai;
78 if (!getaddrinfo( he->h_name, NULL, NULL, &ai )) {
79 for (nai = ai; nai; nai = nai->ai_next) {
80 if (af_type == nai->ai_family &&
81 !memcmp( nai->ai_family == AF_INET ?
82 (char *)&((struct sockaddr_in *)nai->ai_addr)->sin_addr :
83 (char *)&((struct sockaddr_in6 *)nai->ai_addr)->sin6_addr,
84 connectionAddress->data,
85 connectionAddress->length ))
87 freeaddrinfo( ai );
88 goto oki;
91 freeaddrinfo( ai );
92 #else
93 if ((he = gethostbyname( he->h_name )) &&
94 he->h_addrtype == AF_INET)
96 int i;
97 for (i = 0; he->h_addr_list[i]; i++)
98 if (!memcmp( he->h_addr_list[i],
99 connectionAddress->data, 4 ))
100 goto oki;
101 #endif
102 logError( "DNS spoof attempt or misconfigured resolver.\n" );
104 goto gotnone;
105 oki:
106 if (strDup( &name, he->h_name ) &&
107 !strchr( name, '.' ) &&
108 (myDot = strchr( localHostname(), '.' )))
110 if (ASPrintf( &lname, "%s%s", name, myDot )) {
111 #if defined(IPv6) && defined(AF_INET6)
112 if (!getaddrinfo( lname, NULL, NULL, &ai )) {
113 for (nai = ai; nai; nai = nai->ai_next) {
114 if (af_type == nai->ai_family &&
115 !memcmp( nai->ai_family == AF_INET ?
116 (char *)&((struct sockaddr_in *)nai->ai_addr)->sin_addr :
117 (char *)&((struct sockaddr_in6 *)nai->ai_addr)->sin6_addr,
118 connectionAddress->data,
119 connectionAddress->length ))
121 freeaddrinfo( ai );
122 free( name );
123 return lname;
126 freeaddrinfo( ai );
128 #else
129 if ((he = gethostbyname( lname )) &&
130 he->h_addrtype == AF_INET)
132 int i;
133 for (i = 0; he->h_addr_list[i]; i++)
134 if (!memcmp( he->h_addr_list[i],
135 connectionAddress->data, 4 ))
137 free( name );
138 return lname;
141 #endif
142 free( lname );
145 } else {
146 gotnone:
147 /* can't get name, so use emergency fallback */
148 #if defined(IPv6) && defined(AF_INET6)
149 inet_ntop( af_type, connectionAddress->data,
150 dotted, sizeof(dotted) );
151 strDup( &name, dotted );
152 #else
153 ASPrintf( &name, "%[4|'.'hhu", connectionAddress->data );
154 #endif
155 logWarn( "Cannot convert Internet address %s to host name\n",
156 name );
158 return name;
160 #ifdef DNET
161 case FamilyDECnet:
162 break;
163 #endif /* DNET */
164 default:
165 break;
167 return 0;
170 static char *
171 networkAddressToName( CARD16 connectionType, ARRAY8Ptr connectionAddress,
172 struct sockaddr *originalAddress, CARD16 displayNumber )
174 switch (connectionType) {
175 case FamilyInternet:
176 #if defined(IPv6) && defined(AF_INET6)
177 case FamilyInternet6:
178 #endif
180 CARD8 *data;
181 struct hostent *hostent;
182 char *hostname = NULL;
183 char *name;
184 const char *localhost;
185 int multiHomed = False;
186 int type;
187 #if defined(IPv6) && defined(AF_INET6)
188 struct addrinfo *ai = NULL, *nai, hints;
189 char dotted[INET6_ADDRSTRLEN];
191 if (connectionType == FamilyInternet6)
192 type = AF_INET6;
193 else
194 #endif
195 type = AF_INET;
197 data = connectionAddress->data;
198 hostent = gethostbyaddr( (char *)data,
199 connectionAddress->length, type );
200 if (hostent) {
201 if (sourceAddress) {
202 #if defined(IPv6) && defined(AF_INET6)
203 bzero( &hints, sizeof(hints) );
204 hints.ai_flags = AI_CANONNAME;
205 if (!getaddrinfo( hostent->h_name, NULL, &hints, &ai )) {
206 hostname = ai->ai_canonname;
207 for (nai = ai->ai_next; nai; nai = nai->ai_next)
208 if (ai->ai_protocol == nai->ai_protocol &&
209 memcmp( ai->ai_addr, nai->ai_addr,
210 ai->ai_addrlen ))
211 multiHomed = True;
213 #else
214 hostent = gethostbyname( hostent->h_name );
215 if (hostent && hostent->h_addrtype == AF_INET) {
216 multiHomed = hostent->h_addr_list[1] != NULL;
217 hostname = hostent->h_name;
219 #endif
220 } else
221 hostname = hostent->h_name;
224 localhost = localHostname();
227 * protect against bogus host names
229 if (hostname && *hostname && *hostname != '.' && !multiHomed) {
230 if (!strcmp( localhost, hostname ))
231 ASPrintf( &name, "localhost:%d", displayNumber );
232 else {
233 if (removeDomainname) {
234 char *localDot, *remoteDot;
236 /* check for a common domain name. This
237 * could reduce names by recognising common
238 * super-domain names as well, but I don't think
239 * this is as useful, and will confuse more
240 * people
242 if ((localDot = strchr( localhost, '.' )) &&
243 (remoteDot = strchr( hostname, '.' )))
245 /* smash the name in place; it won't
246 * be needed later.
248 if (!strcmp( localDot+1, remoteDot+1 ))
249 *remoteDot = '\0';
253 ASPrintf( &name, "%s:%d", hostname, displayNumber );
255 } else {
256 #if defined(IPv6) && defined(AF_INET6)
257 if (multiHomed) {
258 if (connectionType == FamilyInternet) {
259 data = (CARD8 *)
260 &((struct sockaddr_in *)originalAddress)->sin_addr;
261 } else {
262 data = (CARD8 *)
263 &((struct sockaddr_in6 *)originalAddress)->sin6_addr;
266 inet_ntop( type, data, dotted, sizeof(dotted) );
267 ASPrintf( &name, "%s:%d", dotted, displayNumber );
268 #else
269 if (multiHomed)
270 data = (CARD8 *)
271 &((struct sockaddr_in *)originalAddress)->sin_addr;
272 ASPrintf( &name, "%[4|'.'hhu:%d", data, displayNumber );
273 #endif
275 #if defined(IPv6) && defined(AF_INET6)
276 if (ai)
277 freeaddrinfo( ai );
278 #endif
279 return name;
281 #ifdef DNET
282 case FamilyDECnet:
283 return NULL;
284 #endif /* DNET */
285 default:
286 return NULL;
290 static void
291 convertClientAddress( struct sockaddr *from,
292 ARRAY8Ptr addr, /* return */
293 ARRAY8Ptr port, /* return */
294 CARD16 *type ) /* return */
296 int length, family;
297 CARD8 *data;
299 data = netaddrPort( (XdmcpNetaddr)from, &length );
300 XdmcpAllocARRAY8( port, length );
301 memmove( port->data, data, length );
302 port->length = length;
304 family = convertAddr( (XdmcpNetaddr)from, &length, &data );
305 XdmcpAllocARRAY8( addr, length );
306 memmove( addr->data, data, length );
307 addr->length = length;
309 *type = family;
312 static XdmcpBuffer buffer;
314 static ARRAY8 Hostname;
315 static unsigned long globalSessionID;
317 #define nextSessionID() (++globalSessionID)
319 void initXdmcp( void )
321 /* Set randomly so we are unlikely to reuse id's from a previous
322 * incarnation so we don't say "Alive" to those displays.
323 * Start with low digits 0 to make debugging easier.
325 globalSessionID = (time( (time_t *)0 ) & 0x7fff) * 16000;
327 Hostname.data = (unsigned char *)localHostname();
328 Hostname.length = strlen( (char *)Hostname.data );
331 static void
332 send_willing( struct sockaddr *from, int fromlen,
333 ARRAY8Ptr authenticationName, ARRAY8Ptr status, int fd )
335 XdmcpHeader header;
337 debug( "send <willing> %.*s %.*s\n", authenticationName->length,
338 authenticationName->data,
339 status->length,
340 status->data );
341 header.version = XDM_PROTOCOL_VERSION;
342 header.opcode = (CARD16)WILLING;
343 header.length =
344 6 + authenticationName->length + Hostname.length + status->length;
345 XdmcpWriteHeader( &buffer, &header );
346 XdmcpWriteARRAY8( &buffer, authenticationName );
347 XdmcpWriteARRAY8( &buffer, &Hostname );
348 XdmcpWriteARRAY8( &buffer, status );
349 XdmcpFlush( fd, &buffer, (XdmcpNetaddr)from, fromlen );
352 static void
353 send_unwilling( struct sockaddr *from, int fromlen,
354 ARRAY8Ptr authenticationName, ARRAY8Ptr status, int fd )
356 XdmcpHeader header;
358 debug( "send <unwilling> %.*s %.*s\n", authenticationName->length,
359 authenticationName->data,
360 status->length,
361 status->data );
362 header.version = XDM_PROTOCOL_VERSION;
363 header.opcode = (CARD16)UNWILLING;
364 header.length = 4 + Hostname.length + status->length;
365 XdmcpWriteHeader( &buffer, &header );
366 XdmcpWriteARRAY8( &buffer, &Hostname );
367 XdmcpWriteARRAY8( &buffer, status );
368 XdmcpFlush( fd, &buffer, (XdmcpNetaddr)from, fromlen );
371 static void
372 all_query_respond( struct sockaddr *from, int fromlen,
373 ARRAYofARRAY8Ptr authenticationNames,
374 xdmOpCode type, int fd )
376 ARRAY8Ptr authenticationName;
377 ARRAY8 status;
378 ARRAY8 addr;
379 ARRAY8 port;
380 CARD16 connectionType;
381 int family;
382 int length;
384 family = convertAddr( (XdmcpNetaddr)from, &length, &addr.data );
385 addr.length = length; /* convert int to short */
386 port.data = netaddrPort( (XdmcpNetaddr)from, &length );
387 port.length = length; /* convert int to short */
388 debug( "all_query_respond: conntype=%d, addr=%02[*:hhx\n",
389 family, addr.length, addr.data );
390 if (family < 0)
391 return;
392 connectionType = family;
394 if (type == INDIRECT_QUERY)
395 registerIndirectChoice( &addr, &port, connectionType, 0 );
396 else
397 checkIndirectChoice( &addr, &port, connectionType );
399 authenticationName = chooseAuthentication( authenticationNames );
400 if (isWilling( &addr, connectionType, authenticationName, &status, type ))
401 send_willing( from, fromlen, authenticationName, &status, fd );
402 else
403 if (type == QUERY)
404 send_unwilling( from, fromlen, authenticationName, &status, fd );
405 XdmcpDisposeARRAY8( &status );
408 static void
409 sendForward( CARD16 connectionType, ARRAY8Ptr address, char *closure )
411 #ifdef AF_INET
412 struct sockaddr_in in_addr;
413 #endif
414 #if defined(IPv6) && defined(AF_INET6)
415 struct sockaddr_in6 in6_addr;
416 #endif
417 #ifdef AF_DECnet
418 #endif
419 struct sockaddr *addr;
420 int addrlen;
422 switch (connectionType) {
423 #ifdef AF_INET
424 case FamilyInternet:
425 addr = (struct sockaddr *)&in_addr;
426 bzero( (char *)&in_addr, sizeof(in_addr) );
427 # ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
428 in_addr.sin_len = sizeof(in_addr);
429 # endif
430 in_addr.sin_family = AF_INET;
431 in_addr.sin_port = htons( (short)requestPort );
432 if (address->length != 4)
433 return;
434 memmove( (char *)&in_addr.sin_addr, address->data, address->length );
435 addrlen = sizeof(struct sockaddr_in);
436 break;
437 #endif
438 #if defined(IPv6) && defined(AF_INET6)
439 case FamilyInternet6:
440 addr = (struct sockaddr *)&in6_addr;
441 bzero( (char *)&in6_addr, sizeof(in6_addr) );
442 # ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
443 in6_addr.sin6_len = sizeof(in6_addr);
444 # endif
445 in6_addr.sin6_family = AF_INET6;
446 in6_addr.sin6_port = htons( (short)requestPort );
447 if (address->length != 16)
448 return;
449 memmove( (char *)&in6_addr.sin6_addr, address->data, address->length );
450 addrlen = sizeof(struct sockaddr_in6);
451 break;
452 #endif
453 #ifdef AF_DECnet
454 case FamilyDECnet:
455 #endif
456 default:
457 return;
459 XdmcpFlush( (int)(long)closure, &buffer, (XdmcpNetaddr)addr, addrlen );
460 return;
463 static void
464 indirect_respond( struct sockaddr *from, int fromlen, int length, int fd )
466 ARRAYofARRAY8 queryAuthenticationNames;
467 ARRAY8 clientAddress;
468 ARRAY8 clientPort;
469 CARD16 connectionType;
470 int expectedLen;
471 int i;
472 XdmcpHeader header;
473 int localHostAsWell;
475 debug( "<indirect> respond %d\n", length );
476 if (!XdmcpReadARRAYofARRAY8( &buffer, &queryAuthenticationNames ))
477 return;
478 expectedLen = 1;
479 for (i = 0; i < (int)queryAuthenticationNames.length; i++)
480 expectedLen += 2 + queryAuthenticationNames.data[i].length;
481 if (length == expectedLen) {
482 convertClientAddress( from,
483 &clientAddress, &clientPort, &connectionType );
485 * set up the forward query packet
487 header.version = XDM_PROTOCOL_VERSION;
488 header.opcode = (CARD16)FORWARD_QUERY;
489 header.length = 0;
490 header.length += 2 + clientAddress.length;
491 header.length += 2 + clientPort.length;
492 header.length += 1;
493 for (i = 0; i < (int)queryAuthenticationNames.length; i++)
494 header.length += 2 + queryAuthenticationNames.data[i].length;
495 XdmcpWriteHeader( &buffer, &header );
496 XdmcpWriteARRAY8( &buffer, &clientAddress );
497 XdmcpWriteARRAY8( &buffer, &clientPort );
498 XdmcpWriteARRAYofARRAY8( &buffer, &queryAuthenticationNames );
500 localHostAsWell =
501 forEachMatchingIndirectHost( &clientAddress, &clientPort, connectionType,
502 sendForward, (char *)(long)fd );
504 XdmcpDisposeARRAY8( &clientAddress );
505 XdmcpDisposeARRAY8( &clientPort );
506 if (localHostAsWell)
507 all_query_respond( from, fromlen, &queryAuthenticationNames,
508 INDIRECT_QUERY, fd );
509 } else
510 debug( "<indirect> length error got %d expect %d\n",
511 length, expectedLen );
512 XdmcpDisposeARRAYofARRAY8( &queryAuthenticationNames );
516 * respond to a request on the UDP socket.
519 static void
520 direct_query_respond( struct sockaddr *from, int fromlen,
521 int length, xdmOpCode type, int fd )
523 ARRAYofARRAY8 queryAuthenticationNames;
524 int expectedLen;
525 int i;
527 if (!XdmcpReadARRAYofARRAY8( &buffer, &queryAuthenticationNames ))
528 return;
529 expectedLen = 1;
530 for (i = 0; i < (int)queryAuthenticationNames.length; i++)
531 expectedLen += 2 + queryAuthenticationNames.data[i].length;
532 if (length == expectedLen)
533 all_query_respond( from, fromlen, &queryAuthenticationNames, type, fd );
534 XdmcpDisposeARRAYofARRAY8( &queryAuthenticationNames );
537 static void
538 query_respond( struct sockaddr *from, int fromlen, int length, int fd )
540 debug( "<query> respond %d\n", length );
541 direct_query_respond( from, fromlen, length, QUERY, fd );
544 static void
545 broadcast_respond( struct sockaddr *from, int fromlen, int length, int fd )
547 direct_query_respond( from, fromlen, length, BROADCAST_QUERY, fd );
550 /*ARGSUSED*/
551 static void
552 forward_respond( struct sockaddr *from, int fromlen ATTR_UNUSED,
553 int length, int fd )
555 ARRAY8 clientAddress;
556 ARRAY8 clientPort;
557 ARRAYofARRAY8 authenticationNames;
558 struct sockaddr *client;
559 int clientlen;
560 int expectedLen;
561 int i;
563 debug( "<forward> respond %d\n", length );
564 clientAddress.length = 0;
565 clientAddress.data = 0;
566 clientPort.length = 0;
567 clientPort.data = 0;
568 authenticationNames.length = 0;
569 authenticationNames.data = 0;
570 if (XdmcpReadARRAY8( &buffer, &clientAddress ) &&
571 XdmcpReadARRAY8( &buffer, &clientPort ) &&
572 XdmcpReadARRAYofARRAY8( &buffer, &authenticationNames ))
574 expectedLen = 0;
575 expectedLen += 2 + clientAddress.length;
576 expectedLen += 2 + clientPort.length;
577 expectedLen += 1; /* authenticationNames */
578 for (i = 0; i < (int)authenticationNames.length; i++)
579 expectedLen += 2 + authenticationNames.data[i].length;
580 if (length == expectedLen) {
581 int j;
583 j = 0;
584 for (i = 0; i < (int)clientPort.length; i++)
585 j = j * 256 + clientPort.data[i];
586 debug( "<forward> client address (port %d) %[*hhu\n", j,
587 clientAddress.length, clientAddress.data );
588 switch (from->sa_family) {
589 #ifdef AF_INET
590 case AF_INET:
592 struct sockaddr_in in_addr;
594 if (clientAddress.length != 4 || clientPort.length != 2)
595 goto badAddress;
596 bzero( (char *)&in_addr, sizeof(in_addr) );
597 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
598 in_addr.sin_len = sizeof(in_addr);
599 #endif
600 in_addr.sin_family = AF_INET;
601 memmove( &in_addr.sin_addr, clientAddress.data, 4 );
602 memmove( (char *)&in_addr.sin_port, clientPort.data, 2 );
603 client = (struct sockaddr *)&in_addr;
604 clientlen = sizeof(in_addr);
605 all_query_respond( client, clientlen, &authenticationNames,
606 FORWARD_QUERY, fd );
608 break;
609 #endif
610 #if defined(IPv6) && defined(AF_INET6)
611 case AF_INET6:
613 struct sockaddr_in6 in6_addr;
615 if (clientAddress.length != 16 || clientPort.length != 2)
616 goto badAddress;
617 bzero( (char *)&in6_addr, sizeof(in6_addr) );
618 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
619 in6_addr.sin6_len = sizeof(in6_addr);
620 #endif
621 in6_addr.sin6_family = AF_INET6;
622 memmove( &in6_addr,clientAddress.data,clientAddress.length );
623 memmove( (char *)&in6_addr.sin6_port, clientPort.data, 2 );
624 client = (struct sockaddr *)&in6_addr;
625 clientlen = sizeof(in6_addr);
626 all_query_respond( client, clientlen, &authenticationNames,
627 FORWARD_QUERY, fd );
629 break;
630 #endif
631 #ifdef AF_UNIX
632 case AF_UNIX:
634 struct sockaddr_un un_addr;
636 if (clientAddress.length >= sizeof(un_addr.sun_path))
637 goto badAddress;
638 bzero( (char *)&un_addr, sizeof(un_addr) );
639 un_addr.sun_family = AF_UNIX;
640 memmove( un_addr.sun_path, clientAddress.data, clientAddress.length );
641 un_addr.sun_path[clientAddress.length] = '\0';
642 client = (struct sockaddr *)&un_addr;
643 #if defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN) && !defined(__Lynx__) && defined(UNIXCONN)
644 un_addr.sun_len = strlen( un_addr.sun_path );
645 clientlen = SUN_LEN( &un_addr );
646 #else
647 clientlen = sizeof(un_addr);
648 #endif
649 all_query_respond( client, clientlen, &authenticationNames,
650 FORWARD_QUERY, fd );
652 break;
653 #endif
654 #ifdef AF_CHAOS
655 case AF_CHAOS:
656 goto badAddress;
657 #endif
658 #ifdef AF_DECnet
659 case AF_DECnet:
660 goto badAddress;
661 #endif
663 } else
664 debug( "<forward> length error got %d expect %d\n", length, expectedLen );
666 badAddress:
667 XdmcpDisposeARRAY8( &clientAddress );
668 XdmcpDisposeARRAY8( &clientPort );
669 XdmcpDisposeARRAYofARRAY8( &authenticationNames );
673 static void
674 send_accept( struct sockaddr *to, int tolen, CARD32 sessionID,
675 ARRAY8Ptr authenticationName, ARRAY8Ptr authenticationData,
676 ARRAY8Ptr authorizationName, ARRAY8Ptr authorizationData,
677 int fd )
679 XdmcpHeader header;
681 debug( "<accept> session ID %ld\n", (long)sessionID );
682 header.version = XDM_PROTOCOL_VERSION;
683 header.opcode = (CARD16)ACCEPT;
684 header.length = 4; /* session ID */
685 header.length += 2 + authenticationName->length;
686 header.length += 2 + authenticationData->length;
687 header.length += 2 + authorizationName->length;
688 header.length += 2 + authorizationData->length;
689 XdmcpWriteHeader( &buffer, &header );
690 XdmcpWriteCARD32( &buffer, sessionID );
691 XdmcpWriteARRAY8( &buffer, authenticationName );
692 XdmcpWriteARRAY8( &buffer, authenticationData );
693 XdmcpWriteARRAY8( &buffer, authorizationName );
694 XdmcpWriteARRAY8( &buffer, authorizationData );
695 XdmcpFlush( fd, &buffer, (XdmcpNetaddr)to, tolen );
698 static void
699 send_decline( struct sockaddr *to, int tolen,
700 ARRAY8Ptr authenticationName, ARRAY8Ptr authenticationData,
701 ARRAY8Ptr status, int fd )
703 XdmcpHeader header;
705 debug( "<decline> %.*s\n", status->length, status->data );
706 header.version = XDM_PROTOCOL_VERSION;
707 header.opcode = (CARD16)DECLINE;
708 header.length = 0;
709 header.length += 2 + status->length;
710 header.length += 2 + authenticationName->length;
711 header.length += 2 + authenticationData->length;
712 XdmcpWriteHeader( &buffer, &header );
713 XdmcpWriteARRAY8( &buffer, status );
714 XdmcpWriteARRAY8( &buffer, authenticationName );
715 XdmcpWriteARRAY8( &buffer, authenticationData );
716 XdmcpFlush( fd, &buffer, (XdmcpNetaddr)to, tolen );
719 static ARRAY8 outOfMemory = { (CARD16)13, (CARD8Ptr)"Out of memory" };
720 static ARRAY8 noValidAddr = { (CARD16)16, (CARD8Ptr)"No valid address" };
721 static ARRAY8 noValidAuth = { (CARD16)22, (CARD8Ptr)"No valid authorization" };
722 static ARRAY8 noAuthentic = { (CARD16)29, (CARD8Ptr)"XDM has no authentication key" };
724 static void
725 request_respond( struct sockaddr *from, int fromlen, int length, int fd )
727 CARD16 displayNumber;
728 ARRAY16 connectionTypes;
729 ARRAYofARRAY8 connectionAddresses;
730 ARRAY8 authenticationName;
731 ARRAY8 authenticationData;
732 ARRAYofARRAY8 authorizationNames;
733 ARRAY8 manufacturerDisplayID;
734 ARRAY8Ptr reason = 0;
735 int expectlen;
736 int i, j;
737 struct protoDisplay *pdpy;
738 ARRAY8 authorizationName, authorizationData;
739 ARRAY8Ptr connectionAddress;
741 debug( "<request> respond %d\n", length );
742 connectionTypes.data = 0;
743 connectionAddresses.data = 0;
744 authenticationName.data = 0;
745 authenticationData.data = 0;
746 authorizationNames.data = 0;
747 authorizationName.length = 0;
748 authorizationData.length = 0;
749 manufacturerDisplayID.data = 0;
750 if (XdmcpReadCARD16( &buffer, &displayNumber ) &&
751 XdmcpReadARRAY16( &buffer, &connectionTypes ) &&
752 XdmcpReadARRAYofARRAY8( &buffer, &connectionAddresses ) &&
753 XdmcpReadARRAY8( &buffer, &authenticationName ) &&
754 XdmcpReadARRAY8( &buffer, &authenticationData ) &&
755 XdmcpReadARRAYofARRAY8( &buffer, &authorizationNames ) &&
756 XdmcpReadARRAY8( &buffer, &manufacturerDisplayID ))
758 expectlen = 0;
759 expectlen += 2; /* displayNumber */
760 expectlen += 1 + 2 * connectionTypes.length; /* connectionTypes */
761 expectlen += 1; /* connectionAddresses */
762 for (i = 0; i < (int)connectionAddresses.length; i++)
763 expectlen += 2 + connectionAddresses.data[i].length;
764 expectlen += 2 + authenticationName.length; /* authenticationName */
765 expectlen += 2 + authenticationData.length; /* authenticationData */
766 expectlen += 1; /* authoriationNames */
767 for (i = 0; i < (int)authorizationNames.length; i++)
768 expectlen += 2 + authorizationNames.data[i].length;
769 expectlen += 2 + manufacturerDisplayID.length; /* displayID */
770 if (expectlen != length) {
771 debug( "<request> length error got %d expect %d\n",
772 length, expectlen );
773 goto abort;
775 if (connectionTypes.length == 0 ||
776 connectionAddresses.length != connectionTypes.length)
778 reason = &noValidAddr;
779 pdpy = 0;
780 goto decline;
782 pdpy = findProtoDisplay( (XdmcpNetaddr)from, fromlen, displayNumber );
783 if (!pdpy) {
785 /* Check this Display against the Manager's policy */
786 reason = isAccepting( from, fromlen, displayNumber );
787 if (reason)
788 goto decline;
790 /* Check the Display's stream services against Manager's policy */
791 i = selectConnectionTypeIndex( &connectionTypes,
792 &connectionAddresses );
793 if (i < 0) {
794 reason = &noValidAddr;
795 goto decline;
798 /* The Manager considers this a new session */
799 connectionAddress = &connectionAddresses.data[i];
800 pdpy = newProtoDisplay( (XdmcpNetaddr)from, fromlen, displayNumber,
801 connectionTypes.data[i], connectionAddress,
802 nextSessionID() );
803 debug( "newProtoDisplay %p\n", pdpy );
804 if (!pdpy) {
805 reason = &outOfMemory;
806 goto decline;
809 if (authorizationNames.length == 0)
810 j = 0;
811 else
812 j = selectAuthorizationTypeIndex( &authenticationName,
813 &authorizationNames );
814 if (j < 0) {
815 reason = &noValidAuth;
816 goto decline;
818 if (!checkAuthentication( pdpy,
819 &manufacturerDisplayID,
820 &authenticationName,
821 &authenticationData ))
823 reason = &noAuthentic;
824 goto decline;
826 if (j < (int)authorizationNames.length) {
827 Xauth *auth;
828 setProtoDisplayAuthorization( pdpy,
829 (unsigned short)authorizationNames.data[j].length,
830 (char *)authorizationNames.data[j].data );
831 auth = pdpy->xdmcpAuthorization;
832 if (!auth)
833 auth = pdpy->fileAuthorization;
834 if (auth) {
835 authorizationName.length = auth->name_length;
836 authorizationName.data = (CARD8Ptr) auth->name;
837 authorizationData.length = auth->data_length;
838 authorizationData.data = (CARD8Ptr) auth->data;
841 if (pdpy) {
842 send_accept( from, fromlen, pdpy->sessionID,
843 &authenticationName,
844 &authenticationData,
845 &authorizationName,
846 &authorizationData, fd );
847 } else {
848 decline:
849 send_decline( from, fromlen, &authenticationName,
850 &authenticationData,
851 reason, fd );
852 if (pdpy)
853 disposeProtoDisplay( pdpy );
856 abort:
857 XdmcpDisposeARRAY16( &connectionTypes );
858 XdmcpDisposeARRAYofARRAY8( &connectionAddresses );
859 XdmcpDisposeARRAY8( &authenticationName );
860 XdmcpDisposeARRAY8( &authenticationData );
861 XdmcpDisposeARRAYofARRAY8( &authorizationNames );
862 XdmcpDisposeARRAY8( &manufacturerDisplayID );
866 static void
867 send_failed( struct sockaddr *from, int fromlen,
868 const char *name, CARD32 sessionID, const char *reason, int fd )
870 char buf[360];
871 XdmcpHeader header;
872 ARRAY8 status;
874 sprintf( buf, "Session %ld failed for display %.260s: %s",
875 (long)sessionID, name, reason );
876 debug( "send_failed(%\"s)\n", buf );
877 status.length = strlen( buf );
878 status.data = (CARD8Ptr) buf;
879 header.version = XDM_PROTOCOL_VERSION;
880 header.opcode = (CARD16)FAILED;
881 header.length = 6 + status.length;
882 XdmcpWriteHeader( &buffer, &header );
883 XdmcpWriteCARD32( &buffer, sessionID );
884 XdmcpWriteARRAY8( &buffer, &status );
885 XdmcpFlush( fd, &buffer, (XdmcpNetaddr)from, fromlen );
888 void
889 sendFailed( struct display *d, const char *reason )
891 debug( "display start failed, sending <failed>\n" );
892 send_failed( (struct sockaddr *)(d->from.data), d->from.length, d->name,
893 d->sessionID, reason, d->xdmcpFd );
896 static void
897 send_refuse( struct sockaddr *from, int fromlen, CARD32 sessionID, int fd )
899 XdmcpHeader header;
901 debug( "send <refuse> %ld\n", (long)sessionID );
902 header.version = XDM_PROTOCOL_VERSION;
903 header.opcode = (CARD16)REFUSE;
904 header.length = 4;
905 XdmcpWriteHeader( &buffer, &header );
906 XdmcpWriteCARD32( &buffer, sessionID );
907 XdmcpFlush( fd, &buffer, (XdmcpNetaddr)from, fromlen );
910 static void
911 manage( struct sockaddr *from, int fromlen, int length, int fd )
913 CARD32 sessionID;
914 CARD16 displayNumber;
915 ARRAY8 displayClass;
916 int expectlen;
917 struct protoDisplay *pdpy;
918 struct display *d;
919 char *name = NULL;
920 char *class2 = NULL;
921 XdmcpNetaddr from_save;
922 ARRAY8 clientAddress, clientPort;
923 CARD16 connectionType;
925 debug( "<manage> %d\n", length );
926 displayClass.data = 0;
927 displayClass.length = 0;
928 if (XdmcpReadCARD32( &buffer, &sessionID ) &&
929 XdmcpReadCARD16( &buffer, &displayNumber ) &&
930 XdmcpReadARRAY8( &buffer, &displayClass ))
932 expectlen = 4 + /* session ID */
933 2 + /* displayNumber */
934 2 + displayClass.length; /* displayClass */
935 if (expectlen != length) {
936 debug( "<manage> length error got %d expect %d\n", length, expectlen );
937 goto abort;
939 pdpy = findProtoDisplay( (XdmcpNetaddr)from, fromlen, displayNumber );
940 debug( "<manage> session ID %ld, pdpy %p\n", (long)sessionID, pdpy );
941 if (!pdpy || pdpy->sessionID != sessionID) {
943 * We may have already started a session for this display
944 * but it hasn't seen the response in the form of an
945 * XOpenDisplay() yet. So check if it is in the list of active
946 * displays, and if so check that the session id's match.
947 * If all this is true, then we have a duplicate request that
948 * can be ignored.
950 if (!pdpy &&
951 (d = findDisplayByAddress( (XdmcpNetaddr)from, fromlen,
952 displayNumber )) &&
953 d->sessionID == sessionID)
955 debug( "manage: got duplicate pkt, ignoring\n" );
956 goto abort;
958 debug( "session ID %ld refused\n", (long)sessionID );
959 if (pdpy)
960 debug( "existing session ID %ld\n", (long)pdpy->sessionID );
961 send_refuse( from, fromlen, sessionID, fd );
962 } else {
963 name = networkAddressToName( pdpy->connectionType,
964 &pdpy->connectionAddress,
965 from,
966 pdpy->displayNumber );
967 if (!name) {
968 debug( "could not compute display name\n" );
969 send_failed( from, fromlen, "(no name)", sessionID,
970 "out of memory", fd );
971 goto abort;
973 debug( "computed display name: %s\n", name );
974 if ((d = findDisplayByName( name ))) {
975 debug( "terminating active session for %s\n", d->name );
976 stopDisplay( d );
978 if (displayClass.length) {
979 if (!strNDup( &class2, (char *)displayClass.data,
980 displayClass.length ))
982 send_failed( from, fromlen, name, sessionID,
983 "out of memory", fd );
984 goto abort;
987 if (!(from_save = (XdmcpNetaddr)Malloc( fromlen ))) {
988 send_failed( from, fromlen, name, sessionID,
989 "out of memory", fd );
990 goto abort;
992 memmove( from_save, from, fromlen );
993 if (!(d = newDisplay( name ))) {
994 free( (char *)from_save );
995 send_failed( from, fromlen, name, sessionID,
996 "out of memory", fd );
997 goto abort;
999 d->class2 = class2;
1000 class2 = 0;
1001 d->displayType = dForeign | dTransient | dFromXDMCP;
1002 d->sessionID = pdpy->sessionID;
1003 d->from.data = (unsigned char *)from_save;
1004 d->from.length = fromlen;
1005 d->displayNumber = pdpy->displayNumber;
1006 convertClientAddress( from,
1007 &clientAddress, &clientPort, &connectionType );
1008 d->useChooser = False;
1009 d->xdmcpFd = fd;
1010 if (checkIndirectChoice( &clientAddress, &clientPort, connectionType ) &&
1011 useChooser( &clientAddress, connectionType ))
1013 d->useChooser = True;
1014 debug( "use chooser for %s\n", d->name );
1016 d->clientAddr = clientAddress;
1017 d->clientPort = clientPort;
1018 d->connectionType = connectionType;
1019 if (pdpy->fileAuthorization) {
1020 d->authorizations = (Xauth **)Malloc( sizeof(Xauth *) );
1021 if (!d->authorizations) {
1022 free( (char *)from_save );
1023 free( (char *)d );
1024 send_failed( from, fromlen, name, sessionID,
1025 "out of memory", fd );
1026 goto abort;
1028 d->authorizations[0] = pdpy->fileAuthorization;
1029 d->authNum = 1;
1030 pdpy->fileAuthorization = 0;
1032 disposeProtoDisplay( pdpy );
1033 debug( "starting display %s,%s\n", d->name, d->class2 );
1034 if (loadDisplayResources( d ) < 0) {
1035 logError( "Unable to read configuration for display %s; "
1036 "stopping it.\n", d->name );
1037 stopDisplay( d );
1038 } else
1039 startDisplay( d );
1040 closeGetter();
1043 abort:
1044 XdmcpDisposeARRAY8( &displayClass );
1045 if (name)
1046 free( (char *)name );
1047 if (class2)
1048 free( (char *)class2 );
1051 static void
1052 send_alive( struct sockaddr *from, int fromlen, int length, int fd )
1054 CARD32 sessionID;
1055 CARD16 displayNumber;
1056 struct display *d;
1057 XdmcpHeader header;
1058 CARD8 sendRunning;
1059 CARD32 sendSessionID;
1061 debug( "send <alive>\n" );
1062 if (XdmcpReadCARD16( &buffer, &displayNumber ) &&
1063 XdmcpReadCARD32( &buffer, &sessionID ))
1065 if (length == 6) {
1066 if (!(d = findDisplayBySessionID( sessionID )))
1067 d = findDisplayByAddress( (XdmcpNetaddr)from, fromlen,
1068 displayNumber );
1069 sendRunning = 0;
1070 sendSessionID = 0;
1071 if (d && d->status == running) {
1072 if (d->sessionID == sessionID)
1073 sendRunning = 1;
1074 sendSessionID = d->sessionID;
1076 header.version = XDM_PROTOCOL_VERSION;
1077 header.opcode = (CARD16)ALIVE;
1078 header.length = 5;
1079 debug( "<alive>: %d %ld\n", sendRunning, (long)sendSessionID );
1080 XdmcpWriteHeader( &buffer, &header );
1081 XdmcpWriteCARD8( &buffer, sendRunning );
1082 XdmcpWriteCARD32( &buffer, sendSessionID );
1083 XdmcpFlush( fd, &buffer, (XdmcpNetaddr)from, fromlen );
1089 void
1090 processRequestSocket( int fd )
1092 XdmcpHeader header;
1093 #if defined(IPv6) && defined(AF_INET6)
1094 struct sockaddr_storage addr;
1095 #else
1096 struct sockaddr addr;
1097 #endif
1098 int addrlen = sizeof(addr);
1100 debug( "processRequestSocket\n" );
1101 bzero( (char *)&addr, sizeof(addr) );
1102 if (!XdmcpFill( fd, &buffer, (XdmcpNetaddr)&addr, &addrlen )) {
1103 debug( "XdmcpFill failed\n" );
1104 return;
1106 if (!XdmcpReadHeader( &buffer, &header )) {
1107 debug( "XdmcpReadHeader failed\n" );
1108 return;
1110 if (header.version != XDM_PROTOCOL_VERSION) {
1111 debug( "XDMCP header version read was %d, expected %d\n",
1112 header.version, XDM_PROTOCOL_VERSION );
1113 return;
1115 debug( "header: %d %d %d\n", header.version, header.opcode, header.length );
1116 switch (header.opcode) {
1117 case BROADCAST_QUERY:
1118 broadcast_respond( (struct sockaddr *)&addr, addrlen, header.length, fd );
1119 break;
1120 case QUERY:
1121 query_respond( (struct sockaddr *)&addr, addrlen, header.length, fd );
1122 break;
1123 case INDIRECT_QUERY:
1124 indirect_respond( (struct sockaddr *)&addr, addrlen, header.length, fd );
1125 break;
1126 case FORWARD_QUERY:
1127 forward_respond( (struct sockaddr *)&addr, addrlen, header.length, fd );
1128 break;
1129 case REQUEST:
1130 request_respond( (struct sockaddr *)&addr, addrlen, header.length, fd );
1131 break;
1132 case MANAGE:
1133 manage( (struct sockaddr *)&addr, addrlen, header.length, fd );
1134 break;
1135 case KEEPALIVE:
1136 send_alive( (struct sockaddr *)&addr, addrlen, header.length, fd );
1137 break;