xdmcp.c revision 4642e01f
1/* 2 * Copyright 1989 Network Computing Devices, Inc., Mountain View, California. 3 * 4 * Permission to use, copy, modify, and distribute this software and its 5 * documentation for any purpose and without fee is hereby granted, provided 6 * that the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of N.C.D. not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. N.C.D. makes no representations about the 11 * suitability of this software for any purpose. It is provided "as is" 12 * without express or implied warranty. 13 * 14 */ 15 16#ifdef HAVE_DIX_CONFIG_H 17#include <dix-config.h> 18#endif 19 20#ifdef WIN32 21#include <X11/Xwinsock.h> 22#endif 23 24#include <X11/Xos.h> 25 26#if !defined(WIN32) 27#include <sys/param.h> 28#include <sys/socket.h> 29#include <netinet/in.h> 30#include <netdb.h> 31#endif 32 33#include <stdio.h> 34#include <stdlib.h> 35#include <X11/X.h> 36#include <X11/Xmd.h> 37#include "misc.h" 38#include <X11/Xpoll.h> 39#include "osdep.h" 40#include "input.h" 41#include "dixstruct.h" 42#include "opaque.h" 43#include "site.h" 44 45#ifdef STREAMSCONN 46#include <tiuser.h> 47#include <netconfig.h> 48#include <netdir.h> 49#endif 50 51#ifdef XDMCP 52#undef REQUEST 53 54#ifdef XDMCP_NO_IPV6 55#undef IPv6 56#endif 57 58#include <X11/Xdmcp.h> 59 60#define X_INCLUDE_NETDB_H 61#include <X11/Xos_r.h> 62 63static char *defaultDisplayClass = COMPILEDDISPLAYCLASS; 64 65static int xdmcpSocket, sessionSocket; 66static xdmcp_states state; 67#if defined(IPv6) && defined(AF_INET6) 68static int xdmcpSocket6; 69static struct sockaddr_storage req_sockaddr; 70#else 71static struct sockaddr_in req_sockaddr; 72#endif 73static int req_socklen; 74static CARD32 SessionID; 75static CARD32 timeOutTime; 76static int timeOutRtx; 77static CARD32 defaultKeepaliveDormancy = XDM_DEF_DORMANCY; 78static CARD32 keepaliveDormancy = XDM_DEF_DORMANCY; 79static CARD16 DisplayNumber; 80static xdmcp_states XDM_INIT_STATE = XDM_OFF; 81#ifdef HASXDMAUTH 82static char *xdmAuthCookie; 83#endif 84 85static XdmcpBuffer buffer; 86 87#if defined(IPv6) && defined(AF_INET6) 88 89static struct addrinfo *mgrAddr; 90static struct addrinfo *mgrAddrFirst; 91 92#define SOCKADDR_TYPE struct sockaddr_storage 93#define SOCKADDR_FAMILY(s) ((struct sockaddr *)&(s))->sa_family 94 95#ifdef BSD44SOCKETS 96#define SOCKLEN_FIELD(s) ((struct sockaddr *)&(s))->sa_len 97#define SOCKLEN_TYPE unsigned char 98#else 99#define SOCKLEN_TYPE unsigned int 100#endif 101 102#else 103 104#define SOCKADDR_TYPE struct sockaddr_in 105#define SOCKADDR_FAMILY(s) (s).sin_family 106 107#ifdef BSD44SOCKETS 108#define SOCKLEN_FIELD(s) (s).sin_len 109#define SOCKLEN_TYPE unsigned char 110#else 111#define SOCKLEN_TYPE size_t 112#endif 113 114#endif 115 116static SOCKADDR_TYPE ManagerAddress; 117static SOCKADDR_TYPE FromAddress; 118 119#ifdef SOCKLEN_FIELD 120#define ManagerAddressLen SOCKLEN_FIELD(ManagerAddress) 121#define FromAddressLen SOCKLEN_FIELD(FromAddress) 122#else 123static SOCKLEN_TYPE ManagerAddressLen, FromAddressLen; 124#endif 125 126#if defined(IPv6) && defined(AF_INET6) 127static struct multicastinfo { 128 struct multicastinfo *next; 129 struct addrinfo *ai; 130 int hops; 131} *mcastlist; 132#endif 133 134static void XdmcpAddHost( 135 struct sockaddr *from, 136 int fromlen, 137 ARRAY8Ptr AuthenticationName, 138 ARRAY8Ptr hostname, 139 ARRAY8Ptr status); 140 141static void XdmcpSelectHost( 142 struct sockaddr *host_sockaddr, 143 int host_len, 144 ARRAY8Ptr AuthenticationName); 145 146static void get_xdmcp_sock(void); 147 148static void send_query_msg(void); 149 150static void recv_willing_msg( 151 struct sockaddr * /*from*/, 152 int /*fromlen*/, 153 unsigned /*length*/); 154 155static void send_request_msg(void); 156 157static void recv_accept_msg(unsigned /*length*/); 158 159static void recv_decline_msg(unsigned /*length*/); 160 161static void send_manage_msg(void); 162 163static void recv_refuse_msg(unsigned /*length*/); 164 165static void recv_failed_msg(unsigned /*length*/); 166 167static void send_keepalive_msg(void); 168 169static void recv_alive_msg(unsigned /*length*/); 170 171static void XdmcpFatal( 172 char * /*type*/, 173 ARRAY8Ptr /*status*/); 174 175static void XdmcpWarning(char * /*str*/); 176 177static void get_manager_by_name( 178 int /*argc*/, 179 char ** /*argv*/, 180 int /*i*/); 181 182static void get_fromaddr_by_name(int /*argc*/, char ** /*argv*/, int /*i*/); 183 184#if defined(IPv6) && defined(AF_INET6) 185static int get_mcast_options(int /*argc*/, char ** /*argv*/, int /*i*/); 186#endif 187 188static void receive_packet(int /*socketfd*/); 189 190static void send_packet(void); 191 192static void timeout(void); 193 194static void restart(void); 195 196static void XdmcpBlockHandler( 197 pointer /*data*/, 198 struct timeval ** /*wt*/, 199 pointer /*LastSelectMask*/); 200 201static void XdmcpWakeupHandler( 202 pointer /*data*/, 203 int /*i*/, 204 pointer /*LastSelectMask*/); 205 206/* 207 * Register the Manufacturer display ID 208 */ 209 210static ARRAY8 ManufacturerDisplayID; 211 212static void 213XdmcpRegisterManufacturerDisplayID (char *name, int length) 214{ 215 int i; 216 217 XdmcpDisposeARRAY8 (&ManufacturerDisplayID); 218 if (!XdmcpAllocARRAY8 (&ManufacturerDisplayID, length)) 219 return; 220 for (i = 0; i < length; i++) 221 ManufacturerDisplayID.data[i] = (CARD8) name[i]; 222} 223 224static unsigned short xdm_udp_port = XDM_UDP_PORT; 225static Bool OneSession = FALSE; 226static const char *xdm_from = NULL; 227 228void 229XdmcpUseMsg (void) 230{ 231 ErrorF("-query host-name contact named host for XDMCP\n"); 232 ErrorF("-broadcast broadcast for XDMCP\n"); 233#if defined(IPv6) && defined(AF_INET6) 234 ErrorF("-multicast [addr [hops]] IPv6 multicast for XDMCP\n"); 235#endif 236 ErrorF("-indirect host-name contact named host for indirect XDMCP\n"); 237 ErrorF("-port port-num UDP port number to send messages to\n"); 238 ErrorF("-from local-address specify the local address to connect from\n"); 239 ErrorF("-once Terminate server after one session\n"); 240 ErrorF("-class display-class specify display class to send in manage\n"); 241#ifdef HASXDMAUTH 242 ErrorF("-cookie xdm-auth-bits specify the magic cookie for XDMCP\n"); 243#endif 244 ErrorF("-displayID display-id manufacturer display ID for request\n"); 245} 246 247int 248XdmcpOptions(int argc, char **argv, int i) 249{ 250 if (strcmp(argv[i], "-query") == 0) { 251 get_manager_by_name(argc, argv, i++); 252 XDM_INIT_STATE = XDM_QUERY; 253 AccessUsingXdmcp (); 254 return (i + 1); 255 } 256 if (strcmp(argv[i], "-broadcast") == 0) { 257 XDM_INIT_STATE = XDM_BROADCAST; 258 AccessUsingXdmcp (); 259 return (i + 1); 260 } 261#if defined(IPv6) && defined(AF_INET6) 262 if (strcmp(argv[i], "-multicast") == 0) { 263 i = get_mcast_options(argc, argv, ++i); 264 XDM_INIT_STATE = XDM_MULTICAST; 265 AccessUsingXdmcp (); 266 return (i + 1); 267 } 268#endif 269 if (strcmp(argv[i], "-indirect") == 0) { 270 get_manager_by_name(argc, argv, i++); 271 XDM_INIT_STATE = XDM_INDIRECT; 272 AccessUsingXdmcp (); 273 return (i + 1); 274 } 275 if (strcmp(argv[i], "-port") == 0) { 276 if (++i == argc) { 277 FatalError("Xserver: missing port number in command line\n"); 278 } 279 xdm_udp_port = (unsigned short) atoi(argv[i]); 280 return (i + 1); 281 } 282 if (strcmp(argv[i], "-from") == 0) { 283 get_fromaddr_by_name(argc, argv, ++i); 284 return (i + 1); 285 } 286 if (strcmp(argv[i], "-once") == 0) { 287 OneSession = TRUE; 288 return (i + 1); 289 } 290 if (strcmp(argv[i], "-class") == 0) { 291 if (++i == argc) { 292 FatalError("Xserver: missing class name in command line\n"); 293 } 294 defaultDisplayClass = argv[i]; 295 return (i + 1); 296 } 297#ifdef HASXDMAUTH 298 if (strcmp(argv[i], "-cookie") == 0) { 299 if (++i == argc) { 300 FatalError("Xserver: missing cookie data in command line\n"); 301 } 302 xdmAuthCookie = argv[i]; 303 return (i + 1); 304 } 305#endif 306 if (strcmp(argv[i], "-displayID") == 0) { 307 if (++i == argc) { 308 FatalError("Xserver: missing displayID in command line\n"); 309 } 310 XdmcpRegisterManufacturerDisplayID (argv[i], strlen (argv[i])); 311 return (i + 1); 312 } 313 return (i); 314} 315 316/* 317 * This section is a collection of routines for 318 * registering server-specific data with the XDMCP 319 * state machine. 320 */ 321 322 323/* 324 * Save all broadcast addresses away so BroadcastQuery 325 * packets get sent everywhere 326 */ 327 328#define MAX_BROADCAST 10 329 330/* This stays sockaddr_in since IPv6 doesn't support broadcast */ 331static struct sockaddr_in BroadcastAddresses[MAX_BROADCAST]; 332static int NumBroadcastAddresses; 333 334void 335XdmcpRegisterBroadcastAddress (struct sockaddr_in *addr) 336{ 337 struct sockaddr_in *bcast; 338 if (NumBroadcastAddresses >= MAX_BROADCAST) 339 return; 340 bcast = &BroadcastAddresses[NumBroadcastAddresses++]; 341 bzero (bcast, sizeof (struct sockaddr_in)); 342#ifdef BSD44SOCKETS 343 bcast->sin_len = addr->sin_len; 344#endif 345 bcast->sin_family = addr->sin_family; 346 bcast->sin_port = htons (xdm_udp_port); 347 bcast->sin_addr = addr->sin_addr; 348} 349 350/* 351 * Each authentication type is registered here; Validator 352 * will be called to check all access attempts using 353 * the specified authentication type 354 */ 355 356static ARRAYofARRAY8 AuthenticationNames, AuthenticationDatas; 357typedef struct _AuthenticationFuncs { 358 ValidatorFunc Validator; 359 GeneratorFunc Generator; 360 AddAuthorFunc AddAuth; 361} AuthenticationFuncsRec, *AuthenticationFuncsPtr; 362 363static AuthenticationFuncsPtr AuthenticationFuncsList; 364 365void 366XdmcpRegisterAuthentication ( 367 char *name, 368 int namelen, 369 char *data, 370 int datalen, 371 ValidatorFunc Validator, 372 GeneratorFunc Generator, 373 AddAuthorFunc AddAuth) 374{ 375 int i; 376 ARRAY8 AuthenticationName, AuthenticationData; 377 static AuthenticationFuncsPtr newFuncs; 378 379 if (!XdmcpAllocARRAY8 (&AuthenticationName, namelen)) 380 return; 381 if (!XdmcpAllocARRAY8 (&AuthenticationData, datalen)) 382 { 383 XdmcpDisposeARRAY8 (&AuthenticationName); 384 return; 385 } 386 for (i = 0; i < namelen; i++) 387 AuthenticationName.data[i] = name[i]; 388 for (i = 0; i < datalen; i++) 389 AuthenticationData.data[i] = data[i]; 390 if (!(XdmcpReallocARRAYofARRAY8 (&AuthenticationNames, 391 AuthenticationNames.length + 1) && 392 XdmcpReallocARRAYofARRAY8 (&AuthenticationDatas, 393 AuthenticationDatas.length + 1) && 394 (newFuncs = (AuthenticationFuncsPtr) xalloc ( 395 (AuthenticationNames.length + 1) * sizeof (AuthenticationFuncsRec))))) 396 { 397 XdmcpDisposeARRAY8 (&AuthenticationName); 398 XdmcpDisposeARRAY8 (&AuthenticationData); 399 return; 400 } 401 for (i = 0; i < AuthenticationNames.length - 1; i++) 402 newFuncs[i] = AuthenticationFuncsList[i]; 403 newFuncs[AuthenticationNames.length-1].Validator = Validator; 404 newFuncs[AuthenticationNames.length-1].Generator = Generator; 405 newFuncs[AuthenticationNames.length-1].AddAuth = AddAuth; 406 xfree (AuthenticationFuncsList); 407 AuthenticationFuncsList = newFuncs; 408 AuthenticationNames.data[AuthenticationNames.length-1] = AuthenticationName; 409 AuthenticationDatas.data[AuthenticationDatas.length-1] = AuthenticationData; 410} 411 412/* 413 * Select the authentication type to be used; this is 414 * set by the manager of the host to be connected to. 415 */ 416 417static ARRAY8 noAuthenticationName = {(CARD16) 0, (CARD8Ptr) 0}; 418static ARRAY8 noAuthenticationData = {(CARD16) 0, (CARD8Ptr) 0}; 419static ARRAY8Ptr AuthenticationName = &noAuthenticationName; 420static ARRAY8Ptr AuthenticationData = &noAuthenticationData; 421static AuthenticationFuncsPtr AuthenticationFuncs; 422 423static void 424XdmcpSetAuthentication (ARRAY8Ptr name) 425{ 426 int i; 427 428 for (i = 0; i < AuthenticationNames.length; i++) 429 if (XdmcpARRAY8Equal (&AuthenticationNames.data[i], name)) 430 { 431 AuthenticationName = &AuthenticationNames.data[i]; 432 AuthenticationData = &AuthenticationDatas.data[i]; 433 AuthenticationFuncs = &AuthenticationFuncsList[i]; 434 break; 435 } 436} 437 438/* 439 * Register the host address for the display 440 */ 441 442static ARRAY16 ConnectionTypes; 443static ARRAYofARRAY8 ConnectionAddresses; 444static long xdmcpGeneration; 445 446void 447XdmcpRegisterConnection ( 448 int type, 449 char *address, 450 int addrlen) 451{ 452 int i; 453 CARD8 *newAddress; 454 455 if (xdmcpGeneration != serverGeneration) 456 { 457 XdmcpDisposeARRAY16 (&ConnectionTypes); 458 XdmcpDisposeARRAYofARRAY8 (&ConnectionAddresses); 459 xdmcpGeneration = serverGeneration; 460 } 461 if (xdm_from != NULL) { /* Only register the requested address */ 462 const void *regAddr = address; 463 const void *fromAddr = NULL; 464 int regAddrlen = addrlen; 465 466 if (addrlen == sizeof(struct in_addr)) { 467 if (SOCKADDR_FAMILY(FromAddress) == AF_INET) { 468 fromAddr = &((struct sockaddr_in *)&FromAddress)->sin_addr; 469 } 470#if defined(IPv6) && defined(AF_INET6) 471 else if ((SOCKADDR_FAMILY(FromAddress) == AF_INET6) && 472 IN6_IS_ADDR_V4MAPPED( 473 &((struct sockaddr_in6 *)&FromAddress)->sin6_addr)) { 474 fromAddr = &((struct sockaddr_in6 *)&FromAddress)->sin6_addr.s6_addr[12]; 475 } 476#endif 477 } 478#if defined(IPv6) && defined(AF_INET6) 479 else if (addrlen == sizeof(struct in6_addr)) { 480 if (SOCKADDR_FAMILY(FromAddress) == AF_INET6) { 481 fromAddr = &((struct sockaddr_in6 *)&FromAddress)->sin6_addr; 482 } else if ((SOCKADDR_FAMILY(FromAddress) == AF_INET) && 483 IN6_IS_ADDR_V4MAPPED((struct in6_addr *) address)) { 484 fromAddr = &((struct sockaddr_in *)&FromAddress)->sin_addr; 485 regAddr = &((struct sockaddr_in6 *)&address)->sin6_addr.s6_addr[12]; 486 regAddrlen = sizeof(struct in_addr); 487 } 488 } 489#endif 490 if (fromAddr && memcmp(regAddr, fromAddr, regAddrlen) != 0) { 491 return; 492 } 493 } 494 newAddress = (CARD8 *) xalloc (addrlen * sizeof (CARD8)); 495 if (!newAddress) 496 return; 497 if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1)) 498 { 499 xfree (newAddress); 500 return; 501 } 502 if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses, 503 ConnectionAddresses.length + 1)) 504 { 505 xfree (newAddress); 506 return; 507 } 508 ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type; 509 for (i = 0; i < addrlen; i++) 510 newAddress[i] = address[i]; 511 ConnectionAddresses.data[ConnectionAddresses.length-1].data = newAddress; 512 ConnectionAddresses.data[ConnectionAddresses.length-1].length = addrlen; 513} 514 515/* 516 * Register an Authorization Name. XDMCP advertises this list 517 * to the manager. 518 */ 519 520static ARRAYofARRAY8 AuthorizationNames; 521 522void 523XdmcpRegisterAuthorizations (void) 524{ 525 XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames); 526 RegisterAuthorizations (); 527} 528 529void 530XdmcpRegisterAuthorization (char *name, int namelen) 531{ 532 ARRAY8 authName; 533 int i; 534 535 authName.data = (CARD8 *) xalloc (namelen * sizeof (CARD8)); 536 if (!authName.data) 537 return; 538 if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1)) 539 { 540 xfree (authName.data); 541 return; 542 } 543 for (i = 0; i < namelen; i++) 544 authName.data[i] = (CARD8) name[i]; 545 authName.length = namelen; 546 AuthorizationNames.data[AuthorizationNames.length-1] = authName; 547} 548 549/* 550 * Register the DisplayClass string 551 */ 552 553static ARRAY8 DisplayClass; 554 555static void 556XdmcpRegisterDisplayClass (char *name, int length) 557{ 558 int i; 559 560 XdmcpDisposeARRAY8 (&DisplayClass); 561 if (!XdmcpAllocARRAY8 (&DisplayClass, length)) 562 return; 563 for (i = 0; i < length; i++) 564 DisplayClass.data[i] = (CARD8) name[i]; 565} 566 567/* 568 * initialize XDMCP; create the socket, compute the display 569 * number, set up the state machine 570 */ 571 572void 573XdmcpInit(void) 574{ 575 state = XDM_INIT_STATE; 576#ifdef HASXDMAUTH 577 if (xdmAuthCookie) 578 XdmAuthenticationInit (xdmAuthCookie, strlen (xdmAuthCookie)); 579#endif 580 if (state != XDM_OFF) 581 { 582 XdmcpRegisterAuthorizations(); 583 XdmcpRegisterDisplayClass (defaultDisplayClass, strlen (defaultDisplayClass)); 584 AccessUsingXdmcp(); 585 RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler, 586 (pointer) 0); 587 timeOutRtx = 0; 588 DisplayNumber = (CARD16) atoi(display); 589 get_xdmcp_sock(); 590 send_packet(); 591 } 592} 593 594void 595XdmcpReset (void) 596{ 597 state = XDM_INIT_STATE; 598 if (state != XDM_OFF) 599 { 600 RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler, 601 (pointer) 0); 602 timeOutRtx = 0; 603 send_packet(); 604 } 605} 606 607/* 608 * Called whenever a new connection is created; notices the 609 * first connection and saves it to terminate the session 610 * when it is closed 611 */ 612 613void 614XdmcpOpenDisplay(int sock) 615{ 616 if (state != XDM_AWAIT_MANAGE_RESPONSE) 617 return; 618 state = XDM_RUN_SESSION; 619 sessionSocket = sock; 620} 621 622void 623XdmcpCloseDisplay(int sock) 624{ 625 if ((state != XDM_RUN_SESSION && state != XDM_AWAIT_ALIVE_RESPONSE) 626 || sessionSocket != sock) 627 return; 628 state = XDM_INIT_STATE; 629 if (OneSession) 630 dispatchException |= DE_TERMINATE; 631 else 632 dispatchException |= DE_RESET; 633 isItTimeToYield = TRUE; 634} 635 636/* 637 * called before going to sleep, this routine 638 * may modify the timeout value about to be sent 639 * to select; in this way XDMCP can do appropriate things 640 * dynamically while starting up 641 */ 642 643/*ARGSUSED*/ 644static void 645XdmcpBlockHandler( 646 pointer data, /* unused */ 647 struct timeval **wt, 648 pointer pReadmask) 649{ 650 fd_set *LastSelectMask = (fd_set*)pReadmask; 651 CARD32 millisToGo; 652 653 if (state == XDM_OFF) 654 return; 655 FD_SET(xdmcpSocket, LastSelectMask); 656#if defined(IPv6) && defined(AF_INET6) 657 if (xdmcpSocket6 >= 0) 658 FD_SET(xdmcpSocket6, LastSelectMask); 659#endif 660 if (timeOutTime == 0) 661 return; 662 millisToGo = timeOutTime - GetTimeInMillis(); 663 if ((int) millisToGo < 0) 664 millisToGo = 0; 665 AdjustWaitForDelay (wt, millisToGo); 666} 667 668/* 669 * called after select returns; this routine will 670 * recognise when XDMCP packets await and 671 * process them appropriately 672 */ 673 674/*ARGSUSED*/ 675static void 676XdmcpWakeupHandler( 677 pointer data, /* unused */ 678 int i, 679 pointer pReadmask) 680{ 681 fd_set* LastSelectMask = (fd_set*)pReadmask; 682 fd_set devicesReadable; 683 684 if (state == XDM_OFF) 685 return; 686 if (i > 0) 687 { 688 if (FD_ISSET(xdmcpSocket, LastSelectMask)) 689 { 690 receive_packet(xdmcpSocket); 691 FD_CLR(xdmcpSocket, LastSelectMask); 692 } 693#if defined(IPv6) && defined(AF_INET6) 694 if (xdmcpSocket6 >= 0 && FD_ISSET(xdmcpSocket6, LastSelectMask)) 695 { 696 receive_packet(xdmcpSocket6); 697 FD_CLR(xdmcpSocket6, LastSelectMask); 698 } 699#endif 700 XFD_ANDSET(&devicesReadable, LastSelectMask, &EnabledDevices); 701 if (XFD_ANYSET(&devicesReadable)) 702 { 703 if (state == XDM_AWAIT_USER_INPUT) 704 restart(); 705 else if (state == XDM_RUN_SESSION) 706 keepaliveDormancy = defaultKeepaliveDormancy; 707 } 708 if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION) 709 timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000; 710 } 711 else if (timeOutTime && (int) (GetTimeInMillis() - timeOutTime) >= 0) 712 { 713 if (state == XDM_RUN_SESSION) 714 { 715 state = XDM_KEEPALIVE; 716 send_packet(); 717 } 718 else 719 timeout(); 720 } 721} 722 723/* 724 * This routine should be called from the routine that drives the 725 * user's host menu when the user selects a host 726 */ 727 728static void 729XdmcpSelectHost( 730 struct sockaddr *host_sockaddr, 731 int host_len, 732 ARRAY8Ptr AuthenticationName) 733{ 734 state = XDM_START_CONNECTION; 735 memmove(&req_sockaddr, host_sockaddr, host_len); 736 req_socklen = host_len; 737 XdmcpSetAuthentication (AuthenticationName); 738 send_packet(); 739} 740 741/* 742 * !!! this routine should be replaced by a routine that adds 743 * the host to the user's host menu. the current version just 744 * selects the first host to respond with willing message. 745 */ 746 747/*ARGSUSED*/ 748static void 749XdmcpAddHost( 750 struct sockaddr *from, 751 int fromlen, 752 ARRAY8Ptr AuthenticationName, 753 ARRAY8Ptr hostname, 754 ARRAY8Ptr status) 755{ 756 XdmcpSelectHost(from, fromlen, AuthenticationName); 757} 758 759/* 760 * A message is queued on the socket; read it and 761 * do the appropriate thing 762 */ 763 764static ARRAY8 UnwillingMessage = { (CARD8) 14, (CARD8 *) "Host unwilling" }; 765 766static void 767receive_packet(int socketfd) 768{ 769#if defined(IPv6) && defined(AF_INET6) 770 struct sockaddr_storage from; 771#else 772 struct sockaddr_in from; 773#endif 774 int fromlen = sizeof(from); 775 XdmcpHeader header; 776 777 /* read message off socket */ 778 if (!XdmcpFill (socketfd, &buffer, (XdmcpNetaddr) &from, &fromlen)) 779 return; 780 781 /* reset retransmission backoff */ 782 timeOutRtx = 0; 783 784 if (!XdmcpReadHeader (&buffer, &header)) 785 return; 786 787 if (header.version != XDM_PROTOCOL_VERSION) 788 return; 789 790 switch (header.opcode) { 791 case WILLING: 792 recv_willing_msg((struct sockaddr *) &from, fromlen, header.length); 793 break; 794 case UNWILLING: 795 XdmcpFatal("Manager unwilling", &UnwillingMessage); 796 break; 797 case ACCEPT: 798 recv_accept_msg(header.length); 799 break; 800 case DECLINE: 801 recv_decline_msg(header.length); 802 break; 803 case REFUSE: 804 recv_refuse_msg(header.length); 805 break; 806 case FAILED: 807 recv_failed_msg(header.length); 808 break; 809 case ALIVE: 810 recv_alive_msg(header.length); 811 break; 812 } 813} 814 815/* 816 * send the appropriate message given the current state 817 */ 818 819static void 820send_packet(void) 821{ 822 int rtx; 823 switch (state) { 824 case XDM_QUERY: 825 case XDM_BROADCAST: 826 case XDM_INDIRECT: 827#if defined(IPv6) && defined(AF_INET6) 828 case XDM_MULTICAST: 829#endif 830 send_query_msg(); 831 break; 832 case XDM_START_CONNECTION: 833 send_request_msg(); 834 break; 835 case XDM_MANAGE: 836 send_manage_msg(); 837 break; 838 case XDM_KEEPALIVE: 839 send_keepalive_msg(); 840 break; 841 default: 842 break; 843 } 844 rtx = (XDM_MIN_RTX << timeOutRtx); 845 if (rtx > XDM_MAX_RTX) 846 rtx = XDM_MAX_RTX; 847 timeOutTime = GetTimeInMillis() + rtx * 1000; 848} 849 850/* 851 * The session is declared dead for some reason; too many 852 * timeouts, or Keepalive failure. 853 */ 854 855static void 856XdmcpDeadSession (char *reason) 857{ 858 ErrorF ("XDM: %s, declaring session dead\n", reason); 859 state = XDM_INIT_STATE; 860 isItTimeToYield = TRUE; 861 dispatchException |= DE_RESET; 862 timeOutTime = 0; 863 timeOutRtx = 0; 864 send_packet(); 865} 866 867/* 868 * Timeout waiting for an XDMCP response. 869 */ 870 871static void 872timeout(void) 873{ 874 timeOutRtx++; 875 if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT ) 876 { 877 XdmcpDeadSession ("too many keepalive retransmissions"); 878 return; 879 } 880 else if (timeOutRtx >= XDM_RTX_LIMIT) 881 { 882 /* Quit if "-once" specified, otherwise reset and try again. */ 883 if (OneSession) { 884 dispatchException |= DE_TERMINATE; 885 ErrorF("XDM: too many retransmissions\n"); 886 } else { 887 XdmcpDeadSession("too many retransmissions"); 888 } 889 return; 890 } 891 892#if defined(IPv6) && defined(AF_INET6) 893 if (state == XDM_COLLECT_QUERY || state == XDM_COLLECT_INDIRECT_QUERY) { 894 /* Try next address */ 895 for (mgrAddr = mgrAddr->ai_next; ; mgrAddr = mgrAddr->ai_next) { 896 if (mgrAddr == NULL) { 897 mgrAddr = mgrAddrFirst; 898 } 899 if (mgrAddr->ai_family == AF_INET 900 || mgrAddr->ai_family == AF_INET6) 901 break; 902 } 903#ifndef SIN6_LEN 904 ManagerAddressLen = mgrAddr->ai_addrlen; 905#endif 906 memcpy(&ManagerAddress, mgrAddr->ai_addr, mgrAddr->ai_addrlen); 907 } 908#endif 909 910 switch (state) { 911 case XDM_COLLECT_QUERY: 912 state = XDM_QUERY; 913 break; 914 case XDM_COLLECT_BROADCAST_QUERY: 915 state = XDM_BROADCAST; 916 break; 917#if defined(IPv6) && defined(AF_INET6) 918 case XDM_COLLECT_MULTICAST_QUERY: 919 state = XDM_MULTICAST; 920 break; 921#endif 922 case XDM_COLLECT_INDIRECT_QUERY: 923 state = XDM_INDIRECT; 924 break; 925 case XDM_AWAIT_REQUEST_RESPONSE: 926 state = XDM_START_CONNECTION; 927 break; 928 case XDM_AWAIT_MANAGE_RESPONSE: 929 state = XDM_MANAGE; 930 break; 931 case XDM_AWAIT_ALIVE_RESPONSE: 932 state = XDM_KEEPALIVE; 933 break; 934 default: 935 break; 936 } 937 send_packet(); 938} 939 940static void 941restart(void) 942{ 943 state = XDM_INIT_STATE; 944 timeOutRtx = 0; 945 send_packet(); 946} 947 948static int 949XdmcpCheckAuthentication (ARRAY8Ptr Name, ARRAY8Ptr Data, int packet_type) 950{ 951 return (XdmcpARRAY8Equal (Name, AuthenticationName) && 952 (AuthenticationName->length == 0 || 953 (*AuthenticationFuncs->Validator) (AuthenticationData, Data, packet_type))); 954} 955 956static int 957XdmcpAddAuthorization (ARRAY8Ptr name, ARRAY8Ptr data) 958{ 959 AddAuthorFunc AddAuth; 960 961 if (AuthenticationFuncs && AuthenticationFuncs->AddAuth) 962 AddAuth = AuthenticationFuncs->AddAuth; 963 else 964 AddAuth = AddAuthorization; 965 return (*AddAuth) ((unsigned short)name->length, 966 (char *)name->data, 967 (unsigned short)data->length, 968 (char *)data->data); 969} 970 971/* 972 * from here to the end of this file are routines private 973 * to the state machine. 974 */ 975 976static void 977get_xdmcp_sock(void) 978{ 979#ifdef STREAMSCONN 980 struct netconfig *nconf; 981 982 if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) { 983 XdmcpWarning("t_open() of /dev/udp failed"); 984 return; 985 } 986 987 if( t_bind(xdmcpSocket,NULL,NULL) < 0 ) { 988 XdmcpWarning("UDP socket creation failed"); 989 t_error("t_bind(xdmcpSocket) failed" ); 990 t_close(xdmcpSocket); 991 return; 992 } 993 994 /* 995 * This part of the code looks contrived. It will actually fit in nicely 996 * when the CLTS part of Xtrans is implemented. 997 */ 998 999 if( (nconf=getnetconfigent("udp")) == NULL ) { 1000 XdmcpWarning("UDP socket creation failed: getnetconfigent()"); 1001 t_unbind(xdmcpSocket); 1002 t_close(xdmcpSocket); 1003 return; 1004 } 1005 1006 if( netdir_options(nconf, ND_SET_BROADCAST, xdmcpSocket, NULL) ) { 1007 XdmcpWarning("UDP set broadcast option failed: netdir_options()"); 1008 freenetconfigent(nconf); 1009 t_unbind(xdmcpSocket); 1010 t_close(xdmcpSocket); 1011 return; 1012 } 1013 1014 freenetconfigent(nconf); 1015#else 1016 int soopts = 1; 1017 1018#if defined(IPv6) && defined(AF_INET6) 1019 if ((xdmcpSocket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1020 XdmcpWarning("INET6 UDP socket creation failed"); 1021#endif 1022 if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1023 XdmcpWarning("UDP socket creation failed"); 1024#ifdef SO_BROADCAST 1025 else if (setsockopt(xdmcpSocket, SOL_SOCKET, SO_BROADCAST, (char *)&soopts, 1026 sizeof(soopts)) < 0) 1027 XdmcpWarning("UDP set broadcast socket-option failed"); 1028#endif /* SO_BROADCAST */ 1029 if (xdmcpSocket >= 0 && xdm_from != NULL) { 1030 if (bind(xdmcpSocket, (struct sockaddr *)&FromAddress, 1031 FromAddressLen) < 0) { 1032 FatalError("Xserver: failed to bind to -from address: %s\n", xdm_from); 1033 } 1034 } 1035#endif /* STREAMSCONN */ 1036} 1037 1038static void 1039send_query_msg(void) 1040{ 1041 XdmcpHeader header; 1042 Bool broadcast = FALSE; 1043#if defined(IPv6) && defined(AF_INET6) 1044 Bool multicast = FALSE; 1045#endif 1046 int i; 1047 int socketfd = xdmcpSocket; 1048 1049 header.version = XDM_PROTOCOL_VERSION; 1050 switch(state){ 1051 case XDM_QUERY: 1052 header.opcode = (CARD16) QUERY; 1053 state = XDM_COLLECT_QUERY; 1054 break; 1055 case XDM_BROADCAST: 1056 header.opcode = (CARD16) BROADCAST_QUERY; 1057 state = XDM_COLLECT_BROADCAST_QUERY; 1058 broadcast = TRUE; 1059 break; 1060#if defined(IPv6) && defined(AF_INET6) 1061 case XDM_MULTICAST: 1062 header.opcode = (CARD16) BROADCAST_QUERY; 1063 state = XDM_COLLECT_MULTICAST_QUERY; 1064 multicast = TRUE; 1065 break; 1066#endif 1067 case XDM_INDIRECT: 1068 header.opcode = (CARD16) INDIRECT_QUERY; 1069 state = XDM_COLLECT_INDIRECT_QUERY; 1070 break; 1071 default: 1072 break; 1073 } 1074 header.length = 1; 1075 for (i = 0; i < AuthenticationNames.length; i++) 1076 header.length += 2 + AuthenticationNames.data[i].length; 1077 1078 XdmcpWriteHeader (&buffer, &header); 1079 XdmcpWriteARRAYofARRAY8 (&buffer, &AuthenticationNames); 1080 if (broadcast) 1081 { 1082 int i; 1083 1084 for (i = 0; i < NumBroadcastAddresses; i++) 1085 XdmcpFlush (xdmcpSocket, &buffer, (XdmcpNetaddr) &BroadcastAddresses[i], 1086 sizeof (struct sockaddr_in)); 1087 } 1088#if defined(IPv6) && defined(AF_INET6) 1089 else if (multicast) 1090 { 1091 struct multicastinfo *mcl; 1092 struct addrinfo *ai; 1093 1094 for (mcl = mcastlist; mcl != NULL; mcl = mcl->next) { 1095 for (ai = mcl->ai ; ai != NULL; ai = ai->ai_next) { 1096 if (ai->ai_family == AF_INET) { 1097 unsigned char hopflag = (unsigned char) mcl->hops; 1098 socketfd = xdmcpSocket; 1099 setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_TTL, 1100 &hopflag, sizeof(hopflag)); 1101 } else if (ai->ai_family == AF_INET6) { 1102 int hopflag6 = mcl->hops; 1103 socketfd = xdmcpSocket6; 1104 setsockopt(socketfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1105 &hopflag6, sizeof(hopflag6)); 1106 } else { 1107 continue; 1108 } 1109 XdmcpFlush (socketfd, &buffer, 1110 (XdmcpNetaddr) ai->ai_addr, ai->ai_addrlen); 1111 break; 1112 } 1113 } 1114 } 1115#endif 1116 else 1117 { 1118#if defined(IPv6) && defined(AF_INET6) 1119 if (SOCKADDR_FAMILY(ManagerAddress) == AF_INET6) 1120 socketfd = xdmcpSocket6; 1121#endif 1122 XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &ManagerAddress, 1123 ManagerAddressLen); 1124 } 1125} 1126 1127static void 1128recv_willing_msg( 1129 struct sockaddr *from, 1130 int fromlen, 1131 unsigned length) 1132{ 1133 ARRAY8 authenticationName; 1134 ARRAY8 hostname; 1135 ARRAY8 status; 1136 1137 authenticationName.data = 0; 1138 hostname.data = 0; 1139 status.data = 0; 1140 if (XdmcpReadARRAY8 (&buffer, &authenticationName) && 1141 XdmcpReadARRAY8 (&buffer, &hostname) && 1142 XdmcpReadARRAY8 (&buffer, &status)) 1143 { 1144 if (length == 6 + authenticationName.length + 1145 hostname.length + status.length) 1146 { 1147 switch (state) 1148 { 1149 case XDM_COLLECT_QUERY: 1150 XdmcpSelectHost(from, fromlen, &authenticationName); 1151 break; 1152 case XDM_COLLECT_BROADCAST_QUERY: 1153#if defined(IPv6) && defined(AF_INET6) 1154 case XDM_COLLECT_MULTICAST_QUERY: 1155#endif 1156 case XDM_COLLECT_INDIRECT_QUERY: 1157 XdmcpAddHost(from, fromlen, &authenticationName, &hostname, &status); 1158 break; 1159 default: 1160 break; 1161 } 1162 } 1163 } 1164 XdmcpDisposeARRAY8 (&authenticationName); 1165 XdmcpDisposeARRAY8 (&hostname); 1166 XdmcpDisposeARRAY8 (&status); 1167} 1168 1169static void 1170send_request_msg(void) 1171{ 1172 XdmcpHeader header; 1173 int length; 1174 int i; 1175 CARD16 XdmcpConnectionType; 1176 ARRAY8 authenticationData; 1177 int socketfd = xdmcpSocket; 1178 1179 switch (SOCKADDR_FAMILY(ManagerAddress)) 1180 { 1181 case AF_INET: XdmcpConnectionType=FamilyInternet; break; 1182#if defined(IPv6) && defined(AF_INET6) 1183 case AF_INET6: XdmcpConnectionType=FamilyInternet6; break; 1184#endif 1185 default: XdmcpConnectionType=0xffff; break; 1186 } 1187 1188 header.version = XDM_PROTOCOL_VERSION; 1189 header.opcode = (CARD16) REQUEST; 1190 1191 length = 2; /* display number */ 1192 length += 1 + 2 * ConnectionTypes.length; /* connection types */ 1193 length += 1; /* connection addresses */ 1194 for (i = 0; i < ConnectionAddresses.length; i++) 1195 length += 2 + ConnectionAddresses.data[i].length; 1196 authenticationData.length = 0; 1197 authenticationData.data = 0; 1198 if (AuthenticationFuncs) 1199 { 1200 (*AuthenticationFuncs->Generator) (AuthenticationData, 1201 &authenticationData, 1202 REQUEST); 1203 } 1204 length += 2 + AuthenticationName->length; /* authentication name */ 1205 length += 2 + authenticationData.length; /* authentication data */ 1206 length += 1; /* authorization names */ 1207 for (i = 0; i < AuthorizationNames.length; i++) 1208 length += 2 + AuthorizationNames.data[i].length; 1209 length += 2 + ManufacturerDisplayID.length; /* display ID */ 1210 header.length = length; 1211 1212 if (!XdmcpWriteHeader (&buffer, &header)) 1213 { 1214 XdmcpDisposeARRAY8 (&authenticationData); 1215 return; 1216 } 1217 XdmcpWriteCARD16 (&buffer, DisplayNumber); 1218 XdmcpWriteCARD8 (&buffer, ConnectionTypes.length); 1219 1220 /* The connection array is send reordered, so that connections of */ 1221 /* the same address type as the XDMCP manager connection are send */ 1222 /* first. This works around a bug in xdm. mario@klebsch.de */ 1223 for (i = 0; i < (int)ConnectionTypes.length; i++) 1224 if (ConnectionTypes.data[i]==XdmcpConnectionType) 1225 XdmcpWriteCARD16 (&buffer, ConnectionTypes.data[i]); 1226 for (i = 0; i < (int)ConnectionTypes.length; i++) 1227 if (ConnectionTypes.data[i]!=XdmcpConnectionType) 1228 XdmcpWriteCARD16 (&buffer, ConnectionTypes.data[i]); 1229 1230 XdmcpWriteCARD8 (&buffer, ConnectionAddresses.length); 1231 for (i = 0; i < (int)ConnectionAddresses.length; i++) 1232 if ( (i<ConnectionTypes.length) && 1233 (ConnectionTypes.data[i]==XdmcpConnectionType) ) 1234 XdmcpWriteARRAY8 (&buffer, &ConnectionAddresses.data[i]); 1235 for (i = 0; i < (int)ConnectionAddresses.length; i++) 1236 if ( (i>=ConnectionTypes.length) || 1237 (ConnectionTypes.data[i]!=XdmcpConnectionType) ) 1238 XdmcpWriteARRAY8 (&buffer, &ConnectionAddresses.data[i]); 1239 1240 XdmcpWriteARRAY8 (&buffer, AuthenticationName); 1241 XdmcpWriteARRAY8 (&buffer, &authenticationData); 1242 XdmcpDisposeARRAY8 (&authenticationData); 1243 XdmcpWriteARRAYofARRAY8 (&buffer, &AuthorizationNames); 1244 XdmcpWriteARRAY8 (&buffer, &ManufacturerDisplayID); 1245#if defined(IPv6) && defined(AF_INET6) 1246 if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6) 1247 socketfd = xdmcpSocket6; 1248#endif 1249 if (XdmcpFlush (socketfd, &buffer, 1250 (XdmcpNetaddr) &req_sockaddr, req_socklen)) 1251 state = XDM_AWAIT_REQUEST_RESPONSE; 1252} 1253 1254static void 1255recv_accept_msg(unsigned length) 1256{ 1257 CARD32 AcceptSessionID; 1258 ARRAY8 AcceptAuthenticationName, AcceptAuthenticationData; 1259 ARRAY8 AcceptAuthorizationName, AcceptAuthorizationData; 1260 1261 if (state != XDM_AWAIT_REQUEST_RESPONSE) 1262 return; 1263 AcceptAuthenticationName.data = 0; 1264 AcceptAuthenticationData.data = 0; 1265 AcceptAuthorizationName.data = 0; 1266 AcceptAuthorizationData.data = 0; 1267 if (XdmcpReadCARD32 (&buffer, &AcceptSessionID) && 1268 XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationName) && 1269 XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationData) && 1270 XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationName) && 1271 XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationData)) 1272 { 1273 if (length == 12 + AcceptAuthenticationName.length + 1274 AcceptAuthenticationData.length + 1275 AcceptAuthorizationName.length + 1276 AcceptAuthorizationData.length) 1277 { 1278 if (!XdmcpCheckAuthentication (&AcceptAuthenticationName, 1279 &AcceptAuthenticationData, ACCEPT)) 1280 { 1281 XdmcpFatal ("Authentication Failure", &AcceptAuthenticationName); 1282 } 1283 /* permit access control manipulations from this host */ 1284 AugmentSelf (&req_sockaddr, req_socklen); 1285 /* if the authorization specified in the packet fails 1286 * to be acceptable, enable the local addresses 1287 */ 1288 if (!XdmcpAddAuthorization (&AcceptAuthorizationName, 1289 &AcceptAuthorizationData)) 1290 { 1291 AddLocalHosts (); 1292 } 1293 SessionID = AcceptSessionID; 1294 state = XDM_MANAGE; 1295 send_packet(); 1296 } 1297 } 1298 XdmcpDisposeARRAY8 (&AcceptAuthenticationName); 1299 XdmcpDisposeARRAY8 (&AcceptAuthenticationData); 1300 XdmcpDisposeARRAY8 (&AcceptAuthorizationName); 1301 XdmcpDisposeARRAY8 (&AcceptAuthorizationData); 1302} 1303 1304static void 1305recv_decline_msg(unsigned length) 1306{ 1307 ARRAY8 status, DeclineAuthenticationName, DeclineAuthenticationData; 1308 1309 status.data = 0; 1310 DeclineAuthenticationName.data = 0; 1311 DeclineAuthenticationData.data = 0; 1312 if (XdmcpReadARRAY8 (&buffer, &status) && 1313 XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationName) && 1314 XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationData)) 1315 { 1316 if (length == 6 + status.length + 1317 DeclineAuthenticationName.length + 1318 DeclineAuthenticationData.length && 1319 XdmcpCheckAuthentication (&DeclineAuthenticationName, 1320 &DeclineAuthenticationData, DECLINE)) 1321 { 1322 XdmcpFatal ("Session declined", &status); 1323 } 1324 } 1325 XdmcpDisposeARRAY8 (&status); 1326 XdmcpDisposeARRAY8 (&DeclineAuthenticationName); 1327 XdmcpDisposeARRAY8 (&DeclineAuthenticationData); 1328} 1329 1330static void 1331send_manage_msg(void) 1332{ 1333 XdmcpHeader header; 1334 int socketfd = xdmcpSocket; 1335 1336 header.version = XDM_PROTOCOL_VERSION; 1337 header.opcode = (CARD16) MANAGE; 1338 header.length = 8 + DisplayClass.length; 1339 1340 if (!XdmcpWriteHeader (&buffer, &header)) 1341 return; 1342 XdmcpWriteCARD32 (&buffer, SessionID); 1343 XdmcpWriteCARD16 (&buffer, DisplayNumber); 1344 XdmcpWriteARRAY8 (&buffer, &DisplayClass); 1345 state = XDM_AWAIT_MANAGE_RESPONSE; 1346#if defined(IPv6) && defined(AF_INET6) 1347 if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6) 1348 socketfd = xdmcpSocket6; 1349#endif 1350 XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen); 1351} 1352 1353static void 1354recv_refuse_msg(unsigned length) 1355{ 1356 CARD32 RefusedSessionID; 1357 1358 if (state != XDM_AWAIT_MANAGE_RESPONSE) 1359 return; 1360 if (length != 4) 1361 return; 1362 if (XdmcpReadCARD32 (&buffer, &RefusedSessionID)) 1363 { 1364 if (RefusedSessionID == SessionID) 1365 { 1366 state = XDM_START_CONNECTION; 1367 send_packet(); 1368 } 1369 } 1370} 1371 1372static void 1373recv_failed_msg(unsigned length) 1374{ 1375 CARD32 FailedSessionID; 1376 ARRAY8 status; 1377 1378 if (state != XDM_AWAIT_MANAGE_RESPONSE) 1379 return; 1380 status.data = 0; 1381 if (XdmcpReadCARD32 (&buffer, &FailedSessionID) && 1382 XdmcpReadARRAY8 (&buffer, &status)) 1383 { 1384 if (length == 6 + status.length && 1385 SessionID == FailedSessionID) 1386 { 1387 XdmcpFatal ("Session failed", &status); 1388 } 1389 } 1390 XdmcpDisposeARRAY8 (&status); 1391} 1392 1393static void 1394send_keepalive_msg(void) 1395{ 1396 XdmcpHeader header; 1397 int socketfd = xdmcpSocket; 1398 1399 header.version = XDM_PROTOCOL_VERSION; 1400 header.opcode = (CARD16) KEEPALIVE; 1401 header.length = 6; 1402 1403 XdmcpWriteHeader (&buffer, &header); 1404 XdmcpWriteCARD16 (&buffer, DisplayNumber); 1405 XdmcpWriteCARD32 (&buffer, SessionID); 1406 1407 state = XDM_AWAIT_ALIVE_RESPONSE; 1408#if defined(IPv6) && defined(AF_INET6) 1409 if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6) 1410 socketfd = xdmcpSocket6; 1411#endif 1412 XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen); 1413} 1414 1415static void 1416recv_alive_msg (unsigned length) 1417{ 1418 CARD8 SessionRunning; 1419 CARD32 AliveSessionID; 1420 1421 if (state != XDM_AWAIT_ALIVE_RESPONSE) 1422 return; 1423 if (length != 5) 1424 return; 1425 if (XdmcpReadCARD8 (&buffer, &SessionRunning) && 1426 XdmcpReadCARD32 (&buffer, &AliveSessionID)) 1427 { 1428 if (SessionRunning && AliveSessionID == SessionID) 1429 { 1430 /* backoff dormancy period */ 1431 state = XDM_RUN_SESSION; 1432 if ((GetTimeInMillis() - lastDeviceEventTime.milliseconds) > 1433 keepaliveDormancy * 1000) 1434 { 1435 keepaliveDormancy <<= 1; 1436 if (keepaliveDormancy > XDM_MAX_DORMANCY) 1437 keepaliveDormancy = XDM_MAX_DORMANCY; 1438 } 1439 timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000; 1440 } 1441 else 1442 { 1443 XdmcpDeadSession ("Alive response indicates session dead"); 1444 } 1445 } 1446} 1447 1448static void 1449XdmcpFatal ( 1450 char *type, 1451 ARRAY8Ptr status) 1452{ 1453 FatalError ("XDMCP fatal error: %s %*.*s\n", type, 1454 status->length, status->length, status->data); 1455} 1456 1457static void 1458XdmcpWarning(char *str) 1459{ 1460 ErrorF("XDMCP warning: %s\n", str); 1461} 1462 1463static void 1464get_addr_by_name( 1465 char * argtype, 1466 char * namestr, 1467 int port, 1468 int socktype, 1469 SOCKADDR_TYPE *addr, 1470 SOCKLEN_TYPE *addrlen 1471#if defined(IPv6) && defined(AF_INET6) 1472 , 1473 struct addrinfo **aip, 1474 struct addrinfo **aifirstp 1475#endif 1476 ) 1477{ 1478#if defined(IPv6) && defined(AF_INET6) 1479 struct addrinfo *ai; 1480 struct addrinfo hints; 1481 char portstr[6]; 1482 char *pport = portstr; 1483 int gaierr; 1484 1485 bzero(&hints, sizeof(hints)); 1486 hints.ai_socktype = socktype; 1487 1488 if (port == 0) { 1489 pport = NULL; 1490 } else if (port > 0 && port < 65535) { 1491 sprintf(portstr, "%d", port); 1492 } else { 1493 FatalError("Xserver: port out of range: %d\n", port); 1494 } 1495 1496 if (*aifirstp != NULL) { 1497 freeaddrinfo(*aifirstp); 1498 *aifirstp = NULL; 1499 } 1500 1501 if ((gaierr = getaddrinfo(namestr, pport, &hints, aifirstp)) == 0) { 1502 for (ai = *aifirstp; ai != NULL; ai = ai->ai_next) { 1503 if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) 1504 break; 1505 } 1506 if ((ai == NULL) || (ai->ai_addrlen > sizeof(SOCKADDR_TYPE))) { 1507 FatalError ("Xserver: %s host %s not on supported network type\n", 1508 argtype, namestr); 1509 } else { 1510 *aip = ai; 1511 *addrlen = ai->ai_addrlen; 1512 memcpy(addr, ai->ai_addr, ai->ai_addrlen); 1513 } 1514 } else { 1515 FatalError("Xserver: %s: %s %s\n", gai_strerror(gaierr), argtype, namestr); 1516 } 1517#else 1518 struct hostent *hep; 1519#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 1520 _Xgethostbynameparams hparams; 1521#endif 1522#if defined(WIN32) && (defined(TCPCONN) || defined(DNETCONN)) 1523 _XSERVTransWSAStartup(); 1524#endif 1525 if (!(hep = _XGethostbyname(namestr, hparams))) 1526 { 1527 FatalError("Xserver: %s unknown host: %s\n", argtype, namestr); 1528 } 1529 if (hep->h_length == sizeof (struct in_addr)) 1530 { 1531 memmove(&addr->sin_addr, hep->h_addr, hep->h_length); 1532 *addrlen = sizeof(struct sockaddr_in); 1533 addr->sin_family = AF_INET; 1534 addr->sin_port = htons (port); 1535 } 1536 else 1537 { 1538 FatalError("Xserver: %s host on strange network %s\n", argtype, namestr); 1539 } 1540#endif 1541} 1542 1543static void 1544get_manager_by_name( 1545 int argc, 1546 char **argv, 1547 int i) 1548{ 1549 1550 if ((i + 1) == argc) 1551 { 1552 FatalError("Xserver: missing %s host name in command line\n", argv[i]); 1553 } 1554 1555 get_addr_by_name(argv[i], argv[i+1], xdm_udp_port, SOCK_DGRAM, 1556 &ManagerAddress, &ManagerAddressLen 1557#if defined(IPv6) && defined(AF_INET6) 1558 , &mgrAddr, &mgrAddrFirst 1559#endif 1560 ); 1561} 1562 1563 1564static void 1565get_fromaddr_by_name( 1566 int argc, 1567 char **argv, 1568 int i) 1569{ 1570#if defined(IPv6) && defined(AF_INET6) 1571 struct addrinfo *ai = NULL; 1572 struct addrinfo *aifirst = NULL; 1573#endif 1574 if (i == argc) 1575 { 1576 FatalError("Xserver: missing -from host name in command line\n"); 1577 } 1578 get_addr_by_name("-from", argv[i], 0, 0, &FromAddress, &FromAddressLen 1579#if defined(IPv6) && defined(AF_INET6) 1580 , &ai, &aifirst 1581#endif 1582 ); 1583#if defined(IPv6) && defined(AF_INET6) 1584 if (aifirst != NULL) 1585 freeaddrinfo(aifirst); 1586#endif 1587 xdm_from = argv[i]; 1588} 1589 1590 1591#if defined(IPv6) && defined(AF_INET6) 1592static int 1593get_mcast_options(argc, argv, i) 1594 int argc, i; 1595 char **argv; 1596{ 1597 char *address = XDM_DEFAULT_MCAST_ADDR6; 1598 int hopcount = 1; 1599 struct addrinfo hints; 1600 char portstr[6]; 1601 int gaierr; 1602 struct addrinfo *ai, *firstai; 1603 1604 if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) { 1605 address = argv[i++]; 1606 if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) { 1607 hopcount = strtol(argv[i++], NULL, 10); 1608 if ((hopcount < 1) || (hopcount > 255)) { 1609 FatalError("Xserver: multicast hop count out of range: %d\n", 1610 hopcount); 1611 } 1612 } 1613 } 1614 1615 if (xdm_udp_port > 0 && xdm_udp_port < 65535) { 1616 sprintf(portstr, "%d", xdm_udp_port); 1617 } else { 1618 FatalError("Xserver: port out of range: %d\n", xdm_udp_port); 1619 } 1620 bzero(&hints, sizeof(hints)); 1621 hints.ai_socktype = SOCK_DGRAM; 1622 1623 if ((gaierr = getaddrinfo(address, portstr, &hints, &firstai)) == 0) { 1624 for (ai = firstai; ai != NULL; ai = ai->ai_next) { 1625 if (((ai->ai_family == AF_INET) && 1626 IN_MULTICAST(((struct sockaddr_in *) ai->ai_addr) 1627 ->sin_addr.s_addr)) 1628 || ((ai->ai_family == AF_INET6) && 1629 IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *) ai->ai_addr) 1630 ->sin6_addr))) 1631 break; 1632 } 1633 if (ai == NULL) { 1634 FatalError ("Xserver: address not supported multicast type %s\n", 1635 address); 1636 } else { 1637 struct multicastinfo *mcastinfo, *mcl; 1638 1639 mcastinfo = malloc(sizeof(struct multicastinfo)); 1640 mcastinfo->next = NULL; 1641 mcastinfo->ai = firstai; 1642 mcastinfo->hops = hopcount; 1643 1644 if (mcastlist == NULL) { 1645 mcastlist = mcastinfo; 1646 } else { 1647 for (mcl = mcastlist; mcl->next != NULL; mcl = mcl->next) { 1648 /* Do nothing - just find end of list */ 1649 } 1650 mcl->next = mcastinfo; 1651 } 1652 } 1653 } else { 1654 FatalError("Xserver: %s: %s\n", gai_strerror(gaierr), address); 1655 } 1656 return i; 1657} 1658#endif 1659 1660#else 1661static int xdmcp_non_empty; /* avoid complaint by ranlib */ 1662#endif /* XDMCP */ 1663