9838b7032e
This is strictly the application of the script 'x-indent-all.sh' from util/modular. Compared to the patch that Daniel posted in January, I've added a few indent flags: -bap -psl -T PrivatePtr -T pmWait -T _XFUNCPROTOBEGIN -T _XFUNCPROTOEND -T _X_EXPORT The typedefs were needed to make the output of sdksyms.sh match the previous output, otherwise, the code is formatted badly enough that sdksyms.sh generates incorrect output. The generated code was compared with the previous version and found to be essentially identical -- "assert" line numbers and BUILD_TIME were the only differences found. The comparison was done with this script: dir1=$1 dir2=$2 for dir in $dir1 $dir2; do (cd $dir && find . -name '*.o' | while read file; do dir=`dirname $file` base=`basename $file .o` dump=$dir/$base.dump objdump -d $file > $dump done) done find $dir1 -name '*.dump' | while read dump; do otherdump=`echo $dump | sed "s;$dir1;$dir2;"` diff -u $dump $otherdump done Signed-off-by: Keith Packard <keithp@keithp.com> Acked-by: Daniel Stone <daniel@fooishbar.org> Acked-by: Alan Coopersmith <alan.coopersmith@oracle.com>
1612 lines
46 KiB
C
1612 lines
46 KiB
C
/*
|
|
* Copyright 1989 Network Computing Devices, Inc., Mountain View, California.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software and its
|
|
* documentation for any purpose and without fee is hereby granted, provided
|
|
* that the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting
|
|
* documentation, and that the name of N.C.D. not be used in advertising or
|
|
* publicity pertaining to distribution of the software without specific,
|
|
* written prior permission. N.C.D. makes no representations about the
|
|
* suitability of this software for any purpose. It is provided "as is"
|
|
* without express or implied warranty.
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#include <X11/Xwinsock.h>
|
|
#endif
|
|
|
|
#include <X11/Xos.h>
|
|
|
|
#if !defined(WIN32)
|
|
#include <sys/param.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netdb.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <X11/X.h>
|
|
#include <X11/Xmd.h>
|
|
#include "misc.h"
|
|
#include <X11/Xpoll.h>
|
|
#include "osdep.h"
|
|
#include "input.h"
|
|
#include "dixstruct.h"
|
|
#include "opaque.h"
|
|
#include "site.h"
|
|
|
|
#ifdef STREAMSCONN
|
|
#include <tiuser.h>
|
|
#include <netconfig.h>
|
|
#include <netdir.h>
|
|
#endif
|
|
|
|
#ifdef XDMCP
|
|
#undef REQUEST
|
|
|
|
#ifdef XDMCP_NO_IPV6
|
|
#undef IPv6
|
|
#endif
|
|
|
|
#include <X11/Xdmcp.h>
|
|
|
|
#define X_INCLUDE_NETDB_H
|
|
#include <X11/Xos_r.h>
|
|
|
|
static const char *defaultDisplayClass = COMPILEDDISPLAYCLASS;
|
|
|
|
static int xdmcpSocket, sessionSocket;
|
|
static xdmcp_states state;
|
|
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
static int xdmcpSocket6;
|
|
static struct sockaddr_storage req_sockaddr;
|
|
#else
|
|
static struct sockaddr_in req_sockaddr;
|
|
#endif
|
|
static int req_socklen;
|
|
static CARD32 SessionID;
|
|
static CARD32 timeOutTime;
|
|
static int timeOutRtx;
|
|
static CARD32 defaultKeepaliveDormancy = XDM_DEF_DORMANCY;
|
|
static CARD32 keepaliveDormancy = XDM_DEF_DORMANCY;
|
|
static CARD16 DisplayNumber;
|
|
static xdmcp_states XDM_INIT_STATE = XDM_OFF;
|
|
|
|
#ifdef HASXDMAUTH
|
|
static char *xdmAuthCookie;
|
|
#endif
|
|
|
|
static XdmcpBuffer buffer;
|
|
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
|
|
static struct addrinfo *mgrAddr;
|
|
static struct addrinfo *mgrAddrFirst;
|
|
|
|
#define SOCKADDR_TYPE struct sockaddr_storage
|
|
#define SOCKADDR_FAMILY(s) ((struct sockaddr *)&(s))->sa_family
|
|
|
|
#ifdef BSD44SOCKETS
|
|
#define SOCKLEN_FIELD(s) ((struct sockaddr *)&(s))->sa_len
|
|
#define SOCKLEN_TYPE unsigned char
|
|
#else
|
|
#define SOCKLEN_TYPE unsigned int
|
|
#endif
|
|
|
|
#else
|
|
|
|
#define SOCKADDR_TYPE struct sockaddr_in
|
|
#define SOCKADDR_FAMILY(s) (s).sin_family
|
|
|
|
#ifdef BSD44SOCKETS
|
|
#define SOCKLEN_FIELD(s) (s).sin_len
|
|
#define SOCKLEN_TYPE unsigned char
|
|
#else
|
|
#define SOCKLEN_TYPE size_t
|
|
#endif
|
|
|
|
#endif
|
|
|
|
static SOCKADDR_TYPE ManagerAddress;
|
|
static SOCKADDR_TYPE FromAddress;
|
|
|
|
#ifdef SOCKLEN_FIELD
|
|
#define ManagerAddressLen SOCKLEN_FIELD(ManagerAddress)
|
|
#define FromAddressLen SOCKLEN_FIELD(FromAddress)
|
|
#else
|
|
static SOCKLEN_TYPE ManagerAddressLen, FromAddressLen;
|
|
#endif
|
|
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
static struct multicastinfo {
|
|
struct multicastinfo *next;
|
|
struct addrinfo *ai;
|
|
int hops;
|
|
} *mcastlist;
|
|
#endif
|
|
|
|
static void XdmcpAddHost(const struct sockaddr *from,
|
|
int fromlen,
|
|
ARRAY8Ptr AuthenticationName,
|
|
ARRAY8Ptr hostname, ARRAY8Ptr status);
|
|
|
|
static void XdmcpSelectHost(const struct sockaddr *host_sockaddr,
|
|
int host_len, ARRAY8Ptr AuthenticationName);
|
|
|
|
static void get_xdmcp_sock(void);
|
|
|
|
static void send_query_msg(void);
|
|
|
|
static void recv_willing_msg(struct sockaddr * /*from */ ,
|
|
int /*fromlen */ ,
|
|
unsigned /*length */ );
|
|
|
|
static void send_request_msg(void);
|
|
|
|
static void recv_accept_msg(unsigned /*length */ );
|
|
|
|
static void recv_decline_msg(unsigned /*length */ );
|
|
|
|
static void send_manage_msg(void);
|
|
|
|
static void recv_refuse_msg(unsigned /*length */ );
|
|
|
|
static void recv_failed_msg(unsigned /*length */ );
|
|
|
|
static void send_keepalive_msg(void);
|
|
|
|
static void recv_alive_msg(unsigned /*length */ );
|
|
|
|
static void XdmcpFatal(const char * /*type */ ,
|
|
ARRAY8Ptr /*status */ );
|
|
|
|
static void XdmcpWarning(const char * /*str */ );
|
|
|
|
static void get_manager_by_name(int /*argc */ ,
|
|
char ** /*argv */ ,
|
|
int /*i */ );
|
|
|
|
static void get_fromaddr_by_name(int /*argc */ , char ** /*argv */ ,
|
|
int /*i */ );
|
|
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
static int get_mcast_options(int /*argc */ , char ** /*argv */ , int /*i */ );
|
|
#endif
|
|
|
|
static void receive_packet(int /*socketfd */ );
|
|
|
|
static void send_packet(void);
|
|
|
|
static void timeout(void);
|
|
|
|
static void restart(void);
|
|
|
|
static void XdmcpBlockHandler(pointer /*data */ ,
|
|
struct timeval ** /*wt */ ,
|
|
pointer /*LastSelectMask */ );
|
|
|
|
static void XdmcpWakeupHandler(pointer /*data */ ,
|
|
int /*i */ ,
|
|
pointer /*LastSelectMask */ );
|
|
|
|
/*
|
|
* Register the Manufacturer display ID
|
|
*/
|
|
|
|
static ARRAY8 ManufacturerDisplayID;
|
|
|
|
static void
|
|
XdmcpRegisterManufacturerDisplayID(const char *name, int length)
|
|
{
|
|
int i;
|
|
|
|
XdmcpDisposeARRAY8(&ManufacturerDisplayID);
|
|
if (!XdmcpAllocARRAY8(&ManufacturerDisplayID, length))
|
|
return;
|
|
for (i = 0; i < length; i++)
|
|
ManufacturerDisplayID.data[i] = (CARD8) name[i];
|
|
}
|
|
|
|
static unsigned short xdm_udp_port = XDM_UDP_PORT;
|
|
static Bool OneSession = FALSE;
|
|
static const char *xdm_from = NULL;
|
|
|
|
void
|
|
XdmcpUseMsg(void)
|
|
{
|
|
ErrorF("-query host-name contact named host for XDMCP\n");
|
|
ErrorF("-broadcast broadcast for XDMCP\n");
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
ErrorF("-multicast [addr [hops]] IPv6 multicast for XDMCP\n");
|
|
#endif
|
|
ErrorF("-indirect host-name contact named host for indirect XDMCP\n");
|
|
ErrorF("-port port-num UDP port number to send messages to\n");
|
|
ErrorF
|
|
("-from local-address specify the local address to connect from\n");
|
|
ErrorF("-once Terminate server after one session\n");
|
|
ErrorF("-class display-class specify display class to send in manage\n");
|
|
#ifdef HASXDMAUTH
|
|
ErrorF("-cookie xdm-auth-bits specify the magic cookie for XDMCP\n");
|
|
#endif
|
|
ErrorF("-displayID display-id manufacturer display ID for request\n");
|
|
}
|
|
|
|
int
|
|
XdmcpOptions(int argc, char **argv, int i)
|
|
{
|
|
if (strcmp(argv[i], "-query") == 0) {
|
|
get_manager_by_name(argc, argv, i++);
|
|
XDM_INIT_STATE = XDM_QUERY;
|
|
AccessUsingXdmcp();
|
|
return i + 1;
|
|
}
|
|
if (strcmp(argv[i], "-broadcast") == 0) {
|
|
XDM_INIT_STATE = XDM_BROADCAST;
|
|
AccessUsingXdmcp();
|
|
return i + 1;
|
|
}
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
if (strcmp(argv[i], "-multicast") == 0) {
|
|
i = get_mcast_options(argc, argv, ++i);
|
|
XDM_INIT_STATE = XDM_MULTICAST;
|
|
AccessUsingXdmcp();
|
|
return i + 1;
|
|
}
|
|
#endif
|
|
if (strcmp(argv[i], "-indirect") == 0) {
|
|
get_manager_by_name(argc, argv, i++);
|
|
XDM_INIT_STATE = XDM_INDIRECT;
|
|
AccessUsingXdmcp();
|
|
return i + 1;
|
|
}
|
|
if (strcmp(argv[i], "-port") == 0) {
|
|
if (++i == argc) {
|
|
FatalError("Xserver: missing port number in command line\n");
|
|
}
|
|
xdm_udp_port = (unsigned short) atoi(argv[i]);
|
|
return i + 1;
|
|
}
|
|
if (strcmp(argv[i], "-from") == 0) {
|
|
get_fromaddr_by_name(argc, argv, ++i);
|
|
return i + 1;
|
|
}
|
|
if (strcmp(argv[i], "-once") == 0) {
|
|
OneSession = TRUE;
|
|
return i + 1;
|
|
}
|
|
if (strcmp(argv[i], "-class") == 0) {
|
|
if (++i == argc) {
|
|
FatalError("Xserver: missing class name in command line\n");
|
|
}
|
|
defaultDisplayClass = argv[i];
|
|
return i + 1;
|
|
}
|
|
#ifdef HASXDMAUTH
|
|
if (strcmp(argv[i], "-cookie") == 0) {
|
|
if (++i == argc) {
|
|
FatalError("Xserver: missing cookie data in command line\n");
|
|
}
|
|
xdmAuthCookie = argv[i];
|
|
return i + 1;
|
|
}
|
|
#endif
|
|
if (strcmp(argv[i], "-displayID") == 0) {
|
|
if (++i == argc) {
|
|
FatalError("Xserver: missing displayID in command line\n");
|
|
}
|
|
XdmcpRegisterManufacturerDisplayID(argv[i], strlen(argv[i]));
|
|
return i + 1;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
* This section is a collection of routines for
|
|
* registering server-specific data with the XDMCP
|
|
* state machine.
|
|
*/
|
|
|
|
/*
|
|
* Save all broadcast addresses away so BroadcastQuery
|
|
* packets get sent everywhere
|
|
*/
|
|
|
|
#define MAX_BROADCAST 10
|
|
|
|
/* This stays sockaddr_in since IPv6 doesn't support broadcast */
|
|
static struct sockaddr_in BroadcastAddresses[MAX_BROADCAST];
|
|
static int NumBroadcastAddresses;
|
|
|
|
void
|
|
XdmcpRegisterBroadcastAddress(const struct sockaddr_in *addr)
|
|
{
|
|
struct sockaddr_in *bcast;
|
|
|
|
if (NumBroadcastAddresses >= MAX_BROADCAST)
|
|
return;
|
|
bcast = &BroadcastAddresses[NumBroadcastAddresses++];
|
|
memset(bcast, 0, sizeof(struct sockaddr_in));
|
|
#ifdef BSD44SOCKETS
|
|
bcast->sin_len = addr->sin_len;
|
|
#endif
|
|
bcast->sin_family = addr->sin_family;
|
|
bcast->sin_port = htons(xdm_udp_port);
|
|
bcast->sin_addr = addr->sin_addr;
|
|
}
|
|
|
|
/*
|
|
* Each authentication type is registered here; Validator
|
|
* will be called to check all access attempts using
|
|
* the specified authentication type
|
|
*/
|
|
|
|
static ARRAYofARRAY8 AuthenticationNames, AuthenticationDatas;
|
|
typedef struct _AuthenticationFuncs {
|
|
ValidatorFunc Validator;
|
|
GeneratorFunc Generator;
|
|
AddAuthorFunc AddAuth;
|
|
} AuthenticationFuncsRec, *AuthenticationFuncsPtr;
|
|
|
|
static AuthenticationFuncsPtr AuthenticationFuncsList;
|
|
|
|
void
|
|
XdmcpRegisterAuthentication(const char *name,
|
|
int namelen,
|
|
const char *data,
|
|
int datalen,
|
|
ValidatorFunc Validator,
|
|
GeneratorFunc Generator, AddAuthorFunc AddAuth)
|
|
{
|
|
int i;
|
|
ARRAY8 AuthenticationName, AuthenticationData;
|
|
static AuthenticationFuncsPtr newFuncs;
|
|
|
|
if (!XdmcpAllocARRAY8(&AuthenticationName, namelen))
|
|
return;
|
|
if (!XdmcpAllocARRAY8(&AuthenticationData, datalen)) {
|
|
XdmcpDisposeARRAY8(&AuthenticationName);
|
|
return;
|
|
}
|
|
for (i = 0; i < namelen; i++)
|
|
AuthenticationName.data[i] = name[i];
|
|
for (i = 0; i < datalen; i++)
|
|
AuthenticationData.data[i] = data[i];
|
|
if (!(XdmcpReallocARRAYofARRAY8(&AuthenticationNames,
|
|
AuthenticationNames.length + 1) &&
|
|
XdmcpReallocARRAYofARRAY8(&AuthenticationDatas,
|
|
AuthenticationDatas.length + 1) &&
|
|
(newFuncs =
|
|
malloc((AuthenticationNames.length +
|
|
1) * sizeof(AuthenticationFuncsRec))))) {
|
|
XdmcpDisposeARRAY8(&AuthenticationName);
|
|
XdmcpDisposeARRAY8(&AuthenticationData);
|
|
return;
|
|
}
|
|
for (i = 0; i < AuthenticationNames.length - 1; i++)
|
|
newFuncs[i] = AuthenticationFuncsList[i];
|
|
newFuncs[AuthenticationNames.length - 1].Validator = Validator;
|
|
newFuncs[AuthenticationNames.length - 1].Generator = Generator;
|
|
newFuncs[AuthenticationNames.length - 1].AddAuth = AddAuth;
|
|
free(AuthenticationFuncsList);
|
|
AuthenticationFuncsList = newFuncs;
|
|
AuthenticationNames.data[AuthenticationNames.length - 1] =
|
|
AuthenticationName;
|
|
AuthenticationDatas.data[AuthenticationDatas.length - 1] =
|
|
AuthenticationData;
|
|
}
|
|
|
|
/*
|
|
* Select the authentication type to be used; this is
|
|
* set by the manager of the host to be connected to.
|
|
*/
|
|
|
|
static ARRAY8 noAuthenticationName = { (CARD16) 0, (CARD8Ptr) 0 };
|
|
static ARRAY8 noAuthenticationData = { (CARD16) 0, (CARD8Ptr) 0 };
|
|
|
|
static ARRAY8Ptr AuthenticationName = &noAuthenticationName;
|
|
static ARRAY8Ptr AuthenticationData = &noAuthenticationData;
|
|
static AuthenticationFuncsPtr AuthenticationFuncs;
|
|
|
|
static void
|
|
XdmcpSetAuthentication(const ARRAY8Ptr name)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < AuthenticationNames.length; i++)
|
|
if (XdmcpARRAY8Equal(&AuthenticationNames.data[i], name)) {
|
|
AuthenticationName = &AuthenticationNames.data[i];
|
|
AuthenticationData = &AuthenticationDatas.data[i];
|
|
AuthenticationFuncs = &AuthenticationFuncsList[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Register the host address for the display
|
|
*/
|
|
|
|
static ARRAY16 ConnectionTypes;
|
|
static ARRAYofARRAY8 ConnectionAddresses;
|
|
static long xdmcpGeneration;
|
|
|
|
void
|
|
XdmcpRegisterConnection(int type, const char *address, int addrlen)
|
|
{
|
|
int i;
|
|
CARD8 *newAddress;
|
|
|
|
if (xdmcpGeneration != serverGeneration) {
|
|
XdmcpDisposeARRAY16(&ConnectionTypes);
|
|
XdmcpDisposeARRAYofARRAY8(&ConnectionAddresses);
|
|
xdmcpGeneration = serverGeneration;
|
|
}
|
|
if (xdm_from != NULL) { /* Only register the requested address */
|
|
const void *regAddr = address;
|
|
const void *fromAddr = NULL;
|
|
int regAddrlen = addrlen;
|
|
|
|
if (addrlen == sizeof(struct in_addr)) {
|
|
if (SOCKADDR_FAMILY(FromAddress) == AF_INET) {
|
|
fromAddr = &((struct sockaddr_in *) &FromAddress)->sin_addr;
|
|
}
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
else if ((SOCKADDR_FAMILY(FromAddress) == AF_INET6) &&
|
|
IN6_IS_ADDR_V4MAPPED(&
|
|
((struct sockaddr_in6 *)
|
|
&FromAddress)->sin6_addr)) {
|
|
fromAddr =
|
|
&((struct sockaddr_in6 *) &FromAddress)->sin6_addr.
|
|
s6_addr[12];
|
|
}
|
|
#endif
|
|
}
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
else if (addrlen == sizeof(struct in6_addr)) {
|
|
if (SOCKADDR_FAMILY(FromAddress) == AF_INET6) {
|
|
fromAddr = &((struct sockaddr_in6 *) &FromAddress)->sin6_addr;
|
|
}
|
|
else if ((SOCKADDR_FAMILY(FromAddress) == AF_INET) &&
|
|
IN6_IS_ADDR_V4MAPPED((const struct in6_addr *) address)) {
|
|
fromAddr = &((struct sockaddr_in *) &FromAddress)->sin_addr;
|
|
regAddr =
|
|
&((struct sockaddr_in6 *) &address)->sin6_addr.s6_addr[12];
|
|
regAddrlen = sizeof(struct in_addr);
|
|
}
|
|
}
|
|
#endif
|
|
if (!fromAddr || memcmp(regAddr, fromAddr, regAddrlen) != 0) {
|
|
return;
|
|
}
|
|
}
|
|
if (ConnectionAddresses.length + 1 == 256)
|
|
return;
|
|
newAddress = malloc(addrlen * sizeof(CARD8));
|
|
if (!newAddress)
|
|
return;
|
|
if (!XdmcpReallocARRAY16(&ConnectionTypes, ConnectionTypes.length + 1)) {
|
|
free(newAddress);
|
|
return;
|
|
}
|
|
if (!XdmcpReallocARRAYofARRAY8(&ConnectionAddresses,
|
|
ConnectionAddresses.length + 1)) {
|
|
free(newAddress);
|
|
return;
|
|
}
|
|
ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type;
|
|
for (i = 0; i < addrlen; i++)
|
|
newAddress[i] = address[i];
|
|
ConnectionAddresses.data[ConnectionAddresses.length - 1].data = newAddress;
|
|
ConnectionAddresses.data[ConnectionAddresses.length - 1].length = addrlen;
|
|
}
|
|
|
|
/*
|
|
* Register an Authorization Name. XDMCP advertises this list
|
|
* to the manager.
|
|
*/
|
|
|
|
static ARRAYofARRAY8 AuthorizationNames;
|
|
|
|
void
|
|
XdmcpRegisterAuthorizations(void)
|
|
{
|
|
XdmcpDisposeARRAYofARRAY8(&AuthorizationNames);
|
|
RegisterAuthorizations();
|
|
}
|
|
|
|
void
|
|
XdmcpRegisterAuthorization(const char *name, int namelen)
|
|
{
|
|
ARRAY8 authName;
|
|
int i;
|
|
|
|
authName.data = malloc(namelen * sizeof(CARD8));
|
|
if (!authName.data)
|
|
return;
|
|
if (!XdmcpReallocARRAYofARRAY8
|
|
(&AuthorizationNames, AuthorizationNames.length + 1)) {
|
|
free(authName.data);
|
|
return;
|
|
}
|
|
for (i = 0; i < namelen; i++)
|
|
authName.data[i] = (CARD8) name[i];
|
|
authName.length = namelen;
|
|
AuthorizationNames.data[AuthorizationNames.length - 1] = authName;
|
|
}
|
|
|
|
/*
|
|
* Register the DisplayClass string
|
|
*/
|
|
|
|
static ARRAY8 DisplayClass;
|
|
|
|
static void
|
|
XdmcpRegisterDisplayClass(const char *name, int length)
|
|
{
|
|
int i;
|
|
|
|
XdmcpDisposeARRAY8(&DisplayClass);
|
|
if (!XdmcpAllocARRAY8(&DisplayClass, length))
|
|
return;
|
|
for (i = 0; i < length; i++)
|
|
DisplayClass.data[i] = (CARD8) name[i];
|
|
}
|
|
|
|
/*
|
|
* initialize XDMCP; create the socket, compute the display
|
|
* number, set up the state machine
|
|
*/
|
|
|
|
void
|
|
XdmcpInit(void)
|
|
{
|
|
state = XDM_INIT_STATE;
|
|
#ifdef HASXDMAUTH
|
|
if (xdmAuthCookie)
|
|
XdmAuthenticationInit(xdmAuthCookie, strlen(xdmAuthCookie));
|
|
#endif
|
|
if (state != XDM_OFF) {
|
|
XdmcpRegisterAuthorizations();
|
|
XdmcpRegisterDisplayClass(defaultDisplayClass,
|
|
strlen(defaultDisplayClass));
|
|
AccessUsingXdmcp();
|
|
RegisterBlockAndWakeupHandlers(XdmcpBlockHandler, XdmcpWakeupHandler,
|
|
(pointer) 0);
|
|
timeOutRtx = 0;
|
|
DisplayNumber = (CARD16) atoi(display);
|
|
get_xdmcp_sock();
|
|
send_packet();
|
|
}
|
|
}
|
|
|
|
void
|
|
XdmcpReset(void)
|
|
{
|
|
state = XDM_INIT_STATE;
|
|
if (state != XDM_OFF) {
|
|
RegisterBlockAndWakeupHandlers(XdmcpBlockHandler, XdmcpWakeupHandler,
|
|
(pointer) 0);
|
|
timeOutRtx = 0;
|
|
send_packet();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Called whenever a new connection is created; notices the
|
|
* first connection and saves it to terminate the session
|
|
* when it is closed
|
|
*/
|
|
|
|
void
|
|
XdmcpOpenDisplay(int sock)
|
|
{
|
|
if (state != XDM_AWAIT_MANAGE_RESPONSE)
|
|
return;
|
|
state = XDM_RUN_SESSION;
|
|
sessionSocket = sock;
|
|
}
|
|
|
|
void
|
|
XdmcpCloseDisplay(int sock)
|
|
{
|
|
if ((state != XDM_RUN_SESSION && state != XDM_AWAIT_ALIVE_RESPONSE)
|
|
|| sessionSocket != sock)
|
|
return;
|
|
state = XDM_INIT_STATE;
|
|
if (OneSession)
|
|
dispatchException |= DE_TERMINATE;
|
|
else
|
|
dispatchException |= DE_RESET;
|
|
isItTimeToYield = TRUE;
|
|
}
|
|
|
|
/*
|
|
* called before going to sleep, this routine
|
|
* may modify the timeout value about to be sent
|
|
* to select; in this way XDMCP can do appropriate things
|
|
* dynamically while starting up
|
|
*/
|
|
|
|
/*ARGSUSED*/ static void
|
|
XdmcpBlockHandler(pointer data, /* unused */
|
|
struct timeval **wt, pointer pReadmask)
|
|
{
|
|
fd_set *LastSelectMask = (fd_set *) pReadmask;
|
|
CARD32 millisToGo;
|
|
|
|
if (state == XDM_OFF)
|
|
return;
|
|
FD_SET(xdmcpSocket, LastSelectMask);
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
if (xdmcpSocket6 >= 0)
|
|
FD_SET(xdmcpSocket6, LastSelectMask);
|
|
#endif
|
|
if (timeOutTime == 0)
|
|
return;
|
|
millisToGo = timeOutTime - GetTimeInMillis();
|
|
if ((int) millisToGo < 0)
|
|
millisToGo = 0;
|
|
AdjustWaitForDelay(wt, millisToGo);
|
|
}
|
|
|
|
/*
|
|
* called after select returns; this routine will
|
|
* recognise when XDMCP packets await and
|
|
* process them appropriately
|
|
*/
|
|
|
|
/*ARGSUSED*/ static void
|
|
XdmcpWakeupHandler(pointer data, /* unused */
|
|
int i, pointer pReadmask)
|
|
{
|
|
fd_set *LastSelectMask = (fd_set *) pReadmask;
|
|
fd_set devicesReadable;
|
|
|
|
if (state == XDM_OFF)
|
|
return;
|
|
if (i > 0) {
|
|
if (FD_ISSET(xdmcpSocket, LastSelectMask)) {
|
|
receive_packet(xdmcpSocket);
|
|
FD_CLR(xdmcpSocket, LastSelectMask);
|
|
}
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
if (xdmcpSocket6 >= 0 && FD_ISSET(xdmcpSocket6, LastSelectMask)) {
|
|
receive_packet(xdmcpSocket6);
|
|
FD_CLR(xdmcpSocket6, LastSelectMask);
|
|
}
|
|
#endif
|
|
XFD_ANDSET(&devicesReadable, LastSelectMask, &EnabledDevices);
|
|
if (XFD_ANYSET(&devicesReadable)) {
|
|
if (state == XDM_AWAIT_USER_INPUT)
|
|
restart();
|
|
else if (state == XDM_RUN_SESSION)
|
|
keepaliveDormancy = defaultKeepaliveDormancy;
|
|
}
|
|
if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION)
|
|
timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
|
|
}
|
|
else if (timeOutTime && (int) (GetTimeInMillis() - timeOutTime) >= 0) {
|
|
if (state == XDM_RUN_SESSION) {
|
|
state = XDM_KEEPALIVE;
|
|
send_packet();
|
|
}
|
|
else
|
|
timeout();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This routine should be called from the routine that drives the
|
|
* user's host menu when the user selects a host
|
|
*/
|
|
|
|
static void
|
|
XdmcpSelectHost(const struct sockaddr *host_sockaddr,
|
|
int host_len, ARRAY8Ptr AuthenticationName)
|
|
{
|
|
state = XDM_START_CONNECTION;
|
|
memmove(&req_sockaddr, host_sockaddr, host_len);
|
|
req_socklen = host_len;
|
|
XdmcpSetAuthentication(AuthenticationName);
|
|
send_packet();
|
|
}
|
|
|
|
/*
|
|
* !!! this routine should be replaced by a routine that adds
|
|
* the host to the user's host menu. the current version just
|
|
* selects the first host to respond with willing message.
|
|
*/
|
|
|
|
/*ARGSUSED*/ static void
|
|
XdmcpAddHost(const struct sockaddr *from,
|
|
int fromlen,
|
|
ARRAY8Ptr AuthenticationName, ARRAY8Ptr hostname, ARRAY8Ptr status)
|
|
{
|
|
XdmcpSelectHost(from, fromlen, AuthenticationName);
|
|
}
|
|
|
|
/*
|
|
* A message is queued on the socket; read it and
|
|
* do the appropriate thing
|
|
*/
|
|
|
|
static ARRAY8 UnwillingMessage = { (CARD8) 14, (CARD8 *) "Host unwilling" };
|
|
|
|
static void
|
|
receive_packet(int socketfd)
|
|
{
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
struct sockaddr_storage from;
|
|
#else
|
|
struct sockaddr_in from;
|
|
#endif
|
|
int fromlen = sizeof(from);
|
|
XdmcpHeader header;
|
|
|
|
/* read message off socket */
|
|
if (!XdmcpFill(socketfd, &buffer, (XdmcpNetaddr) & from, &fromlen))
|
|
return;
|
|
|
|
/* reset retransmission backoff */
|
|
timeOutRtx = 0;
|
|
|
|
if (!XdmcpReadHeader(&buffer, &header))
|
|
return;
|
|
|
|
if (header.version != XDM_PROTOCOL_VERSION)
|
|
return;
|
|
|
|
switch (header.opcode) {
|
|
case WILLING:
|
|
recv_willing_msg((struct sockaddr *) &from, fromlen, header.length);
|
|
break;
|
|
case UNWILLING:
|
|
XdmcpFatal("Manager unwilling", &UnwillingMessage);
|
|
break;
|
|
case ACCEPT:
|
|
recv_accept_msg(header.length);
|
|
break;
|
|
case DECLINE:
|
|
recv_decline_msg(header.length);
|
|
break;
|
|
case REFUSE:
|
|
recv_refuse_msg(header.length);
|
|
break;
|
|
case FAILED:
|
|
recv_failed_msg(header.length);
|
|
break;
|
|
case ALIVE:
|
|
recv_alive_msg(header.length);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* send the appropriate message given the current state
|
|
*/
|
|
|
|
static void
|
|
send_packet(void)
|
|
{
|
|
int rtx;
|
|
|
|
switch (state) {
|
|
case XDM_QUERY:
|
|
case XDM_BROADCAST:
|
|
case XDM_INDIRECT:
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
case XDM_MULTICAST:
|
|
#endif
|
|
send_query_msg();
|
|
break;
|
|
case XDM_START_CONNECTION:
|
|
send_request_msg();
|
|
break;
|
|
case XDM_MANAGE:
|
|
send_manage_msg();
|
|
break;
|
|
case XDM_KEEPALIVE:
|
|
send_keepalive_msg();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
rtx = (XDM_MIN_RTX << timeOutRtx);
|
|
if (rtx > XDM_MAX_RTX)
|
|
rtx = XDM_MAX_RTX;
|
|
timeOutTime = GetTimeInMillis() + rtx * 1000;
|
|
}
|
|
|
|
/*
|
|
* The session is declared dead for some reason; too many
|
|
* timeouts, or Keepalive failure.
|
|
*/
|
|
|
|
static void
|
|
XdmcpDeadSession(const char *reason)
|
|
{
|
|
ErrorF("XDM: %s, declaring session dead\n", reason);
|
|
state = XDM_INIT_STATE;
|
|
isItTimeToYield = TRUE;
|
|
dispatchException |= DE_RESET;
|
|
timeOutTime = 0;
|
|
timeOutRtx = 0;
|
|
send_packet();
|
|
}
|
|
|
|
/*
|
|
* Timeout waiting for an XDMCP response.
|
|
*/
|
|
|
|
static void
|
|
timeout(void)
|
|
{
|
|
timeOutRtx++;
|
|
if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT) {
|
|
XdmcpDeadSession("too many keepalive retransmissions");
|
|
return;
|
|
}
|
|
else if (timeOutRtx >= XDM_RTX_LIMIT) {
|
|
/* Quit if "-once" specified, otherwise reset and try again. */
|
|
if (OneSession) {
|
|
dispatchException |= DE_TERMINATE;
|
|
ErrorF("XDM: too many retransmissions\n");
|
|
}
|
|
else {
|
|
XdmcpDeadSession("too many retransmissions");
|
|
}
|
|
return;
|
|
}
|
|
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
if (state == XDM_COLLECT_QUERY || state == XDM_COLLECT_INDIRECT_QUERY) {
|
|
/* Try next address */
|
|
for (mgrAddr = mgrAddr->ai_next;; mgrAddr = mgrAddr->ai_next) {
|
|
if (mgrAddr == NULL) {
|
|
mgrAddr = mgrAddrFirst;
|
|
}
|
|
if (mgrAddr->ai_family == AF_INET || mgrAddr->ai_family == AF_INET6)
|
|
break;
|
|
}
|
|
#ifndef SIN6_LEN
|
|
ManagerAddressLen = mgrAddr->ai_addrlen;
|
|
#endif
|
|
memcpy(&ManagerAddress, mgrAddr->ai_addr, mgrAddr->ai_addrlen);
|
|
}
|
|
#endif
|
|
|
|
switch (state) {
|
|
case XDM_COLLECT_QUERY:
|
|
state = XDM_QUERY;
|
|
break;
|
|
case XDM_COLLECT_BROADCAST_QUERY:
|
|
state = XDM_BROADCAST;
|
|
break;
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
case XDM_COLLECT_MULTICAST_QUERY:
|
|
state = XDM_MULTICAST;
|
|
break;
|
|
#endif
|
|
case XDM_COLLECT_INDIRECT_QUERY:
|
|
state = XDM_INDIRECT;
|
|
break;
|
|
case XDM_AWAIT_REQUEST_RESPONSE:
|
|
state = XDM_START_CONNECTION;
|
|
break;
|
|
case XDM_AWAIT_MANAGE_RESPONSE:
|
|
state = XDM_MANAGE;
|
|
break;
|
|
case XDM_AWAIT_ALIVE_RESPONSE:
|
|
state = XDM_KEEPALIVE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
send_packet();
|
|
}
|
|
|
|
static void
|
|
restart(void)
|
|
{
|
|
state = XDM_INIT_STATE;
|
|
timeOutRtx = 0;
|
|
send_packet();
|
|
}
|
|
|
|
static int
|
|
XdmcpCheckAuthentication(ARRAY8Ptr Name, ARRAY8Ptr Data, int packet_type)
|
|
{
|
|
return (XdmcpARRAY8Equal(Name, AuthenticationName) &&
|
|
(AuthenticationName->length == 0 ||
|
|
(*AuthenticationFuncs->Validator) (AuthenticationData, Data,
|
|
packet_type)));
|
|
}
|
|
|
|
static int
|
|
XdmcpAddAuthorization(ARRAY8Ptr name, ARRAY8Ptr data)
|
|
{
|
|
AddAuthorFunc AddAuth;
|
|
|
|
if (AuthenticationFuncs && AuthenticationFuncs->AddAuth)
|
|
AddAuth = AuthenticationFuncs->AddAuth;
|
|
else
|
|
AddAuth = AddAuthorization;
|
|
return (*AddAuth) ((unsigned short) name->length,
|
|
(char *) name->data,
|
|
(unsigned short) data->length, (char *) data->data);
|
|
}
|
|
|
|
/*
|
|
* from here to the end of this file are routines private
|
|
* to the state machine.
|
|
*/
|
|
|
|
static void
|
|
get_xdmcp_sock(void)
|
|
{
|
|
#ifdef STREAMSCONN
|
|
struct netconfig *nconf;
|
|
|
|
if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) {
|
|
XdmcpWarning("t_open() of /dev/udp failed");
|
|
return;
|
|
}
|
|
|
|
if (t_bind(xdmcpSocket, NULL, NULL) < 0) {
|
|
XdmcpWarning("UDP socket creation failed");
|
|
t_error("t_bind(xdmcpSocket) failed");
|
|
t_close(xdmcpSocket);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* This part of the code looks contrived. It will actually fit in nicely
|
|
* when the CLTS part of Xtrans is implemented.
|
|
*/
|
|
|
|
if ((nconf = getnetconfigent("udp")) == NULL) {
|
|
XdmcpWarning("UDP socket creation failed: getnetconfigent()");
|
|
t_unbind(xdmcpSocket);
|
|
t_close(xdmcpSocket);
|
|
return;
|
|
}
|
|
|
|
if (netdir_options(nconf, ND_SET_BROADCAST, xdmcpSocket, NULL)) {
|
|
XdmcpWarning("UDP set broadcast option failed: netdir_options()");
|
|
freenetconfigent(nconf);
|
|
t_unbind(xdmcpSocket);
|
|
t_close(xdmcpSocket);
|
|
return;
|
|
}
|
|
|
|
freenetconfigent(nconf);
|
|
#else
|
|
int soopts = 1;
|
|
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
if ((xdmcpSocket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
|
|
XdmcpWarning("INET6 UDP socket creation failed");
|
|
#endif
|
|
if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
|
|
XdmcpWarning("UDP socket creation failed");
|
|
#ifdef SO_BROADCAST
|
|
else if (setsockopt(xdmcpSocket, SOL_SOCKET, SO_BROADCAST, (char *) &soopts,
|
|
sizeof(soopts)) < 0)
|
|
XdmcpWarning("UDP set broadcast socket-option failed");
|
|
#endif /* SO_BROADCAST */
|
|
if (xdmcpSocket >= 0 && xdm_from != NULL) {
|
|
if (bind(xdmcpSocket, (struct sockaddr *) &FromAddress,
|
|
FromAddressLen) < 0) {
|
|
FatalError("Xserver: failed to bind to -from address: %s\n",
|
|
xdm_from);
|
|
}
|
|
}
|
|
#endif /* STREAMSCONN */
|
|
}
|
|
|
|
static void
|
|
send_query_msg(void)
|
|
{
|
|
XdmcpHeader header;
|
|
Bool broadcast = FALSE;
|
|
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
Bool multicast = FALSE;
|
|
#endif
|
|
int i;
|
|
int socketfd = xdmcpSocket;
|
|
|
|
header.version = XDM_PROTOCOL_VERSION;
|
|
switch (state) {
|
|
case XDM_QUERY:
|
|
header.opcode = (CARD16) QUERY;
|
|
state = XDM_COLLECT_QUERY;
|
|
break;
|
|
case XDM_BROADCAST:
|
|
header.opcode = (CARD16) BROADCAST_QUERY;
|
|
state = XDM_COLLECT_BROADCAST_QUERY;
|
|
broadcast = TRUE;
|
|
break;
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
case XDM_MULTICAST:
|
|
header.opcode = (CARD16) BROADCAST_QUERY;
|
|
state = XDM_COLLECT_MULTICAST_QUERY;
|
|
multicast = TRUE;
|
|
break;
|
|
#endif
|
|
case XDM_INDIRECT:
|
|
header.opcode = (CARD16) INDIRECT_QUERY;
|
|
state = XDM_COLLECT_INDIRECT_QUERY;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
header.length = 1;
|
|
for (i = 0; i < AuthenticationNames.length; i++)
|
|
header.length += 2 + AuthenticationNames.data[i].length;
|
|
|
|
XdmcpWriteHeader(&buffer, &header);
|
|
XdmcpWriteARRAYofARRAY8(&buffer, &AuthenticationNames);
|
|
if (broadcast) {
|
|
int i;
|
|
|
|
for (i = 0; i < NumBroadcastAddresses; i++)
|
|
XdmcpFlush(xdmcpSocket, &buffer,
|
|
(XdmcpNetaddr) & BroadcastAddresses[i],
|
|
sizeof(struct sockaddr_in));
|
|
}
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
else if (multicast) {
|
|
struct multicastinfo *mcl;
|
|
struct addrinfo *ai;
|
|
|
|
for (mcl = mcastlist; mcl != NULL; mcl = mcl->next) {
|
|
for (ai = mcl->ai; ai != NULL; ai = ai->ai_next) {
|
|
if (ai->ai_family == AF_INET) {
|
|
unsigned char hopflag = (unsigned char) mcl->hops;
|
|
|
|
socketfd = xdmcpSocket;
|
|
setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_TTL,
|
|
&hopflag, sizeof(hopflag));
|
|
}
|
|
else if (ai->ai_family == AF_INET6) {
|
|
int hopflag6 = mcl->hops;
|
|
|
|
socketfd = xdmcpSocket6;
|
|
setsockopt(socketfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
|
|
&hopflag6, sizeof(hopflag6));
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
XdmcpFlush(socketfd, &buffer,
|
|
(XdmcpNetaddr) ai->ai_addr, ai->ai_addrlen);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
else {
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
if (SOCKADDR_FAMILY(ManagerAddress) == AF_INET6)
|
|
socketfd = xdmcpSocket6;
|
|
#endif
|
|
XdmcpFlush(socketfd, &buffer, (XdmcpNetaddr) & ManagerAddress,
|
|
ManagerAddressLen);
|
|
}
|
|
}
|
|
|
|
static void
|
|
recv_willing_msg(struct sockaddr *from, int fromlen, unsigned length)
|
|
{
|
|
ARRAY8 authenticationName;
|
|
ARRAY8 hostname;
|
|
ARRAY8 status;
|
|
|
|
authenticationName.data = 0;
|
|
hostname.data = 0;
|
|
status.data = 0;
|
|
if (XdmcpReadARRAY8(&buffer, &authenticationName) &&
|
|
XdmcpReadARRAY8(&buffer, &hostname) &&
|
|
XdmcpReadARRAY8(&buffer, &status)) {
|
|
if (length == 6 + authenticationName.length +
|
|
hostname.length + status.length) {
|
|
switch (state) {
|
|
case XDM_COLLECT_QUERY:
|
|
XdmcpSelectHost(from, fromlen, &authenticationName);
|
|
break;
|
|
case XDM_COLLECT_BROADCAST_QUERY:
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
case XDM_COLLECT_MULTICAST_QUERY:
|
|
#endif
|
|
case XDM_COLLECT_INDIRECT_QUERY:
|
|
XdmcpAddHost(from, fromlen, &authenticationName, &hostname,
|
|
&status);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
XdmcpDisposeARRAY8(&authenticationName);
|
|
XdmcpDisposeARRAY8(&hostname);
|
|
XdmcpDisposeARRAY8(&status);
|
|
}
|
|
|
|
static void
|
|
send_request_msg(void)
|
|
{
|
|
XdmcpHeader header;
|
|
int length;
|
|
int i;
|
|
CARD16 XdmcpConnectionType;
|
|
ARRAY8 authenticationData;
|
|
int socketfd = xdmcpSocket;
|
|
|
|
switch (SOCKADDR_FAMILY(ManagerAddress)) {
|
|
case AF_INET:
|
|
XdmcpConnectionType = FamilyInternet;
|
|
break;
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
case AF_INET6:
|
|
XdmcpConnectionType = FamilyInternet6;
|
|
break;
|
|
#endif
|
|
default:
|
|
XdmcpConnectionType = 0xffff;
|
|
break;
|
|
}
|
|
|
|
header.version = XDM_PROTOCOL_VERSION;
|
|
header.opcode = (CARD16) REQUEST;
|
|
|
|
length = 2; /* display number */
|
|
length += 1 + 2 * ConnectionTypes.length; /* connection types */
|
|
length += 1; /* connection addresses */
|
|
for (i = 0; i < ConnectionAddresses.length; i++)
|
|
length += 2 + ConnectionAddresses.data[i].length;
|
|
authenticationData.length = 0;
|
|
authenticationData.data = 0;
|
|
if (AuthenticationFuncs) {
|
|
(*AuthenticationFuncs->Generator) (AuthenticationData,
|
|
&authenticationData, REQUEST);
|
|
}
|
|
length += 2 + AuthenticationName->length; /* authentication name */
|
|
length += 2 + authenticationData.length; /* authentication data */
|
|
length += 1; /* authorization names */
|
|
for (i = 0; i < AuthorizationNames.length; i++)
|
|
length += 2 + AuthorizationNames.data[i].length;
|
|
length += 2 + ManufacturerDisplayID.length; /* display ID */
|
|
header.length = length;
|
|
|
|
if (!XdmcpWriteHeader(&buffer, &header)) {
|
|
XdmcpDisposeARRAY8(&authenticationData);
|
|
return;
|
|
}
|
|
XdmcpWriteCARD16(&buffer, DisplayNumber);
|
|
XdmcpWriteCARD8(&buffer, ConnectionTypes.length);
|
|
|
|
/* The connection array is send reordered, so that connections of */
|
|
/* the same address type as the XDMCP manager connection are send */
|
|
/* first. This works around a bug in xdm. mario@klebsch.de */
|
|
for (i = 0; i < (int) ConnectionTypes.length; i++)
|
|
if (ConnectionTypes.data[i] == XdmcpConnectionType)
|
|
XdmcpWriteCARD16(&buffer, ConnectionTypes.data[i]);
|
|
for (i = 0; i < (int) ConnectionTypes.length; i++)
|
|
if (ConnectionTypes.data[i] != XdmcpConnectionType)
|
|
XdmcpWriteCARD16(&buffer, ConnectionTypes.data[i]);
|
|
|
|
XdmcpWriteCARD8(&buffer, ConnectionAddresses.length);
|
|
for (i = 0; i < (int) ConnectionAddresses.length; i++)
|
|
if ((i < ConnectionTypes.length) &&
|
|
(ConnectionTypes.data[i] == XdmcpConnectionType))
|
|
XdmcpWriteARRAY8(&buffer, &ConnectionAddresses.data[i]);
|
|
for (i = 0; i < (int) ConnectionAddresses.length; i++)
|
|
if ((i >= ConnectionTypes.length) ||
|
|
(ConnectionTypes.data[i] != XdmcpConnectionType))
|
|
XdmcpWriteARRAY8(&buffer, &ConnectionAddresses.data[i]);
|
|
|
|
XdmcpWriteARRAY8(&buffer, AuthenticationName);
|
|
XdmcpWriteARRAY8(&buffer, &authenticationData);
|
|
XdmcpDisposeARRAY8(&authenticationData);
|
|
XdmcpWriteARRAYofARRAY8(&buffer, &AuthorizationNames);
|
|
XdmcpWriteARRAY8(&buffer, &ManufacturerDisplayID);
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
|
|
socketfd = xdmcpSocket6;
|
|
#endif
|
|
if (XdmcpFlush(socketfd, &buffer,
|
|
(XdmcpNetaddr) & req_sockaddr, req_socklen))
|
|
state = XDM_AWAIT_REQUEST_RESPONSE;
|
|
}
|
|
|
|
static void
|
|
recv_accept_msg(unsigned length)
|
|
{
|
|
CARD32 AcceptSessionID;
|
|
ARRAY8 AcceptAuthenticationName, AcceptAuthenticationData;
|
|
ARRAY8 AcceptAuthorizationName, AcceptAuthorizationData;
|
|
|
|
if (state != XDM_AWAIT_REQUEST_RESPONSE)
|
|
return;
|
|
AcceptAuthenticationName.data = 0;
|
|
AcceptAuthenticationData.data = 0;
|
|
AcceptAuthorizationName.data = 0;
|
|
AcceptAuthorizationData.data = 0;
|
|
if (XdmcpReadCARD32(&buffer, &AcceptSessionID) &&
|
|
XdmcpReadARRAY8(&buffer, &AcceptAuthenticationName) &&
|
|
XdmcpReadARRAY8(&buffer, &AcceptAuthenticationData) &&
|
|
XdmcpReadARRAY8(&buffer, &AcceptAuthorizationName) &&
|
|
XdmcpReadARRAY8(&buffer, &AcceptAuthorizationData)) {
|
|
if (length == 12 + AcceptAuthenticationName.length +
|
|
AcceptAuthenticationData.length +
|
|
AcceptAuthorizationName.length + AcceptAuthorizationData.length) {
|
|
if (!XdmcpCheckAuthentication(&AcceptAuthenticationName,
|
|
&AcceptAuthenticationData, ACCEPT)) {
|
|
XdmcpFatal("Authentication Failure", &AcceptAuthenticationName);
|
|
}
|
|
/* permit access control manipulations from this host */
|
|
AugmentSelf(&req_sockaddr, req_socklen);
|
|
/* if the authorization specified in the packet fails
|
|
* to be acceptable, enable the local addresses
|
|
*/
|
|
if (!XdmcpAddAuthorization(&AcceptAuthorizationName,
|
|
&AcceptAuthorizationData)) {
|
|
AddLocalHosts();
|
|
}
|
|
SessionID = AcceptSessionID;
|
|
state = XDM_MANAGE;
|
|
send_packet();
|
|
}
|
|
}
|
|
XdmcpDisposeARRAY8(&AcceptAuthenticationName);
|
|
XdmcpDisposeARRAY8(&AcceptAuthenticationData);
|
|
XdmcpDisposeARRAY8(&AcceptAuthorizationName);
|
|
XdmcpDisposeARRAY8(&AcceptAuthorizationData);
|
|
}
|
|
|
|
static void
|
|
recv_decline_msg(unsigned length)
|
|
{
|
|
ARRAY8 status, DeclineAuthenticationName, DeclineAuthenticationData;
|
|
|
|
status.data = 0;
|
|
DeclineAuthenticationName.data = 0;
|
|
DeclineAuthenticationData.data = 0;
|
|
if (XdmcpReadARRAY8(&buffer, &status) &&
|
|
XdmcpReadARRAY8(&buffer, &DeclineAuthenticationName) &&
|
|
XdmcpReadARRAY8(&buffer, &DeclineAuthenticationData)) {
|
|
if (length == 6 + status.length +
|
|
DeclineAuthenticationName.length +
|
|
DeclineAuthenticationData.length &&
|
|
XdmcpCheckAuthentication(&DeclineAuthenticationName,
|
|
&DeclineAuthenticationData, DECLINE)) {
|
|
XdmcpFatal("Session declined", &status);
|
|
}
|
|
}
|
|
XdmcpDisposeARRAY8(&status);
|
|
XdmcpDisposeARRAY8(&DeclineAuthenticationName);
|
|
XdmcpDisposeARRAY8(&DeclineAuthenticationData);
|
|
}
|
|
|
|
static void
|
|
send_manage_msg(void)
|
|
{
|
|
XdmcpHeader header;
|
|
int socketfd = xdmcpSocket;
|
|
|
|
header.version = XDM_PROTOCOL_VERSION;
|
|
header.opcode = (CARD16) MANAGE;
|
|
header.length = 8 + DisplayClass.length;
|
|
|
|
if (!XdmcpWriteHeader(&buffer, &header))
|
|
return;
|
|
XdmcpWriteCARD32(&buffer, SessionID);
|
|
XdmcpWriteCARD16(&buffer, DisplayNumber);
|
|
XdmcpWriteARRAY8(&buffer, &DisplayClass);
|
|
state = XDM_AWAIT_MANAGE_RESPONSE;
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
|
|
socketfd = xdmcpSocket6;
|
|
#endif
|
|
XdmcpFlush(socketfd, &buffer, (XdmcpNetaddr) & req_sockaddr, req_socklen);
|
|
}
|
|
|
|
static void
|
|
recv_refuse_msg(unsigned length)
|
|
{
|
|
CARD32 RefusedSessionID;
|
|
|
|
if (state != XDM_AWAIT_MANAGE_RESPONSE)
|
|
return;
|
|
if (length != 4)
|
|
return;
|
|
if (XdmcpReadCARD32(&buffer, &RefusedSessionID)) {
|
|
if (RefusedSessionID == SessionID) {
|
|
state = XDM_START_CONNECTION;
|
|
send_packet();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
recv_failed_msg(unsigned length)
|
|
{
|
|
CARD32 FailedSessionID;
|
|
ARRAY8 status;
|
|
|
|
if (state != XDM_AWAIT_MANAGE_RESPONSE)
|
|
return;
|
|
status.data = 0;
|
|
if (XdmcpReadCARD32(&buffer, &FailedSessionID) &&
|
|
XdmcpReadARRAY8(&buffer, &status)) {
|
|
if (length == 6 + status.length && SessionID == FailedSessionID) {
|
|
XdmcpFatal("Session failed", &status);
|
|
}
|
|
}
|
|
XdmcpDisposeARRAY8(&status);
|
|
}
|
|
|
|
static void
|
|
send_keepalive_msg(void)
|
|
{
|
|
XdmcpHeader header;
|
|
int socketfd = xdmcpSocket;
|
|
|
|
header.version = XDM_PROTOCOL_VERSION;
|
|
header.opcode = (CARD16) KEEPALIVE;
|
|
header.length = 6;
|
|
|
|
XdmcpWriteHeader(&buffer, &header);
|
|
XdmcpWriteCARD16(&buffer, DisplayNumber);
|
|
XdmcpWriteCARD32(&buffer, SessionID);
|
|
|
|
state = XDM_AWAIT_ALIVE_RESPONSE;
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
|
|
socketfd = xdmcpSocket6;
|
|
#endif
|
|
XdmcpFlush(socketfd, &buffer, (XdmcpNetaddr) & req_sockaddr, req_socklen);
|
|
}
|
|
|
|
static void
|
|
recv_alive_msg(unsigned length)
|
|
{
|
|
CARD8 SessionRunning;
|
|
CARD32 AliveSessionID;
|
|
|
|
if (state != XDM_AWAIT_ALIVE_RESPONSE)
|
|
return;
|
|
if (length != 5)
|
|
return;
|
|
if (XdmcpReadCARD8(&buffer, &SessionRunning) &&
|
|
XdmcpReadCARD32(&buffer, &AliveSessionID)) {
|
|
if (SessionRunning && AliveSessionID == SessionID) {
|
|
/* backoff dormancy period */
|
|
state = XDM_RUN_SESSION;
|
|
if ((GetTimeInMillis() - lastDeviceEventTime.milliseconds) >
|
|
keepaliveDormancy * 1000) {
|
|
keepaliveDormancy <<= 1;
|
|
if (keepaliveDormancy > XDM_MAX_DORMANCY)
|
|
keepaliveDormancy = XDM_MAX_DORMANCY;
|
|
}
|
|
timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
|
|
}
|
|
else {
|
|
XdmcpDeadSession("Alive response indicates session dead");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
XdmcpFatal(const char *type, ARRAY8Ptr status)
|
|
{
|
|
FatalError("XDMCP fatal error: %s %*.*s\n", type,
|
|
status->length, status->length, status->data);
|
|
}
|
|
|
|
static void
|
|
XdmcpWarning(const char *str)
|
|
{
|
|
ErrorF("XDMCP warning: %s\n", str);
|
|
}
|
|
|
|
static void
|
|
get_addr_by_name(const char *argtype,
|
|
const char *namestr,
|
|
int port,
|
|
int socktype, SOCKADDR_TYPE * addr, SOCKLEN_TYPE * addrlen
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
, struct addrinfo **aip, struct addrinfo **aifirstp
|
|
#endif
|
|
)
|
|
{
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
struct addrinfo *ai;
|
|
struct addrinfo hints;
|
|
char portstr[6];
|
|
char *pport = portstr;
|
|
int gaierr;
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_socktype = socktype;
|
|
|
|
if (port == 0) {
|
|
pport = NULL;
|
|
}
|
|
else if (port > 0 && port < 65535) {
|
|
snprintf(portstr, sizeof(portstr), "%d", port);
|
|
}
|
|
else {
|
|
FatalError("Xserver: port out of range: %d\n", port);
|
|
}
|
|
|
|
if (*aifirstp != NULL) {
|
|
freeaddrinfo(*aifirstp);
|
|
*aifirstp = NULL;
|
|
}
|
|
|
|
if ((gaierr = getaddrinfo(namestr, pport, &hints, aifirstp)) == 0) {
|
|
for (ai = *aifirstp; ai != NULL; ai = ai->ai_next) {
|
|
if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6)
|
|
break;
|
|
}
|
|
if ((ai == NULL) || (ai->ai_addrlen > sizeof(SOCKADDR_TYPE))) {
|
|
FatalError("Xserver: %s host %s not on supported network type\n",
|
|
argtype, namestr);
|
|
}
|
|
else {
|
|
*aip = ai;
|
|
*addrlen = ai->ai_addrlen;
|
|
memcpy(addr, ai->ai_addr, ai->ai_addrlen);
|
|
}
|
|
}
|
|
else {
|
|
FatalError("Xserver: %s: %s %s\n", gai_strerror(gaierr), argtype,
|
|
namestr);
|
|
}
|
|
#else
|
|
struct hostent *hep;
|
|
|
|
#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
|
|
_Xgethostbynameparams hparams;
|
|
#endif
|
|
#if defined(WIN32) && defined(TCPCONN)
|
|
_XSERVTransWSAStartup();
|
|
#endif
|
|
if (!(hep = _XGethostbyname(namestr, hparams))) {
|
|
FatalError("Xserver: %s unknown host: %s\n", argtype, namestr);
|
|
}
|
|
if (hep->h_length == sizeof(struct in_addr)) {
|
|
memmove(&addr->sin_addr, hep->h_addr, hep->h_length);
|
|
*addrlen = sizeof(struct sockaddr_in);
|
|
addr->sin_family = AF_INET;
|
|
addr->sin_port = htons(port);
|
|
}
|
|
else {
|
|
FatalError("Xserver: %s host on strange network %s\n", argtype,
|
|
namestr);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
get_manager_by_name(int argc, char **argv, int i)
|
|
{
|
|
|
|
if ((i + 1) == argc) {
|
|
FatalError("Xserver: missing %s host name in command line\n", argv[i]);
|
|
}
|
|
|
|
get_addr_by_name(argv[i], argv[i + 1], xdm_udp_port, SOCK_DGRAM,
|
|
&ManagerAddress, &ManagerAddressLen
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
, &mgrAddr, &mgrAddrFirst
|
|
#endif
|
|
);
|
|
}
|
|
|
|
static void
|
|
get_fromaddr_by_name(int argc, char **argv, int i)
|
|
{
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
struct addrinfo *ai = NULL;
|
|
struct addrinfo *aifirst = NULL;
|
|
#endif
|
|
if (i == argc) {
|
|
FatalError("Xserver: missing -from host name in command line\n");
|
|
}
|
|
get_addr_by_name("-from", argv[i], 0, 0, &FromAddress, &FromAddressLen
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
, &ai, &aifirst
|
|
#endif
|
|
);
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
if (aifirst != NULL)
|
|
freeaddrinfo(aifirst);
|
|
#endif
|
|
xdm_from = argv[i];
|
|
}
|
|
|
|
#if defined(IPv6) && defined(AF_INET6)
|
|
static int
|
|
get_mcast_options(int argc, char **argv, int i)
|
|
{
|
|
const char *address = XDM_DEFAULT_MCAST_ADDR6;
|
|
int hopcount = 1;
|
|
struct addrinfo hints;
|
|
char portstr[6];
|
|
int gaierr;
|
|
struct addrinfo *ai, *firstai;
|
|
|
|
if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) {
|
|
address = argv[i++];
|
|
if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) {
|
|
hopcount = strtol(argv[i++], NULL, 10);
|
|
if ((hopcount < 1) || (hopcount > 255)) {
|
|
FatalError("Xserver: multicast hop count out of range: %d\n",
|
|
hopcount);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (xdm_udp_port > 0 && xdm_udp_port < 65535) {
|
|
snprintf(portstr, sizeof(portstr), "%d", xdm_udp_port);
|
|
}
|
|
else {
|
|
FatalError("Xserver: port out of range: %d\n", xdm_udp_port);
|
|
}
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
|
|
if ((gaierr = getaddrinfo(address, portstr, &hints, &firstai)) == 0) {
|
|
for (ai = firstai; ai != NULL; ai = ai->ai_next) {
|
|
if (((ai->ai_family == AF_INET) &&
|
|
IN_MULTICAST(((struct sockaddr_in *) ai->ai_addr)
|
|
->sin_addr.s_addr))
|
|
|| ((ai->ai_family == AF_INET6) &&
|
|
IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *) ai->ai_addr)
|
|
->sin6_addr)))
|
|
break;
|
|
}
|
|
if (ai == NULL) {
|
|
FatalError("Xserver: address not supported multicast type %s\n",
|
|
address);
|
|
}
|
|
else {
|
|
struct multicastinfo *mcastinfo, *mcl;
|
|
|
|
mcastinfo = malloc(sizeof(struct multicastinfo));
|
|
mcastinfo->next = NULL;
|
|
mcastinfo->ai = firstai;
|
|
mcastinfo->hops = hopcount;
|
|
|
|
if (mcastlist == NULL) {
|
|
mcastlist = mcastinfo;
|
|
}
|
|
else {
|
|
for (mcl = mcastlist; mcl->next != NULL; mcl = mcl->next) {
|
|
/* Do nothing - just find end of list */
|
|
}
|
|
mcl->next = mcastinfo;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
FatalError("Xserver: %s: %s\n", gai_strerror(gaierr), address);
|
|
}
|
|
return i;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
static int xdmcp_non_empty; /* avoid complaint by ranlib */
|
|
#endif /* XDMCP */
|