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
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
41 #include "dm_socket.h"
43 #include <sys/types.h>
47 #if defined(IPv6) && defined(AF_INET6)
48 # include <arpa/inet.h>
53 networkAddressToHostname( CARD16 connectionType
, ARRAY8Ptr connectionAddress
)
55 switch (connectionType
) {
57 #if defined(IPv6) && defined(AF_INET6)
62 char *myDot
, *name
, *lname
;
64 #if defined(IPv6) && defined(AF_INET6)
65 char dotted
[INET6_ADDRSTRLEN
];
67 if (connectionType
== FamilyInternet6
)
73 he
= gethostbyaddr( (char *)connectionAddress
->data
,
74 connectionAddress
->length
, af_type
);
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
))
93 if ((he
= gethostbyname( he
->h_name
)) &&
94 he
->h_addrtype
== AF_INET
)
97 for (i
= 0; he
->h_addr_list
[i
]; i
++)
98 if (!memcmp( he
->h_addr_list
[i
],
99 connectionAddress
->data
, 4 ))
102 logError( "DNS spoof attempt or misconfigured resolver.\n" );
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
))
129 if ((he
= gethostbyname( lname
)) &&
130 he
->h_addrtype
== AF_INET
)
133 for (i
= 0; he
->h_addr_list
[i
]; i
++)
134 if (!memcmp( he
->h_addr_list
[i
],
135 connectionAddress
->data
, 4 ))
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
);
153 ASPrintf( &name
, "%[4|'.'hhu", connectionAddress
->data
);
155 logWarn( "Cannot convert Internet address %s to host name\n",
171 networkAddressToName( CARD16 connectionType
, ARRAY8Ptr connectionAddress
,
172 struct sockaddr
*originalAddress
, CARD16 displayNumber
)
174 switch (connectionType
) {
176 #if defined(IPv6) && defined(AF_INET6)
177 case FamilyInternet6
:
181 struct hostent
*hostent
;
182 char *hostname
= NULL
;
184 const char *localhost
;
185 int multiHomed
= False
;
187 #if defined(IPv6) && defined(AF_INET6)
188 struct addrinfo
*ai
= NULL
, *nai
, hints
;
189 char dotted
[INET6_ADDRSTRLEN
];
191 if (connectionType
== FamilyInternet6
)
197 data
= connectionAddress
->data
;
198 hostent
= gethostbyaddr( (char *)data
,
199 connectionAddress
->length
, type
);
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
,
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
;
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
);
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
242 if ((localDot
= strchr( localhost
, '.' )) &&
243 (remoteDot
= strchr( hostname
, '.' )))
245 /* smash the name in place; it won't
248 if (!strcmp( localDot
+1, remoteDot
+1 ))
253 ASPrintf( &name
, "%s:%d", hostname
, displayNumber
);
256 #if defined(IPv6) && defined(AF_INET6)
258 if (connectionType
== FamilyInternet
) {
260 &((struct sockaddr_in
*)originalAddress
)->sin_addr
;
263 &((struct sockaddr_in6
*)originalAddress
)->sin6_addr
;
266 inet_ntop( type
, data
, dotted
, sizeof(dotted
) );
267 ASPrintf( &name
, "%s:%d", dotted
, displayNumber
);
271 &((struct sockaddr_in
*)originalAddress
)->sin_addr
;
272 ASPrintf( &name
, "%[4|'.'hhu:%d", data
, displayNumber
);
275 #if defined(IPv6) && defined(AF_INET6)
291 convertClientAddress( struct sockaddr
*from
,
292 ARRAY8Ptr addr
, /* return */
293 ARRAY8Ptr port
, /* return */
294 CARD16
*type
) /* return */
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
;
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
);
332 send_willing( struct sockaddr
*from
, int fromlen
,
333 ARRAY8Ptr authenticationName
, ARRAY8Ptr status
, int fd
)
337 debug( "send <willing> %.*s %.*s\n", authenticationName
->length
,
338 authenticationName
->data
,
341 header
.version
= XDM_PROTOCOL_VERSION
;
342 header
.opcode
= (CARD16
)WILLING
;
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
);
353 send_unwilling( struct sockaddr
*from
, int fromlen
,
354 ARRAY8Ptr authenticationName
, ARRAY8Ptr status
, int fd
)
358 debug( "send <unwilling> %.*s %.*s\n", authenticationName
->length
,
359 authenticationName
->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
);
372 all_query_respond( struct sockaddr
*from
, int fromlen
,
373 ARRAYofARRAY8Ptr authenticationNames
,
374 xdmOpCode type
, int fd
)
376 ARRAY8Ptr authenticationName
;
380 CARD16 connectionType
;
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
);
392 connectionType
= family
;
394 if (type
== INDIRECT_QUERY
)
395 registerIndirectChoice( &addr
, &port
, connectionType
, 0 );
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
);
404 send_unwilling( from
, fromlen
, authenticationName
, &status
, fd
);
405 XdmcpDisposeARRAY8( &status
);
409 sendForward( CARD16 connectionType
, ARRAY8Ptr address
, char *closure
)
412 struct sockaddr_in in_addr
;
414 #if defined(IPv6) && defined(AF_INET6)
415 struct sockaddr_in6 in6_addr
;
419 struct sockaddr
*addr
;
422 switch (connectionType
) {
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
);
430 in_addr
.sin_family
= AF_INET
;
431 in_addr
.sin_port
= htons( (short)requestPort
);
432 if (address
->length
!= 4)
434 memmove( (char *)&in_addr
.sin_addr
, address
->data
, address
->length
);
435 addrlen
= sizeof(struct sockaddr_in
);
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
);
445 in6_addr
.sin6_family
= AF_INET6
;
446 in6_addr
.sin6_port
= htons( (short)requestPort
);
447 if (address
->length
!= 16)
449 memmove( (char *)&in6_addr
.sin6_addr
, address
->data
, address
->length
);
450 addrlen
= sizeof(struct sockaddr_in6
);
459 XdmcpFlush( (int)(long)closure
, &buffer
, (XdmcpNetaddr
)addr
, addrlen
);
464 indirect_respond( struct sockaddr
*from
, int fromlen
, int length
, int fd
)
466 ARRAYofARRAY8 queryAuthenticationNames
;
467 ARRAY8 clientAddress
;
469 CARD16 connectionType
;
475 debug( "<indirect> respond %d\n", length
);
476 if (!XdmcpReadARRAYofARRAY8( &buffer
, &queryAuthenticationNames
))
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
;
490 header
.length
+= 2 + clientAddress
.length
;
491 header
.length
+= 2 + clientPort
.length
;
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
);
501 forEachMatchingIndirectHost( &clientAddress
, &clientPort
, connectionType
,
502 sendForward
, (char *)(long)fd
);
504 XdmcpDisposeARRAY8( &clientAddress
);
505 XdmcpDisposeARRAY8( &clientPort
);
507 all_query_respond( from
, fromlen
, &queryAuthenticationNames
,
508 INDIRECT_QUERY
, fd
);
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.
520 direct_query_respond( struct sockaddr
*from
, int fromlen
,
521 int length
, xdmOpCode type
, int fd
)
523 ARRAYofARRAY8 queryAuthenticationNames
;
527 if (!XdmcpReadARRAYofARRAY8( &buffer
, &queryAuthenticationNames
))
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
);
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
);
545 broadcast_respond( struct sockaddr
*from
, int fromlen
, int length
, int fd
)
547 direct_query_respond( from
, fromlen
, length
, BROADCAST_QUERY
, fd
);
552 forward_respond( struct sockaddr
*from
, int fromlen ATTR_UNUSED
,
555 ARRAY8 clientAddress
;
557 ARRAYofARRAY8 authenticationNames
;
558 struct sockaddr
*client
;
563 debug( "<forward> respond %d\n", length
);
564 clientAddress
.length
= 0;
565 clientAddress
.data
= 0;
566 clientPort
.length
= 0;
568 authenticationNames
.length
= 0;
569 authenticationNames
.data
= 0;
570 if (XdmcpReadARRAY8( &buffer
, &clientAddress
) &&
571 XdmcpReadARRAY8( &buffer
, &clientPort
) &&
572 XdmcpReadARRAYofARRAY8( &buffer
, &authenticationNames
))
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
) {
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
) {
592 struct sockaddr_in in_addr
;
594 if (clientAddress
.length
!= 4 || clientPort
.length
!= 2)
596 bzero( (char *)&in_addr
, sizeof(in_addr
) );
597 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
598 in_addr
.sin_len
= sizeof(in_addr
);
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
,
610 #if defined(IPv6) && defined(AF_INET6)
613 struct sockaddr_in6 in6_addr
;
615 if (clientAddress
.length
!= 16 || clientPort
.length
!= 2)
617 bzero( (char *)&in6_addr
, sizeof(in6_addr
) );
618 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
619 in6_addr
.sin6_len
= sizeof(in6_addr
);
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
,
634 struct sockaddr_un un_addr
;
636 if (clientAddress
.length
>= sizeof(un_addr
.sun_path
))
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
);
647 clientlen
= sizeof(un_addr
);
649 all_query_respond( client
, clientlen
, &authenticationNames
,
664 debug( "<forward> length error got %d expect %d\n", length
, expectedLen
);
667 XdmcpDisposeARRAY8( &clientAddress
);
668 XdmcpDisposeARRAY8( &clientPort
);
669 XdmcpDisposeARRAYofARRAY8( &authenticationNames
);
674 send_accept( struct sockaddr
*to
, int tolen
, CARD32 sessionID
,
675 ARRAY8Ptr authenticationName
, ARRAY8Ptr authenticationData
,
676 ARRAY8Ptr authorizationName
, ARRAY8Ptr authorizationData
,
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
);
699 send_decline( struct sockaddr
*to
, int tolen
,
700 ARRAY8Ptr authenticationName
, ARRAY8Ptr authenticationData
,
701 ARRAY8Ptr status
, int fd
)
705 debug( "<decline> %.*s\n", status
->length
, status
->data
);
706 header
.version
= XDM_PROTOCOL_VERSION
;
707 header
.opcode
= (CARD16
)DECLINE
;
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" };
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;
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
))
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",
775 if (connectionTypes
.length
== 0 ||
776 connectionAddresses
.length
!= connectionTypes
.length
)
778 reason
= &noValidAddr
;
782 pdpy
= findProtoDisplay( (XdmcpNetaddr
)from
, fromlen
, displayNumber
);
785 /* Check this Display against the Manager's policy */
786 reason
= isAccepting( from
, fromlen
, displayNumber
);
790 /* Check the Display's stream services against Manager's policy */
791 i
= selectConnectionTypeIndex( &connectionTypes
,
792 &connectionAddresses
);
794 reason
= &noValidAddr
;
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
,
803 debug( "newProtoDisplay %p\n", pdpy
);
805 reason
= &outOfMemory
;
809 if (authorizationNames
.length
== 0)
812 j
= selectAuthorizationTypeIndex( &authenticationName
,
813 &authorizationNames
);
815 reason
= &noValidAuth
;
818 if (!checkAuthentication( pdpy
,
819 &manufacturerDisplayID
,
821 &authenticationData
))
823 reason
= &noAuthentic
;
826 if (j
< (int)authorizationNames
.length
) {
828 setProtoDisplayAuthorization( pdpy
,
829 (unsigned short)authorizationNames
.data
[j
].length
,
830 (char *)authorizationNames
.data
[j
].data
);
831 auth
= pdpy
->xdmcpAuthorization
;
833 auth
= pdpy
->fileAuthorization
;
835 authorizationName
.length
= auth
->name_length
;
836 authorizationName
.data
= (CARD8Ptr
) auth
->name
;
837 authorizationData
.length
= auth
->data_length
;
838 authorizationData
.data
= (CARD8Ptr
) auth
->data
;
842 send_accept( from
, fromlen
, pdpy
->sessionID
,
846 &authorizationData
, fd
);
849 send_decline( from
, fromlen
, &authenticationName
,
853 disposeProtoDisplay( pdpy
);
857 XdmcpDisposeARRAY16( &connectionTypes
);
858 XdmcpDisposeARRAYofARRAY8( &connectionAddresses
);
859 XdmcpDisposeARRAY8( &authenticationName
);
860 XdmcpDisposeARRAY8( &authenticationData
);
861 XdmcpDisposeARRAYofARRAY8( &authorizationNames
);
862 XdmcpDisposeARRAY8( &manufacturerDisplayID
);
867 send_failed( struct sockaddr
*from
, int fromlen
,
868 const char *name
, CARD32 sessionID
, const char *reason
, int fd
)
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
);
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
);
897 send_refuse( struct sockaddr
*from
, int fromlen
, CARD32 sessionID
, int fd
)
901 debug( "send <refuse> %ld\n", (long)sessionID
);
902 header
.version
= XDM_PROTOCOL_VERSION
;
903 header
.opcode
= (CARD16
)REFUSE
;
905 XdmcpWriteHeader( &buffer
, &header
);
906 XdmcpWriteCARD32( &buffer
, sessionID
);
907 XdmcpFlush( fd
, &buffer
, (XdmcpNetaddr
)from
, fromlen
);
911 manage( struct sockaddr
*from
, int fromlen
, int length
, int fd
)
914 CARD16 displayNumber
;
917 struct protoDisplay
*pdpy
;
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
);
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
951 (d
= findDisplayByAddress( (XdmcpNetaddr
)from
, fromlen
,
953 d
->sessionID
== sessionID
)
955 debug( "manage: got duplicate pkt, ignoring\n" );
958 debug( "session ID %ld refused\n", (long)sessionID
);
960 debug( "existing session ID %ld\n", (long)pdpy
->sessionID
);
961 send_refuse( from
, fromlen
, sessionID
, fd
);
963 name
= networkAddressToName( pdpy
->connectionType
,
964 &pdpy
->connectionAddress
,
966 pdpy
->displayNumber
);
968 debug( "could not compute display name\n" );
969 send_failed( from
, fromlen
, "(no name)", sessionID
,
970 "out of memory", fd
);
973 debug( "computed display name: %s\n", name
);
974 if ((d
= findDisplayByName( name
))) {
975 debug( "terminating active session for %s\n", d
->name
);
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
);
987 if (!(from_save
= (XdmcpNetaddr
)Malloc( fromlen
))) {
988 send_failed( from
, fromlen
, name
, sessionID
,
989 "out of memory", fd
);
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
);
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
;
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
);
1024 send_failed( from
, fromlen
, name
, sessionID
,
1025 "out of memory", fd
);
1028 d
->authorizations
[0] = pdpy
->fileAuthorization
;
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
);
1044 XdmcpDisposeARRAY8( &displayClass
);
1046 free( (char *)name
);
1048 free( (char *)class2
);
1052 send_alive( struct sockaddr
*from
, int fromlen
, int length
, int fd
)
1055 CARD16 displayNumber
;
1059 CARD32 sendSessionID
;
1061 debug( "send <alive>\n" );
1062 if (XdmcpReadCARD16( &buffer
, &displayNumber
) &&
1063 XdmcpReadCARD32( &buffer
, &sessionID
))
1066 if (!(d
= findDisplayBySessionID( sessionID
)))
1067 d
= findDisplayByAddress( (XdmcpNetaddr
)from
, fromlen
,
1071 if (d
&& d
->status
== running
) {
1072 if (d
->sessionID
== sessionID
)
1074 sendSessionID
= d
->sessionID
;
1076 header
.version
= XDM_PROTOCOL_VERSION
;
1077 header
.opcode
= (CARD16
)ALIVE
;
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
);
1090 processRequestSocket( int fd
)
1093 #if defined(IPv6) && defined(AF_INET6)
1094 struct sockaddr_storage addr
;
1096 struct sockaddr addr
;
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" );
1106 if (!XdmcpReadHeader( &buffer
, &header
)) {
1107 debug( "XdmcpReadHeader failed\n" );
1110 if (header
.version
!= XDM_PROTOCOL_VERSION
) {
1111 debug( "XDMCP header version read was %d, expected %d\n",
1112 header
.version
, XDM_PROTOCOL_VERSION
);
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
);
1121 query_respond( (struct sockaddr
*)&addr
, addrlen
, header
.length
, fd
);
1123 case INDIRECT_QUERY
:
1124 indirect_respond( (struct sockaddr
*)&addr
, addrlen
, header
.length
, fd
);
1127 forward_respond( (struct sockaddr
*)&addr
, addrlen
, header
.length
, fd
);
1130 request_respond( (struct sockaddr
*)&addr
, addrlen
, header
.length
, fd
);
1133 manage( (struct sockaddr
*)&addr
, addrlen
, header
.length
, fd
);
1136 send_alive( (struct sockaddr
*)&addr
, addrlen
, header
.length
, fd
);