X-Git-Url: https://git.sesse.net/?p=rdpsrv;a=blobdiff_plain;f=Xserver%2Fprograms%2FXserver%2Fos%2Fxdmcp.c;fp=Xserver%2Fprograms%2FXserver%2Fos%2Fxdmcp.c;h=5de14cd3250f32dd9f2f1093bf96b1a76870d520;hp=0000000000000000000000000000000000000000;hb=b6e6afccf37f4ad0515ef2a698f714fdf1bf23b3;hpb=e3340a110a3b01756b8e67531395a33b40a17d37 diff --git a/Xserver/programs/Xserver/os/xdmcp.c b/Xserver/programs/Xserver/os/xdmcp.c new file mode 100644 index 0000000..5de14cd --- /dev/null +++ b/Xserver/programs/Xserver/os/xdmcp.c @@ -0,0 +1,1464 @@ +/* $XConsortium: xdmcp.c /main/34 1996/12/02 10:23:29 lehors $ */ +/* $XFree86: xc/programs/Xserver/os/xdmcp.c,v 3.9 1997/01/18 06:58:04 dawes Exp $ */ +/* + * 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 WIN32 +/* avoid conflicting definitions */ +#define BOOL wBOOL +#define ATOM wATOM +#define FreeResource wFreeResource +#include +#undef BOOL +#undef ATOM +#undef FreeResource +#undef CreateWindowA +#undef RT_FONT +#undef RT_CURSOR +#endif +#include "Xos.h" +#if !defined(MINIX) && !defined(WIN32) +#ifndef Lynx +#include +#include +#else +#include +#endif +#include +#include +#else +#if defined(MINIX) +#include +#include +#include +#include +#include +#include +#include +#endif +#endif +#include +#include "X.h" +#include "Xmd.h" +#include "misc.h" +#include "Xpoll.h" +#include "osdep.h" +#include "input.h" +#include "dixstruct.h" +#include "opaque.h" + +#ifdef STREAMSCONN +#include +#include +#include +#endif + +#ifdef XDMCP +#undef REQUEST +#include "Xdmcp.h" + +extern char *display; +extern fd_set EnabledDevices; +extern fd_set AllClients; +extern char *defaultDisplayClass; + +static int xdmcpSocket, sessionSocket; +static xdmcp_states state; +static struct sockaddr_in req_sockaddr; +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; + +static struct sockaddr_in ManagerAddress; + +static void get_xdmcp_sock( +#if NeedFunctionPrototypes + void +#endif +); + +static void send_query_msg( +#if NeedFunctionPrototypes + void +#endif +); + +static void recv_willing_msg( +#if NeedFunctionPrototypes + struct sockaddr_in */*from*/, + int /*fromlen*/, + unsigned /*length*/ +#endif +); + +static void send_request_msg( +#if NeedFunctionPrototypes + void +#endif +); + +static void recv_accept_msg( +#if NeedFunctionPrototypes + unsigned /*length*/ +#endif +); + +static void recv_decline_msg( +#if NeedFunctionPrototypes + unsigned /*length*/ +#endif +); + +static void send_manage_msg( +#if NeedFunctionPrototypes + void +#endif +); + +static void recv_refuse_msg( +#if NeedFunctionPrototypes + unsigned /*length*/ +#endif +); + +static void recv_failed_msg( +#if NeedFunctionPrototypes + unsigned /*length*/ +#endif +); + +static void send_keepalive_msg( +#if NeedFunctionPrototypes + void +#endif +); + +static void recv_alive_msg( +#if NeedFunctionPrototypes + unsigned /*length*/ +#endif +); + +static XdmcpFatal( +#if NeedFunctionPrototypes + char */*type*/, + ARRAY8Ptr /*status*/ +#endif +); + +static XdmcpWarning( +#if NeedFunctionPrototypes + char */*str*/ +#endif +); + +static get_manager_by_name( +#if NeedFunctionPrototypes + int /*argc*/, + char **/*argv*/, + int /*i*/ +#endif +); + +static void receive_packet( +#if NeedFunctionPrototypes + void +#endif +); + +static send_packet( +#if NeedFunctionPrototypes + void +#endif +); + +extern int XdmcpDeadSession( +#if NeedFunctionPrototypes + char */*reason*/ +#endif +); + +static void timeout( +#if NeedFunctionPrototypes + void +#endif +); + +static restart( +#if NeedFunctionPrototypes + void +#endif +); + +static void XdmcpBlockHandler( +#if NeedFunctionPrototypes + pointer /*data*/, + struct timeval **/*wt*/, + pointer /*LastSelectMask*/ +#endif +); + +static void XdmcpWakeupHandler( +#if NeedFunctionPrototypes + pointer /*data*/, + int /*i*/, + pointer /*LastSelectMask*/ +#endif +); + +void XdmcpRegisterManufacturerDisplayID( +#if NeedFunctionPrototypes + char * /*name*/, + int /*length*/ +#endif +); + +#ifdef MINIX +static void read_cb( +#if NeedFunctionPrototypes + nbio_ref_t /*ref*/, + int /*res*/, + int /*err*/ +#endif +); +#endif + +static short xdm_udp_port = XDM_UDP_PORT; +static Bool OneSession = FALSE; + +XdmcpUseMsg () +{ + ErrorF("-query host-name contact named host for XDMCP\n"); + ErrorF("-broadcast broadcast for XDMCP\n"); + ErrorF("-indirect host-name contact named host for indirect XDMCP\n"); + ErrorF("-port port-num UDP port number to send messages to\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(argc, argv, i) + int argc, i; + char **argv; +{ + 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 (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) { + ++i; + xdm_udp_port = atoi(argv[i]); + return (i + 1); + } + if (strcmp(argv[i], "-once") == 0) { + OneSession = TRUE; + return (i + 1); + } + if (strcmp(argv[i], "-class") == 0) { + ++i; + defaultDisplayClass = argv[i]; + return (i + 1); + } +#ifdef HASXDMAUTH + if (strcmp(argv[i], "-cookie") == 0) { + ++i; + xdmAuthCookie = argv[i]; + return (i + 1); + } +#endif + if (strcmp(argv[i], "-displayID") == 0) { + ++i; + 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 + +static struct sockaddr_in BroadcastAddresses[MAX_BROADCAST]; +static int NumBroadcastAddresses; + +void +XdmcpRegisterBroadcastAddress (addr) + struct sockaddr_in *addr; +{ + struct sockaddr_in *bcast; + if (NumBroadcastAddresses >= MAX_BROADCAST) + return; + bcast = &BroadcastAddresses[NumBroadcastAddresses++]; + bzero (bcast, 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 { + Bool (*Validator)(); + Bool (*Generator)(); + Bool (*AddAuth)(); +} AuthenticationFuncsRec, *AuthenticationFuncsPtr; + +static AuthenticationFuncsPtr AuthenticationFuncsList; + +void +XdmcpRegisterAuthentication (name, namelen, data, datalen, Validator, Generator, AddAuth) + char *name; + int namelen; + char *data; + int datalen; + Bool (*Validator)(); + Bool (*Generator)(); + Bool (*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 = (AuthenticationFuncsPtr) xalloc ( + (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; + xfree (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. + */ + +ARRAY8 noAuthenticationName = {(CARD16) 0, (CARD8Ptr) 0}; +ARRAY8 noAuthenticationData = {(CARD16) 0, (CARD8Ptr) 0}; +ARRAY8Ptr AuthenticationName = &noAuthenticationName; +ARRAY8Ptr AuthenticationData = &noAuthenticationData; +AuthenticationFuncsPtr AuthenticationFuncs; + +void +XdmcpSetAuthentication (name) + 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 (type, address, addrlen) + int type; + char *address; + int addrlen; +{ + int i; + CARD8 *newAddress; + + if (xdmcpGeneration != serverGeneration) + { + XdmcpDisposeARRAY16 (&ConnectionTypes); + XdmcpDisposeARRAYofARRAY8 (&ConnectionAddresses); + xdmcpGeneration = serverGeneration; + } + newAddress = (CARD8 *) xalloc (addrlen * sizeof (CARD8)); + if (!newAddress) + return; + if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1)) + { + xfree (newAddress); + return; + } + if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses, + ConnectionAddresses.length + 1)) + { + xfree (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 () +{ + XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames); + RegisterAuthorizations (); +} + +void +XdmcpRegisterAuthorization (name, namelen) + char *name; + int namelen; +{ + ARRAY8 authName; + int i; + + authName.data = (CARD8 *) xalloc (namelen * sizeof (CARD8)); + if (!authName.data) + return; + if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1)) + { + xfree (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 + */ + +ARRAY8 DisplayClass; + +void +XdmcpRegisterDisplayClass (name, length) + 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]; +} + +/* + * Register the Manufacturer display ID + */ + +ARRAY8 ManufacturerDisplayID; + +void +XdmcpRegisterManufacturerDisplayID (name, length) + 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]; +} + +/* + * initialize XDMCP; create the socket, compute the display + * number, set up the state machine + */ + +void +XdmcpInit() +{ + 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 () +{ + 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(sock) + int sock; +{ + if (state != XDM_AWAIT_MANAGE_RESPONSE) + return; + state = XDM_RUN_SESSION; + sessionSocket = sock; +} + +void +XdmcpCloseDisplay(sock) + 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(data, wt, pReadmask) + pointer data; /* unused */ + struct timeval **wt; + pointer pReadmask; +{ + fd_set *LastSelectMask = (fd_set*)pReadmask; + CARD32 millisToGo, wtMillis; + static struct timeval waittime; + + if (state == XDM_OFF) + return; + FD_SET(xdmcpSocket, LastSelectMask); + if (timeOutTime == 0) + return; + millisToGo = GetTimeInMillis(); + if (millisToGo < timeOutTime) + millisToGo = timeOutTime - millisToGo; + else + millisToGo = 0; + if (*wt == NULL) + { + waittime.tv_sec = (millisToGo) / 1000; + waittime.tv_usec = 1000 * (millisToGo % 1000); + *wt = &waittime; + } + else + { + wtMillis = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000; + if (millisToGo < wtMillis) + { + (*wt)->tv_sec = (millisToGo) / 1000; + (*wt)->tv_usec = 1000 * (millisToGo % 1000); + } + } +} + +/* + * called after select returns; this routine will + * recognise when XDMCP packets await and + * process them appropriately + */ + +/*ARGSUSED*/ +static void +XdmcpWakeupHandler(data, i, pReadmask) + 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(); + FD_CLR(xdmcpSocket, LastSelectMask); + } + 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 && GetTimeInMillis() >= timeOutTime) + { + 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 + */ + +XdmcpSelectHost(host_sockaddr, host_len, AuthenticationName) + struct sockaddr_in *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*/ +XdmcpAddHost(from, fromlen, AuthenticationName, hostname, status) + struct sockaddr_in *from; + ARRAY8Ptr AuthenticationName, hostname, status; +{ + XdmcpSelectHost(from, fromlen, AuthenticationName); +} + +/* + * A message is queued on the socket; read it and + * do the appropriate thing + */ + +ARRAY8 UnwillingMessage = { (CARD8) 14, (CARD8 *) "Host unwilling" }; + +static void +receive_packet() +{ + struct sockaddr_in from; + int fromlen = sizeof(struct sockaddr_in); + XdmcpHeader header; + + /* read message off socket */ + if (!XdmcpFill (xdmcpSocket, &buffer, (struct sockaddr *) &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(&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 +send_packet() +{ + int rtx; + switch (state) { + case XDM_QUERY: + case XDM_BROADCAST: + case XDM_INDIRECT: + 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; + } + 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. + */ + +XdmcpDeadSession (reason) + 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() +{ + timeOutRtx++; + if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT ) + { + XdmcpDeadSession ("too many keepalive retransmissions"); + return; + } + else if (timeOutRtx >= XDM_RTX_LIMIT) + { + ErrorF("XDM: too many retransmissions\n"); + state = XDM_AWAIT_USER_INPUT; + timeOutTime = 0; + timeOutRtx = 0; + return; + } + + switch (state) { + case XDM_COLLECT_QUERY: + state = XDM_QUERY; + break; + case XDM_COLLECT_BROADCAST_QUERY: + state = XDM_BROADCAST; + break; + 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; + } + send_packet(); +} + +static +restart() +{ + state = XDM_INIT_STATE; + timeOutRtx = 0; + send_packet(); +} + +XdmcpCheckAuthentication (Name, Data, packet_type) + ARRAY8Ptr Name, Data; + int packet_type; +{ + return (XdmcpARRAY8Equal (Name, AuthenticationName) && + (AuthenticationName->length == 0 || + (*AuthenticationFuncs->Validator) (AuthenticationData, Data, packet_type))); +} + +XdmcpAddAuthorization (name, data) + ARRAY8Ptr name, data; +{ + Bool (*AddAuth)(), AddAuthorization(); + + 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() +{ +#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 +#ifndef _MINIX + int soopts = 1; + + if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) +#else /* MINIX */ + char *udp_device; + int r, s_errno; + nwio_udpopt_t udpopt; + nbio_ref_t ref; + + udp_device= getenv("UDP_DEVICE"); + if (udp_device == NULL) + udp_device= UDP_DEVICE; + xdmcpSocket= open(udp_device, O_RDWR); + if (xdmcpSocket != -1) + { + udpopt.nwuo_flags= NWUO_COPY | NWUO_LP_SEL | NWUO_EN_LOC | + NWUO_DI_BROAD | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL | + NWUO_DI_IPOPT; + r= ioctl(xdmcpSocket, NWIOSUDPOPT, &udpopt); + if (r == -1) + { + s_errno= errno; + close(xdmcpSocket); + xdmcpSocket= -1; + errno= s_errno; + } + ioctl(xdmcpSocket, NWIOGUDPOPT, &udpopt); + ErrorF("0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", + udpopt.nwuo_flags, + udpopt.nwuo_locport, + udpopt.nwuo_remport, + udpopt.nwuo_locaddr, + udpopt.nwuo_remaddr); + } + if (xdmcpSocket != -1) + { + fcntl(xdmcpSocket, F_SETFD, fcntl(xdmcpSocket, F_GETFD) | + FD_ASYNCHIO); + nbio_register(xdmcpSocket); + ref.ref_int= xdmcpSocket; + nbio_setcallback(xdmcpSocket, ASIO_READ, read_cb, ref); + } + if (xdmcpSocket == -1) +#endif /* !MINIX */ + 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 */ +#endif /* STREAMSCONN */ +} + +static void +send_query_msg() +{ + XdmcpHeader header; + Bool broadcast = FALSE; + int i; + + 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; + case XDM_INDIRECT: + header.opcode = (CARD16) INDIRECT_QUERY; + state = XDM_COLLECT_INDIRECT_QUERY; + 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, &BroadcastAddresses[i], + sizeof (struct sockaddr_in)); + } + else + { + XdmcpFlush (xdmcpSocket, &buffer, &ManagerAddress, + sizeof (ManagerAddress)); + } +} + +static void +recv_willing_msg(from, fromlen, length) + struct sockaddr_in *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: + case XDM_COLLECT_INDIRECT_QUERY: + XdmcpAddHost(from, fromlen, &authenticationName, &hostname, &status); + break; + } + } + } + XdmcpDisposeARRAY8 (&authenticationName); + XdmcpDisposeARRAY8 (&hostname); + XdmcpDisposeARRAY8 (&status); +} + +static void +send_request_msg() +{ + XdmcpHeader header; + int length; + int i; + ARRAY8 authenticationData; + + 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); + XdmcpWriteARRAY16 (&buffer, &ConnectionTypes); + XdmcpWriteARRAYofARRAY8 (&buffer, &ConnectionAddresses); + + XdmcpWriteARRAY8 (&buffer, AuthenticationName); + XdmcpWriteARRAY8 (&buffer, &authenticationData); + XdmcpDisposeARRAY8 (&authenticationData); + XdmcpWriteARRAYofARRAY8 (&buffer, &AuthorizationNames); + XdmcpWriteARRAY8 (&buffer, &ManufacturerDisplayID); + if (XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen)) + state = XDM_AWAIT_REQUEST_RESPONSE; +} + +static void +recv_accept_msg(length) + 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(length) + 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() +{ + XdmcpHeader header; + + 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; + XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen); +} + +static void +recv_refuse_msg(length) + 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(length) + 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() +{ + XdmcpHeader header; + + 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; + XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen); +} + +static void +recv_alive_msg (length) + unsigned length; +{ + CARD8 SessionRunning; + CARD32 AliveSessionID; + int dormancy; + + 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 respose indicates session dead"); + } + } +} + +static +XdmcpFatal (type, status) + char *type; + ARRAY8Ptr status; +{ + FatalError ("XDMCP fatal error: %s %*.*s\n", type, + status->length, status->length, status->data); +} + +static +XdmcpWarning(str) + char *str; +{ + ErrorF("XDMCP warning: %s\n", str); +} + +static +get_manager_by_name(argc, argv, i) + int argc, i; + char **argv; +{ + struct hostent *hep; + + if (i == argc) + { + ErrorF("Xserver: missing host name in command line\n"); + exit(1); + } + if (!(hep = gethostbyname(argv[i]))) + { + ErrorF("Xserver: unknown host: %s\n", argv[i]); + exit(1); + } +#ifndef _MINIX + if (hep->h_length == sizeof (struct in_addr)) +#else + if (hep->h_length == sizeof (ipaddr_t)) +#endif + { + memmove(&ManagerAddress.sin_addr, hep->h_addr, hep->h_length); +#ifdef BSD44SOCKETS + ManagerAddress.sin_len = sizeof(ManagerAddress); +#endif + ManagerAddress.sin_family = AF_INET; + ManagerAddress.sin_port = htons (xdm_udp_port); + } + else + { + ErrorF ("Xserver: host on strange network %s\n", argv[i]); + exit (1); + } +} + +#ifdef MINIX +static char read_buffer[XDM_MAX_MSGLEN+sizeof(udp_io_hdr_t)]; +static int read_inprogress; +static int read_size; + +int +XdmcpFill (fd, buffer, from, fromlen) +int fd; +XdmcpBufferPtr buffer; +XdmcpNetaddr from; /* return */ +int *fromlen; /* return */ +{ + int r; + + if (read_inprogress) + return 0; + + if (read_size != 0) + { + r= read_size; + read_size= 0; + return MNX_XdmcpFill(fd, buffer, from, fromlen, read_buffer, + r); + } + + r= read(fd, read_buffer, sizeof(read_buffer)); + if (r > 0) + { + return MNX_XdmcpFill(fd, buffer, from, fromlen, read_buffer, + r); + } + else if (r == -1 && errno == EINPROGRESS) + { + read_inprogress= 1; + nbio_inprogress(fd, ASIO_READ, 1 /* read */, 0 /* write */, + 0 /* except */); + return 0; + } + else + FatalError("XdmcpFill: read failed: %s\n", + r == 0 ? "EOF" : strerror(errno)); + return 0; +} + +static void read_cb(ref, res, err) +nbio_ref_t ref; +int res; +int err; +{ + if (res <= 0) + { + FatalError("xdmcp'read_cb: read failed: %s\n", + res == 0 ? "EOF" : strerror(err)); + } + read_inprogress= 0; + read_size= res; +} +#endif + +#else +static int xdmcp_non_empty; /* avoid complaint by ranlib */ +#endif /* XDMCP */