summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic Lee <llyzs@163.com>2010-05-30 17:08:24 +0800
committerVic Lee <llyzs@163.com>2010-05-30 17:19:02 +0800
commita9957d6417aff61be68117472075ebdd0996542f (patch)
tree0f2ba0a282982070c643385bffcbdc9643901374
Initial commit
-rw-r--r--.gitignore20
-rw-r--r--AUTHORS5
-rw-r--r--COPYING0
-rw-r--r--ChangeLog0
-rw-r--r--INSTALL0
-rw-r--r--Makefile.am47
-rw-r--r--NEWS0
-rw-r--r--README8
-rwxr-xr-xautogen.sh13
-rw-r--r--configure.ac35
-rw-r--r--xdmcpclient.c530
-rw-r--r--xdmcpclient.h51
-rw-r--r--xqproxy.c170
-rw-r--r--xqproxy.man144
-rwxr-xr-xxqssh19
15 files changed, 1042 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b295e48
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,20 @@
+Makefile
+Makefile.in
+aclocal.m4
+config.guess
+config.h.in
+config.sub
+configure
+depcomp
+install-sh
+missing
+.deps
+autom4te.cache
+config.h
+*~
+config.log
+config.status
+stamp-h1
+*.o
+xqproxy.1
+xqproxy
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..a26e7b5
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,5 @@
+Maintainers:
+
+ Vic Lee <llyzs@163.com>
+
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/COPYING
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/INSTALL
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..6e91105
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,47 @@
+bin_PROGRAMS = xqproxy
+
+AM_CFLAGS = $(libxdmcp_CFLAGS)
+xqproxy_LDADD = $(libxdmcp_LIBS)
+
+xqproxy_SOURCES = \
+ xdmcpclient.c \
+ xdmcpclient.h \
+ xqproxy.c
+
+appman_PRE = \
+ xqproxy.man
+
+# App default files (*.ad)
+
+EXTRA_DIST = ChangeLog autogen.sh xqssh
+
+appmandir = $(APP_MAN_DIR)
+
+appman_DATA = $(appman_PRE:man=@APP_MAN_SUFFIX@)
+
+EXTRA_DIST += $(appman_PRE)
+CLEANFILES = $(appman_DATA)
+
+SED = sed
+
+# Strings to replace in man pages
+XORGRELSTRING = @PACKAGE_STRING@
+ XORGMANNAME = X Version 11
+
+MAN_SUBSTS = \
+ -e 's|__vendorversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
+ -e 's|__xorgversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
+ -e 's|__xservername__|Xorg|g' \
+ -e 's|__xconfigfile__|xorg.conf|g' \
+ -e 's|__projectroot__|$(prefix)|g' \
+ -e 's|__apploaddir__|$(appdefaultdir)|' \
+ -e 's|__appmansuffix__|$(APP_MAN_SUFFIX)|g' \
+ -e 's|__libmansuffix__|$(LIB_MAN_SUFFIX)|g' \
+ -e 's|__adminmansuffix__|$(ADMIN_MAN_SUFFIX)|g' \
+ -e 's|__miscmansuffix__|$(MISC_MAN_SUFFIX)|g' \
+ -e 's|__filemansuffix__|$(FILE_MAN_SUFFIX)|g'
+
+SUFFIXES = .$(APP_MAN_SUFFIX) .man
+
+.man.$(APP_MAN_SUFFIX):
+ sed $(MAN_SUBSTS) < $< > $@
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..efd6dfc
--- /dev/null
+++ b/README
@@ -0,0 +1,8 @@
+This package contains the following binary executable:
+
+xqproxy - XDMCP Query Proxy
+
+Please see man pages for more information.
+
+To compile on Debian, you need libxdmcp-dev package installed.
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..e81f989
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,13 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+autoreconf -v --install || exit 1
+cd $ORIGDIR || exit $?
+
+$srcdir/configure --enable-maintainer-mode "$@"
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..aa24b03
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,35 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.59])
+AC_INIT(xqproxy,[0.1.0])
+AM_INIT_AUTOMAKE([dist-bzip2])
+AM_MAINTAINER_MODE
+
+# Require xorg-macros version 1.2.0 or newer for XORG_CHANGELOG macro
+m4_ifndef([XORG_MACROS_VERSION], [AC_FATAL([must install xorg-macros 1.2 or later before running autoconf/autogen])])
+XORG_MACROS_VERSION(1.2)
+
+AM_CONFIG_HEADER(config.h)
+
+AC_PROG_CC
+AC_PROG_INSTALL
+
+# Only use -Wall if we have gcc
+if test "x$GCC" = "xyes"; then
+ if test -z "`echo "$CFLAGS" | grep "\-Wall" 2> /dev/null`" ; then
+ CFLAGS="$CFLAGS -Wall"
+ fi
+fi
+
+PKG_CHECK_MODULES(libxdmcp, [
+ xdmcp >= 1.0.0
+])
+AC_SUBST(libxdmcp_LIBS)
+AC_SUBST(libxdmcp_CFLAGS)
+
+XORG_MANPAGE_SECTIONS
+XORG_RELEASE_VERSION
+XORG_CHANGELOG
+
+AC_OUTPUT([Makefile])
diff --git a/xdmcpclient.c b/xdmcpclient.c
new file mode 100644
index 0000000..be27e25
--- /dev/null
+++ b/xdmcpclient.c
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2009 Vic Lee
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * 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 AUTHORS OR COPYRIGHT
+ * HOLDERS 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <X11/Xdmcp.h>
+#include "xdmcpclient.h"
+
+static const char* HEX = "0123456789abcdef";
+
+static void
+PrintARRAY8 (ARRAY8Ptr arr, int ascii)
+{
+ int i;
+ for (i = 0; i < arr->length; i++)
+ {
+ if (ascii)
+ {
+ putc (arr->data[i], stdout);
+ }
+ else
+ {
+ putc (HEX[arr->data[i] / 16 % 16], stdout);
+ putc (HEX[arr->data[i] % 16], stdout);
+ }
+ }
+}
+
+static char*
+ConvertARRAY8toString (ARRAY8Ptr arr, int ascii)
+{
+ char *s;
+ int i;
+
+ if (ascii)
+ {
+ s = (char*) malloc (arr->length + 1);
+ for (i = 0; i < arr->length; i++)
+ {
+ s[i] = arr->data[i];
+ }
+ s[arr->length] = 0;
+ }
+ else
+ {
+ s = (char*) malloc (arr->length * 2 + 1);
+ for (i = 0; i < arr->length; i++)
+ {
+ s[i * 2] = HEX[arr->data[i] / 16 % 16];
+ s[i * 2 + 1] = HEX[arr->data[i] % 16];
+ }
+ s[arr->length * 2] = 0;
+ }
+ return s;
+}
+
+static int
+ARRAY8ofARRAY8Len (ARRAYofARRAY8Ptr arr)
+{
+ int i;
+ int len;
+ len = 0;
+ for (i = 0; i < arr->length; i++)
+ {
+ len += 2 + arr->data[i].length;
+ }
+ return len;
+}
+
+struct _XdmcpClient
+{
+ struct sockaddr_storage Addr;
+ int AddrLen;
+ int Sock;
+ int Timeout;
+
+ XdmcpHeader header;
+ XdmcpBuffer buffer;
+
+ ARRAYofARRAY8 AuthenNames;
+ ARRAYofARRAY8 AuthenDatas;
+ ARRAY8 AuthenName;
+ ARRAY8 AuthenData;
+
+ ARRAYofARRAY8 AuthorNames;
+ ARRAY8 AuthorName;
+ ARRAY8 AuthorData;
+
+ int DisplayNumber;
+ ARRAY8 DisplayClass;
+ ARRAY8 DisplayID;
+
+ CARD32 SessionID;
+};
+
+static void
+XdmcpClientRegisterAuthen (XdmcpClient *client, const char *name, const char *data, int datalen)
+{
+ int i;
+ int len;
+ int namelen;
+ ARRAY8 n, d;
+
+ namelen = strlen (name);
+ XdmcpAllocARRAY8 (&n, namelen);
+ XdmcpAllocARRAY8 (&d, datalen);
+ for (i = 0; i < namelen; i++) n.data[i] = name[i];
+ for (i = 0; i < datalen; i++) d.data[i] = data[i];
+
+ len = client->AuthenNames.length + 1;
+ XdmcpReallocARRAYofARRAY8 (&client->AuthenNames, len);
+ XdmcpReallocARRAYofARRAY8 (&client->AuthenDatas, len);
+ client->AuthenNames.data[len - 1] = n;
+ client->AuthenDatas.data[len - 1] = d;
+}
+
+static void
+XdmcpClientRegisterDisplayClass (XdmcpClient *client, const char *displayclass)
+{
+ int len;
+
+ XdmcpDisposeARRAY8 (&client->DisplayClass);
+ len = strlen (displayclass);
+ XdmcpAllocARRAY8 (&client->DisplayClass, len);
+ memcpy (client->DisplayClass.data, displayclass, len);
+}
+
+static void
+XdmcpClientRegisterDisplayID (XdmcpClient *client, const char *displayid)
+{
+ int len;
+
+ XdmcpDisposeARRAY8 (&client->DisplayID);
+ len = strlen (displayid);
+ XdmcpAllocARRAY8 (&client->DisplayID, len);
+ memcpy (client->DisplayID.data, displayid, len);
+}
+
+static void
+XdmcpClientRegisterAuthor (XdmcpClient *client, const char *name)
+{
+ int i;
+ int len;
+ int namelen;
+ ARRAY8 n;
+
+ namelen = strlen (name);
+ XdmcpAllocARRAY8 (&n, namelen);
+ for (i = 0; i < namelen; i++) n.data[i] = name[i];
+
+ len = client->AuthorNames.length + 1;
+ XdmcpReallocARRAYofARRAY8 (&client->AuthorNames, len);
+ client->AuthorNames.data[len - 1] = n;
+}
+
+int
+XdmcpClientRegisterServer (XdmcpClient *client, const char *host, const char *port)
+{
+ struct addrinfo hints;
+ struct addrinfo *res;
+ int error;
+
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = PF_UNSPEC;
+ error = getaddrinfo (host, port, &hints, &res);
+ if (error)
+ {
+ printf ("Error> getaddrinfo on %s:%s failed: %s.\n", host, port, gai_strerror (error));
+ return FALSE;
+ }
+ while (res)
+ {
+ /* TODO: Somehow gdm does not response on IPv6? will figure it out later */
+ if (res->ai_family == AF_INET)
+ {
+ break;
+ }
+ res = res->ai_next;
+ }
+ if (res == NULL)
+ {
+ printf ("Error> host not on supported network type.\n");
+ return FALSE;
+ }
+
+ memmove (&client->Addr, res->ai_addr, res->ai_addrlen);
+ client->AddrLen = res->ai_addrlen;
+
+ printf ("Client> Server address %s:%s registered.\n", host, port);
+
+ return TRUE;
+}
+
+XdmcpClient*
+XdmcpClientNew (int display_number, int timeout)
+{
+ XdmcpClient *client;
+ int sock;
+
+ sock = socket (AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ {
+ printf ("Error> failed to create socket.\n");
+ return NULL;
+ }
+
+ client = (XdmcpClient*) malloc (sizeof (XdmcpClient));
+ memset (client, 0, sizeof (XdmcpClient));
+ client->Sock = sock;
+ client->Timeout = timeout;
+
+ XdmcpClientRegisterAuthen (client, "XDM-AUTHENTICATION-1", "test", 4);
+ XdmcpClientRegisterDisplayClass (client, "xqproxy");
+ XdmcpClientRegisterDisplayID (client, "xqproxy");
+ XdmcpClientRegisterAuthor (client, "MIT-MAGIC-COOKIE-1");
+
+ client->DisplayNumber = display_number;
+
+ printf ("Client> Initialized on display :%i.\n", display_number);
+
+ return client;
+}
+
+void
+XdmcpClientFree (XdmcpClient *client)
+{
+ if (client->Sock > 0)
+ {
+ close (client->Sock);
+ }
+ XdmcpDisposeARRAYofARRAY8 (&client->AuthenNames);
+ XdmcpDisposeARRAYofARRAY8 (&client->AuthenDatas);
+ XdmcpDisposeARRAYofARRAY8 (&client->AuthorNames);
+ free (client);
+}
+
+int
+XdmcpClientReceivePacket (XdmcpClient *client)
+{
+ fd_set fsread;
+ fd_set fserr;
+ struct timeval timeout;
+ int ret;
+
+ FD_ZERO (&fsread);
+ FD_SET (client->Sock, &fsread);
+ FD_ZERO (&fserr);
+ FD_SET (client->Sock, &fserr);
+ timeout.tv_sec = client->Timeout;
+ timeout.tv_usec = 0;
+
+ ret = select(FD_SETSIZE, &fsread, NULL, &fserr, &timeout);
+ if (ret < 0)
+ {
+ printf("Error> Failed to call select().\n");
+ return FALSE;
+ }
+ if (FD_ISSET (client->Sock, &fserr))
+ {
+ printf("Error> Socket error.\n");
+ return FALSE;
+ }
+ if (!FD_ISSET (client->Sock, &fsread))
+ {
+ printf ("Error> No response from the server.\n");
+ return FALSE;
+ }
+
+ if (!XdmcpFill (client->Sock, &client->buffer, (XdmcpNetaddr) &client->Addr, &client->AddrLen))
+ {
+ printf ("Error> Failed to receive from the server.\n");
+ return FALSE;
+ }
+ if (!XdmcpReadHeader (&client->buffer, &client->header))
+ {
+ printf ("Error> Received corrupted packet header.\n");
+ return FALSE;
+ }
+ if (client->header.version != XDM_PROTOCOL_VERSION)
+ {
+ printf ("Error> Received unsupported version %i.\n", client->header.version);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+int
+XdmcpClientSetAuth (XdmcpClient *client, ARRAY8Ptr authenname)
+{
+ int ret = FALSE;
+ int i;
+ if (authenname->length == 0)
+ {
+ ret = TRUE;
+ }
+ else
+ {
+ for (i = 0; i < client->AuthenNames.length; i++)
+ {
+ if (XdmcpARRAY8Equal (&client->AuthenNames.data[i], authenname))
+ {
+ client->AuthenName = client->AuthenNames.data[i];
+ client->AuthenData = client->AuthenDatas.data[i];
+ ret = TRUE;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+int
+XdmcpClientQuery (XdmcpClient *client)
+{
+ int ret;
+ ARRAY8 authenname = { 0 };
+ ARRAY8 hostname = { 0 };
+ ARRAY8 status = { 0 };
+
+ client->header.version = XDM_PROTOCOL_VERSION;
+ client->header.opcode = (CARD16) QUERY;
+ client->header.length = 1;
+ client->header.length += ARRAY8ofARRAY8Len (&client->AuthenNames);
+ XdmcpWriteHeader (&client->buffer, &client->header);
+ XdmcpWriteARRAYofARRAY8 (&client->buffer, &client->AuthenNames);
+ XdmcpFlush (client->Sock, &client->buffer, (XdmcpNetaddr) &client->Addr, client->AddrLen);
+
+ printf ("Client> QUERY packet sent to server.\n");
+
+ if (!XdmcpClientReceivePacket (client)) return FALSE;
+
+ switch (client->header.opcode)
+ {
+ case WILLING:
+ break;
+ case UNWILLING:
+ printf ("Error> Server is unwilling to accept remote login.\n");
+ return FALSE;
+ default:
+ printf ("Error> Unexpected response %i\n", client->header.opcode);
+ return FALSE;
+ }
+
+ ret = FALSE;
+ if (XdmcpReadARRAY8 (&client->buffer, &authenname) &&
+ XdmcpReadARRAY8 (&client->buffer, &hostname) &&
+ XdmcpReadARRAY8 (&client->buffer, &status))
+ {
+ printf ("Server> WILLING (authen:");
+ PrintARRAY8 (&authenname, TRUE);
+ printf (" host:");
+ PrintARRAY8 (&hostname, TRUE);
+ printf (" status:");
+ PrintARRAY8 (&status, TRUE);
+ printf (")\n");
+ if (client->header.length == 6 + authenname.length + hostname.length + status.length)
+ {
+ ret = XdmcpClientSetAuth (client, &authenname);
+ if (!ret)
+ {
+ printf ("Error> Unsupported authentication name\n");
+ }
+ }
+ else
+ {
+ printf ("Error> Header length unmatched\n");
+ }
+ }
+ else
+ {
+ printf ("Error> Corrupted willing packet\n");
+ }
+ XdmcpDisposeARRAY8 (&authenname);
+ XdmcpDisposeARRAY8 (&hostname);
+ XdmcpDisposeARRAY8 (&status);
+
+ return ret;
+}
+
+int
+XdmcpClientAddXauth (XdmcpClient *client)
+{
+ char *cmd;
+ int len;
+ char *authorname, *authordata;
+ int ret;
+
+ authorname = ConvertARRAY8toString (&client->AuthorName, TRUE);
+ authordata = ConvertARRAY8toString (&client->AuthorData, FALSE);
+
+ len = 20 + strlen (authorname) + strlen (authordata);
+ cmd = (char*) malloc (len + 1);
+ snprintf (cmd, len, "xauth add :%i %s %s", client->DisplayNumber, authorname, authordata);
+ ret = system (cmd);
+
+ printf ("Client> '%s' returns %i\n", cmd, ret);
+
+ free (authorname);
+ free (authordata);
+ free (cmd);
+
+ return (ret == 0);
+}
+
+int
+XdmcpClientRequest (XdmcpClient *client)
+{
+ int ret;
+ ARRAY8 AcceptAuthenName = { 0 }, AcceptAuthenData = { 0 };
+
+ client->header.version = XDM_PROTOCOL_VERSION;
+ client->header.opcode = (CARD16) REQUEST;
+
+ client->header.length = 2; /* display number */
+ /* TODO: Connection Types */
+ client->header.length += 1 + 2 * 0; /* connection types */
+ client->header.length += 1; /* connection addresses */
+ /* for each connection type, += 2 + data.length */
+ client->header.length += 2 + client->AuthenName.length;
+ client->header.length += 2 + client->AuthenData.length;
+ client->header.length += 1; /* authorization names */
+ client->header.length += ARRAY8ofARRAY8Len (&client->AuthorNames);
+ client->header.length += 2 + client->DisplayID.length;
+
+ XdmcpWriteHeader (&client->buffer, &client->header);
+ XdmcpWriteCARD16 (&client->buffer, (CARD16) client->DisplayNumber);
+ XdmcpWriteCARD8 (&client->buffer, (CARD8) 0);
+ /* connection types here */
+ XdmcpWriteCARD8 (&client->buffer, (CARD8) 0);
+ /* connection addresses here */
+ XdmcpWriteARRAY8 (&client->buffer, &client->AuthenName);
+ XdmcpWriteARRAY8 (&client->buffer, &client->AuthenData);
+ XdmcpWriteARRAYofARRAY8 (&client->buffer, &client->AuthorNames);
+ XdmcpWriteARRAY8 (&client->buffer, &client->DisplayID);
+
+ XdmcpFlush (client->Sock, &client->buffer, (XdmcpNetaddr) &client->Addr, client->AddrLen);
+
+ printf ("Client> REQUEST packet sent.\n");
+
+ if (!XdmcpClientReceivePacket (client)) return FALSE;
+
+ switch (client->header.opcode)
+ {
+ case ACCEPT:
+ break;
+ case DECLINE:
+ printf ("Error> Server declined remote login request.\n");
+ return FALSE;
+ default:
+ printf ("Error> Unexpected response %i\n", client->header.opcode);
+ return FALSE;
+ }
+
+ ret = FALSE;
+
+ if (XdmcpReadCARD32 (&client->buffer, &client->SessionID) &&
+ XdmcpReadARRAY8 (&client->buffer, &AcceptAuthenName) &&
+ XdmcpReadARRAY8 (&client->buffer, &AcceptAuthenData) &&
+ XdmcpReadARRAY8 (&client->buffer, &client->AuthorName) &&
+ XdmcpReadARRAY8 (&client->buffer, &client->AuthorData))
+ {
+ printf ("Server> ACCEPT (sessionid:%u authen:", (unsigned int) client->SessionID);
+ PrintARRAY8 (&AcceptAuthenName, TRUE);
+ printf (" authendata:");
+ PrintARRAY8 (&AcceptAuthenData, FALSE);
+ printf (" author:");
+ PrintARRAY8 (&client->AuthorName, TRUE);
+ printf (" authordata:");
+ PrintARRAY8 (&client->AuthorData, FALSE);
+ printf (")\n");
+ ret = TRUE;
+ }
+ else
+ {
+ printf ("Error> Corrupted accept packet\n");
+ }
+
+ return ret;
+}
+
+int
+XdmcpClientManage (XdmcpClient *client, unsigned int sessionid)
+{
+ client->header.version = XDM_PROTOCOL_VERSION;
+ client->header.opcode = (CARD16) MANAGE;
+ client->header.length = 8 + client->DisplayClass.length;
+
+ if (sessionid > 0)
+ {
+ client->SessionID = (CARD32) sessionid;
+ }
+
+ XdmcpWriteHeader (&client->buffer, &client->header);
+ XdmcpWriteCARD32 (&client->buffer, client->SessionID);
+ XdmcpWriteCARD16 (&client->buffer, (CARD16) client->DisplayNumber);
+ XdmcpWriteARRAY8 (&client->buffer, &client->DisplayClass);
+
+ XdmcpFlush (client->Sock, &client->buffer, (XdmcpNetaddr) &client->Addr, client->AddrLen);
+
+ printf ("Client> MANAGE packet sent for session %u.\n", (unsigned int) client->SessionID);
+
+ return TRUE;
+}
+
diff --git a/xdmcpclient.h b/xdmcpclient.h
new file mode 100644
index 0000000..2cc5a48
--- /dev/null
+++ b/xdmcpclient.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2009 Vic Lee
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * 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 AUTHORS OR COPYRIGHT
+ * HOLDERS 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.
+ */
+
+#ifndef __XDMCPCLIENT_H__
+#define __XDMCPCLIENT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _XdmcpClient XdmcpClient;
+
+/* Constructor / Destructor */
+XdmcpClient* XdmcpClientNew (int display_number, int timeout);
+void XdmcpClientFree (XdmcpClient *client);
+
+int XdmcpClientRegisterServer (XdmcpClient *client, const char *host, const char *port);
+
+/* Sending / Receiving */
+int XdmcpClientQuery (XdmcpClient *client);
+int XdmcpClientRequest (XdmcpClient *client);
+int XdmcpClientAddXauth (XdmcpClient *client);
+int XdmcpClientManage (XdmcpClient *client, unsigned int sessionid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XDMCPCLIENT_H__ */
diff --git a/xqproxy.c b/xqproxy.c
new file mode 100644
index 0000000..21a0452
--- /dev/null
+++ b/xqproxy.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2009 Vic Lee
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * 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 AUTHORS OR COPYRIGHT
+ * HOLDERS 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xdmcpclient.h"
+
+#define XQPROXY_ERROR_ARGUMENT 1
+#define XQPROXY_ERROR_INIT 2
+#define XQPROXY_ERROR_RESOLVE 3
+#define XQPROXY_ERROR_QUERY 4
+#define XQPROXY_ERROR_REQUEST 5
+#define XQPROXY_ERROR_XAUTH 6
+#define XQPROXY_ERROR_MANAGE 7
+
+int
+main (int argc, char *argv[])
+{
+ XdmcpClient *client;
+ int ret = 0;
+ int i;
+ int display = 0;
+ unsigned int sessionid = 0;
+ const char *host = "localhost", *port = "177";
+ int do_query = 0;
+ int do_xauth = 0;
+ int do_manage = 0;
+ int timeout = 5;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], "-display") == 0)
+ {
+ if (i + 1 >= argc)
+ {
+ printf ("Error> Missing argument value %s\n", argv[i]);
+ return XQPROXY_ERROR_ARGUMENT;
+ }
+ display = atoi (argv[++i]);
+ continue;
+ }
+ if (strcmp (argv[i], "-host") == 0)
+ {
+ if (i + 1 >= argc)
+ {
+ printf ("Error> Missing argument value %s\n", argv[i]);
+ return XQPROXY_ERROR_ARGUMENT;
+ }
+ host = argv[++i];
+ continue;
+ }
+ if (strcmp (argv[i], "-port") == 0)
+ {
+ if (i + 1 >= argc)
+ {
+ printf ("Error> Missing argument value %s\n", argv[i]);
+ return XQPROXY_ERROR_ARGUMENT;
+ }
+ port = argv[++i];
+ continue;
+ }
+ if (strcmp (argv[i], "-sessionid") == 0)
+ {
+ if (i + 1 >= argc)
+ {
+ printf ("Error> Missing argument value %s\n", argv[i]);
+ return XQPROXY_ERROR_ARGUMENT;
+ }
+ sessionid = (unsigned int) atoi (argv[++i]);
+ continue;
+ }
+ if (strcmp (argv[i], "-timeout") == 0)
+ {
+ if (i + 1 >= argc)
+ {
+ printf ("Error> Missing argument value %s\n", argv[i]);
+ return XQPROXY_ERROR_ARGUMENT;
+ }
+ timeout = (unsigned int) atoi (argv[++i]);
+ continue;
+ }
+ if (strcmp (argv[i], "-query") == 0)
+ {
+ do_query = 1;
+ continue;
+ }
+ if (strcmp (argv[i], "-xauth") == 0)
+ {
+ do_xauth = 1;
+ continue;
+ }
+ if (strcmp (argv[i], "-manage") == 0)
+ {
+ do_manage = 1;
+ continue;
+ }
+ }
+
+ if (do_xauth && !do_query)
+ {
+ printf ("Error> Argument -xauth must be used together with -query\n");
+ return XQPROXY_ERROR_ARGUMENT;
+ }
+
+ if (!do_query && !do_manage)
+ {
+ printf ("Error> Either -query or -manage must be supplied\n");
+ return XQPROXY_ERROR_ARGUMENT;
+ }
+
+ if (do_manage && !sessionid && !do_query)
+ {
+ printf ("Error> Argument -sessionid must be supplied if -manage is used without -query\n");
+ return XQPROXY_ERROR_ARGUMENT;
+ }
+
+ if (sessionid && do_query)
+ {
+ printf ("Error> Argument -sessionid cannot be used together with -query\n");
+ return XQPROXY_ERROR_ARGUMENT;
+ }
+
+ client = XdmcpClientNew (display, timeout);
+ if (!client) return XQPROXY_ERROR_INIT;
+ if (XdmcpClientRegisterServer (client, host, port))
+ {
+ if (do_query)
+ {
+ if (!XdmcpClientQuery (client)) ret = XQPROXY_ERROR_QUERY;
+ else if (!XdmcpClientRequest (client)) ret = XQPROXY_ERROR_REQUEST;
+ else if (do_xauth && !XdmcpClientAddXauth (client)) ret = XQPROXY_ERROR_XAUTH;
+ }
+ if (ret == 0 && do_manage)
+ {
+ if (!XdmcpClientManage (client, sessionid))
+ {
+ ret = XQPROXY_ERROR_MANAGE;
+ }
+ }
+ }
+ else
+ {
+ ret = XQPROXY_ERROR_RESOLVE;
+ }
+ XdmcpClientFree (client);
+ return ret;
+}
diff --git a/xqproxy.man b/xqproxy.man
new file mode 100644
index 0000000..d8155bb
--- /dev/null
+++ b/xqproxy.man
@@ -0,0 +1,144 @@
+.\" Copyright (c) 2009 Vic Lee
+.\"
+.\" Permission is hereby granted, free of charge, to any person
+.\" obtaining a copy of this software and associated documentation
+.\" files (the "Software"), to deal in the Software without
+.\" restriction, including without limitation the rights to use,
+.\" copy, modify, merge, publish, distribute, sublicense, and/or sell
+.\" copies of the Software, and to permit persons to whom the
+.\" Software is furnished to do so, subject to the following
+.\" conditions:
+.\"
+.\" 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 AUTHORS OR COPYRIGHT
+.\" HOLDERS 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.
+.\"
+.de EX \"Begin example
+.ne 5
+.if n .sp 1
+.if t .sp .5
+.nf
+.in +.5i
+..
+.de EE
+.fi
+.in -.5i
+.if n .sp 1
+.if t .sp .5
+..
+.TH XQPROXY 1 __xorgversion__
+.SH NAME
+xqproxy \- XDMCP Query Proxy
+.SH SYNOPSIS
+.B xqproxy
+[-display n] [-host hostname] [-port port] [-timeout seconds] [-query [-xauth]]
+[-manage [-sessionid session-id]]
+.SH DESCRIPTION
+.I xqproxy
+is a proxy program that can send XDMCP query to a display manager to establish
+XDM session for an existing local X display.
+.SH OPTIONS
+.PP
+.TP 8
+.B \-display n
+The local display number. Default is 0.
+.PP
+.TP 8
+.B \-host hostname
+The hostname of the remote display manager. Default is localhost.
+.PP
+.TP 8
+.B \-port port
+The XDMCP UDP port of the remote display manager. Default is 177.
+.PP
+.TP 8
+.B \-timeout seconds
+Timeout value while waiting for response from the server.
+.PP
+.TP 8
+.B \-query
+Sends QUERY and REQUEST to the display manager to request a new session. The
+session id and magic cookie will be printed in stdout.
+.PP
+.TP 8
+.B \-xauth
+When use together with -query option, xqproxy will call xauth to add the magic
+cookie to local .Xauthority database.
+.PP
+.TP 8
+.B \-manage
+Sends MANAGE to the display manager to start the session. If this option is
+used together with -query, it will always use the session id returned from the
+display manager. Otherwise, it will uses the session id assigned by -sessionid
+argument.
+.PP
+.TP 8
+.B \-sessionid session-id
+The new session id returned from the display manager. This option is useful
+only if -manage option is used separately.
+.SH EXAMPLES
+.PP
+The following command request the display manager on REMOTEHOST to establish
+an XDM session directly to a local X server on display :1 :
+.PP
+ xqproxy -display 1 -host \fIREMOTEHOST\fP -query -xauth -manage
+.PP
+The following shell script request the display manager supplied by the first
+argument to establish an XDM session over a secure SSH tunnel on a local
+display supplied by the second argument (note that xqproxy runs on the server)
+:
+.PP
+ #!/bin/sh
+.br
+ # Usage: xqssh <server> <local_display_number>
+.br
+ SSH=$(which ssh)
+.br
+ if [ "x$SSH" = "x" ]; then
+.br
+ echo openssh is required in order to use xqssh.
+.br
+ exit 1
+.br
+ fi
+.br
+ QUERY=$(ssh $1 xqproxy -display $2 -query)
+.br
+ echo "$QUERY"
+.br
+ SESSIONID=$(echo "$QUERY" | awk '/ACCEPT/ {print substr($3,12)}')
+.br
+ COOKIE=$(echo "$QUERY" | awk '/ACCEPT/ {print substr($7,12,32)}')
+.br
+ if [ "x$SESSIONID" = "x" ] || [ "x$COOKIE" = "x" ]; then
+.br
+ exit 1
+.br
+ fi
+.br
+ xauth add :$2 MIT-MAGIC-COOKIE-1 $COOKIE
+.br
+ PORT=$(expr 6000 + $2)
+.br
+ ssh -R $PORT:localhost:$PORT -fN $1
+.br
+ ssh $1 xqproxy -display $2 -manage -sessionid $SESSIONID
+.br
+ exit 0
+.PP
+.SH "SEE ALSO"
+ssh(1)
+.SH BUGS
+.PP
+Please send bugs to Vic Lee <llyzs@163.com>
+.SH AUTHORS
+Vic Lee
+
diff --git a/xqssh b/xqssh
new file mode 100755
index 0000000..9e43fed
--- /dev/null
+++ b/xqssh
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Usage: xqssh <server> <local_display_number>
+SSH=$(which ssh)
+if [ "x$SSH" = "x" ]; then
+ echo openssh is required in order to use xqssh.
+ exit 1
+fi
+QUERY=$(ssh $1 xqproxy -display $2 -query)
+echo "$QUERY"
+SESSIONID=$(echo "$QUERY" | awk '/ACCEPT/ {print substr($3,12)}')
+COOKIE=$(echo "$QUERY" | awk '/ACCEPT/ {print substr($7,12,32)}')
+if [ "x$SESSIONID" = "x" ] || [ "x$COOKIE" = "x" ]; then
+ exit 1
+fi
+xauth add :$2 MIT-MAGIC-COOKIE-1 $COOKIE
+PORT=$(expr 6000 + $2)
+ssh -R $PORT:localhost:$PORT -fN $1
+ssh $1 xqproxy -display $2 -manage -sessionid $SESSIONID
+exit 0