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