summaryrefslogtreecommitdiff
path: root/xdmcp.c
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:53 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:53 +0000
commitdf3e1beed5bbb631975127133464b7e24fc38497 (patch)
tree6291fb1c51fb790c2f236249b5f44eb9bedfdc7b /xdmcp.c
R6.6 is the Xorg base-lineXORG-MAIN
Diffstat (limited to 'xdmcp.c')
-rw-r--r--xdmcp.c1226
1 files changed, 1226 insertions, 0 deletions
diff --git a/xdmcp.c b/xdmcp.c
new file mode 100644
index 0000000..6e16575
--- /dev/null
+++ b/xdmcp.c
@@ -0,0 +1,1226 @@
+/* $Xorg: xdmcp.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */
+/*
+
+Copyright 1988, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+/*
+ * xdm - display manager daemon
+ * Author: Keith Packard, MIT X Consortium
+ *
+ * xdmcp.c - Support for XDMCP
+ */
+
+# include "dm.h"
+
+#ifdef XDMCP
+
+# include <X11/X.h>
+# include <X11/Xfuncs.h>
+# include <sys/types.h>
+# include <ctype.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <netdb.h>
+
+#ifdef X_NOT_STDC_ENV
+#define Time_t long
+extern Time_t time ();
+#else
+#include <time.h>
+#define Time_t time_t
+#endif
+
+#define getString(name,len) ((name = malloc (len + 1)) ? 1 : 0)
+
+/*
+ * interface to policy routines
+ */
+
+extern ARRAY8Ptr ChooseAuthentication ();
+extern int Willing ();
+extern ARRAY8Ptr Accept ();
+extern int SelectConnectionTypeIndex ();
+
+int xdmcpFd = -1;
+int chooserFd = -1;
+
+FD_TYPE WellKnownSocketsMask;
+int WellKnownSocketsMax;
+
+#define pS(s) ((s) ? ((char *) (s)) : "empty string")
+
+DestroyWellKnownSockets ()
+{
+ if (xdmcpFd != -1)
+ {
+ close (xdmcpFd);
+ xdmcpFd = -1;
+ }
+ if (chooserFd != -1)
+ {
+ close (chooserFd);
+ chooserFd = -1;
+ }
+}
+
+AnyWellKnownSockets ()
+{
+ return xdmcpFd != -1 || chooserFd != -1;
+}
+
+static XdmcpBuffer buffer;
+
+/*ARGSUSED*/
+static void
+sendForward (connectionType, address, closure)
+ CARD16 connectionType;
+ ARRAY8Ptr address;
+ char *closure;
+{
+#ifdef AF_INET
+ struct sockaddr_in in_addr;
+#endif
+#ifdef AF_DECnet
+#endif
+ struct sockaddr *addr;
+ int addrlen;
+
+ switch (connectionType)
+ {
+#ifdef AF_INET
+ case FamilyInternet:
+ addr = (struct sockaddr *) &in_addr;
+ bzero ((char *) &in_addr, sizeof (in_addr));
+#ifdef BSD44SOCKETS
+ in_addr.sin_len = sizeof(in_addr);
+#endif
+ in_addr.sin_family = AF_INET;
+ in_addr.sin_port = htons ((short) XDM_UDP_PORT);
+ if (address->length != 4)
+ return;
+ memmove( (char *) &in_addr.sin_addr, address->data, address->length);
+ addrlen = sizeof (struct sockaddr_in);
+ break;
+#endif
+#ifdef AF_DECnet
+ case FamilyDECnet:
+#endif
+ default:
+ return;
+ }
+ XdmcpFlush (xdmcpFd, &buffer, addr, addrlen);
+}
+
+extern char *NetaddrAddress();
+extern char *NetaddrPort();
+
+static void
+ClientAddress (from, addr, port, type)
+ struct sockaddr *from;
+ ARRAY8Ptr addr, port; /* return */
+ CARD16 *type; /* return */
+{
+ int length, family;
+ char *data;
+
+ data = NetaddrPort(from, &length);
+ XdmcpAllocARRAY8 (port, length);
+ memmove( port->data, data, length);
+ port->length = length;
+
+ family = ConvertAddr(from, &length, &data);
+ XdmcpAllocARRAY8 (addr, length);
+ memmove( addr->data, data, length);
+ addr->length = length;
+
+ *type = family;
+}
+
+static void
+all_query_respond (from, fromlen, authenticationNames, type)
+ struct sockaddr *from;
+ int fromlen;
+ ARRAYofARRAY8Ptr authenticationNames;
+ xdmOpCode type;
+{
+ ARRAY8Ptr authenticationName;
+ ARRAY8 status;
+ ARRAY8 addr;
+ CARD16 connectionType;
+ int family;
+ int length;
+
+ family = ConvertAddr(from, &length, &(addr.data));
+ addr.length = length; /* convert int to short */
+ Debug ("all_query_respond: conntype=%d, addr=%lx, len=%d\n",
+ family, *(addr.data), addr.length);
+ if (family < 0)
+ return;
+ connectionType = family;
+
+ if (type == INDIRECT_QUERY)
+ RememberIndirectClient (&addr, connectionType);
+ else
+ ForgetIndirectClient (&addr, connectionType);
+
+ authenticationName = ChooseAuthentication (authenticationNames);
+ if (Willing (&addr, connectionType, authenticationName, &status, type))
+ send_willing (from, fromlen, authenticationName, &status);
+ else
+ if (type == QUERY)
+ send_unwilling (from, fromlen, authenticationName, &status);
+ XdmcpDisposeARRAY8 (&status);
+}
+
+static void
+indirect_respond (from, fromlen, length)
+ struct sockaddr *from;
+ int fromlen;
+ int length;
+{
+ ARRAYofARRAY8 queryAuthenticationNames;
+ ARRAY8 clientAddress;
+ ARRAY8 clientPort;
+ CARD16 connectionType;
+ int expectedLen;
+ int i;
+ XdmcpHeader header;
+ int localHostAsWell;
+
+ Debug ("Indirect respond %d\n", length);
+ if (!XdmcpReadARRAYofARRAY8 (&buffer, &queryAuthenticationNames))
+ return;
+ expectedLen = 1;
+ for (i = 0; i < (int)queryAuthenticationNames.length; i++)
+ expectedLen += 2 + queryAuthenticationNames.data[i].length;
+ if (length == expectedLen)
+ {
+ ClientAddress (from, &clientAddress, &clientPort, &connectionType);
+ /*
+ * set up the forward query packet
+ */
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) FORWARD_QUERY;
+ header.length = 0;
+ header.length += 2 + clientAddress.length;
+ header.length += 2 + clientPort.length;
+ header.length += 1;
+ for (i = 0; i < (int)queryAuthenticationNames.length; i++)
+ header.length += 2 + queryAuthenticationNames.data[i].length;
+ XdmcpWriteHeader (&buffer, &header);
+ XdmcpWriteARRAY8 (&buffer, &clientAddress);
+ XdmcpWriteARRAY8 (&buffer, &clientPort);
+ XdmcpWriteARRAYofARRAY8 (&buffer, &queryAuthenticationNames);
+
+ localHostAsWell = ForEachMatchingIndirectHost (&clientAddress, connectionType, sendForward, (char *) 0);
+
+ XdmcpDisposeARRAY8 (&clientAddress);
+ XdmcpDisposeARRAY8 (&clientPort);
+ if (localHostAsWell)
+ all_query_respond (from, fromlen, &queryAuthenticationNames,
+ INDIRECT_QUERY);
+ }
+ else
+ {
+ Debug ("Indirect length error got %d expect %d\n", length, expectedLen);
+ }
+ XdmcpDisposeARRAYofARRAY8 (&queryAuthenticationNames);
+}
+
+static void
+ProcessRequestSocket ()
+{
+ XdmcpHeader header;
+ struct sockaddr_in addr;
+ int addrlen = sizeof addr;
+
+ Debug ("ProcessRequestSocket\n");
+ bzero ((char *) &addr, sizeof (addr));
+ if (!XdmcpFill (xdmcpFd, &buffer, &addr, &addrlen)) {
+ Debug ("XdmcpFill failed\n");
+ return;
+ }
+ if (!XdmcpReadHeader (&buffer, &header)) {
+ Debug ("XdmcpReadHeader failed\n");
+ return;
+ }
+ if (header.version != XDM_PROTOCOL_VERSION) {
+ Debug ("XDMCP header version read was %d, expected %d\n",
+ header.version, XDM_PROTOCOL_VERSION);
+ return;
+ }
+ Debug ("header: %d %d %d\n", header.version, header.opcode, header.length);
+ switch (header.opcode)
+ {
+ case BROADCAST_QUERY:
+ broadcast_respond (&addr, addrlen, header.length);
+ break;
+ case QUERY:
+ query_respond (&addr, addrlen, header.length);
+ break;
+ case INDIRECT_QUERY:
+ indirect_respond (&addr, addrlen, header.length);
+ break;
+ case FORWARD_QUERY:
+ forward_respond (&addr, addrlen, header.length);
+ break;
+ case REQUEST:
+ request_respond (&addr, addrlen, header.length);
+ break;
+ case MANAGE:
+ manage (&addr, addrlen, header.length);
+ break;
+ case KEEPALIVE:
+ send_alive (&addr, addrlen, header.length);
+ break;
+ }
+}
+
+WaitForSomething ()
+{
+ FD_TYPE reads;
+ int nready;
+ extern int Rescan, ChildReady;
+
+ Debug ("WaitForSomething\n");
+ if (AnyWellKnownSockets () && !ChildReady) {
+ reads = WellKnownSocketsMask;
+ nready = select (WellKnownSocketsMax + 1, &reads, 0, 0, 0);
+ Debug ("select returns %d. Rescan: %d ChildReady: %d\n",
+ nready, Rescan, ChildReady);
+ if (nready > 0)
+ {
+ if (xdmcpFd >= 0 && FD_ISSET (xdmcpFd, &reads))
+ ProcessRequestSocket ();
+ if (chooserFd >= 0 && FD_ISSET (chooserFd, &reads))
+ ProcessChooserSocket (chooserFd);
+ }
+ if (ChildReady)
+ {
+ WaitForChild ();
+ }
+ } else
+ WaitForChild ();
+}
+
+/*
+ * respond to a request on the UDP socket.
+ */
+
+static ARRAY8 Hostname;
+
+void
+registerHostname (name, namelen)
+ char *name;
+ int namelen;
+{
+ int i;
+
+ if (!XdmcpReallocARRAY8 (&Hostname, namelen))
+ return;
+ for (i = 0; i < namelen; i++)
+ Hostname.data[i] = name[i];
+}
+
+static void
+direct_query_respond (from, fromlen, length, type)
+ struct sockaddr *from;
+ int fromlen;
+ int length;
+ xdmOpCode type;
+{
+ ARRAYofARRAY8 queryAuthenticationNames;
+ int expectedLen;
+ int i;
+
+ if (!XdmcpReadARRAYofARRAY8 (&buffer, &queryAuthenticationNames))
+ return;
+ expectedLen = 1;
+ for (i = 0; i < (int)queryAuthenticationNames.length; i++)
+ expectedLen += 2 + queryAuthenticationNames.data[i].length;
+ if (length == expectedLen)
+ all_query_respond (from, fromlen, &queryAuthenticationNames, type);
+ XdmcpDisposeARRAYofARRAY8 (&queryAuthenticationNames);
+}
+
+query_respond (from, fromlen, length)
+ struct sockaddr *from;
+ int fromlen;
+ int length;
+{
+ Debug ("Query respond %d\n", length);
+ direct_query_respond (from, fromlen, length, QUERY);
+}
+
+broadcast_respond (from, fromlen, length)
+ struct sockaddr *from;
+ int fromlen;
+ int length;
+{
+ direct_query_respond (from, fromlen, length, BROADCAST_QUERY);
+}
+
+/* computes an X display name */
+
+static char *
+NetworkAddressToName(connectionType, connectionAddress, displayNumber)
+ CARD16 connectionType;
+ ARRAY8Ptr connectionAddress;
+ CARD16 displayNumber;
+{
+ switch (connectionType)
+ {
+ case FamilyInternet:
+ {
+ CARD8 *data;
+ struct hostent *hostent;
+ char *name;
+ char *localhost, *localHostname();
+
+ data = connectionAddress->data;
+ hostent = gethostbyaddr ((char *)data,
+ connectionAddress->length, AF_INET);
+
+ localhost = localHostname ();
+
+ /*
+ * protect against bogus host names
+ */
+ if (hostent && hostent->h_name && hostent->h_name[0]
+ && (hostent->h_name[0] != '.'))
+ {
+ if (!strcmp (localhost, hostent->h_name))
+ {
+ if (!getString (name, 10))
+ return 0;
+ sprintf (name, ":%d", displayNumber);
+ }
+ else
+ {
+ if (removeDomainname)
+ {
+ char *localDot, *remoteDot;
+
+ /* check for a common domain name. This
+ * could reduce names by recognising common
+ * super-domain names as well, but I don't think
+ * this is as useful, and will confuse more
+ * people
+ */
+ if ((localDot = strchr(localhost, '.')) &&
+ (remoteDot = strchr(hostent->h_name, '.')))
+ {
+ /* smash the name in place; it won't
+ * be needed later.
+ */
+ if (!strcmp (localDot+1, remoteDot+1))
+ *remoteDot = '\0';
+ }
+ }
+
+ if (!getString (name, strlen (hostent->h_name) + 10))
+ return 0;
+ sprintf (name, "%s:%d", hostent->h_name, displayNumber);
+ }
+ }
+ else
+ {
+ if (!getString (name, 25))
+ return 0;
+ sprintf(name, "%d.%d.%d.%d:%d",
+ data[0], data[1], data[2], data[3], displayNumber);
+ }
+ return name;
+ }
+#ifdef DNET
+ case FamilyDECnet:
+ return NULL;
+#endif /* DNET */
+ default:
+ return NULL;
+ }
+}
+
+/*ARGSUSED*/
+forward_respond (from, fromlen, length)
+ struct sockaddr *from;
+ int fromlen;
+ int length;
+{
+ ARRAY8 clientAddress;
+ ARRAY8 clientPort;
+ ARRAYofARRAY8 authenticationNames;
+ struct sockaddr *client;
+ int clientlen;
+ int expectedLen;
+ int i;
+
+ Debug ("Forward respond %d\n", length);
+ clientAddress.length = 0;
+ clientAddress.data = 0;
+ clientPort.length = 0;
+ clientPort.data = 0;
+ authenticationNames.length = 0;
+ authenticationNames.data = 0;
+ if (XdmcpReadARRAY8 (&buffer, &clientAddress) &&
+ XdmcpReadARRAY8 (&buffer, &clientPort) &&
+ XdmcpReadARRAYofARRAY8 (&buffer, &authenticationNames))
+ {
+ expectedLen = 0;
+ expectedLen += 2 + clientAddress.length;
+ expectedLen += 2 + clientPort.length;
+ expectedLen += 1; /* authenticationNames */
+ for (i = 0; i < (int)authenticationNames.length; i++)
+ expectedLen += 2 + authenticationNames.data[i].length;
+ if (length == expectedLen)
+ {
+ int j;
+
+ j = 0;
+ for (i = 0; i < (int)clientPort.length; i++)
+ j = j * 256 + clientPort.data[i];
+ Debug ("Forward client address (port %d)", j);
+ for (i = 0; i < (int)clientAddress.length; i++)
+ Debug (" %d", clientAddress.data[i]);
+ Debug ("\n");
+ switch (from->sa_family)
+ {
+#ifdef AF_INET
+ case AF_INET:
+ {
+ struct sockaddr_in in_addr;
+
+ if (clientAddress.length != 4 ||
+ clientPort.length != 2)
+ {
+ goto badAddress;
+ }
+ bzero ((char *) &in_addr, sizeof (in_addr));
+#ifdef BSD44SOCKETS
+ in_addr.sin_len = sizeof(in_addr);
+#endif
+ in_addr.sin_family = AF_INET;
+ memmove( &in_addr.sin_addr, clientAddress.data, 4);
+ memmove( (char *) &in_addr.sin_port, clientPort.data, 2);
+ client = (struct sockaddr *) &in_addr;
+ clientlen = sizeof (in_addr);
+ all_query_respond (client, clientlen, &authenticationNames,
+ FORWARD_QUERY);
+ }
+ break;
+#endif
+#ifdef AF_UNIX
+ case AF_UNIX:
+ {
+ struct sockaddr_un un_addr;
+
+ if (clientAddress.length >= sizeof (un_addr.sun_path))
+ goto badAddress;
+ bzero ((char *) &un_addr, sizeof (un_addr));
+ un_addr.sun_family = AF_UNIX;
+ memmove( un_addr.sun_path, clientAddress.data, clientAddress.length);
+ un_addr.sun_path[clientAddress.length] = '\0';
+ client = (struct sockaddr *) &un_addr;
+#ifdef BSD44SOCKETS
+ un_addr.sun_len = strlen(un_addr.sun_path);
+ clientlen = SUN_LEN(&un_addr);
+#else
+ clientlen = sizeof (un_addr);
+#endif
+ all_query_respond (client, clientlen, &authenticationNames,
+ FORWARD_QUERY);
+ }
+ break;
+#endif
+#ifdef AF_CHAOS
+ case AF_CHAOS:
+ goto badAddress;
+#endif
+#ifdef AF_DECnet
+ case AF_DECnet:
+ goto badAddress;
+#endif
+ }
+ }
+ else
+ {
+ Debug ("Forward length error got %d expect %d\n", length, expectedLen);
+ }
+ }
+badAddress:
+ XdmcpDisposeARRAY8 (&clientAddress);
+ XdmcpDisposeARRAY8 (&clientPort);
+ XdmcpDisposeARRAYofARRAY8 (&authenticationNames);
+}
+
+send_willing (from, fromlen, authenticationName, status)
+ struct sockaddr *from;
+ int fromlen;
+ ARRAY8Ptr authenticationName;
+ ARRAY8Ptr status;
+{
+ XdmcpHeader header;
+
+ Debug ("Send willing %*.*s %*.*s\n", authenticationName->length,
+ authenticationName->length,
+ pS(authenticationName->data),
+ status->length,
+ status->length,
+ pS(status->data));
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) WILLING;
+ header.length = 6 + authenticationName->length +
+ Hostname.length + status->length;
+ XdmcpWriteHeader (&buffer, &header);
+ XdmcpWriteARRAY8 (&buffer, authenticationName);
+ XdmcpWriteARRAY8 (&buffer, &Hostname);
+ XdmcpWriteARRAY8 (&buffer, status);
+ XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
+}
+
+send_unwilling (from, fromlen, authenticationName, status)
+ struct sockaddr *from;
+ int fromlen;
+ ARRAY8Ptr authenticationName;
+ ARRAY8Ptr status;
+{
+ XdmcpHeader header;
+
+ Debug ("Send unwilling %*.*s %*.*s\n", authenticationName->length,
+ authenticationName->length,
+ pS(authenticationName->data),
+ status->length,
+ status->length,
+ pS(status->data));
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) UNWILLING;
+ header.length = 4 + Hostname.length + status->length;
+ XdmcpWriteHeader (&buffer, &header);
+ XdmcpWriteARRAY8 (&buffer, &Hostname);
+ XdmcpWriteARRAY8 (&buffer, status);
+ XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
+}
+
+static unsigned long globalSessionID;
+
+#define NextSessionID() (++globalSessionID)
+
+void init_session_id()
+{
+ /* Set randomly so we are unlikely to reuse id's from a previous
+ * incarnation so we don't say "Alive" to those displays.
+ * Start with low digits 0 to make debugging easier.
+ */
+ globalSessionID = (time((Time_t)0)&0x7fff) * 16000;
+}
+
+static ARRAY8 outOfMemory = { (CARD16) 13, (CARD8Ptr) "Out of memory" };
+static ARRAY8 noValidAddr = { (CARD16) 16, (CARD8Ptr) "No valid address" };
+static ARRAY8 noValidAuth = { (CARD16) 22, (CARD8Ptr) "No valid authorization" };
+static ARRAY8 noAuthentic = { (CARD16) 29, (CARD8Ptr) "XDM has no authentication key" };
+
+request_respond (from, fromlen, length)
+ struct sockaddr *from;
+ int fromlen;
+ int length;
+{
+ CARD16 displayNumber;
+ ARRAY16 connectionTypes;
+ ARRAYofARRAY8 connectionAddresses;
+ ARRAY8 authenticationName;
+ ARRAY8 authenticationData;
+ ARRAYofARRAY8 authorizationNames;
+ ARRAY8 manufacturerDisplayID;
+ ARRAY8Ptr reason;
+ int expectlen;
+ int i, j;
+ struct protoDisplay *pdpy;
+ ARRAY8 authorizationName, authorizationData;
+ ARRAY8Ptr connectionAddress;
+
+ Debug ("Request respond %d\n", length);
+ connectionTypes.data = 0;
+ connectionAddresses.data = 0;
+ authenticationName.data = 0;
+ authenticationData.data = 0;
+ authorizationNames.data = 0;
+ authorizationName.length = 0;
+ authorizationData.length = 0;
+ manufacturerDisplayID.data = 0;
+ if (XdmcpReadCARD16 (&buffer, &displayNumber) &&
+ XdmcpReadARRAY16 (&buffer, &connectionTypes) &&
+ XdmcpReadARRAYofARRAY8 (&buffer, &connectionAddresses) &&
+ XdmcpReadARRAY8 (&buffer, &authenticationName) &&
+ XdmcpReadARRAY8 (&buffer, &authenticationData) &&
+ XdmcpReadARRAYofARRAY8 (&buffer, &authorizationNames) &&
+ XdmcpReadARRAY8 (&buffer, &manufacturerDisplayID))
+ {
+ expectlen = 0;
+ expectlen += 2; /* displayNumber */
+ expectlen += 1 + 2*connectionTypes.length; /* connectionTypes */
+ expectlen += 1; /* connectionAddresses */
+ for (i = 0; i < (int)connectionAddresses.length; i++)
+ expectlen += 2 + connectionAddresses.data[i].length;
+ expectlen += 2 + authenticationName.length; /* authenticationName */
+ expectlen += 2 + authenticationData.length; /* authenticationData */
+ expectlen += 1; /* authoriationNames */
+ for (i = 0; i < (int)authorizationNames.length; i++)
+ expectlen += 2 + authorizationNames.data[i].length;
+ expectlen += 2 + manufacturerDisplayID.length; /* displayID */
+ if (expectlen != length)
+ {
+ Debug ("Request length error got %d expect %d\n", length, expectlen);
+ goto abort;
+ }
+ if (connectionTypes.length == 0 ||
+ connectionAddresses.length != connectionTypes.length)
+ {
+ reason = &noValidAddr;
+ pdpy = 0;
+ goto decline;
+ }
+ pdpy = FindProtoDisplay (from, fromlen, displayNumber);
+ if (!pdpy) {
+
+ /* Check this Display against the Manager's policy */
+ reason = Accept (from, fromlen, displayNumber);
+ if (reason)
+ goto decline;
+
+ /* Check the Display's stream services against Manager's policy */
+ i = SelectConnectionTypeIndex (&connectionTypes,
+ &connectionAddresses);
+ if (i < 0) {
+ reason = &noValidAddr;
+ goto decline;
+ }
+
+ /* The Manager considers this a new session */
+ connectionAddress = &connectionAddresses.data[i];
+ pdpy = NewProtoDisplay (from, fromlen, displayNumber,
+ connectionTypes.data[i], connectionAddress,
+ NextSessionID());
+ Debug ("NewProtoDisplay 0x%x\n", pdpy);
+ if (!pdpy) {
+ reason = &outOfMemory;
+ goto decline;
+ }
+ }
+ if (authorizationNames.length == 0)
+ j = 0;
+ else
+ j = SelectAuthorizationTypeIndex (&authenticationName,
+ &authorizationNames);
+ if (j < 0)
+ {
+ reason = &noValidAuth;
+ goto decline;
+ }
+ if (!CheckAuthentication (pdpy,
+ &manufacturerDisplayID,
+ &authenticationName,
+ &authenticationData))
+ {
+ reason = &noAuthentic;
+ goto decline;
+ }
+ if (j < (int)authorizationNames.length)
+ {
+ Xauth *auth;
+ SetProtoDisplayAuthorization (pdpy,
+ (unsigned short) authorizationNames.data[j].length,
+ (char *) authorizationNames.data[j].data);
+ auth = pdpy->xdmcpAuthorization;
+ if (!auth)
+ auth = pdpy->fileAuthorization;
+ if (auth)
+ {
+ authorizationName.length = auth->name_length;
+ authorizationName.data = (CARD8Ptr) auth->name;
+ authorizationData.length = auth->data_length;
+ authorizationData.data = (CARD8Ptr) auth->data;
+ }
+ }
+ if (pdpy)
+ {
+ send_accept (from, fromlen, pdpy->sessionID,
+ &authenticationName,
+ &authenticationData,
+ &authorizationName,
+ &authorizationData);
+ }
+ else
+ {
+decline: ;
+ send_decline (from, fromlen, &authenticationName,
+ &authenticationData,
+ reason);
+ if (pdpy)
+ DisposeProtoDisplay (pdpy);
+ }
+ }
+abort:
+ XdmcpDisposeARRAY16 (&connectionTypes);
+ XdmcpDisposeARRAYofARRAY8 (&connectionAddresses);
+ XdmcpDisposeARRAY8 (&authenticationName);
+ XdmcpDisposeARRAY8 (&authenticationData);
+ XdmcpDisposeARRAYofARRAY8 (&authorizationNames);
+ XdmcpDisposeARRAY8 (&manufacturerDisplayID);
+}
+
+send_accept (to, tolen, sessionID,
+ authenticationName, authenticationData,
+ authorizationName, authorizationData)
+ struct sockaddr *to;
+ int tolen;
+ CARD32 sessionID;
+ ARRAY8Ptr authenticationName, authenticationData;
+ ARRAY8Ptr authorizationName, authorizationData;
+{
+ XdmcpHeader header;
+
+ Debug ("Accept Session ID %d\n", sessionID);
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) ACCEPT;
+ header.length = 4; /* session ID */
+ header.length += 2 + authenticationName->length;
+ header.length += 2 + authenticationData->length;
+ header.length += 2 + authorizationName->length;
+ header.length += 2 + authorizationData->length;
+ XdmcpWriteHeader (&buffer, &header);
+ XdmcpWriteCARD32 (&buffer, sessionID);
+ XdmcpWriteARRAY8 (&buffer, authenticationName);
+ XdmcpWriteARRAY8 (&buffer, authenticationData);
+ XdmcpWriteARRAY8 (&buffer, authorizationName);
+ XdmcpWriteARRAY8 (&buffer, authorizationData);
+ XdmcpFlush (xdmcpFd, &buffer, to, tolen);
+}
+
+send_decline (to, tolen, authenticationName, authenticationData, status)
+ struct sockaddr *to;
+ int tolen;
+ ARRAY8Ptr authenticationName, authenticationData;
+ ARRAY8Ptr status;
+{
+ XdmcpHeader header;
+
+ Debug ("Decline %*.*s\n", status->length, status->length, pS(status->data));
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) DECLINE;
+ header.length = 0;
+ header.length += 2 + status->length;
+ header.length += 2 + authenticationName->length;
+ header.length += 2 + authenticationData->length;
+ XdmcpWriteHeader (&buffer, &header);
+ XdmcpWriteARRAY8 (&buffer, status);
+ XdmcpWriteARRAY8 (&buffer, authenticationName);
+ XdmcpWriteARRAY8 (&buffer, authenticationData);
+ XdmcpFlush (xdmcpFd, &buffer, to, tolen);
+}
+
+manage (from, fromlen, length)
+ struct sockaddr *from;
+ int fromlen;
+ int length;
+{
+ CARD32 sessionID;
+ CARD16 displayNumber;
+ ARRAY8 displayClass;
+ int expectlen;
+ struct protoDisplay *pdpy;
+ struct display *d;
+ char *name = NULL;
+ char *class = NULL;
+ XdmcpNetaddr from_save;
+ ARRAY8 clientAddress, clientPort;
+ CARD16 connectionType;
+
+ Debug ("Manage %d\n", length);
+ displayClass.data = 0;
+ displayClass.length = 0;
+ if (XdmcpReadCARD32 (&buffer, &sessionID) &&
+ XdmcpReadCARD16 (&buffer, &displayNumber) &&
+ XdmcpReadARRAY8 (&buffer, &displayClass))
+ {
+ expectlen = 4 + /* session ID */
+ 2 + /* displayNumber */
+ 2 + displayClass.length; /* displayClass */
+ if (expectlen != length)
+ {
+ Debug ("Manage length error got %d expect %d\n", length, expectlen);
+ goto abort;
+ }
+ pdpy = FindProtoDisplay (from, fromlen, displayNumber);
+ Debug ("Manage Session ID %d, pdpy 0x%x\n", sessionID, pdpy);
+ if (!pdpy || pdpy->sessionID != sessionID)
+ {
+ /*
+ * We may have already started a session for this display
+ * but it hasn't seen the response in the form of an
+ * XOpenDisplay() yet. So check if it is in the list of active
+ * displays, and if so check that the session id's match.
+ * If all this is true, then we have a duplicate request that
+ * can be ignored.
+ */
+ if (!pdpy
+ && (d = FindDisplayByAddress(from, fromlen, displayNumber))
+ && d->sessionID == sessionID) {
+ Debug("manage: got duplicate pkt, ignoring\n");
+ goto abort;
+ }
+ Debug ("Session ID %d refused\n", sessionID);
+ if (pdpy)
+ Debug ("Existing Session ID %d\n", pdpy->sessionID);
+ send_refuse (from, fromlen, sessionID);
+ }
+ else
+ {
+ name = NetworkAddressToName (pdpy->connectionType,
+ &pdpy->connectionAddress,
+ pdpy->displayNumber);
+ Debug ("Computed display name: %s\n", name);
+ if (!name)
+ {
+ send_failed (from, fromlen, "(no name)", sessionID, "out of memory");
+ goto abort;
+ }
+ d = FindDisplayByName (name);
+ if (d)
+ {
+ extern void StopDisplay ();
+
+ Debug ("Terminating active session for %s\n", d->name);
+ StopDisplay (d);
+ }
+ class = malloc (displayClass.length + 1);
+ if (!class)
+ {
+ send_failed (from, fromlen, name, sessionID, "out of memory");
+ goto abort;
+ }
+ if (displayClass.length)
+ {
+ memmove( class, displayClass.data, displayClass.length);
+ class[displayClass.length] = '\0';
+ }
+ else
+ {
+ free ((char *) class);
+ class = (char *) NULL;
+ }
+ from_save = (XdmcpNetaddr) malloc (fromlen);
+ if (!from_save)
+ {
+ send_failed (from, fromlen, name, sessionID, "out of memory");
+ goto abort;
+ }
+ memmove( from_save, from, fromlen);
+ d = NewDisplay (name, class);
+ if (!d)
+ {
+ free ((char *) from_save);
+ send_failed (from, fromlen, name, sessionID, "out of memory");
+ goto abort;
+ }
+ d->displayType.location = Foreign;
+ d->displayType.lifetime = Transient;
+ d->displayType.origin = FromXDMCP;
+ d->sessionID = pdpy->sessionID;
+ d->from = from_save;
+ d->fromlen = fromlen;
+ d->displayNumber = pdpy->displayNumber;
+ ClientAddress (from, &clientAddress, &clientPort, &connectionType);
+ d->useChooser = 0;
+ if (IsIndirectClient (&clientAddress, connectionType))
+ {
+ Debug ("IsIndirectClient\n");
+ ForgetIndirectClient (&clientAddress, connectionType);
+ if (UseChooser (&clientAddress, connectionType))
+ {
+ d->useChooser = 1;
+ Debug ("Use chooser for %s\n", d->name);
+ }
+ }
+ d->clientAddr = clientAddress;
+ d->connectionType = connectionType;
+ XdmcpDisposeARRAY8 (&clientPort);
+ if (pdpy->fileAuthorization)
+ {
+ d->authorizations = (Xauth **) malloc (sizeof (Xauth *));
+ if (!d->authorizations)
+ {
+ free ((char *) from_save);
+ free ((char *) d);
+ send_failed (from, fromlen, name, sessionID, "out of memory");
+ goto abort;
+ }
+ d->authorizations[0] = pdpy->fileAuthorization;
+ d->authNum = 1;
+ pdpy->fileAuthorization = 0;
+ }
+ DisposeProtoDisplay (pdpy);
+ Debug ("Starting display %s,%s\n", d->name, d->class);
+ StartDisplay (d);
+ }
+ }
+abort:
+ XdmcpDisposeARRAY8 (&displayClass);
+ if (name) free ((char*) name);
+ if (class) free ((char*) class);
+}
+
+SendFailed (d, reason)
+ struct display *d;
+ char *reason;
+{
+ Debug ("Display start failed, sending Failed\n");
+ send_failed (d->from, d->fromlen, d->name, d->sessionID, reason);
+}
+
+send_failed (from, fromlen, name, sessionID, reason)
+ struct sockaddr *from;
+ int fromlen;
+ char *name;
+ CARD32 sessionID;
+ char *reason;
+{
+ static char buf[256];
+ XdmcpHeader header;
+ ARRAY8 status;
+
+ sprintf (buf, "Session %d failed for display %s: %s",
+ sessionID, name, reason);
+ Debug ("Send failed %d %s\n", sessionID, buf);
+ status.length = strlen (buf);
+ status.data = (CARD8Ptr) buf;
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) FAILED;
+ header.length = 6 + status.length;
+ XdmcpWriteHeader (&buffer, &header);
+ XdmcpWriteCARD32 (&buffer, sessionID);
+ XdmcpWriteARRAY8 (&buffer, &status);
+ XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
+}
+
+send_refuse (from, fromlen, sessionID)
+ struct sockaddr *from;
+ int fromlen;
+ CARD32 sessionID;
+{
+ XdmcpHeader header;
+
+ Debug ("Send refuse %d\n", sessionID);
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) REFUSE;
+ header.length = 4;
+ XdmcpWriteHeader (&buffer, &header);
+ XdmcpWriteCARD32 (&buffer, sessionID);
+ XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
+}
+
+send_alive (from, fromlen, length)
+ struct sockaddr *from;
+ int fromlen;
+ int length;
+{
+ CARD32 sessionID;
+ CARD16 displayNumber;
+ struct display *d;
+ XdmcpHeader header;
+ CARD8 sendRunning;
+ CARD32 sendSessionID;
+
+ Debug ("Send alive\n");
+ if (XdmcpReadCARD16 (&buffer, &displayNumber) &&
+ XdmcpReadCARD32 (&buffer, &sessionID))
+ {
+ if (length == 6)
+ {
+ d = FindDisplayBySessionID (sessionID);
+ if (!d) {
+ d = FindDisplayByAddress (from, fromlen, displayNumber);
+ }
+ sendRunning = 0;
+ sendSessionID = 0;
+ if (d && d->status == running)
+ {
+ if (d->sessionID == sessionID)
+ sendRunning = 1;
+ sendSessionID = d->sessionID;
+ }
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) ALIVE;
+ header.length = 5;
+ Debug ("alive: %d %d\n", sendRunning, sendSessionID);
+ XdmcpWriteHeader (&buffer, &header);
+ XdmcpWriteCARD8 (&buffer, sendRunning);
+ XdmcpWriteCARD32 (&buffer, sendSessionID);
+ XdmcpFlush (xdmcpFd, &buffer, from, fromlen);
+ }
+ }
+}
+
+char *
+NetworkAddressToHostname (connectionType, connectionAddress)
+ CARD16 connectionType;
+ ARRAY8Ptr connectionAddress;
+{
+ char *name = 0;
+
+ switch (connectionType)
+ {
+ case FamilyInternet:
+ {
+ struct hostent *hostent;
+ char dotted[20];
+ char *local_name;
+
+ hostent = gethostbyaddr ((char *)connectionAddress->data,
+ connectionAddress->length, AF_INET);
+
+ if (hostent)
+ local_name = hostent->h_name;
+ else {
+ /* can't get name, so use emergency fallback */
+ sprintf(dotted, "%d.%d.%d.%d",
+ connectionAddress->data[0],
+ connectionAddress->data[1],
+ connectionAddress->data[2],
+ connectionAddress->data[3]);
+ local_name = dotted;
+ LogError ("Cannot convert Internet address %s to host name\n",
+ dotted);
+ }
+ if (!getString (name, strlen (local_name)))
+ break;
+ strcpy (name, local_name);
+ break;
+ }
+#ifdef DNET
+ case FamilyDECnet:
+ break;
+#endif /* DNET */
+ default:
+ break;
+ }
+ return name;
+}
+
+static
+HostnameToNetworkAddress (name, connectionType, connectionAddress)
+char *name;
+CARD16 connectionType;
+ARRAY8Ptr connectionAddress;
+{
+ switch (connectionType)
+ {
+ case FamilyInternet:
+ {
+ struct hostent *hostent;
+
+ hostent = gethostbyname (name);
+ if (!hostent)
+ return FALSE;
+ if (!XdmcpAllocARRAY8 (connectionAddress, hostent->h_length))
+ return FALSE;
+ memmove( connectionAddress->data, hostent->h_addr, hostent->h_length);
+ return TRUE;
+ }
+#ifdef DNET
+ case FamilyDECnet:
+ return FALSE;
+#endif
+ }
+ return FALSE;
+}
+
+/*
+ * converts a display name into a network address, using
+ * the same rules as XOpenDisplay (algorithm cribbed from there)
+ */
+
+static
+NameToNetworkAddress(name, connectionTypep, connectionAddress, displayNumber)
+char *name;
+CARD16Ptr connectionTypep;
+ARRAY8Ptr connectionAddress;
+CARD16Ptr displayNumber;
+{
+ char *colon, *display_number;
+ char hostname[1024];
+ int dnet = FALSE;
+ CARD16 number;
+ CARD16 connectionType;
+
+ colon = strchr(name, ':');
+ if (!colon)
+ return FALSE;
+ if (colon != name)
+ {
+ if (colon - name > sizeof (hostname))
+ return FALSE;
+ strncpy (hostname, name, colon - name);
+ hostname[colon - name] = '\0';
+ }
+ else
+ {
+ strcpy (hostname, localHostname ());
+ }
+ if (colon[1] == ':')
+ {
+ dnet = TRUE;
+ colon++;
+ }
+#ifndef DNETCONN
+ if (dnet)
+ return FALSE;
+#endif
+ display_number = colon + 1;
+ while (*display_number && *display_number != '.')
+ {
+ if (!isascii (*display_number) || !isdigit(*display_number))
+ return FALSE;
+ }
+ if (display_number == colon + 1)
+ return FALSE;
+ number = atoi (colon + 1);
+#ifdef DNETCONN
+ if (dnet)
+ connectionType = FamilyDECnet;
+ else
+#endif
+ connectionType = FamilyInternet;
+ if (!HostnameToNetworkAddress (hostname, connectionType, connectionAddress))
+ return FALSE;
+ *displayNumber = number;
+ *connectionTypep = connectionType;
+ return TRUE;
+}
+
+#endif /* XDMCP */