xdmcp.c revision b86d567b
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 if (ConnectionAddresses.length + 1 == 256) 495 return; 496 newAddress = xalloc (addrlen * sizeof (CARD8)); 497 if (!newAddress) 498 return; 499 if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1)) 500 { 501 xfree (newAddress); 502 return; 503 } 504 if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses, 505 ConnectionAddresses.length + 1)) 506 { 507 xfree (newAddress); 508 return; 509 } 510 ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type; 511 for (i = 0; i < addrlen; i++) 512 newAddress[i] = address[i]; 513 ConnectionAddresses.data[ConnectionAddresses.length-1].data = newAddress; 514 ConnectionAddresses.data[ConnectionAddresses.length-1].length = addrlen; 515} 516 517/* 518 * Register an Authorization Name. XDMCP advertises this list 519 * to the manager. 520 */ 521 522static ARRAYofARRAY8 AuthorizationNames; 523 524void 525XdmcpRegisterAuthorizations (void) 526{ 527 XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames); 528 RegisterAuthorizations (); 529} 530 531void 532XdmcpRegisterAuthorization (char *name, int namelen) 533{ 534 ARRAY8 authName; 535 int i; 536 537 authName.data = (CARD8 *) xalloc (namelen * sizeof (CARD8)); 538 if (!authName.data) 539 return; 540 if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1)) 541 { 542 xfree (authName.data); 543 return; 544 } 545 for (i = 0; i < namelen; i++) 546 authName.data[i] = (CARD8) name[i]; 547 authName.length = namelen; 548 AuthorizationNames.data[AuthorizationNames.length-1] = authName; 549} 550 551/* 552 * Register the DisplayClass string 553 */ 554 555static ARRAY8 DisplayClass; 556 557static void 558XdmcpRegisterDisplayClass (char *name, int length) 559{ 560 int i; 561 562 XdmcpDisposeARRAY8 (&DisplayClass); 563 if (!XdmcpAllocARRAY8 (&DisplayClass, length)) 564 return; 565 for (i = 0; i < length; i++) 566 DisplayClass.data[i] = (CARD8) name[i]; 567} 568 569/* 570 * initialize XDMCP; create the socket, compute the display 571 * number, set up the state machine 572 */ 573 574void 575XdmcpInit(void) 576{ 577 state = XDM_INIT_STATE; 578#ifdef HASXDMAUTH 579 if (xdmAuthCookie) 580 XdmAuthenticationInit (xdmAuthCookie, strlen (xdmAuthCookie)); 581#endif 582 if (state != XDM_OFF) 583 { 584 XdmcpRegisterAuthorizations(); 585 XdmcpRegisterDisplayClass (defaultDisplayClass, strlen (defaultDisplayClass)); 586 AccessUsingXdmcp(); 587 RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler, 588 (pointer) 0); 589 timeOutRtx = 0; 590 DisplayNumber = (CARD16) atoi(display); 591 get_xdmcp_sock(); 592 send_packet(); 593 } 594} 595 596void 597XdmcpReset (void) 598{ 599 state = XDM_INIT_STATE; 600 if (state != XDM_OFF) 601 { 602 RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler, 603 (pointer) 0); 604 timeOutRtx = 0; 605 send_packet(); 606 } 607} 608 609/* 610 * Called whenever a new connection is created; notices the 611 * first connection and saves it to terminate the session 612 * when it is closed 613 */ 614 615void 616XdmcpOpenDisplay(int sock) 617{ 618 if (state != XDM_AWAIT_MANAGE_RESPONSE) 619 return; 620 state = XDM_RUN_SESSION; 621 sessionSocket = sock; 622} 623 624void 625XdmcpCloseDisplay(int sock) 626{ 627 if ((state != XDM_RUN_SESSION && state != XDM_AWAIT_ALIVE_RESPONSE) 628 || sessionSocket != sock) 629 return; 630 state = XDM_INIT_STATE; 631 if (OneSession) 632 dispatchException |= DE_TERMINATE; 633 else 634 dispatchException |= DE_RESET; 635 isItTimeToYield = TRUE; 636} 637 638/* 639 * called before going to sleep, this routine 640 * may modify the timeout value about to be sent 641 * to select; in this way XDMCP can do appropriate things 642 * dynamically while starting up 643 */ 644 645/*ARGSUSED*/ 646static void 647XdmcpBlockHandler( 648 pointer data, /* unused */ 649 struct timeval **wt, 650 pointer pReadmask) 651{ 652 fd_set *LastSelectMask = (fd_set*)pReadmask; 653 CARD32 millisToGo; 654 655 if (state == XDM_OFF) 656 return; 657 FD_SET(xdmcpSocket, LastSelectMask); 658#if defined(IPv6) && defined(AF_INET6) 659 if (xdmcpSocket6 >= 0) 660 FD_SET(xdmcpSocket6, LastSelectMask); 661#endif 662 if (timeOutTime == 0) 663 return; 664 millisToGo = timeOutTime - GetTimeInMillis(); 665 if ((int) millisToGo < 0) 666 millisToGo = 0; 667 AdjustWaitForDelay (wt, millisToGo); 668} 669 670/* 671 * called after select returns; this routine will 672 * recognise when XDMCP packets await and 673 * process them appropriately 674 */ 675 676/*ARGSUSED*/ 677static void 678XdmcpWakeupHandler( 679 pointer data, /* unused */ 680 int i, 681 pointer pReadmask) 682{ 683 fd_set* LastSelectMask = (fd_set*)pReadmask; 684 fd_set devicesReadable; 685 686 if (state == XDM_OFF) 687 return; 688 if (i > 0) 689 { 690 if (FD_ISSET(xdmcpSocket, LastSelectMask)) 691 { 692 receive_packet(xdmcpSocket); 693 FD_CLR(xdmcpSocket, LastSelectMask); 694 } 695#if defined(IPv6) && defined(AF_INET6) 696 if (xdmcpSocket6 >= 0 && FD_ISSET(xdmcpSocket6, LastSelectMask)) 697 { 698 receive_packet(xdmcpSocket6); 699 FD_CLR(xdmcpSocket6, LastSelectMask); 700 } 701#endif 702 XFD_ANDSET(&devicesReadable, LastSelectMask, &EnabledDevices); 703 if (XFD_ANYSET(&devicesReadable)) 704 { 705 if (state == XDM_AWAIT_USER_INPUT) 706 restart(); 707 else if (state == XDM_RUN_SESSION) 708 keepaliveDormancy = defaultKeepaliveDormancy; 709 } 710 if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION) 711 timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000; 712 } 713 else if (timeOutTime && (int) (GetTimeInMillis() - timeOutTime) >= 0) 714 { 715 if (state == XDM_RUN_SESSION) 716 { 717 state = XDM_KEEPALIVE; 718 send_packet(); 719 } 720 else 721 timeout(); 722 } 723} 724 725/* 726 * This routine should be called from the routine that drives the 727 * user's host menu when the user selects a host 728 */ 729 730static void 731XdmcpSelectHost( 732 struct sockaddr *host_sockaddr, 733 int host_len, 734 ARRAY8Ptr AuthenticationName) 735{ 736 state = XDM_START_CONNECTION; 737 memmove(&req_sockaddr, host_sockaddr, host_len); 738 req_socklen = host_len; 739 XdmcpSetAuthentication (AuthenticationName); 740 send_packet(); 741} 742 743/* 744 * !!! this routine should be replaced by a routine that adds 745 * the host to the user's host menu. the current version just 746 * selects the first host to respond with willing message. 747 */ 748 749/*ARGSUSED*/ 750static void 751XdmcpAddHost( 752 struct sockaddr *from, 753 int fromlen, 754 ARRAY8Ptr AuthenticationName, 755 ARRAY8Ptr hostname, 756 ARRAY8Ptr status) 757{ 758 XdmcpSelectHost(from, fromlen, AuthenticationName); 759} 760 761/* 762 * A message is queued on the socket; read it and 763 * do the appropriate thing 764 */ 765 766static ARRAY8 UnwillingMessage = { (CARD8) 14, (CARD8 *) "Host unwilling" }; 767 768static void 769receive_packet(int socketfd) 770{ 771#if defined(IPv6) && defined(AF_INET6) 772 struct sockaddr_storage from; 773#else 774 struct sockaddr_in from; 775#endif 776 int fromlen = sizeof(from); 777 XdmcpHeader header; 778 779 /* read message off socket */ 780 if (!XdmcpFill (socketfd, &buffer, (XdmcpNetaddr) &from, &fromlen)) 781 return; 782 783 /* reset retransmission backoff */ 784 timeOutRtx = 0; 785 786 if (!XdmcpReadHeader (&buffer, &header)) 787 return; 788 789 if (header.version != XDM_PROTOCOL_VERSION) 790 return; 791 792 switch (header.opcode) { 793 case WILLING: 794 recv_willing_msg((struct sockaddr *) &from, fromlen, header.length); 795 break; 796 case UNWILLING: 797 XdmcpFatal("Manager unwilling", &UnwillingMessage); 798 break; 799 case ACCEPT: 800 recv_accept_msg(header.length); 801 break; 802 case DECLINE: 803 recv_decline_msg(header.length); 804 break; 805 case REFUSE: 806 recv_refuse_msg(header.length); 807 break; 808 case FAILED: 809 recv_failed_msg(header.length); 810 break; 811 case ALIVE: 812 recv_alive_msg(header.length); 813 break; 814 } 815} 816 817/* 818 * send the appropriate message given the current state 819 */ 820 821static void 822send_packet(void) 823{ 824 int rtx; 825 switch (state) { 826 case XDM_QUERY: 827 case XDM_BROADCAST: 828 case XDM_INDIRECT: 829#if defined(IPv6) && defined(AF_INET6) 830 case XDM_MULTICAST: 831#endif 832 send_query_msg(); 833 break; 834 case XDM_START_CONNECTION: 835 send_request_msg(); 836 break; 837 case XDM_MANAGE: 838 send_manage_msg(); 839 break; 840 case XDM_KEEPALIVE: 841 send_keepalive_msg(); 842 break; 843 default: 844 break; 845 } 846 rtx = (XDM_MIN_RTX << timeOutRtx); 847 if (rtx > XDM_MAX_RTX) 848 rtx = XDM_MAX_RTX; 849 timeOutTime = GetTimeInMillis() + rtx * 1000; 850} 851 852/* 853 * The session is declared dead for some reason; too many 854 * timeouts, or Keepalive failure. 855 */ 856 857static void 858XdmcpDeadSession (char *reason) 859{ 860 ErrorF ("XDM: %s, declaring session dead\n", reason); 861 state = XDM_INIT_STATE; 862 isItTimeToYield = TRUE; 863 dispatchException |= DE_RESET; 864 timeOutTime = 0; 865 timeOutRtx = 0; 866 send_packet(); 867} 868 869/* 870 * Timeout waiting for an XDMCP response. 871 */ 872 873static void 874timeout(void) 875{ 876 timeOutRtx++; 877 if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT ) 878 { 879 XdmcpDeadSession ("too many keepalive retransmissions"); 880 return; 881 } 882 else if (timeOutRtx >= XDM_RTX_LIMIT) 883 { 884 /* Quit if "-once" specified, otherwise reset and try again. */ 885 if (OneSession) { 886 dispatchException |= DE_TERMINATE; 887 ErrorF("XDM: too many retransmissions\n"); 888 } else { 889 XdmcpDeadSession("too many retransmissions"); 890 } 891 return; 892 } 893 894#if defined(IPv6) && defined(AF_INET6) 895 if (state == XDM_COLLECT_QUERY || state == XDM_COLLECT_INDIRECT_QUERY) { 896 /* Try next address */ 897 for (mgrAddr = mgrAddr->ai_next; ; mgrAddr = mgrAddr->ai_next) { 898 if (mgrAddr == NULL) { 899 mgrAddr = mgrAddrFirst; 900 } 901 if (mgrAddr->ai_family == AF_INET 902 || mgrAddr->ai_family == AF_INET6) 903 break; 904 } 905#ifndef SIN6_LEN 906 ManagerAddressLen = mgrAddr->ai_addrlen; 907#endif 908 memcpy(&ManagerAddress, mgrAddr->ai_addr, mgrAddr->ai_addrlen); 909 } 910#endif 911 912 switch (state) { 913 case XDM_COLLECT_QUERY: 914 state = XDM_QUERY; 915 break; 916 case XDM_COLLECT_BROADCAST_QUERY: 917 state = XDM_BROADCAST; 918 break; 919#if defined(IPv6) && defined(AF_INET6) 920 case XDM_COLLECT_MULTICAST_QUERY: 921 state = XDM_MULTICAST; 922 break; 923#endif 924 case XDM_COLLECT_INDIRECT_QUERY: 925 state = XDM_INDIRECT; 926 break; 927 case XDM_AWAIT_REQUEST_RESPONSE: 928 state = XDM_START_CONNECTION; 929 break; 930 case XDM_AWAIT_MANAGE_RESPONSE: 931 state = XDM_MANAGE; 932 break; 933 case XDM_AWAIT_ALIVE_RESPONSE: 934 state = XDM_KEEPALIVE; 935 break; 936 default: 937 break; 938 } 939 send_packet(); 940} 941 942static void 943restart(void) 944{ 945 state = XDM_INIT_STATE; 946 timeOutRtx = 0; 947 send_packet(); 948} 949 950static int 951XdmcpCheckAuthentication (ARRAY8Ptr Name, ARRAY8Ptr Data, int packet_type) 952{ 953 return (XdmcpARRAY8Equal (Name, AuthenticationName) && 954 (AuthenticationName->length == 0 || 955 (*AuthenticationFuncs->Validator) (AuthenticationData, Data, packet_type))); 956} 957 958static int 959XdmcpAddAuthorization (ARRAY8Ptr name, ARRAY8Ptr data) 960{ 961 AddAuthorFunc AddAuth; 962 963 if (AuthenticationFuncs && AuthenticationFuncs->AddAuth) 964 AddAuth = AuthenticationFuncs->AddAuth; 965 else 966 AddAuth = AddAuthorization; 967 return (*AddAuth) ((unsigned short)name->length, 968 (char *)name->data, 969 (unsigned short)data->length, 970 (char *)data->data); 971} 972 973/* 974 * from here to the end of this file are routines private 975 * to the state machine. 976 */ 977 978static void 979get_xdmcp_sock(void) 980{ 981#ifdef STREAMSCONN 982 struct netconfig *nconf; 983 984 if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) { 985 XdmcpWarning("t_open() of /dev/udp failed"); 986 return; 987 } 988 989 if( t_bind(xdmcpSocket,NULL,NULL) < 0 ) { 990 XdmcpWarning("UDP socket creation failed"); 991 t_error("t_bind(xdmcpSocket) failed" ); 992 t_close(xdmcpSocket); 993 return; 994 } 995 996 /* 997 * This part of the code looks contrived. It will actually fit in nicely 998 * when the CLTS part of Xtrans is implemented. 999 */ 1000 1001 if( (nconf=getnetconfigent("udp")) == NULL ) { 1002 XdmcpWarning("UDP socket creation failed: getnetconfigent()"); 1003 t_unbind(xdmcpSocket); 1004 t_close(xdmcpSocket); 1005 return; 1006 } 1007 1008 if( netdir_options(nconf, ND_SET_BROADCAST, xdmcpSocket, NULL) ) { 1009 XdmcpWarning("UDP set broadcast option failed: netdir_options()"); 1010 freenetconfigent(nconf); 1011 t_unbind(xdmcpSocket); 1012 t_close(xdmcpSocket); 1013 return; 1014 } 1015 1016 freenetconfigent(nconf); 1017#else 1018 int soopts = 1; 1019 1020#if defined(IPv6) && defined(AF_INET6) 1021 if ((xdmcpSocket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1022 XdmcpWarning("INET6 UDP socket creation failed"); 1023#endif 1024 if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1025 XdmcpWarning("UDP socket creation failed"); 1026#ifdef SO_BROADCAST 1027 else if (setsockopt(xdmcpSocket, SOL_SOCKET, SO_BROADCAST, (char *)&soopts, 1028 sizeof(soopts)) < 0) 1029 XdmcpWarning("UDP set broadcast socket-option failed"); 1030#endif /* SO_BROADCAST */ 1031 if (xdmcpSocket >= 0 && xdm_from != NULL) { 1032 if (bind(xdmcpSocket, (struct sockaddr *)&FromAddress, 1033 FromAddressLen) < 0) { 1034 FatalError("Xserver: failed to bind to -from address: %s\n", xdm_from); 1035 } 1036 } 1037#endif /* STREAMSCONN */ 1038} 1039 1040static void 1041send_query_msg(void) 1042{ 1043 XdmcpHeader header; 1044 Bool broadcast = FALSE; 1045#if defined(IPv6) && defined(AF_INET6) 1046 Bool multicast = FALSE; 1047#endif 1048 int i; 1049 int socketfd = xdmcpSocket; 1050 1051 header.version = XDM_PROTOCOL_VERSION; 1052 switch(state){ 1053 case XDM_QUERY: 1054 header.opcode = (CARD16) QUERY; 1055 state = XDM_COLLECT_QUERY; 1056 break; 1057 case XDM_BROADCAST: 1058 header.opcode = (CARD16) BROADCAST_QUERY; 1059 state = XDM_COLLECT_BROADCAST_QUERY; 1060 broadcast = TRUE; 1061 break; 1062#if defined(IPv6) && defined(AF_INET6) 1063 case XDM_MULTICAST: 1064 header.opcode = (CARD16) BROADCAST_QUERY; 1065 state = XDM_COLLECT_MULTICAST_QUERY; 1066 multicast = TRUE; 1067 break; 1068#endif 1069 case XDM_INDIRECT: 1070 header.opcode = (CARD16) INDIRECT_QUERY; 1071 state = XDM_COLLECT_INDIRECT_QUERY; 1072 break; 1073 default: 1074 break; 1075 } 1076 header.length = 1; 1077 for (i = 0; i < AuthenticationNames.length; i++) 1078 header.length += 2 + AuthenticationNames.data[i].length; 1079 1080 XdmcpWriteHeader (&buffer, &header); 1081 XdmcpWriteARRAYofARRAY8 (&buffer, &AuthenticationNames); 1082 if (broadcast) 1083 { 1084 int i; 1085 1086 for (i = 0; i < NumBroadcastAddresses; i++) 1087 XdmcpFlush (xdmcpSocket, &buffer, (XdmcpNetaddr) &BroadcastAddresses[i], 1088 sizeof (struct sockaddr_in)); 1089 } 1090#if defined(IPv6) && defined(AF_INET6) 1091 else if (multicast) 1092 { 1093 struct multicastinfo *mcl; 1094 struct addrinfo *ai; 1095 1096 for (mcl = mcastlist; mcl != NULL; mcl = mcl->next) { 1097 for (ai = mcl->ai ; ai != NULL; ai = ai->ai_next) { 1098 if (ai->ai_family == AF_INET) { 1099 unsigned char hopflag = (unsigned char) mcl->hops; 1100 socketfd = xdmcpSocket; 1101 setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_TTL, 1102 &hopflag, sizeof(hopflag)); 1103 } else if (ai->ai_family == AF_INET6) { 1104 int hopflag6 = mcl->hops; 1105 socketfd = xdmcpSocket6; 1106 setsockopt(socketfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1107 &hopflag6, sizeof(hopflag6)); 1108 } else { 1109 continue; 1110 } 1111 XdmcpFlush (socketfd, &buffer, 1112 (XdmcpNetaddr) ai->ai_addr, ai->ai_addrlen); 1113 break; 1114 } 1115 } 1116 } 1117#endif 1118 else 1119 { 1120#if defined(IPv6) && defined(AF_INET6) 1121 if (SOCKADDR_FAMILY(ManagerAddress) == AF_INET6) 1122 socketfd = xdmcpSocket6; 1123#endif 1124 XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &ManagerAddress, 1125 ManagerAddressLen); 1126 } 1127} 1128 1129static void 1130recv_willing_msg( 1131 struct sockaddr *from, 1132 int fromlen, 1133 unsigned length) 1134{ 1135 ARRAY8 authenticationName; 1136 ARRAY8 hostname; 1137 ARRAY8 status; 1138 1139 authenticationName.data = 0; 1140 hostname.data = 0; 1141 status.data = 0; 1142 if (XdmcpReadARRAY8 (&buffer, &authenticationName) && 1143 XdmcpReadARRAY8 (&buffer, &hostname) && 1144 XdmcpReadARRAY8 (&buffer, &status)) 1145 { 1146 if (length == 6 + authenticationName.length + 1147 hostname.length + status.length) 1148 { 1149 switch (state) 1150 { 1151 case XDM_COLLECT_QUERY: 1152 XdmcpSelectHost(from, fromlen, &authenticationName); 1153 break; 1154 case XDM_COLLECT_BROADCAST_QUERY: 1155#if defined(IPv6) && defined(AF_INET6) 1156 case XDM_COLLECT_MULTICAST_QUERY: 1157#endif 1158 case XDM_COLLECT_INDIRECT_QUERY: 1159 XdmcpAddHost(from, fromlen, &authenticationName, &hostname, &status); 1160 break; 1161 default: 1162 break; 1163 } 1164 } 1165 } 1166 XdmcpDisposeARRAY8 (&authenticationName); 1167 XdmcpDisposeARRAY8 (&hostname); 1168 XdmcpDisposeARRAY8 (&status); 1169} 1170 1171static void 1172send_request_msg(void) 1173{ 1174 XdmcpHeader header; 1175 int length; 1176 int i; 1177 CARD16 XdmcpConnectionType; 1178 ARRAY8 authenticationData; 1179 int socketfd = xdmcpSocket; 1180 1181 switch (SOCKADDR_FAMILY(ManagerAddress)) 1182 { 1183 case AF_INET: XdmcpConnectionType=FamilyInternet; break; 1184#if defined(IPv6) && defined(AF_INET6) 1185 case AF_INET6: XdmcpConnectionType=FamilyInternet6; break; 1186#endif 1187 default: XdmcpConnectionType=0xffff; break; 1188 } 1189 1190 header.version = XDM_PROTOCOL_VERSION; 1191 header.opcode = (CARD16) REQUEST; 1192 1193 length = 2; /* display number */ 1194 length += 1 + 2 * ConnectionTypes.length; /* connection types */ 1195 length += 1; /* connection addresses */ 1196 for (i = 0; i < ConnectionAddresses.length; i++) 1197 length += 2 + ConnectionAddresses.data[i].length; 1198 authenticationData.length = 0; 1199 authenticationData.data = 0; 1200 if (AuthenticationFuncs) 1201 { 1202 (*AuthenticationFuncs->Generator) (AuthenticationData, 1203 &authenticationData, 1204 REQUEST); 1205 } 1206 length += 2 + AuthenticationName->length; /* authentication name */ 1207 length += 2 + authenticationData.length; /* authentication data */ 1208 length += 1; /* authorization names */ 1209 for (i = 0; i < AuthorizationNames.length; i++) 1210 length += 2 + AuthorizationNames.data[i].length; 1211 length += 2 + ManufacturerDisplayID.length; /* display ID */ 1212 header.length = length; 1213 1214 if (!XdmcpWriteHeader (&buffer, &header)) 1215 { 1216 XdmcpDisposeARRAY8 (&authenticationData); 1217 return; 1218 } 1219 XdmcpWriteCARD16 (&buffer, DisplayNumber); 1220 XdmcpWriteCARD8 (&buffer, ConnectionTypes.length); 1221 1222 /* The connection array is send reordered, so that connections of */ 1223 /* the same address type as the XDMCP manager connection are send */ 1224 /* first. This works around a bug in xdm. mario@klebsch.de */ 1225 for (i = 0; i < (int)ConnectionTypes.length; i++) 1226 if (ConnectionTypes.data[i]==XdmcpConnectionType) 1227 XdmcpWriteCARD16 (&buffer, ConnectionTypes.data[i]); 1228 for (i = 0; i < (int)ConnectionTypes.length; i++) 1229 if (ConnectionTypes.data[i]!=XdmcpConnectionType) 1230 XdmcpWriteCARD16 (&buffer, ConnectionTypes.data[i]); 1231 1232 XdmcpWriteCARD8 (&buffer, ConnectionAddresses.length); 1233 for (i = 0; i < (int)ConnectionAddresses.length; i++) 1234 if ( (i<ConnectionTypes.length) && 1235 (ConnectionTypes.data[i]==XdmcpConnectionType) ) 1236 XdmcpWriteARRAY8 (&buffer, &ConnectionAddresses.data[i]); 1237 for (i = 0; i < (int)ConnectionAddresses.length; i++) 1238 if ( (i>=ConnectionTypes.length) || 1239 (ConnectionTypes.data[i]!=XdmcpConnectionType) ) 1240 XdmcpWriteARRAY8 (&buffer, &ConnectionAddresses.data[i]); 1241 1242 XdmcpWriteARRAY8 (&buffer, AuthenticationName); 1243 XdmcpWriteARRAY8 (&buffer, &authenticationData); 1244 XdmcpDisposeARRAY8 (&authenticationData); 1245 XdmcpWriteARRAYofARRAY8 (&buffer, &AuthorizationNames); 1246 XdmcpWriteARRAY8 (&buffer, &ManufacturerDisplayID); 1247#if defined(IPv6) && defined(AF_INET6) 1248 if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6) 1249 socketfd = xdmcpSocket6; 1250#endif 1251 if (XdmcpFlush (socketfd, &buffer, 1252 (XdmcpNetaddr) &req_sockaddr, req_socklen)) 1253 state = XDM_AWAIT_REQUEST_RESPONSE; 1254} 1255 1256static void 1257recv_accept_msg(unsigned length) 1258{ 1259 CARD32 AcceptSessionID; 1260 ARRAY8 AcceptAuthenticationName, AcceptAuthenticationData; 1261 ARRAY8 AcceptAuthorizationName, AcceptAuthorizationData; 1262 1263 if (state != XDM_AWAIT_REQUEST_RESPONSE) 1264 return; 1265 AcceptAuthenticationName.data = 0; 1266 AcceptAuthenticationData.data = 0; 1267 AcceptAuthorizationName.data = 0; 1268 AcceptAuthorizationData.data = 0; 1269 if (XdmcpReadCARD32 (&buffer, &AcceptSessionID) && 1270 XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationName) && 1271 XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationData) && 1272 XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationName) && 1273 XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationData)) 1274 { 1275 if (length == 12 + AcceptAuthenticationName.length + 1276 AcceptAuthenticationData.length + 1277 AcceptAuthorizationName.length + 1278 AcceptAuthorizationData.length) 1279 { 1280 if (!XdmcpCheckAuthentication (&AcceptAuthenticationName, 1281 &AcceptAuthenticationData, ACCEPT)) 1282 { 1283 XdmcpFatal ("Authentication Failure", &AcceptAuthenticationName); 1284 } 1285 /* permit access control manipulations from this host */ 1286 AugmentSelf (&req_sockaddr, req_socklen); 1287 /* if the authorization specified in the packet fails 1288 * to be acceptable, enable the local addresses 1289 */ 1290 if (!XdmcpAddAuthorization (&AcceptAuthorizationName, 1291 &AcceptAuthorizationData)) 1292 { 1293 AddLocalHosts (); 1294 } 1295 SessionID = AcceptSessionID; 1296 state = XDM_MANAGE; 1297 send_packet(); 1298 } 1299 } 1300 XdmcpDisposeARRAY8 (&AcceptAuthenticationName); 1301 XdmcpDisposeARRAY8 (&AcceptAuthenticationData); 1302 XdmcpDisposeARRAY8 (&AcceptAuthorizationName); 1303 XdmcpDisposeARRAY8 (&AcceptAuthorizationData); 1304} 1305 1306static void 1307recv_decline_msg(unsigned length) 1308{ 1309 ARRAY8 status, DeclineAuthenticationName, DeclineAuthenticationData; 1310 1311 status.data = 0; 1312 DeclineAuthenticationName.data = 0; 1313 DeclineAuthenticationData.data = 0; 1314 if (XdmcpReadARRAY8 (&buffer, &status) && 1315 XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationName) && 1316 XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationData)) 1317 { 1318 if (length == 6 + status.length + 1319 DeclineAuthenticationName.length + 1320 DeclineAuthenticationData.length && 1321 XdmcpCheckAuthentication (&DeclineAuthenticationName, 1322 &DeclineAuthenticationData, DECLINE)) 1323 { 1324 XdmcpFatal ("Session declined", &status); 1325 } 1326 } 1327 XdmcpDisposeARRAY8 (&status); 1328 XdmcpDisposeARRAY8 (&DeclineAuthenticationName); 1329 XdmcpDisposeARRAY8 (&DeclineAuthenticationData); 1330} 1331 1332static void 1333send_manage_msg(void) 1334{ 1335 XdmcpHeader header; 1336 int socketfd = xdmcpSocket; 1337 1338 header.version = XDM_PROTOCOL_VERSION; 1339 header.opcode = (CARD16) MANAGE; 1340 header.length = 8 + DisplayClass.length; 1341 1342 if (!XdmcpWriteHeader (&buffer, &header)) 1343 return; 1344 XdmcpWriteCARD32 (&buffer, SessionID); 1345 XdmcpWriteCARD16 (&buffer, DisplayNumber); 1346 XdmcpWriteARRAY8 (&buffer, &DisplayClass); 1347 state = XDM_AWAIT_MANAGE_RESPONSE; 1348#if defined(IPv6) && defined(AF_INET6) 1349 if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6) 1350 socketfd = xdmcpSocket6; 1351#endif 1352 XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen); 1353} 1354 1355static void 1356recv_refuse_msg(unsigned length) 1357{ 1358 CARD32 RefusedSessionID; 1359 1360 if (state != XDM_AWAIT_MANAGE_RESPONSE) 1361 return; 1362 if (length != 4) 1363 return; 1364 if (XdmcpReadCARD32 (&buffer, &RefusedSessionID)) 1365 { 1366 if (RefusedSessionID == SessionID) 1367 { 1368 state = XDM_START_CONNECTION; 1369 send_packet(); 1370 } 1371 } 1372} 1373 1374static void 1375recv_failed_msg(unsigned length) 1376{ 1377 CARD32 FailedSessionID; 1378 ARRAY8 status; 1379 1380 if (state != XDM_AWAIT_MANAGE_RESPONSE) 1381 return; 1382 status.data = 0; 1383 if (XdmcpReadCARD32 (&buffer, &FailedSessionID) && 1384 XdmcpReadARRAY8 (&buffer, &status)) 1385 { 1386 if (length == 6 + status.length && 1387 SessionID == FailedSessionID) 1388 { 1389 XdmcpFatal ("Session failed", &status); 1390 } 1391 } 1392 XdmcpDisposeARRAY8 (&status); 1393} 1394 1395static void 1396send_keepalive_msg(void) 1397{ 1398 XdmcpHeader header; 1399 int socketfd = xdmcpSocket; 1400 1401 header.version = XDM_PROTOCOL_VERSION; 1402 header.opcode = (CARD16) KEEPALIVE; 1403 header.length = 6; 1404 1405 XdmcpWriteHeader (&buffer, &header); 1406 XdmcpWriteCARD16 (&buffer, DisplayNumber); 1407 XdmcpWriteCARD32 (&buffer, SessionID); 1408 1409 state = XDM_AWAIT_ALIVE_RESPONSE; 1410#if defined(IPv6) && defined(AF_INET6) 1411 if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6) 1412 socketfd = xdmcpSocket6; 1413#endif 1414 XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen); 1415} 1416 1417static void 1418recv_alive_msg (unsigned length) 1419{ 1420 CARD8 SessionRunning; 1421 CARD32 AliveSessionID; 1422 1423 if (state != XDM_AWAIT_ALIVE_RESPONSE) 1424 return; 1425 if (length != 5) 1426 return; 1427 if (XdmcpReadCARD8 (&buffer, &SessionRunning) && 1428 XdmcpReadCARD32 (&buffer, &AliveSessionID)) 1429 { 1430 if (SessionRunning && AliveSessionID == SessionID) 1431 { 1432 /* backoff dormancy period */ 1433 state = XDM_RUN_SESSION; 1434 if ((GetTimeInMillis() - lastDeviceEventTime.milliseconds) > 1435 keepaliveDormancy * 1000) 1436 { 1437 keepaliveDormancy <<= 1; 1438 if (keepaliveDormancy > XDM_MAX_DORMANCY) 1439 keepaliveDormancy = XDM_MAX_DORMANCY; 1440 } 1441 timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000; 1442 } 1443 else 1444 { 1445 XdmcpDeadSession ("Alive response indicates session dead"); 1446 } 1447 } 1448} 1449 1450static void 1451XdmcpFatal ( 1452 char *type, 1453 ARRAY8Ptr status) 1454{ 1455 FatalError ("XDMCP fatal error: %s %*.*s\n", type, 1456 status->length, status->length, status->data); 1457} 1458 1459static void 1460XdmcpWarning(char *str) 1461{ 1462 ErrorF("XDMCP warning: %s\n", str); 1463} 1464 1465static void 1466get_addr_by_name( 1467 char * argtype, 1468 char * namestr, 1469 int port, 1470 int socktype, 1471 SOCKADDR_TYPE *addr, 1472 SOCKLEN_TYPE *addrlen 1473#if defined(IPv6) && defined(AF_INET6) 1474 , 1475 struct addrinfo **aip, 1476 struct addrinfo **aifirstp 1477#endif 1478 ) 1479{ 1480#if defined(IPv6) && defined(AF_INET6) 1481 struct addrinfo *ai; 1482 struct addrinfo hints; 1483 char portstr[6]; 1484 char *pport = portstr; 1485 int gaierr; 1486 1487 bzero(&hints, sizeof(hints)); 1488 hints.ai_socktype = socktype; 1489 1490 if (port == 0) { 1491 pport = NULL; 1492 } else if (port > 0 && port < 65535) { 1493 sprintf(portstr, "%d", port); 1494 } else { 1495 FatalError("Xserver: port out of range: %d\n", port); 1496 } 1497 1498 if (*aifirstp != NULL) { 1499 freeaddrinfo(*aifirstp); 1500 *aifirstp = NULL; 1501 } 1502 1503 if ((gaierr = getaddrinfo(namestr, pport, &hints, aifirstp)) == 0) { 1504 for (ai = *aifirstp; ai != NULL; ai = ai->ai_next) { 1505 if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) 1506 break; 1507 } 1508 if ((ai == NULL) || (ai->ai_addrlen > sizeof(SOCKADDR_TYPE))) { 1509 FatalError ("Xserver: %s host %s not on supported network type\n", 1510 argtype, namestr); 1511 } else { 1512 *aip = ai; 1513 *addrlen = ai->ai_addrlen; 1514 memcpy(addr, ai->ai_addr, ai->ai_addrlen); 1515 } 1516 } else { 1517 FatalError("Xserver: %s: %s %s\n", gai_strerror(gaierr), argtype, namestr); 1518 } 1519#else 1520 struct hostent *hep; 1521#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 1522 _Xgethostbynameparams hparams; 1523#endif 1524#if defined(WIN32) && (defined(TCPCONN) || defined(DNETCONN)) 1525 _XSERVTransWSAStartup(); 1526#endif 1527 if (!(hep = _XGethostbyname(namestr, hparams))) 1528 { 1529 FatalError("Xserver: %s unknown host: %s\n", argtype, namestr); 1530 } 1531 if (hep->h_length == sizeof (struct in_addr)) 1532 { 1533 memmove(&addr->sin_addr, hep->h_addr, hep->h_length); 1534 *addrlen = sizeof(struct sockaddr_in); 1535 addr->sin_family = AF_INET; 1536 addr->sin_port = htons (port); 1537 } 1538 else 1539 { 1540 FatalError("Xserver: %s host on strange network %s\n", argtype, namestr); 1541 } 1542#endif 1543} 1544 1545static void 1546get_manager_by_name( 1547 int argc, 1548 char **argv, 1549 int i) 1550{ 1551 1552 if ((i + 1) == argc) 1553 { 1554 FatalError("Xserver: missing %s host name in command line\n", argv[i]); 1555 } 1556 1557 get_addr_by_name(argv[i], argv[i+1], xdm_udp_port, SOCK_DGRAM, 1558 &ManagerAddress, &ManagerAddressLen 1559#if defined(IPv6) && defined(AF_INET6) 1560 , &mgrAddr, &mgrAddrFirst 1561#endif 1562 ); 1563} 1564 1565 1566static void 1567get_fromaddr_by_name( 1568 int argc, 1569 char **argv, 1570 int i) 1571{ 1572#if defined(IPv6) && defined(AF_INET6) 1573 struct addrinfo *ai = NULL; 1574 struct addrinfo *aifirst = NULL; 1575#endif 1576 if (i == argc) 1577 { 1578 FatalError("Xserver: missing -from host name in command line\n"); 1579 } 1580 get_addr_by_name("-from", argv[i], 0, 0, &FromAddress, &FromAddressLen 1581#if defined(IPv6) && defined(AF_INET6) 1582 , &ai, &aifirst 1583#endif 1584 ); 1585#if defined(IPv6) && defined(AF_INET6) 1586 if (aifirst != NULL) 1587 freeaddrinfo(aifirst); 1588#endif 1589 xdm_from = argv[i]; 1590} 1591 1592 1593#if defined(IPv6) && defined(AF_INET6) 1594static int 1595get_mcast_options(argc, argv, i) 1596 int argc, i; 1597 char **argv; 1598{ 1599 char *address = XDM_DEFAULT_MCAST_ADDR6; 1600 int hopcount = 1; 1601 struct addrinfo hints; 1602 char portstr[6]; 1603 int gaierr; 1604 struct addrinfo *ai, *firstai; 1605 1606 if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) { 1607 address = argv[i++]; 1608 if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) { 1609 hopcount = strtol(argv[i++], NULL, 10); 1610 if ((hopcount < 1) || (hopcount > 255)) { 1611 FatalError("Xserver: multicast hop count out of range: %d\n", 1612 hopcount); 1613 } 1614 } 1615 } 1616 1617 if (xdm_udp_port > 0 && xdm_udp_port < 65535) { 1618 sprintf(portstr, "%d", xdm_udp_port); 1619 } else { 1620 FatalError("Xserver: port out of range: %d\n", xdm_udp_port); 1621 } 1622 bzero(&hints, sizeof(hints)); 1623 hints.ai_socktype = SOCK_DGRAM; 1624 1625 if ((gaierr = getaddrinfo(address, portstr, &hints, &firstai)) == 0) { 1626 for (ai = firstai; ai != NULL; ai = ai->ai_next) { 1627 if (((ai->ai_family == AF_INET) && 1628 IN_MULTICAST(((struct sockaddr_in *) ai->ai_addr) 1629 ->sin_addr.s_addr)) 1630 || ((ai->ai_family == AF_INET6) && 1631 IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *) ai->ai_addr) 1632 ->sin6_addr))) 1633 break; 1634 } 1635 if (ai == NULL) { 1636 FatalError ("Xserver: address not supported multicast type %s\n", 1637 address); 1638 } else { 1639 struct multicastinfo *mcastinfo, *mcl; 1640 1641 mcastinfo = malloc(sizeof(struct multicastinfo)); 1642 mcastinfo->next = NULL; 1643 mcastinfo->ai = firstai; 1644 mcastinfo->hops = hopcount; 1645 1646 if (mcastlist == NULL) { 1647 mcastlist = mcastinfo; 1648 } else { 1649 for (mcl = mcastlist; mcl->next != NULL; mcl = mcl->next) { 1650 /* Do nothing - just find end of list */ 1651 } 1652 mcl->next = mcastinfo; 1653 } 1654 } 1655 } else { 1656 FatalError("Xserver: %s: %s\n", gai_strerror(gaierr), address); 1657 } 1658 return i; 1659} 1660#endif 1661 1662#else 1663static int xdmcp_non_empty; /* avoid complaint by ranlib */ 1664#endif /* XDMCP */ 1665