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