summaryrefslogtreecommitdiff
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
R6.6 is the Xorg base-lineXORG-MAIN
-rw-r--r--Chooser.ad44
-rw-r--r--access.c748
-rw-r--r--auth.c1278
-rw-r--r--choose.c508
-rw-r--r--chooser.c1005
-rw-r--r--config/GiveConsole10
-rw-r--r--config/README11
-rw-r--r--config/TakeConsole7
-rw-r--r--config/Xaccess68
-rw-r--r--config/Xservers.fs11
-rw-r--r--config/Xservers.ws.cpp13
-rw-r--r--config/Xsetup_03
-rw-r--r--config/xdm-config.cpp19
-rw-r--r--daemon.c146
-rw-r--r--dm.c855
-rw-r--r--dm.h360
-rw-r--r--dpylist.c274
-rw-r--r--error.c195
-rw-r--r--file.c258
-rw-r--r--genauth.c228
-rw-r--r--greet.h187
-rw-r--r--greeter/Login.c904
-rw-r--r--greeter/Login.h106
-rw-r--r--greeter/LoginP.h96
-rw-r--r--greeter/greet.c410
-rw-r--r--greeter/verify.c173
-rw-r--r--krb5auth.c266
-rw-r--r--mitauth.c91
-rw-r--r--netaddr.c242
-rw-r--r--policy.c162
-rw-r--r--protodpy.c173
-rw-r--r--reset.c116
-rw-r--r--resource.c472
-rw-r--r--rpcauth.c88
-rw-r--r--server.c419
-rw-r--r--session.c878
-rw-r--r--socket.c123
-rw-r--r--streams.c147
-rw-r--r--util.c263
-rw-r--r--xdm.man.cpp1258
-rw-r--r--xdmauth.c301
-rw-r--r--xdmcp.c1226
-rw-r--r--xdmshell.c222
43 files changed, 14364 insertions, 0 deletions
diff --git a/Chooser.ad b/Chooser.ad
new file mode 100644
index 0000000..4dc4c74
--- /dev/null
+++ b/Chooser.ad
@@ -0,0 +1,44 @@
+*ShapeStyle: Oval
+*cursor: left_ptr
+*allowShellResize: true
+*label.label: XDMCP Host Menu
+*label.borderWidth: 0
+*label.skipAdjust: true
+*paned*showGrip: false
+!*viewport.horizDistance: 20
+!*viewport.height: 200
+*viewport.width: 400
+*viewport.height: 50
+*viewport.allowVert: true
+*viewport.fromVert: label
+*viewport.resizeable: true
+*viewport.allowResize: true
+
+*list.translations: #override \
+ <BtnDown>: Set() CheckWilling() \n\
+ <BtnUp>(2): Accept()
+*list.defaultColumns: 1
+*list.forceFolumns: true
+
+*box.skipAdjust: true
+*cancel.fromHoriz: viewport
+*cancel.fromVert: label
+*cancel.vertDistance: 100
+*cancel.bottom: ChainBottom
+*cancel.top: ChainBottom
+*cancel.left: ChainRight
+*cancel.right: ChainRight
+
+*accept.fromHoriz: viewport
+*accept.fromVert: cancel
+*accept.bottom: ChainBottom
+*accept.top: ChainBottom
+*accept.left: ChainRight
+*accept.right: ChainRight
+
+*cancel.translations: #override \
+ <BtnUp>: Cancel() unset()
+*accept.translations: #override \
+ <BtnUp>: Accept() unset()
+*ping.translations: #override \
+ <BtnUp>: Ping() unset()
diff --git a/access.c b/access.c
new file mode 100644
index 0000000..2328ba6
--- /dev/null
+++ b/access.c
@@ -0,0 +1,748 @@
+/*
+ * $Xorg: access.c,v 1.5 2001/02/09 02:05:40 xorgcvs Exp $
+ *
+Copyright 1990, 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.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+/*
+ * Access control for XDMCP - keep a database of allowable display addresses
+ * and (potentially) a list of hosts to send ForwardQuery packets to
+ */
+
+# include "dm.h"
+
+#ifdef XDMCP
+
+# include <X11/Xos.h>
+# include <X11/Xdmcp.h>
+# include <X11/X.h>
+# include <stdio.h>
+# include <ctype.h>
+# include <netinet/in.h>
+# include <netdb.h>
+# include <sys/socket.h>
+
+#define ALIAS_CHARACTER '%'
+#define NEGATE_CHARACTER '!'
+#define CHOOSER_STRING "CHOOSER"
+#define BROADCAST_STRING "BROADCAST"
+
+#define HOST_ALIAS 0
+#define HOST_ADDRESS 1
+#define HOST_BROADCAST 2
+#define HOST_CHOOSER 3
+
+typedef struct _hostEntry {
+ struct _hostEntry *next;
+ int type;
+ union _hostOrAlias {
+ char *aliasName;
+ ARRAY8 hostAddress;
+ } entry;
+} HostEntry;
+
+#define DISPLAY_ALIAS 0
+#define DISPLAY_PATTERN 1
+#define DISPLAY_ADDRESS 2
+
+typedef struct _displayEntry {
+ struct _displayEntry *next;
+ int type;
+ int notAllowed;
+ int chooser;
+ union _displayType {
+ char *aliasName;
+ char *displayPattern;
+ struct _display {
+ ARRAY8 clientAddress;
+ CARD16 connectionType;
+ } displayAddress;
+ } entry;
+ HostEntry *hosts;
+} DisplayEntry;
+
+static DisplayEntry *database;
+
+static ARRAY8 localAddress;
+
+ARRAY8Ptr
+getLocalAddress ()
+{
+ static int haveLocalAddress;
+
+ if (!haveLocalAddress)
+ {
+ struct hostent *hostent;
+
+ hostent = gethostbyname (localHostname());
+ XdmcpAllocARRAY8 (&localAddress, hostent->h_length);
+ memmove( localAddress.data, hostent->h_addr, hostent->h_length);
+ }
+ return &localAddress;
+}
+
+static void
+FreeHostEntry (h)
+ HostEntry *h;
+{
+ switch (h->type) {
+ case HOST_ALIAS:
+ free (h->entry.aliasName);
+ break;
+ case HOST_ADDRESS:
+ XdmcpDisposeARRAY8 (&h->entry.hostAddress);
+ break;
+ case HOST_CHOOSER:
+ break;
+ }
+ free ((char *) h);
+}
+
+static void
+FreeDisplayEntry (d)
+ DisplayEntry *d;
+{
+ HostEntry *h, *next;
+ switch (d->type) {
+ case DISPLAY_ALIAS:
+ free (d->entry.aliasName);
+ break;
+ case DISPLAY_PATTERN:
+ free (d->entry.displayPattern);
+ break;
+ case DISPLAY_ADDRESS:
+ XdmcpDisposeARRAY8 (&d->entry.displayAddress);
+ break;
+ }
+ for (h = d->hosts; h; h = next) {
+ next = h->next;
+ FreeHostEntry (h);
+ }
+ free ((char *) d);
+}
+
+static void
+FreeAccessDatabase ()
+{
+ DisplayEntry *d, *next;
+
+ for (d = database; d; d = next)
+ {
+ next = d->next;
+ FreeDisplayEntry (d);
+ }
+ database = 0;
+}
+
+#define WORD_LEN 256
+static char wordBuffer[WORD_LEN];
+static int nextIsEOF;
+
+static char *
+ReadWord (file, EOFatEOL)
+ FILE *file;
+ int EOFatEOL;
+{
+ int c;
+ char *wordp;
+ int quoted;
+
+ wordp = wordBuffer;
+ if (nextIsEOF)
+ {
+ nextIsEOF = FALSE;
+ return NULL;
+ }
+ quoted = FALSE;
+ for (;;) {
+ c = getc (file);
+ switch (c) {
+ case '#':
+ if (quoted)
+ {
+ *wordp++ = c;
+ break;
+ }
+ while ((c = getc (file)) != EOF && c != '\n')
+ ;
+ case '\n':
+ case EOF:
+ if (c == EOF || (EOFatEOL && !quoted))
+ {
+ ungetc (c, file);
+ if (wordp == wordBuffer)
+ return NULL;
+ *wordp = '\0';
+ nextIsEOF = TRUE;
+ return wordBuffer;
+ }
+ case ' ':
+ case '\t':
+ if (wordp != wordBuffer)
+ {
+ ungetc (c, file);
+ *wordp = '\0';
+ return wordBuffer;
+ }
+ break;
+ case '\\':
+ if (!quoted)
+ {
+ quoted = TRUE;
+ continue;
+ }
+ default:
+ *wordp++ = c;
+ break;
+ }
+ quoted = FALSE;
+ }
+}
+
+static HostEntry *
+ReadHostEntry (file)
+ FILE *file;
+{
+ char *hostOrAlias;
+ HostEntry *h;
+ struct hostent *hostent;
+
+tryagain:
+ hostOrAlias = ReadWord (file, TRUE);
+ if (!hostOrAlias)
+ return NULL;
+ h = (HostEntry *) malloc (sizeof (DisplayEntry));
+ if (*hostOrAlias == ALIAS_CHARACTER)
+ {
+ h->type = HOST_ALIAS;
+ h->entry.aliasName = malloc (strlen (hostOrAlias) + 1);
+ if (!h->entry.aliasName) {
+ free ((char *) h);
+ return NULL;
+ }
+ strcpy (h->entry.aliasName, hostOrAlias);
+ }
+ else if (!strcmp (hostOrAlias, CHOOSER_STRING))
+ {
+ h->type = HOST_CHOOSER;
+ }
+ else if (!strcmp (hostOrAlias, BROADCAST_STRING))
+ {
+ h->type = HOST_BROADCAST;
+ }
+ else
+ {
+ h->type = HOST_ADDRESS;
+ hostent = gethostbyname (hostOrAlias);
+ if (!hostent)
+ {
+ Debug ("No such host %s\n", hostOrAlias);
+ LogError ("Access file \"%s\", host \"%s\" not found\n", accessFile, hostOrAlias);
+ free ((char *) h);
+ goto tryagain;
+ }
+ if (!XdmcpAllocARRAY8 (&h->entry.hostAddress, hostent->h_length))
+ {
+ LogOutOfMem ("ReadHostEntry\n");
+ free ((char *) h);
+ return NULL;
+ }
+ memmove( h->entry.hostAddress.data, hostent->h_addr, hostent->h_length);
+ }
+ return h;
+}
+
+static int
+HasGlobCharacters (s)
+ char *s;
+{
+ for (;;)
+ switch (*s++) {
+ case '?':
+ case '*':
+ return 1;
+ case '\0':
+ return 0;
+ }
+}
+
+static DisplayEntry *
+ReadDisplayEntry (file)
+ FILE *file;
+{
+ char *displayOrAlias;
+ DisplayEntry *d;
+ struct _display *display;
+ HostEntry *h, **prev;
+ struct hostent *hostent;
+
+ displayOrAlias = ReadWord (file, FALSE);
+ if (!displayOrAlias)
+ return NULL;
+ d = (DisplayEntry *) malloc (sizeof (DisplayEntry));
+ d->notAllowed = 0;
+ d->chooser = 0;
+ if (*displayOrAlias == ALIAS_CHARACTER)
+ {
+ d->type = DISPLAY_ALIAS;
+ d->entry.aliasName = malloc (strlen (displayOrAlias) + 1);
+ if (!d->entry.aliasName)
+ {
+ free ((char *) d);
+ return NULL;
+ }
+ strcpy (d->entry.aliasName, displayOrAlias);
+ }
+ else
+ {
+ if (*displayOrAlias == NEGATE_CHARACTER)
+ {
+ d->notAllowed = 1;
+ ++displayOrAlias;
+ }
+ if (HasGlobCharacters (displayOrAlias))
+ {
+ d->type = DISPLAY_PATTERN;
+ d->entry.displayPattern = malloc (strlen (displayOrAlias) + 1);
+ if (!d->entry.displayPattern)
+ {
+ free ((char *) d);
+ return NULL;
+ }
+ strcpy (d->entry.displayPattern, displayOrAlias);
+ }
+ else
+ {
+ if ((hostent = gethostbyname (displayOrAlias)) == NULL)
+ {
+ LogError ("Access file %s, display %s unknown\n", accessFile, displayOrAlias);
+ free ((char *) d);
+ return NULL;
+ }
+ d->type = DISPLAY_ADDRESS;
+ display = &d->entry.displayAddress;
+ if (!XdmcpAllocARRAY8 (&display->clientAddress, hostent->h_length))
+ {
+ free ((char *) d);
+ return NULL;
+ }
+ memmove( display->clientAddress.data, hostent->h_addr, hostent->h_length);
+ switch (hostent->h_addrtype)
+ {
+#ifdef AF_UNIX
+ case AF_UNIX:
+ display->connectionType = FamilyLocal;
+ break;
+#endif
+#ifdef AF_INET
+ case AF_INET:
+ display->connectionType = FamilyInternet;
+ break;
+#endif
+#ifdef AF_DECnet
+ case AF_DECnet:
+ display->connectionType = FamilyDECnet;
+ break;
+#endif
+ default:
+ display->connectionType = FamilyLocal;
+ break;
+ }
+ }
+ }
+ prev = &d->hosts;
+ while ((h = ReadHostEntry (file)))
+ {
+ if (h->type == HOST_CHOOSER)
+ {
+ FreeHostEntry (h);
+ d->chooser = 1;
+ } else {
+ *prev = h;
+ prev = &h->next;
+ }
+ }
+ *prev = NULL;
+ return d;
+}
+
+static
+ReadAccessDatabase (file)
+ FILE *file;
+{
+ DisplayEntry *d, **prev;
+
+ prev = &database;
+ while ((d = ReadDisplayEntry (file)))
+ {
+ *prev = d;
+ prev = &d->next;
+ }
+ *prev = NULL;
+}
+
+ScanAccessDatabase ()
+{
+ FILE *datafile;
+
+ FreeAccessDatabase ();
+ if (*accessFile)
+ {
+ datafile = fopen (accessFile, "r");
+ if (!datafile)
+ {
+ LogError ("Cannot open access control file %s, no XDMCP reqeusts will be granted\n", accessFile);
+ return 0;
+ }
+ ReadAccessDatabase (datafile);
+ fclose (datafile);
+ }
+ return 1;
+}
+
+/*
+ * calls the given function for each valid indirect entry. Returns TRUE if
+ * the local host exists on any of the lists, else FALSE
+ */
+
+#define MAX_DEPTH 32
+
+static int indirectAlias ();
+
+static int
+scanHostlist (h, clientAddress, connectionType, function, closure, depth, broadcast)
+ HostEntry *h;
+ ARRAY8Ptr clientAddress;
+ CARD16 connectionType;
+ int (*function)();
+ char *closure;
+ int depth;
+ int broadcast;
+{
+ int haveLocalhost = 0;
+
+ for (; h; h = h->next)
+ {
+ switch (h->type) {
+ case HOST_ALIAS:
+ if (indirectAlias (h->entry.aliasName, clientAddress,
+ connectionType, function, closure, depth,
+ broadcast))
+ haveLocalhost = 1;
+ break;
+ case HOST_ADDRESS:
+ if (XdmcpARRAY8Equal (getLocalAddress(), &h->entry.hostAddress))
+ haveLocalhost = 1;
+ else if (function)
+ (*function) (connectionType, &h->entry.hostAddress, closure);
+ break;
+ case HOST_BROADCAST:
+ if (broadcast)
+ {
+ ARRAY8 temp;
+
+ if (function)
+ {
+ temp.data = (BYTE *) BROADCAST_STRING;
+ temp.length = strlen ((char *)temp.data);
+ (*function) (connectionType, &temp, closure);
+ }
+ }
+ break;
+ }
+ }
+ return haveLocalhost;
+}
+
+/* Returns non-0 iff string is matched by pattern. Does case folding.
+ */
+static int
+patternMatch (string, pattern)
+ char *string, *pattern;
+{
+ int p, s;
+
+ if (!string)
+ string = "";
+
+ for (;;)
+ {
+ s = *string++;
+ switch (p = *pattern++) {
+ case '*':
+ if (!*pattern)
+ return 1;
+ for (string--; *string; string++)
+ if (patternMatch (string, pattern))
+ return 1;
+ return 0;
+ case '?':
+ if (s == '\0')
+ return 0;
+ break;
+ case '\0':
+ return s == '\0';
+ case '\\':
+ p = *pattern++;
+ /* fall through */
+ default:
+ if (isupper(p)) p = tolower(p);
+ if (isupper(s)) s = tolower(s);
+ if (p != s)
+ return 0;
+ }
+ }
+}
+
+static int
+indirectAlias (alias, clientAddress, connectionType, function, closure, depth,
+ broadcast)
+ char *alias;
+ ARRAY8Ptr clientAddress;
+ CARD16 connectionType;
+ int (*function)();
+ char *closure;
+ int depth;
+ int broadcast;
+{
+ DisplayEntry *d;
+ int haveLocalhost = 0;
+
+ if (depth == MAX_DEPTH)
+ return 0;
+ for (d = database; d; d = d->next)
+ {
+ if (d->type != DISPLAY_ALIAS || !patternMatch (alias, d->entry.aliasName))
+ continue;
+ if (scanHostlist (d->hosts, clientAddress, connectionType,
+ function, closure, depth + 1, broadcast))
+ {
+ haveLocalhost = 1;
+ }
+ }
+ return haveLocalhost;
+}
+
+ARRAY8Ptr IndirectChoice ();
+
+int ForEachMatchingIndirectHost (clientAddress, connectionType, function, closure)
+ ARRAY8Ptr clientAddress;
+ CARD16 connectionType;
+ int (*function)();
+ char *closure;
+{
+ int haveLocalhost = 0;
+ DisplayEntry *d;
+ char *clientName = NULL, *NetworkAddressToHostname ();
+
+ for (d = database; d; d = d->next)
+ {
+ switch (d->type) {
+ case DISPLAY_ALIAS:
+ continue;
+ case DISPLAY_PATTERN:
+ if (!clientName)
+ clientName = NetworkAddressToHostname (connectionType,
+ clientAddress);
+ if (!patternMatch (clientName, d->entry.displayPattern))
+ continue;
+ break;
+ case DISPLAY_ADDRESS:
+ if (d->entry.displayAddress.connectionType != connectionType ||
+ !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
+ clientAddress))
+ {
+ continue;
+ }
+ break;
+ }
+ if (!d->hosts)
+ continue;
+ if (d->notAllowed)
+ break;
+ if (d->chooser)
+ {
+ ARRAY8Ptr choice;
+
+ choice = IndirectChoice (clientAddress, connectionType);
+ if (!choice || XdmcpARRAY8Equal (getLocalAddress(), choice))
+ haveLocalhost = 1;
+ else
+ (*function) (connectionType, choice, closure);
+ }
+ else if (scanHostlist (d->hosts, clientAddress, connectionType,
+ function, closure, 0, FALSE))
+ {
+ haveLocalhost = 1;
+ }
+ break;
+ }
+ if (clientName)
+ free (clientName);
+ return haveLocalhost;
+}
+
+int UseChooser (clientAddress, connectionType)
+ ARRAY8Ptr clientAddress;
+ CARD16 connectionType;
+{
+ DisplayEntry *d;
+ char *clientName = NULL, *NetworkAddressToHostname ();
+
+ for (d = database; d; d = d->next)
+ {
+ switch (d->type) {
+ case DISPLAY_ALIAS:
+ continue;
+ case DISPLAY_PATTERN:
+ if (!clientName)
+ clientName = NetworkAddressToHostname (connectionType,
+ clientAddress);
+ if (!patternMatch (clientName, d->entry.displayPattern))
+ continue;
+ break;
+ case DISPLAY_ADDRESS:
+ if (d->entry.displayAddress.connectionType != connectionType ||
+ !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
+ clientAddress))
+ {
+ continue;
+ }
+ break;
+ }
+ if (!d->hosts)
+ continue;
+ if (d->notAllowed)
+ break;
+ if (d->chooser && !IndirectChoice (clientAddress, connectionType)) {
+ if (clientName)
+ free (clientName);
+ return 1;
+ }
+ break;
+ }
+ if (clientName)
+ free (clientName);
+ return 0;
+}
+
+void ForEachChooserHost (clientAddress, connectionType, function, closure)
+ ARRAY8Ptr clientAddress;
+ CARD16 connectionType;
+ int (*function)();
+ char *closure;
+{
+ int haveLocalhost = 0;
+ DisplayEntry *d;
+ char *clientName = NULL, *NetworkAddressToHostname ();
+
+ for (d = database; d; d = d->next)
+ {
+ switch (d->type) {
+ case DISPLAY_ALIAS:
+ continue;
+ case DISPLAY_PATTERN:
+ if (!clientName)
+ clientName = NetworkAddressToHostname (connectionType,
+ clientAddress);
+ if (!patternMatch (clientName, d->entry.displayPattern))
+ continue;
+ break;
+ case DISPLAY_ADDRESS:
+ if (d->entry.displayAddress.connectionType != connectionType ||
+ !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
+ clientAddress))
+ {
+ continue;
+ }
+ break;
+ }
+ if (!d->hosts)
+ continue;
+ if (d->notAllowed)
+ break;
+ if (!d->chooser)
+ break;
+ if (scanHostlist (d->hosts, clientAddress, connectionType,
+ function, closure, 0, TRUE))
+ {
+ haveLocalhost = 1;
+ }
+ break;
+ }
+ if (clientName)
+ free (clientName);
+ if (haveLocalhost)
+ (*function) (connectionType, getLocalAddress(), closure);
+}
+
+/*
+ * returns TRUE if the given client is acceptable to the local host. The
+ * given display client is acceptable if it occurs without a host list.
+ */
+
+int AcceptableDisplayAddress (clientAddress, connectionType, type)
+ ARRAY8Ptr clientAddress;
+ CARD16 connectionType;
+ xdmOpCode type;
+{
+ DisplayEntry *d;
+ char *clientName = NULL, *NetworkAddressToHostname ();
+
+ if (!*accessFile)
+ return 1;
+ if (type == INDIRECT_QUERY)
+ return 1;
+ for (d = database; d; d = d->next)
+ {
+ if (d->hosts)
+ continue;
+ switch (d->type) {
+ case DISPLAY_ALIAS:
+ continue;
+ case DISPLAY_PATTERN:
+ if (!clientName)
+ clientName = NetworkAddressToHostname (connectionType,
+ clientAddress);
+ if (!patternMatch (clientName, d->entry.displayPattern))
+ continue;
+ break;
+ case DISPLAY_ADDRESS:
+ if (d->entry.displayAddress.connectionType != connectionType ||
+ !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress,
+ clientAddress))
+ {
+ continue;
+ }
+ break;
+ }
+ break;
+ }
+ if (clientName)
+ free (clientName);
+ return (d != 0) && (d->notAllowed == 0);
+}
+
+#endif /* XDMCP */
diff --git a/auth.c b/auth.c
new file mode 100644
index 0000000..ac92968
--- /dev/null
+++ b/auth.c
@@ -0,0 +1,1278 @@
+/* $Xorg: auth.c,v 1.5 2001/02/09 02:05:40 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
+ *
+ * auth.c
+ *
+ * maintain the authorization generation daemon
+ */
+
+#include "dm.h"
+#include <X11/X.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#include <sys/socket.h>
+#ifndef ESIX
+# include <sys/ioctl.h>
+#endif /* !ESIX */
+
+#ifdef TCPCONN
+# include <netinet/in.h>
+#endif
+#ifdef DNETCONN
+# include <netdnet/dn.h>
+# include <netdnet/dnetdb.h>
+#endif
+
+#if (defined(_POSIX_SOURCE) && !defined(AIXV3)) || defined(hpux) || defined(USG) || defined(SVR4)
+#define NEED_UTSNAME
+#include <sys/utsname.h>
+#endif
+
+#if defined(SYSV) && defined(SYSV386)
+# include <sys/stream.h>
+# ifdef ISC
+# include <sys/sioctl.h>
+# endif /* ISC */
+# ifdef ESIX
+# include <lan/net_ioctl.h>
+# endif /* ESIX */
+#endif /* SYSV386 */
+
+#ifdef SVR4
+# include <netdb.h>
+# include <sys/sockio.h>
+#ifdef USL
+# include <sys/stropts.h>
+#endif
+#endif
+#ifdef __convex__
+# include <sync/queue.h>
+# include <sync/sema.h>
+#endif
+#include <net/if.h>
+
+extern int MitInitAuth ();
+extern Xauth *MitGetAuth ();
+
+#ifdef HASXDMAUTH
+extern int XdmInitAuth ();
+extern Xauth *XdmGetAuth ();
+#ifdef XDMCP
+extern void XdmGetXdmcpAuth ();
+#else
+#define XdmGetXdmcpAuth NULL
+#endif
+#endif
+
+#ifdef SECURE_RPC
+extern int SecureRPCInitAuth ();
+extern Xauth *SecureRPCGetAuth ();
+#endif
+
+#ifdef K5AUTH
+extern int Krb5InitAuth ();
+extern Xauth *Krb5GetAuth ();
+#endif
+
+struct AuthProtocol {
+ unsigned short name_length;
+ char *name;
+ int (*InitAuth)();
+ Xauth *(*GetAuth)();
+ void (*GetXdmcpAuth)();
+ int inited;
+};
+
+static struct AuthProtocol AuthProtocols[] = {
+{ (unsigned short) 18, "MIT-MAGIC-COOKIE-1",
+ MitInitAuth, MitGetAuth, NULL
+},
+#ifdef HASXDMAUTH
+{ (unsigned short) 19, "XDM-AUTHORIZATION-1",
+ XdmInitAuth, XdmGetAuth, XdmGetXdmcpAuth,
+},
+#endif
+#ifdef SECURE_RPC
+{ (unsigned short) 9, "SUN-DES-1",
+ SecureRPCInitAuth, SecureRPCGetAuth, NULL,
+},
+#endif
+#ifdef K5AUTH
+{ (unsigned short) 14, "MIT-KERBEROS-5",
+ Krb5InitAuth, Krb5GetAuth, NULL,
+},
+#endif
+};
+
+#define NUM_AUTHORIZATION (sizeof (AuthProtocols) / sizeof (AuthProtocols[0]))
+
+static struct AuthProtocol *
+findProtocol (name_length, name)
+ unsigned short name_length;
+ char *name;
+{
+ int i;
+
+ for (i = 0; i < NUM_AUTHORIZATION; i++)
+ if (AuthProtocols[i].name_length == name_length &&
+ memcmp(AuthProtocols[i].name, name, name_length) == 0)
+ {
+ return &AuthProtocols[i];
+ }
+ return (struct AuthProtocol *) 0;
+}
+
+ValidAuthorization (name_length, name)
+ unsigned short name_length;
+ char *name;
+{
+ if (findProtocol (name_length, name))
+ return TRUE;
+ return FALSE;
+}
+
+static Xauth *
+GenerateAuthorization (name_length, name)
+unsigned short name_length;
+char *name;
+{
+ struct AuthProtocol *a;
+ Xauth *auth = 0;
+ int i;
+
+ Debug ("GenerateAuthorization %*.*s\n",
+ name_length, name_length, name);
+ a = findProtocol (name_length, name);
+ if (a)
+ {
+ if (!a->inited)
+ {
+ (*a->InitAuth) (name_length, name);
+ a->inited = TRUE;
+ }
+ auth = (*a->GetAuth) (name_length, name);
+ if (auth)
+ {
+ Debug ("Got 0x%x (%d %*.*s) ", auth,
+ auth->name_length, auth->name_length,
+ auth->name_length, auth->name);
+ for (i = 0; i < (int)auth->data_length; i++)
+ Debug (" %02x", auth->data[i] & 0xff);
+ Debug ("\n");
+ }
+ else
+ Debug ("Got (null)\n");
+ }
+ else
+ {
+ Debug ("Unknown authorization %*.*s\n", name_length, name_length, name);
+ }
+ return auth;
+}
+
+#ifdef XDMCP
+
+SetProtoDisplayAuthorization (pdpy,
+ authorizationNameLen, authorizationName)
+ struct protoDisplay *pdpy;
+ unsigned short authorizationNameLen;
+ char *authorizationName;
+{
+ struct AuthProtocol *a;
+ Xauth *auth;
+
+ a = findProtocol (authorizationNameLen, authorizationName);
+ pdpy->xdmcpAuthorization = pdpy->fileAuthorization = 0;
+ if (a)
+ {
+ if (!a->inited)
+ {
+ (*a->InitAuth) (authorizationNameLen, authorizationName);
+ a->inited = TRUE;
+ }
+ if (a->GetXdmcpAuth)
+ {
+ (*a->GetXdmcpAuth) (pdpy, authorizationNameLen, authorizationName);
+ auth = pdpy->xdmcpAuthorization;
+ }
+ else
+ {
+ auth = (*a->GetAuth) (authorizationNameLen, authorizationName);
+ pdpy->fileAuthorization = auth;
+ pdpy->xdmcpAuthorization = 0;
+ }
+ if (auth)
+ Debug ("Got 0x%x (%d %*.*s)\n", auth,
+ auth->name_length, auth->name_length,
+ auth->name_length, auth->name);
+ else
+ Debug ("Got (null)\n");
+ }
+}
+
+#endif /* XDMCP */
+
+void
+CleanUpFileName (src, dst, len)
+ char *src, *dst;
+ int len;
+{
+ while (*src) {
+ if (--len <= 0)
+ break;
+ switch (*src & 0x7f)
+ {
+ case '/':
+ *dst++ = '_';
+ break;
+ case '-':
+ *dst++ = '.';
+ break;
+ default:
+ *dst++ = (*src & 0x7f);
+ }
+ ++src;
+ }
+ *dst = '\0';
+}
+
+static char authdir1[] = "authdir";
+static char authdir2[] = "authfiles";
+
+static
+MakeServerAuthFile (d)
+ struct display *d;
+{
+ int len;
+#ifdef SYSV
+#define NAMELEN 14
+#else
+#define NAMELEN 255
+#endif
+ char cleanname[NAMELEN];
+ int r;
+ struct stat statb;
+
+ if (d->clientAuthFile && *d->clientAuthFile)
+ len = strlen (d->clientAuthFile) + 1;
+ else
+ {
+ CleanUpFileName (d->name, cleanname, NAMELEN - 8);
+ len = strlen (authDir) + strlen (authdir1) + strlen (authdir2)
+ + strlen (cleanname) + 14;
+ }
+ if (d->authFile)
+ free (d->authFile);
+ d->authFile = malloc ((unsigned) len);
+ if (!d->authFile)
+ return FALSE;
+ if (d->clientAuthFile && *d->clientAuthFile)
+ strcpy (d->authFile, d->clientAuthFile);
+ else
+ {
+ sprintf (d->authFile, "%s/%s", authDir, authdir1);
+ r = stat(d->authFile, &statb);
+ if (r == 0) {
+ if (statb.st_uid != 0)
+ (void) chown(d->authFile, 0, statb.st_gid);
+ if ((statb.st_mode & 0077) != 0)
+ (void) chmod(d->authFile, statb.st_mode & 0700);
+ } else {
+ if (errno == ENOENT)
+ r = mkdir(d->authFile, 0700);
+ if (r < 0) {
+ free (d->authFile);
+ d->authFile = NULL;
+ return FALSE;
+ }
+ }
+ sprintf (d->authFile, "%s/%s/%s", authDir, authdir1, authdir2);
+ r = mkdir(d->authFile, 0700);
+ if (r < 0 && errno != EEXIST) {
+ free (d->authFile);
+ d->authFile = NULL;
+ return FALSE;
+ }
+ sprintf (d->authFile, "%s/%s/%s/A%s-XXXXXX",
+ authDir, authdir1, authdir2, cleanname);
+ (void) mktemp (d->authFile);
+ }
+ return TRUE;
+}
+
+SaveServerAuthorizations (d, auths, count)
+ struct display *d;
+ Xauth **auths;
+ int count;
+{
+ FILE *auth_file;
+ int mask;
+ int ret;
+ int i;
+
+ mask = umask (0077);
+ if (!d->authFile && !MakeServerAuthFile (d))
+ return FALSE;
+ (void) unlink (d->authFile);
+ auth_file = fopen (d->authFile, "w");
+ umask (mask);
+ if (!auth_file) {
+ Debug ("Can't creat auth file %s\n", d->authFile);
+ LogError ("Cannot open server authorization file %s\n", d->authFile);
+ free (d->authFile);
+ d->authFile = NULL;
+ ret = FALSE;
+ }
+ else
+ {
+ Debug ("File: %s auth: %x\n", d->authFile, auths);
+ ret = TRUE;
+ for (i = 0; i < count; i++)
+ {
+ /*
+ * User-based auths may not have data until
+ * a user logs in. In which case don't write
+ * to the auth file so xrdb and setup programs don't fail.
+ */
+ if (auths[i]->data_length > 0)
+ if (!XauWriteAuth (auth_file, auths[i]) ||
+ fflush (auth_file) == EOF)
+ {
+ LogError ("Cannot write server authorization file %s\n",
+ d->authFile);
+ ret = FALSE;
+ free (d->authFile);
+ d->authFile = NULL;
+ }
+ }
+ fclose (auth_file);
+ }
+ return ret;
+}
+
+void
+SetLocalAuthorization (d)
+ struct display *d;
+{
+ Xauth *auth, **auths;
+ int i, j;
+
+ if (d->authorizations)
+ {
+ for (i = 0; i < d->authNum; i++)
+ XauDisposeAuth (d->authorizations[i]);
+ free ((char *) d->authorizations);
+ d->authorizations = (Xauth **) NULL;
+ d->authNum = 0;
+ }
+ if (!d->authNames)
+ return;
+ for (i = 0; d->authNames[i]; i++)
+ ;
+ d->authNameNum = i;
+ if (d->authNameLens)
+ free ((char *) d->authNameLens);
+ d->authNameLens = (unsigned short *) malloc
+ (d->authNameNum * sizeof (unsigned short));
+ if (!d->authNameLens)
+ return;
+ for (i = 0; i < d->authNameNum; i++)
+ d->authNameLens[i] = strlen (d->authNames[i]);
+ auths = (Xauth **) malloc (d->authNameNum * sizeof (Xauth *));
+ if (!auths)
+ return;
+ j = 0;
+ for (i = 0; i < d->authNameNum; i++)
+ {
+ auth = GenerateAuthorization (d->authNameLens[i], d->authNames[i]);
+ if (auth)
+ auths[j++] = auth;
+ }
+ if (SaveServerAuthorizations (d, auths, j))
+ {
+ d->authorizations = auths;
+ d->authNum = j;
+ }
+ else
+ {
+ for (i = 0; i < j; i++)
+ XauDisposeAuth (auths[i]);
+ free ((char *) auths);
+ }
+}
+
+/*
+ * Set the authorization to use for xdm's initial connection
+ * to the X server. Cannot use user-based authorizations
+ * because no one has logged in yet, so we don't have any
+ * user credentials.
+ * Well, actually we could use SUN-DES-1 because we tell the server
+ * to allow root in. This is bogus and should be fixed.
+ */
+SetAuthorization (d)
+ struct display *d;
+{
+ register Xauth **auth = d->authorizations;
+ int i;
+
+ for (i = 0; i < d->authNum; i++)
+ {
+ if (auth[i]->name_length == 9 &&
+ memcmp(auth[i]->name, "SUN-DES-1", 9) == 0)
+ continue;
+ if (auth[i]->name_length == 14 &&
+ memcmp(auth[i]->name, "MIT-KERBEROS-5", 14) == 0)
+ continue;
+ XSetAuthorization (auth[i]->name, (int) auth[i]->name_length,
+ auth[i]->data, (int) auth[i]->data_length);
+ }
+}
+
+static
+openFiles (name, new_name, oldp, newp)
+char *name, *new_name;
+FILE **oldp, **newp;
+{
+ int mask;
+
+ strcpy (new_name, name);
+ strcat (new_name, "-n");
+ mask = umask (0077);
+ (void) unlink (new_name);
+ *newp = fopen (new_name, "w");
+ (void) umask (mask);
+ if (!*newp) {
+ Debug ("can't open new file %s\n", new_name);
+ return 0;
+ }
+ *oldp = fopen (name, "r");
+ Debug ("opens succeeded %s %s\n", name, new_name);
+ return 1;
+}
+
+static
+binaryEqual (a, b, len)
+char *a, *b;
+unsigned short len;
+{
+ while (len-- > 0)
+ if (*a++ != *b++)
+ return 0;
+ return 1;
+}
+
+static
+dumpBytes (len, data)
+unsigned short len;
+char *data;
+{
+ unsigned short i;
+
+ Debug ("%d: ", len);
+ for (i = 0; i < len; i++)
+ Debug ("%02x ", data[i] & 0377);
+ Debug ("\n");
+}
+
+static
+dumpAuth (auth)
+ Xauth *auth;
+{
+ Debug ("family: %d\n", auth->family);
+ Debug ("addr: ");
+ dumpBytes (auth->address_length, auth->address);
+ Debug ("number: ");
+ dumpBytes (auth->number_length, auth->number);
+ Debug ("name: ");
+ dumpBytes (auth->name_length, auth->name);
+ Debug ("data: ");
+ dumpBytes (auth->data_length, auth->data);
+}
+
+struct addrList {
+ unsigned short family;
+ unsigned short address_length;
+ char *address;
+ unsigned short number_length;
+ char *number;
+ unsigned short name_length;
+ char *name;
+ struct addrList *next;
+};
+
+static struct addrList *addrs;
+
+static
+initAddrs ()
+{
+ addrs = 0;
+}
+
+static
+doneAddrs ()
+{
+ struct addrList *a, *n;
+ for (a = addrs; a; a = n) {
+ n = a->next;
+ if (a->address)
+ free (a->address);
+ if (a->number)
+ free (a->number);
+ free ((char *) a);
+ }
+}
+
+static checkEntry ();
+
+static void
+saveEntry (auth)
+ Xauth *auth;
+{
+ struct addrList *new;
+
+ new = (struct addrList *) malloc (sizeof (struct addrList));
+ if (!new) {
+ LogOutOfMem ("saveEntry");
+ return;
+ }
+ if ((new->address_length = auth->address_length) > 0) {
+ new->address = malloc (auth->address_length);
+ if (!new->address) {
+ LogOutOfMem ("saveEntry");
+ free ((char *) new);
+ return;
+ }
+ memmove( new->address, auth->address, (int) auth->address_length);
+ } else
+ new->address = 0;
+ if ((new->number_length = auth->number_length) > 0) {
+ new->number = malloc (auth->number_length);
+ if (!new->number) {
+ LogOutOfMem ("saveEntry");
+ free (new->address);
+ free ((char *) new);
+ return;
+ }
+ memmove( new->number, auth->number, (int) auth->number_length);
+ } else
+ new->number = 0;
+ if ((new->name_length = auth->name_length) > 0) {
+ new->name = malloc (auth->name_length);
+ if (!new->name) {
+ LogOutOfMem ("saveEntry");
+ free (new->number);
+ free (new->address);
+ free ((char *) new);
+ return;
+ }
+ memmove( new->name, auth->name, (int) auth->name_length);
+ } else
+ new->name = 0;
+ new->family = auth->family;
+ new->next = addrs;
+ addrs = new;
+}
+
+static
+checkEntry (auth)
+ Xauth *auth;
+{
+ struct addrList *a;
+
+ for (a = addrs; a; a = a->next) {
+ if (a->family == auth->family &&
+ a->address_length == auth->address_length &&
+ binaryEqual (a->address, auth->address, auth->address_length) &&
+ a->number_length == auth->number_length &&
+ binaryEqual (a->number, auth->number, auth->number_length) &&
+ a->name_length == auth->name_length &&
+ binaryEqual (a->name, auth->name, auth->name_length))
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int doWrite;
+
+static
+writeAuth (file, auth)
+ FILE *file;
+ Xauth *auth;
+{
+ if (debugLevel >= 15) { /* normally too verbose */
+ Debug ("writeAuth: doWrite = %d\n", doWrite);
+ dumpAuth (auth); /* does Debug only */
+ }
+ if (doWrite)
+ XauWriteAuth (file, auth);
+}
+
+static
+writeAddr (family, addr_length, addr, file, auth)
+ int family;
+ int addr_length;
+ char *addr;
+ FILE *file;
+ Xauth *auth;
+{
+ auth->family = (unsigned short) family;
+ auth->address_length = addr_length;
+ auth->address = addr;
+ Debug ("writeAddr: writing and saving an entry\n");
+ writeAuth (file, auth);
+ saveEntry (auth);
+}
+
+static
+DefineLocal (file, auth)
+ FILE *file;
+ Xauth *auth;
+{
+ char displayname[100];
+ char tmp_displayname[100];
+
+ strcpy(tmp_displayname, "");
+
+ /* stolen from xinit.c */
+
+/* Make sure this produces the same string as _XGetHostname in lib/X/XlibInt.c.
+ * Otherwise, Xau will not be able to find your cookies in the Xauthority file.
+ *
+ * Note: POSIX says that the ``nodename'' member of utsname does _not_ have
+ * to have sufficient information for interfacing to the network,
+ * and so, you may be better off using gethostname (if it exists).
+ */
+
+#ifdef NEED_UTSNAME
+
+ /* hpux:
+ * Why not use gethostname()? Well, at least on my system, I've had to
+ * make an ugly kernel patch to get a name longer than 8 characters, and
+ * uname() lets me access to the whole string (it smashes release, you
+ * see), whereas gethostname() kindly truncates it for me.
+ */
+ {
+ struct utsname name;
+
+ uname(&name);
+ strcpy(displayname, name.nodename);
+ }
+ writeAddr (FamilyLocal, strlen (displayname), displayname, file, auth);
+
+ strcpy(tmp_displayname, displayname);
+#endif
+
+#if (!defined(NEED_UTSNAME) || defined (hpux))
+ /* AIXV3:
+ * In AIXV3, _POSIX_SOURCE is defined, but uname gives only first
+ * field of hostname. Thus, we use gethostname instead.
+ */
+
+ /*
+ * For HP-UX, HP's Xlib expects a fully-qualified domain name, which
+ * is achieved by using gethostname(). For compatability, we must
+ * also still create the entry using uname() above.
+ */
+ gethostname(displayname, sizeof(displayname));
+
+ /*
+ * If gethostname and uname both returned the same name,
+ * do not write a duplicate entry.
+ */
+ if (strcmp (displayname, tmp_displayname))
+ writeAddr (FamilyLocal, strlen (displayname), displayname,
+ file, auth);
+#endif
+}
+
+#ifdef USL
+/* Deal with different SIOCGIFCONF ioctl semantics on UnixWare */
+static int
+ifioctl (fd, cmd, arg)
+ int fd;
+ int cmd;
+ char *arg;
+{
+ struct strioctl ioc;
+ int ret;
+
+ bzero((char *) &ioc, sizeof(ioc));
+ ioc.ic_cmd = cmd;
+ ioc.ic_timout = 0;
+ if (cmd == SIOCGIFCONF)
+ {
+ ioc.ic_len = ((struct ifconf *) arg)->ifc_len;
+ ioc.ic_dp = ((struct ifconf *) arg)->ifc_buf;
+ }
+ else
+ {
+ ioc.ic_len = sizeof(struct ifreq);
+ ioc.ic_dp = arg;
+ }
+ ret = ioctl(fd, I_STR, (char *) &ioc);
+ if (ret >= 0 && cmd == SIOCGIFCONF)
+ ((struct ifconf *) arg)->ifc_len = ioc.ic_len;
+ return(ret);
+}
+#endif /* USL */
+
+
+#ifdef WINTCP /* NCR with Wollongong TCP */
+
+#include <sys/un.h>
+#include <stropts.h>
+#include <tiuser.h>
+
+#include <sys/stream.h>
+#include <net/if.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+
+static
+DefineSelf (fd, file, auth)
+ int fd;
+ FILE *file;
+ Xauth *auth;
+{
+ /*
+ * The Wolongong drivers used by NCR SVR4/MP-RAS don't understand the
+ * socket IO calls that most other drivers seem to like. Because of
+ * this, this routine must be special cased for NCR. Eventually,
+ * this will be cleared up.
+ */
+
+ struct ipb ifnet;
+ struct in_ifaddr ifaddr;
+ struct strioctl str;
+ unsigned char *addr;
+ int family, len, ipfd;
+
+ if ((ipfd = open ("/dev/ip", O_RDWR, 0 )) < 0)
+ LogError ("Getting interface configuration");
+
+ /* Indicate that we want to start at the begining */
+ ifnet.ib_next = (struct ipb *) 1;
+
+ while (ifnet.ib_next)
+ {
+ str.ic_cmd = IPIOC_GETIPB;
+ str.ic_timout = 0;
+ str.ic_len = sizeof (struct ipb);
+ str.ic_dp = (char *) &ifnet;
+
+ if (ioctl (ipfd, (int) I_STR, (char *) &str) < 0)
+ {
+ close (ipfd);
+ LogError ("Getting interface configuration");
+ }
+
+ ifaddr.ia_next = (struct in_ifaddr *) ifnet.if_addrlist;
+ str.ic_cmd = IPIOC_GETINADDR;
+ str.ic_timout = 0;
+ str.ic_len = sizeof (struct in_ifaddr);
+ str.ic_dp = (char *) &ifaddr;
+
+ if (ioctl (ipfd, (int) I_STR, (char *) &str) < 0)
+ {
+ close (ipfd);
+ LogError ("Getting interface configuration");
+ }
+
+ /*
+ * Ignore the 127.0.0.1 entry.
+ */
+ if (IA_SIN(&ifaddr)->sin_addr.s_addr == htonl(0x7f000001) )
+ continue;
+
+ writeAddr (FamilyInternet, 4, (char *)&(IA_SIN(&ifaddr)->sin_addr), file, auth);
+
+ }
+ close(ipfd);
+
+}
+
+#else /* WINTCP */
+
+#ifdef SIOCGIFCONF
+
+/* Define this host for access control. Find all the hosts the OS knows about
+ * for this fd and add them to the selfhosts list.
+ */
+static
+DefineSelf (fd, file, auth)
+ int fd;
+ FILE *file;
+ Xauth *auth;
+{
+ char buf[2048];
+ struct ifconf ifc;
+ register int n;
+ int len;
+ char *addr;
+ int family;
+ register struct ifreq *ifr;
+
+ ifc.ifc_len = sizeof (buf);
+ ifc.ifc_buf = buf;
+
+#ifdef USL
+ if (ifioctl (fd, SIOCGIFCONF, (char *) &ifc) < 0)
+#else
+ if (ioctl (fd, SIOCGIFCONF, (char *) &ifc) < 0)
+#endif
+ LogError ("Trouble getting network interface configuration");
+ for (ifr = ifc.ifc_req
+#ifdef BSD44SOCKETS
+ ; (char *)ifr < ifc.ifc_buf + ifc.ifc_len;
+ ifr = (struct ifreq *)((char *)ifr + sizeof (struct ifreq) +
+ (ifr->ifr_addr.sa_len > sizeof (ifr->ifr_addr) ?
+ ifr->ifr_addr.sa_len - sizeof (ifr->ifr_addr) : 0))
+#else
+ , n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0; ifr++
+#endif
+ )
+ {
+#ifdef DNETCONN
+ /*
+ * this is ugly but SIOCGIFCONF returns decnet addresses in
+ * a different form from other decnet calls
+ */
+ if (ifr->ifr_addr.sa_family == AF_DECnet) {
+ len = sizeof (struct dn_naddr);
+ addr = (char *)ifr->ifr_addr.sa_data;
+ family = FamilyDECnet;
+ } else
+#endif
+ {
+ if (ConvertAddr (&ifr->ifr_addr, &len, &addr) < 0)
+ continue;
+ if (len == 0)
+ {
+ Debug ("Skipping zero length address\n");
+ continue;
+ }
+ /*
+ * don't write out 'localhost' entries, as
+ * they may conflict with other local entries.
+ * DefineLocal will always be called to add
+ * the local entry anyway, so this one can
+ * be tossed.
+ */
+ if (len == 4 &&
+ addr[0] == 127 && addr[1] == 0 &&
+ addr[2] == 0 && addr[3] == 1)
+ {
+ Debug ("Skipping localhost address\n");
+ continue;
+ }
+ family = FamilyInternet;
+ }
+ Debug ("DefineSelf: write network address, length %d\n", len);
+ writeAddr (family, len, addr, file, auth);
+ }
+}
+
+#else /* SIOCGIFCONF */
+
+/* Define this host for access control. Find all the hosts the OS knows about
+ * for this fd and add them to the selfhosts list.
+ */
+static
+DefineSelf (fd, file, auth)
+ int fd;
+{
+ register int n;
+ int len;
+ caddr_t addr;
+ int family;
+
+ struct utsname name;
+ register struct hostent *hp;
+
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+ } saddr;
+
+ struct sockaddr_in *inetaddr;
+
+ /* hpux:
+ * Why not use gethostname()? Well, at least on my system, I've had to
+ * make an ugly kernel patch to get a name longer than 8 characters, and
+ * uname() lets me access to the whole string (it smashes release, you
+ * see), whereas gethostname() kindly truncates it for me.
+ */
+ uname(&name);
+ hp = gethostbyname (name.nodename);
+ if (hp != NULL) {
+ saddr.sa.sa_family = hp->h_addrtype;
+ inetaddr = (struct sockaddr_in *) (&(saddr.sa));
+ memmove( (char *) &(inetaddr->sin_addr), (char *) hp->h_addr, (int) hp->h_length);
+ family = ConvertAddr ( &(saddr.sa), &len, &addr);
+ if ( family >= 0) {
+ writeAddr (FamilyInternet, sizeof (inetaddr->sin_addr),
+ (char *) (&inetaddr->sin_addr), file, auth);
+ }
+ }
+}
+
+#endif /* SIOCGIFCONF else */
+
+#endif /* WINTCP */
+
+
+static
+setAuthNumber (auth, name)
+ Xauth *auth;
+ char *name;
+{
+ char *colon;
+ char *dot, *number;
+
+ Debug ("setAuthNumber %s\n", name);
+ colon = strrchr(name, ':');
+ if (colon) {
+ ++colon;
+ dot = strchr(colon, '.');
+ if (dot)
+ auth->number_length = dot - colon;
+ else
+ auth->number_length = strlen (colon);
+ number = malloc (auth->number_length + 1);
+ if (number) {
+ strncpy (number, colon, auth->number_length);
+ number[auth->number_length] = '\0';
+ } else {
+ LogOutOfMem ("setAuthNumber");
+ auth->number_length = 0;
+ }
+ auth->number = number;
+ Debug ("setAuthNumber: %s\n", number);
+ }
+}
+
+static
+writeLocalAuth (file, auth, name)
+ FILE *file;
+ Xauth *auth;
+ char *name;
+{
+ int fd;
+
+ Debug ("writeLocalAuth: %s %.*s\n", name, auth->name_length, auth->name);
+ setAuthNumber (auth, name);
+#ifdef STREAMSCONN
+ fd = t_open ("/dev/tcp", O_RDWR, 0);
+ t_bind(fd, NULL, NULL);
+ DefineSelf (fd, file, auth);
+ t_unbind (fd);
+ t_close (fd);
+#endif
+#ifdef TCPCONN
+ fd = socket (AF_INET, SOCK_STREAM, 0);
+ DefineSelf (fd, file, auth);
+ close (fd);
+#endif
+#ifdef DNETCONN
+ fd = socket (AF_DECnet, SOCK_STREAM, 0);
+ DefineSelf (fd, file, auth);
+ close (fd);
+#endif
+ DefineLocal (file, auth);
+}
+
+#ifdef XDMCP
+
+static void
+writeRemoteAuth (file, auth, peer, peerlen, name)
+ FILE *file;
+ Xauth *auth;
+ XdmcpNetaddr peer;
+ int peerlen;
+ char *name;
+{
+ int family = FamilyLocal;
+ char *addr;
+
+ Debug ("writeRemoteAuth: %s %.*s\n", name, auth->name_length, auth->name);
+ if (!peer || peerlen < 2)
+ return;
+ setAuthNumber (auth, name);
+ family = ConvertAddr (peer, &peerlen, &addr);
+ Debug ("writeRemoteAuth: family %d\n", family);
+ if (family != FamilyLocal)
+ {
+ Debug ("writeRemoteAuth: %d, %d, %x\n",
+ family, peerlen, *(int *)addr);
+ writeAddr (family, peerlen, addr, file, auth);
+ }
+ else
+ {
+ writeLocalAuth (file, auth, name);
+ }
+}
+
+#endif /* XDMCP */
+
+void
+SetUserAuthorization (d, verify)
+ struct display *d;
+ struct verify_info *verify;
+{
+ FILE *old, *new;
+ char home_name[1024], backup_name[1024], new_name[1024];
+ char *name;
+ char *home;
+ char *envname = 0;
+ int lockStatus;
+ Xauth *entry, **auths;
+ int setenv;
+ char **setEnv (), *getEnv ();
+ struct stat statb;
+ int i;
+ int magicCookie;
+ int data_len;
+
+ Debug ("SetUserAuthorization\n");
+ auths = d->authorizations;
+ if (auths) {
+ home = getEnv (verify->userEnviron, "HOME");
+ lockStatus = LOCK_ERROR;
+ if (home) {
+ strcpy (home_name, home);
+ if (home[strlen(home) - 1] != '/')
+ strcat (home_name, "/");
+ strcat (home_name, ".Xauthority");
+ Debug ("XauLockAuth %s\n", home_name);
+ lockStatus = XauLockAuth (home_name, 1, 2, 10);
+ Debug ("Lock is %d\n", lockStatus);
+ if (lockStatus == LOCK_SUCCESS) {
+ if (openFiles (home_name, new_name, &old, &new)) {
+ name = home_name;
+ setenv = 0;
+ } else {
+ Debug ("openFiles failed\n");
+ XauUnlockAuth (home_name);
+ lockStatus = LOCK_ERROR;
+ }
+ }
+ }
+ if (lockStatus != LOCK_SUCCESS) {
+ sprintf (backup_name, "%s/.XauthXXXXXX", d->userAuthDir);
+ (void) mktemp (backup_name);
+ lockStatus = XauLockAuth (backup_name, 1, 2, 10);
+ Debug ("backup lock is %d\n", lockStatus);
+ if (lockStatus == LOCK_SUCCESS) {
+ if (openFiles (backup_name, new_name, &old, &new)) {
+ name = backup_name;
+ setenv = 1;
+ } else {
+ XauUnlockAuth (backup_name);
+ lockStatus = LOCK_ERROR;
+ }
+ }
+ }
+ if (lockStatus != LOCK_SUCCESS) {
+ Debug ("can't lock auth file %s or backup %s\n",
+ home_name, backup_name);
+ LogError ("can't lock authorization file %s or backup %s\n",
+ home_name, backup_name);
+ return;
+ }
+ initAddrs ();
+ doWrite = 1;
+ Debug ("%d authorization protocols for %s\n", d->authNum, d->name);
+ /*
+ * Write MIT-MAGIC-COOKIE-1 authorization first, so that
+ * R4 clients which only knew that, and used the first
+ * matching entry will continue to function
+ */
+ magicCookie = -1;
+ for (i = 0; i < d->authNum; i++)
+ {
+ if (auths[i]->name_length == 18 &&
+ !strncmp (auths[i]->name, "MIT-MAGIC-COOKIE-1", 18))
+ {
+ magicCookie = i;
+ if (d->displayType.location == Local)
+ writeLocalAuth (new, auths[i], d->name);
+#ifdef XDMCP
+ else
+ writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name);
+#endif
+ break;
+ }
+ }
+ /* now write other authorizations */
+ for (i = 0; i < d->authNum; i++)
+ {
+ if (i != magicCookie)
+ {
+ data_len = auths[i]->data_length;
+ /* client will just use default Kerberos cache, so don't
+ * even write cache info into the authority file.
+ */
+ if (auths[i]->name_length == 14 &&
+ !strncmp (auths[i]->name, "MIT-KERBEROS-5", 14))
+ auths[i]->data_length = 0;
+ if (d->displayType.location == Local)
+ writeLocalAuth (new, auths[i], d->name);
+#ifdef XDMCP
+ else
+ writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name);
+#endif
+ auths[i]->data_length = data_len;
+ }
+ }
+ if (old) {
+ if (fstat (fileno (old), &statb) != -1)
+ chmod (new_name, (int) (statb.st_mode & 0777));
+ /*SUPPRESS 560*/
+ while ((entry = XauReadAuth (old))) {
+ if (!checkEntry (entry))
+ {
+ Debug ("Writing an entry\n");
+ writeAuth (new, entry);
+ }
+ XauDisposeAuth (entry);
+ }
+ fclose (old);
+ }
+ doneAddrs ();
+ fclose (new);
+ if (unlink (name) == -1)
+ Debug ("unlink %s failed\n", name);
+ envname = name;
+ if (link (new_name, name) == -1) {
+ Debug ("link failed %s %s\n", new_name, name);
+ LogError ("Can't move authorization into place\n");
+ setenv = 1;
+ envname = new_name;
+ } else {
+ Debug ("new is in place, go for it!\n");
+ unlink (new_name);
+ }
+ if (setenv) {
+ verify->userEnviron = setEnv (verify->userEnviron,
+ "XAUTHORITY", envname);
+ verify->systemEnviron = setEnv (verify->systemEnviron,
+ "XAUTHORITY", envname);
+ }
+ XauUnlockAuth (name);
+ if (envname)
+ chown (envname, verify->uid, verify->gid);
+ }
+ Debug ("done SetUserAuthorization\n");
+}
+
+void
+RemoveUserAuthorization (d, verify)
+ struct display *d;
+ struct verify_info *verify;
+{
+ char *home;
+ Xauth **auths, *entry;
+ char name[1024], new_name[1024];
+ int lockStatus;
+ FILE *old, *new;
+ struct stat statb;
+ int i;
+ char *getEnv ();
+
+ if (!(auths = d->authorizations))
+ return;
+ home = getEnv (verify->userEnviron, "HOME");
+ if (!home)
+ return;
+ Debug ("RemoveUserAuthorization\n");
+ strcpy (name, home);
+ if (home[strlen(home) - 1] != '/')
+ strcat (name, "/");
+ strcat (name, ".Xauthority");
+ Debug ("XauLockAuth %s\n", name);
+ lockStatus = XauLockAuth (name, 1, 2, 10);
+ Debug ("Lock is %d\n", lockStatus);
+ if (lockStatus != LOCK_SUCCESS)
+ return;
+ if (openFiles (name, new_name, &old, &new))
+ {
+ initAddrs ();
+ doWrite = 0;
+ for (i = 0; i < d->authNum; i++)
+ {
+ if (d->displayType.location == Local)
+ writeLocalAuth (new, auths[i], d->name);
+#ifdef XDMCP
+ else
+ writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name);
+#endif
+ }
+ doWrite = 1;
+ if (old) {
+ if (fstat (fileno (old), &statb) != -1)
+ chmod (new_name, (int) (statb.st_mode & 0777));
+ /*SUPPRESS 560*/
+ while ((entry = XauReadAuth (old))) {
+ if (!checkEntry (entry))
+ {
+ Debug ("Writing an entry\n");
+ writeAuth (new, entry);
+ }
+ XauDisposeAuth (entry);
+ }
+ fclose (old);
+ }
+ doneAddrs ();
+ fclose (new);
+ if (unlink (name) == -1)
+ Debug ("unlink %s failed\n", name);
+ if (link (new_name, name) == -1) {
+ Debug ("link failed %s %s\n", new_name, name);
+ LogError ("Can't move authorization into place\n");
+ } else {
+ Debug ("new is in place, go for it!\n");
+ unlink (new_name);
+ }
+ }
+ XauUnlockAuth (name);
+}
diff --git a/choose.c b/choose.c
new file mode 100644
index 0000000..1e88be7
--- /dev/null
+++ b/choose.c
@@ -0,0 +1,508 @@
+/*
+ * $Xorg: choose.c,v 1.5 2001/02/09 02:05:40 xorgcvs Exp $
+ *
+Copyright 1990, 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.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+/*
+ * choose.c
+ *
+ * xdm interface to chooser program
+ */
+
+#include "dm.h"
+
+#ifdef XDMCP
+
+#include <X11/X.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <ctype.h>
+#include <errno.h>
+#if defined(STREAMSCONN)
+# include <tiuser.h>
+#endif
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#define Time_t long
+extern Time_t time ();
+#else
+#include <time.h>
+#define Time_t time_t
+#endif
+
+static
+FormatBytes (data, length, buf, buflen)
+ unsigned char *data;
+ int length;
+ char *buf;
+ int buflen;
+{
+ int i;
+ static char HexChars[] = "0123456789abcdef";
+
+ if (buflen < length * 2 + 1)
+ return 0;
+ for (i = 0; i < length; i++)
+ {
+ *buf++ = HexChars[(data[i] >> 4) & 0xf];
+ *buf++ = HexChars[(data[i]) & 0xf];
+ }
+ *buf++ = '\0';
+ return 1;
+}
+
+static
+FormatARRAY8 (a, buf, buflen)
+ ARRAY8Ptr a;
+ char *buf;
+ int buflen;
+{
+ return FormatBytes (a->data, a->length, buf, buflen);
+}
+
+/* Converts an Internet address in ARRAY8 format to a string in
+ familiar dotted address notation, e.g., "18.24.0.11"
+ Returns 1 if successful, 0 if not.
+ */
+static int
+ARRAY8ToDottedDecimal (a, buf, buflen)
+ ARRAY8Ptr a;
+ char *buf;
+ int buflen;
+{
+ if (a->length != 4 || buflen < 20)
+ return 0;
+ sprintf(buf, "%d.%d.%d.%d",
+ a->data[0], a->data[1], a->data[2], a->data[3]);
+ return 1;
+}
+
+typedef struct _IndirectUsers {
+ struct _IndirectUsers *next;
+ ARRAY8 client;
+ CARD16 connectionType;
+} IndirectUsersRec, *IndirectUsersPtr;
+
+static IndirectUsersPtr indirectUsers;
+
+RememberIndirectClient (clientAddress, connectionType)
+ ARRAY8Ptr clientAddress;
+ CARD16 connectionType;
+{
+ IndirectUsersPtr i;
+
+ for (i = indirectUsers; i; i = i->next)
+ if (XdmcpARRAY8Equal (clientAddress, &i->client) &&
+ connectionType == i->connectionType)
+ return 1;
+ i = (IndirectUsersPtr) malloc (sizeof (IndirectUsersRec));
+ if (!XdmcpCopyARRAY8 (clientAddress, &i->client))
+ {
+ free ((char *) i);
+ return 0;
+ }
+ i->connectionType = connectionType;
+ i->next = indirectUsers;
+ indirectUsers = i;
+ return 1;
+}
+
+ForgetIndirectClient (clientAddress, connectionType)
+ ARRAY8Ptr clientAddress;
+ CARD16 connectionType;
+{
+ IndirectUsersPtr i, prev;
+
+ prev = 0;
+ for (i = indirectUsers; i; i = i->next)
+ {
+ if (XdmcpARRAY8Equal (clientAddress, &i->client) &&
+ connectionType == i->connectionType)
+ {
+ if (prev)
+ prev->next = i->next;
+ else
+ indirectUsers = i->next;
+ XdmcpDisposeARRAY8 (&i->client);
+ free ((char *) i);
+ break;
+ }
+ prev = i;
+ }
+}
+
+IsIndirectClient (clientAddress, connectionType)
+ ARRAY8Ptr clientAddress;
+ CARD16 connectionType;
+{
+ IndirectUsersPtr i;
+
+ for (i = indirectUsers; i; i = i->next)
+ if (XdmcpARRAY8Equal (clientAddress, &i->client) &&
+ connectionType == i->connectionType)
+ return 1;
+ return 0;
+}
+
+extern char *NetaddrPort();
+
+static
+FormatChooserArgument (buf, len)
+ char *buf;
+ int len;
+{
+ unsigned char addr_buf[1024];
+ int addr_len = sizeof (addr_buf);
+ unsigned char result_buf[1024];
+ int result_len = 0;
+ int netfamily;
+
+ if (GetChooserAddr (addr_buf, &addr_len) == -1)
+ {
+ LogError ("Cannot get return address for chooser socket\n");
+ Debug ("Cannot get chooser socket address\n");
+ return 0;
+ }
+ netfamily = NetaddrFamily((XdmcpNetaddr)addr_buf);
+ switch (netfamily) {
+ case AF_INET:
+ {
+ char *port;
+ int portlen;
+ ARRAY8Ptr localAddress, getLocalAddress ();
+
+ port = NetaddrPort((XdmcpNetaddr)addr_buf, &portlen);
+ result_buf[0] = netfamily >> 8;
+ result_buf[1] = netfamily & 0xFF;
+ result_buf[2] = port[0];
+ result_buf[3] = port[1];
+ localAddress = getLocalAddress ();
+ memmove( (char *)result_buf+4, (char *)localAddress->data, 4);
+ result_len = 8;
+ }
+ break;
+#ifdef AF_DECnet
+ case AF_DECnet:
+ break;
+#endif
+ default:
+ Debug ("Chooser family %d isn't known\n", netfamily);
+ return 0;
+ }
+
+ return FormatBytes (result_buf, result_len, buf, len);
+}
+
+typedef struct _Choices {
+ struct _Choices *next;
+ ARRAY8 client;
+ CARD16 connectionType;
+ ARRAY8 choice;
+ Time_t time;
+} ChoiceRec, *ChoicePtr;
+
+static ChoicePtr choices;
+
+ARRAY8Ptr
+IndirectChoice (clientAddress, connectionType)
+ ARRAY8Ptr clientAddress;
+ CARD16 connectionType;
+{
+ ChoicePtr c, next, prev;
+ Time_t now;
+
+ now = time ((Time_t*)0);
+ prev = 0;
+ for (c = choices; c; c = next)
+ {
+ next = c->next;
+ Debug ("Choice checking timeout: %d >? %d\n", now - c->time, choiceTimeout);
+ if (now - c->time > (Time_t)choiceTimeout)
+ {
+ Debug ("Timeout choice %d > %d\n", now - c->time, choiceTimeout);
+ if (prev)
+ prev->next = next;
+ else
+ choices = next;
+ XdmcpDisposeARRAY8 (&c->client);
+ XdmcpDisposeARRAY8 (&c->choice);
+ free ((char *) c);
+ }
+ else
+ {
+ if (XdmcpARRAY8Equal (clientAddress, &c->client) &&
+ connectionType == c->connectionType)
+ return &c->choice;
+ prev = c;
+ }
+ }
+ return 0;
+}
+
+static int
+RegisterIndirectChoice (clientAddress, connectionType, choice)
+ ARRAY8Ptr clientAddress, choice;
+ CARD16 connectionType;
+{
+ ChoicePtr c;
+ int insert;
+ int found = 0;
+
+ Debug ("Got indirect choice back\n");
+ for (c = choices; c; c = c->next) {
+ if (XdmcpARRAY8Equal (clientAddress, &c->client) &&
+ connectionType == c->connectionType) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ return 0;
+
+ insert = 0;
+ if (!c)
+ {
+ c = (ChoicePtr) malloc (sizeof (ChoiceRec));
+ insert = 1;
+ if (!c)
+ return 0;
+ c->connectionType = connectionType;
+ if (!XdmcpCopyARRAY8 (clientAddress, &c->client))
+ {
+ free ((char *) c);
+ return 0;
+ }
+ }
+ else
+ {
+ XdmcpDisposeARRAY8 (&c->choice);
+ }
+ if (!XdmcpCopyARRAY8 (choice, &c->choice))
+ {
+ XdmcpDisposeARRAY8 (&c->client);
+ free ((char *) c);
+ return 0;
+ }
+ if (insert)
+ {
+ c->next = choices;
+ choices = c;
+ }
+ c->time = time (0);
+ return 1;
+}
+
+#ifdef notdef
+static
+RemoveIndirectChoice (clientAddress, connectionType)
+ ARRAY8Ptr clientAddress;
+ CARD16 connectionType;
+{
+ ChoicePtr c, prev;
+
+ prev = 0;
+ for (c = choices; c; c = c->next)
+ {
+ if (XdmcpARRAY8Equal (clientAddress, &c->client) &&
+ connectionType == c->connectionType)
+ {
+ if (prev)
+ prev->next = c->next;
+ else
+ choices = c->next;
+ XdmcpDisposeARRAY8 (&c->client);
+ XdmcpDisposeARRAY8 (&c->choice);
+ free ((char *) c);
+ return;
+ }
+ prev = c;
+ }
+}
+#endif
+
+/*ARGSUSED*/
+static
+AddChooserHost (connectionType, addr, closure)
+ CARD16 connectionType;
+ ARRAY8Ptr addr;
+ char *closure;
+{
+ char ***argp, **parseArgs();
+ char hostbuf[1024];
+
+ argp = (char ***) closure;
+ if (addr->length == strlen ("BROADCAST") &&
+ !strncmp ((char *)addr->data, "BROADCAST", addr->length))
+ {
+ *argp = parseArgs (*argp, "BROADCAST");
+ }
+ else if (ARRAY8ToDottedDecimal (addr, hostbuf, sizeof (hostbuf)))
+ {
+ *argp = parseArgs (*argp, hostbuf);
+ }
+}
+
+ProcessChooserSocket (fd)
+ int fd;
+{
+ int client_fd;
+ char buf[1024];
+ int len;
+ XdmcpBuffer buffer;
+ ARRAY8 clientAddress;
+ CARD16 connectionType;
+ ARRAY8 choice;
+#if defined(STREAMSCONN)
+ struct t_call *call;
+ int flags=0;
+#endif
+
+ Debug ("Process chooser socket\n");
+ len = sizeof (buf);
+#if defined(STREAMSCONN)
+ call = (struct t_call *)t_alloc( fd, T_CALL, T_ALL );
+ if( call == NULL )
+ {
+ t_error( "ProcessChooserSocket: t_alloc failed" );
+ LogError ("Cannot setup to listen on chooser connection\n");
+ return;
+ }
+ if( t_listen( fd, call ) < 0 )
+ {
+ t_error( "ProcessChooserSocket: t_listen failed" );
+ t_free( (char *)call, T_CALL );
+ LogError ("Cannot listen on chooser connection\n");
+ return;
+ }
+ client_fd = t_open ("/dev/tcp", O_RDWR, NULL);
+ if (client_fd == -1)
+ {
+ t_error( "ProcessChooserSocket: t_open failed" );
+ t_free( (char *)call, T_CALL );
+ LogError ("Cannot open new chooser connection\n");
+ return;
+ }
+ if( t_bind( client_fd, NULL, NULL ) < 0 )
+ {
+ t_error( "ProcessChooserSocket: t_bind failed" );
+ t_free( (char *)call, T_CALL );
+ LogError ("Cannot bind new chooser connection\n");
+ t_close (client_fd);
+ return;
+ }
+ if( t_accept (fd, client_fd, call) < 0 )
+ {
+ t_error( "ProcessChooserSocket: t_accept failed" );
+ LogError ("Cannot accept chooser connection\n");
+ t_free( (char *)call, T_CALL );
+ t_unbind (client_fd);
+ t_close (client_fd);
+ return;
+ }
+#else
+ client_fd = accept (fd, (struct sockaddr *)buf, &len);
+ if (client_fd == -1)
+ {
+ LogError ("Cannot accept chooser connection\n");
+ return;
+ }
+#endif
+ Debug ("Accepted %d\n", client_fd);
+
+#if defined(STREAMSCONN)
+ len = t_rcv (client_fd, buf, sizeof (buf),&flags);
+#else
+ len = read (client_fd, buf, sizeof (buf));
+#endif
+ Debug ("Read returns %d\n", len);
+ if (len > 0)
+ {
+ buffer.data = (BYTE *) buf;
+ buffer.size = sizeof (buf);
+ buffer.count = len;
+ buffer.pointer = 0;
+ clientAddress.data = 0;
+ clientAddress.length = 0;
+ choice.data = 0;
+ choice.length = 0;
+ if (XdmcpReadARRAY8 (&buffer, &clientAddress) &&
+ XdmcpReadCARD16 (&buffer, &connectionType) &&
+ XdmcpReadARRAY8 (&buffer, &choice))
+ {
+ Debug ("Read from chooser succesfully\n");
+ if (!RegisterIndirectChoice (&clientAddress, connectionType, &choice))
+ Debug ("Invalid chooser reply\n");
+ }
+ XdmcpDisposeARRAY8 (&clientAddress);
+ XdmcpDisposeARRAY8 (&choice);
+ }
+ else
+ {
+ LogError ("Choice response read error: %s\n", strerror(errno));
+ }
+
+#if defined(STREAMSCONN)
+ t_unbind (client_fd);
+ t_free( (char *)call, T_CALL );
+ t_close (client_fd);
+#else
+ close (client_fd);
+#endif
+}
+
+RunChooser (d)
+ struct display *d;
+{
+ char **args, **parseArgs(), **systemEnv();
+ char buf[1024];
+ char **env;
+
+ Debug ("RunChooser %s\n", d->name);
+ SetTitle (d->name, "chooser", (char *) 0);
+ LoadXloginResources (d);
+ args = parseArgs ((char **) 0, d->chooser);
+ strcpy (buf, "-xdmaddress ");
+ if (FormatChooserArgument (buf + strlen (buf), sizeof (buf) - strlen (buf)))
+ args = parseArgs (args, buf);
+ strcpy (buf, "-clientaddress ");
+ if (FormatARRAY8 (&d->clientAddr, buf + strlen (buf), sizeof (buf) - strlen (buf)))
+ args = parseArgs (args, buf);
+ sprintf (buf, "-connectionType %d", d->connectionType);
+ args = parseArgs (args, buf);
+ ForEachChooserHost (&d->clientAddr, d->connectionType, AddChooserHost,
+ (char *) &args);
+ env = systemEnv (d, (char *) 0, (char *) 0);
+ Debug ("Running %s\n", args[0]);
+ execute (args, env);
+ Debug ("Couldn't run %s\n", args[0]);
+ LogError ("Cannot execute %s\n", args[0]);
+ exit (REMANAGE_DISPLAY);
+}
+
+#endif /* XDMCP */
diff --git a/chooser.c b/chooser.c
new file mode 100644
index 0000000..3724691
--- /dev/null
+++ b/chooser.c
@@ -0,0 +1,1005 @@
+/*
+ * $Xorg: chooser.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $
+ *
+Copyright 1990, 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.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+/*
+ * Chooser - display a menu of names and let the user select one
+ */
+
+/*
+ * Layout:
+ *
+ * +--------------------------------------------------+
+ * | +------------------+ |
+ * | | Label | |
+ * | +------------------+ |
+ * | +-+--------------+ |
+ * | |^| name-1 | |
+ * | ||| name-2 | |
+ * | |v| name-3 | |
+ * | | | name-4 | |
+ * | | | name-5 | |
+ * | | | name-6 | |
+ * | +----------------+ |
+ * | cancel accept ping |
+ * +--------------------------------------------------+
+ */
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xatom.h>
+
+#include <X11/Xaw/Paned.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/Viewport.h>
+#include <X11/Xaw/List.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Command.h>
+
+#include "dm.h"
+
+#include <X11/Xdmcp.h>
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef SVR4
+#include <sys/sockio.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#ifdef STREAMSCONN
+#ifdef WINTCP /* NCR with Wollongong TCP */
+#include <netinet/ip.h>
+#endif
+#include <stropts.h>
+#include <tiuser.h>
+#include <netconfig.h>
+#include <netdir.h>
+#endif
+
+#ifdef XKB
+#include <X11/extensions/XKBbells.h>
+#endif
+
+#define BROADCAST_HOSTNAME "BROADCAST"
+
+#ifndef ishexdigit
+#define ishexdigit(c) (isdigit(c) || 'a' <= (c) && (c) <= 'f')
+#endif
+
+#ifdef hpux
+# include <sys/utsname.h>
+# ifdef HAS_IFREQ
+# include <net/if.h>
+# endif
+#else
+#ifdef __convex__
+# include <sync/queue.h>
+# include <sync/sema.h>
+#endif
+# include <net/if.h>
+#endif /* hpux */
+
+#include <netdb.h>
+
+Widget toplevel, label, viewport, paned, list, box, cancel, acceptit, ping;
+
+static void CvtStringToARRAY8();
+
+static struct _app_resources {
+ ARRAY8Ptr xdmAddress;
+ ARRAY8Ptr clientAddress;
+ int connectionType;
+} app_resources;
+
+#define offset(field) XtOffsetOf(struct _app_resources, field)
+
+#define XtRARRAY8 "ARRAY8"
+
+static XtResource resources[] = {
+ {"xdmAddress", "XdmAddress", XtRARRAY8, sizeof (ARRAY8Ptr),
+ offset (xdmAddress), XtRString, NULL },
+ {"clientAddress", "ClientAddress", XtRARRAY8, sizeof (ARRAY8Ptr),
+ offset (clientAddress), XtRString, NULL },
+ {"connectionType", "ConnectionType", XtRInt, sizeof (int),
+ offset (connectionType), XtRImmediate, (XtPointer) 0 }
+};
+#undef offset
+
+static XrmOptionDescRec options[] = {
+ "-xdmaddress", "*xdmAddress", XrmoptionSepArg, NULL,
+ "-clientaddress", "*clientAddress", XrmoptionSepArg, NULL,
+ "-connectionType", "*connectionType", XrmoptionSepArg, NULL,
+};
+
+typedef struct _hostAddr {
+ struct _hostAddr *next;
+ struct sockaddr *addr;
+ int addrlen;
+ xdmOpCode type;
+} HostAddr;
+
+static HostAddr *hostAddrdb;
+
+typedef struct _hostName {
+ struct _hostName *next;
+ char *fullname;
+ int willing;
+ ARRAY8 hostname, status;
+ CARD16 connectionType;
+ ARRAY8 hostaddr;
+} HostName;
+
+static HostName *hostNamedb;
+
+static int socketFD;
+
+static int pingTry;
+
+#define PING_INTERVAL 2000
+#define TRIES 3
+
+static XdmcpBuffer directBuffer, broadcastBuffer;
+static XdmcpBuffer buffer;
+
+/* ARGSUSED */
+static void
+PingHosts (closure, id)
+ XtPointer closure;
+ XtIntervalId *id;
+{
+ HostAddr *hosts;
+
+ for (hosts = hostAddrdb; hosts; hosts = hosts->next)
+ {
+ if (hosts->type == QUERY)
+ XdmcpFlush (socketFD, &directBuffer, hosts->addr, hosts->addrlen);
+ else
+ XdmcpFlush (socketFD, &broadcastBuffer, hosts->addr, hosts->addrlen);
+ }
+ if (++pingTry < TRIES)
+ XtAddTimeOut (PING_INTERVAL, PingHosts, (XtPointer) 0);
+}
+
+char **NameTable;
+int NameTableSize;
+
+static int
+HostnameCompare (a, b)
+#ifdef __STDC__
+ const void *a, *b;
+#else
+ char *a, *b;
+#endif
+{
+ return strcmp (*(char **)a, *(char **)b);
+}
+
+static void
+RebuildTable (size)
+ int size;
+{
+ char **newTable = 0;
+ HostName *names;
+ int i;
+
+ if (size)
+ {
+ newTable = (char **) malloc (size * sizeof (char *));
+ if (!newTable)
+ return;
+ for (names = hostNamedb, i = 0; names; names = names->next, i++)
+ newTable[i] = names->fullname;
+ qsort (newTable, size, sizeof (char *), HostnameCompare);
+ }
+ XawListChange (list, newTable, size, 0, TRUE);
+ if (NameTable)
+ free ((char *) NameTable);
+ NameTable = newTable;
+ NameTableSize = size;
+}
+
+static int
+AddHostname (hostname, status, addr, willing)
+ ARRAY8Ptr hostname, status;
+ struct sockaddr *addr;
+ int willing;
+{
+ HostName *new, **names, *name;
+ ARRAY8 hostAddr;
+ CARD16 connectionType;
+ int fulllen;
+
+ switch (addr->sa_family)
+ {
+ case AF_INET:
+ hostAddr.data = (CARD8 *) &((struct sockaddr_in *) addr)->sin_addr;
+ hostAddr.length = 4;
+ connectionType = FamilyInternet;
+ break;
+ default:
+ hostAddr.data = (CARD8 *) "";
+ hostAddr.length = 0;
+ connectionType = FamilyLocal;
+ break;
+ }
+ for (names = &hostNamedb; *names; names = & (*names)->next)
+ {
+ name = *names;
+ if (connectionType == name->connectionType &&
+ XdmcpARRAY8Equal (&hostAddr, &name->hostaddr))
+ {
+ if (XdmcpARRAY8Equal (status, &name->status))
+ {
+ return 0;
+ }
+ break;
+ }
+ }
+ if (!*names)
+ {
+ new = (HostName *) malloc (sizeof (HostName));
+ if (!new)
+ return 0;
+ if (hostname->length)
+ {
+ switch (addr->sa_family)
+ {
+ case AF_INET:
+ {
+ struct hostent *hostent;
+ char *host;
+
+ hostent = gethostbyaddr ((char *)hostAddr.data, hostAddr.length, AF_INET);
+ if (hostent)
+ {
+ XdmcpDisposeARRAY8 (hostname);
+ host = hostent->h_name;
+ XdmcpAllocARRAY8 (hostname, strlen (host));
+ memmove( hostname->data, host, hostname->length);
+ }
+ }
+ }
+ }
+ if (!XdmcpAllocARRAY8 (&new->hostaddr, hostAddr.length))
+ {
+ free ((char *) new->fullname);
+ free ((char *) new);
+ return 0;
+ }
+ memmove( new->hostaddr.data, hostAddr.data, hostAddr.length);
+ new->connectionType = connectionType;
+ new->hostname = *hostname;
+
+ *names = new;
+ new->next = 0;
+ NameTableSize++;
+ }
+ else
+ {
+ new = *names;
+ free (new->fullname);
+ XdmcpDisposeARRAY8 (&new->status);
+ XdmcpDisposeARRAY8 (hostname);
+ }
+ new->willing = willing;
+ new->status = *status;
+
+ hostname = &new->hostname;
+ fulllen = hostname->length;
+ if (fulllen < 30)
+ fulllen = 30;
+ new->fullname = malloc (fulllen + status->length + 10);
+ if (!new->fullname)
+ {
+ new->fullname = "Unknown";
+ }
+ else
+ {
+ sprintf (new->fullname, "%-30.*s %*.*s",
+ hostname->length, hostname->data,
+ status->length, status->length, status->data);
+ }
+ RebuildTable (NameTableSize);
+ return 1;
+}
+
+static void
+DisposeHostname (host)
+ HostName *host;
+{
+ XdmcpDisposeARRAY8 (&host->hostname);
+ XdmcpDisposeARRAY8 (&host->hostaddr);
+ XdmcpDisposeARRAY8 (&host->status);
+ free ((char *) host->fullname);
+ free ((char *) host);
+}
+
+static void
+RemoveHostname (host)
+ HostName *host;
+{
+ HostName **prev, *hosts;
+
+ prev = &hostNamedb;;
+ for (hosts = hostNamedb; hosts; hosts = hosts->next)
+ {
+ if (hosts == host)
+ break;
+ prev = &hosts->next;
+ }
+ if (!hosts)
+ return;
+ *prev = host->next;
+ DisposeHostname (host);
+ NameTableSize--;
+ RebuildTable (NameTableSize);
+}
+
+static void
+EmptyHostnames ()
+{
+ HostName *hosts, *next;
+
+ for (hosts = hostNamedb; hosts; hosts = next)
+ {
+ next = hosts->next;
+ DisposeHostname (hosts);
+ }
+ NameTableSize = 0;
+ hostNamedb = 0;
+ RebuildTable (NameTableSize);
+}
+
+/* ARGSUSED */
+static void
+ReceivePacket (closure, source, id)
+ XtPointer closure;
+ int *source;
+ XtInputId *id;
+{
+ XdmcpHeader header;
+ ARRAY8 authenticationName;
+ ARRAY8 hostname;
+ ARRAY8 status;
+ int saveHostname = 0;
+ struct sockaddr addr;
+ int addrlen;
+
+ addrlen = sizeof (addr);
+ if (!XdmcpFill (socketFD, &buffer, &addr, &addrlen))
+ return;
+ if (!XdmcpReadHeader (&buffer, &header))
+ return;
+ if (header.version != XDM_PROTOCOL_VERSION)
+ return;
+ hostname.data = 0;
+ status.data = 0;
+ authenticationName.data = 0;
+ switch (header.opcode) {
+ case WILLING:
+ if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
+ XdmcpReadARRAY8 (&buffer, &hostname) &&
+ XdmcpReadARRAY8 (&buffer, &status))
+ {
+ if (header.length == 6 + authenticationName.length +
+ hostname.length + status.length)
+ {
+ if (AddHostname (&hostname, &status, &addr, header.opcode == (int) WILLING))
+ saveHostname = 1;
+ }
+ }
+ XdmcpDisposeARRAY8 (&authenticationName);
+ break;
+ case UNWILLING:
+ if (XdmcpReadARRAY8 (&buffer, &hostname) &&
+ XdmcpReadARRAY8 (&buffer, &status))
+ {
+ if (header.length == 4 + hostname.length + status.length)
+ {
+ if (AddHostname (&hostname, &status, &addr, header.opcode == (int) WILLING))
+ saveHostname = 1;
+
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if (!saveHostname)
+ {
+ XdmcpDisposeARRAY8 (&hostname);
+ XdmcpDisposeARRAY8 (&status);
+ }
+}
+
+static void
+RegisterHostaddr (addr, len, type)
+ struct sockaddr *addr;
+ int len;
+ xdmOpCode type;
+{
+ HostAddr *host, **prev;
+
+ host = (HostAddr *) malloc (sizeof (HostAddr));
+ if (!host)
+ return;
+ host->addr = (struct sockaddr *) malloc (len);
+ if (!host->addr)
+ {
+ free ((char *) host);
+ return;
+ }
+ memmove( (char *) host->addr, (char *) addr, len);
+ host->addrlen = len;
+ host->type = type;
+ for (prev = &hostAddrdb; *prev; prev = &(*prev)->next)
+ ;
+ *prev = host;
+ host->next = NULL;
+}
+
+/*
+ * Register the address for this host.
+ * Called with each of the names on the command line.
+ * The special name "BROADCAST" looks up all the broadcast
+ * addresses on the local host.
+ */
+
+static void
+RegisterHostname (name)
+ char *name;
+{
+ struct hostent *hostent;
+ struct sockaddr_in in_addr;
+ struct ifconf ifc;
+ register struct ifreq *ifr;
+ struct sockaddr broad_addr;
+ char buf[2048];
+ int n;
+
+ if (!strcmp (name, BROADCAST_HOSTNAME))
+ {
+#ifdef WINTCP /* NCR with Wollongong TCP */
+ int ipfd;
+ struct ifconf *ifcp;
+ struct strioctl ioc;
+
+ ifcp = (struct ifconf *)buf;
+ ifcp->ifc_buf = buf+4;
+ ifcp->ifc_len = sizeof (buf) - 4;
+
+ if ((ipfd=open( "/dev/ip", O_RDONLY )) < 0 )
+ {
+ t_error( "RegisterHostname() t_open(/dev/ip) failed" );
+ return;
+ }
+
+ ioc.ic_cmd = IPIOC_GETIFCONF;
+ ioc.ic_timout = 60;
+ ioc.ic_len = sizeof( buf );
+ ioc.ic_dp = (char *)ifcp;
+
+ if (ioctl (ipfd, (int) I_STR, (char *) &ioc) < 0)
+ {
+ perror( "RegisterHostname() ioctl(I_STR(IPIOC_GETIFCONF)) failed" );
+ close( ipfd );
+ return;
+ }
+
+ for (ifr = ifcp->ifc_req,
+n = ifcp->ifc_len / sizeof (struct ifreq);
+ --n >= 0;
+ ifr++)
+#else /* WINTCP */
+ ifc.ifc_len = sizeof (buf);
+ ifc.ifc_buf = buf;
+ if (ioctl (socketFD, (int) SIOCGIFCONF, (char *) &ifc) < 0)
+ return;
+ for (ifr = ifc.ifc_req
+#ifdef BSD44SOCKETS
+ ; (char *)ifr < ifc.ifc_buf + ifc.ifc_len;
+ ifr = (struct ifreq *)((char *)ifr + sizeof (struct ifreq) +
+ (ifr->ifr_addr.sa_len > sizeof (ifr->ifr_addr) ?
+ ifr->ifr_addr.sa_len - sizeof (ifr->ifr_addr) : 0))
+#else
+ , n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0; ifr++
+#endif
+ )
+#endif /* WINTCP */
+ {
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+
+ broad_addr = ifr->ifr_addr;
+ ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
+ htonl (INADDR_BROADCAST);
+#ifdef SIOCGIFBRDADDR
+ {
+ struct ifreq broad_req;
+
+ broad_req = *ifr;
+#ifdef WINTCP /* NCR with Wollongong TCP */
+ ioc.ic_cmd = IPIOC_GETIFFLAGS;
+ ioc.ic_timout = 0;
+ ioc.ic_len = sizeof( broad_req );
+ ioc.ic_dp = (char *)&broad_req;
+
+ if (ioctl (ipfd, I_STR, (char *) &ioc) != -1 &&
+#else /* WINTCP */
+ if (ioctl (socketFD, SIOCGIFFLAGS, (char *) &broad_req) != -1 &&
+#endif /* WINTCP */
+ (broad_req.ifr_flags & IFF_BROADCAST) &&
+ (broad_req.ifr_flags & IFF_UP)
+ )
+ {
+ broad_req = *ifr;
+#ifdef WINTCP /* NCR with Wollongong TCP */
+ ioc.ic_cmd = IPIOC_GETIFBRDADDR;
+ ioc.ic_timout = 0;
+ ioc.ic_len = sizeof( broad_req );
+ ioc.ic_dp = (char *)&broad_req;
+
+ if (ioctl (ipfd, I_STR, (char *) &ioc) != -1)
+#else /* WINTCP */
+ if (ioctl (socketFD, SIOCGIFBRDADDR, &broad_req) != -1)
+#endif /* WINTCP */
+ broad_addr = broad_req.ifr_addr;
+ else
+ continue;
+ }
+ else
+ continue;
+ }
+#endif
+ in_addr = *((struct sockaddr_in *) &broad_addr);
+ in_addr.sin_port = htons (XDM_UDP_PORT);
+#ifdef BSD44SOCKETS
+ in_addr.sin_len = sizeof(in_addr);
+#endif
+ RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
+ BROADCAST_QUERY);
+ }
+ }
+ else
+ {
+
+ /* address as hex string, e.g., "12180022" (depreciated) */
+ if (strlen(name) == 8 &&
+ FromHex(name, (char *)&in_addr.sin_addr, strlen(name)) == 0)
+ {
+ in_addr.sin_family = AF_INET;
+ }
+ /* Per RFC 1123, check first for IP address in dotted-decimal form */
+ else if ((in_addr.sin_addr.s_addr = inet_addr(name)) != -1)
+ in_addr.sin_family = AF_INET;
+ else
+ {
+ hostent = gethostbyname (name);
+ if (!hostent)
+ return;
+ if (hostent->h_addrtype != AF_INET || hostent->h_length != 4)
+ return;
+ in_addr.sin_family = hostent->h_addrtype;
+ memmove( &in_addr.sin_addr, hostent->h_addr, 4);
+ }
+ in_addr.sin_port = htons (XDM_UDP_PORT);
+#ifdef BSD44SOCKETS
+ in_addr.sin_len = sizeof(in_addr);
+#endif
+ RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr),
+ QUERY);
+ }
+}
+
+static ARRAYofARRAY8 AuthenticationNames;
+
+static void
+RegisterAuthenticationName (name, namelen)
+ char *name;
+ int namelen;
+{
+ ARRAY8Ptr authName;
+ if (!XdmcpReallocARRAYofARRAY8 (&AuthenticationNames,
+ AuthenticationNames.length + 1))
+ return;
+ authName = &AuthenticationNames.data[AuthenticationNames.length-1];
+ if (!XdmcpAllocARRAY8 (authName, namelen))
+ return;
+ memmove( authName->data, name, namelen);
+}
+
+int
+InitXDMCP (argv)
+ char **argv;
+{
+ int soopts = 1;
+ XdmcpHeader header;
+ int i;
+
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) BROADCAST_QUERY;
+ header.length = 1;
+ for (i = 0; i < (int)AuthenticationNames.length; i++)
+ header.length += 2 + AuthenticationNames.data[i].length;
+ XdmcpWriteHeader (&broadcastBuffer, &header);
+ XdmcpWriteARRAYofARRAY8 (&broadcastBuffer, &AuthenticationNames);
+
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) QUERY;
+ header.length = 1;
+ for (i = 0; i < (int)AuthenticationNames.length; i++)
+ header.length += 2 + AuthenticationNames.data[i].length;
+ XdmcpWriteHeader (&directBuffer, &header);
+ XdmcpWriteARRAYofARRAY8 (&directBuffer, &AuthenticationNames);
+#if defined(STREAMSCONN)
+ if ((socketFD = t_open ("/dev/udp", O_RDWR, 0)) < 0)
+ return 0;
+ if (t_bind( socketFD, NULL, NULL ) < 0) {
+ t_close(socketFD);
+ return 0;
+ }
+
+ /*
+ * This part of the code looks contrived. It will actually fit in nicely
+ * when the CLTS part of Xtrans is implemented.
+ */
+ {
+ struct netconfig *nconf;
+
+ if( (nconf=getnetconfigent("udp")) == NULL ) {
+ t_unbind(socketFD);
+ t_close(socketFD);
+ return 0;
+ }
+
+ if( netdir_options(nconf, ND_SET_BROADCAST, socketFD, NULL) ) {
+ freenetconfigent(nconf);
+ t_unbind(socketFD);
+ t_close(socketFD);
+ return 0;
+ }
+
+ freenetconfigent(nconf);
+ }
+#else
+ if ((socketFD = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
+ return 0;
+#endif
+#ifdef SO_BROADCAST
+ soopts = 1;
+ if (setsockopt (socketFD, SOL_SOCKET, SO_BROADCAST, (char *)&soopts, sizeof (soopts)) < 0)
+ perror ("setsockopt");
+#endif
+
+ XtAddInput (socketFD, (XtPointer) XtInputReadMask, ReceivePacket,
+ (XtPointer) 0);
+ while (*argv)
+ {
+ RegisterHostname (*argv);
+ ++argv;
+ }
+ pingTry = 0;
+ PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL);
+ return 1;
+}
+
+static void
+Choose (h)
+ HostName *h;
+{
+ if (app_resources.xdmAddress)
+ {
+ struct sockaddr_in in_addr;
+ struct sockaddr *addr;
+ int family;
+ int len;
+ int fd;
+ char buf[1024];
+ XdmcpBuffer buffer;
+ char *xdm;
+#if defined(STREAMSCONN)
+ struct t_call call, rcv;
+#endif
+
+ xdm = (char *) app_resources.xdmAddress->data;
+ family = (xdm[0] << 8) + xdm[1];
+ switch (family) {
+ case AF_INET:
+#ifdef BSD44SOCKETS
+ in_addr.sin_len = sizeof(in_addr);
+#endif
+ in_addr.sin_family = family;
+ memmove( &in_addr.sin_port, xdm + 2, 2);
+ memmove( &in_addr.sin_addr, xdm + 4, 4);
+ addr = (struct sockaddr *) &in_addr;
+ len = sizeof (in_addr);
+ break;
+ }
+#if defined(STREAMSCONN)
+ if ((fd = t_open ("/dev/tcp", O_RDWR, NULL)) == -1)
+ {
+ fprintf (stderr, "Cannot create response endpoint\n");
+ fflush(stderr);
+ exit (REMANAGE_DISPLAY);
+ }
+ if (t_bind (fd, NULL, NULL) == -1)
+ {
+ fprintf (stderr, "Cannot bind response endpoint\n");
+ fflush(stderr);
+ t_close (fd);
+ exit (REMANAGE_DISPLAY);
+ }
+ call.addr.buf=(char *)addr;
+ call.addr.len=len;
+ call.addr.maxlen=len;
+ call.opt.len=0;
+ call.opt.maxlen=0;
+ call.udata.len=0;
+ call.udata.maxlen=0;
+ if (t_connect (fd, &call, NULL) == -1)
+ {
+ t_error ("Cannot connect to xdm\n");
+ fflush(stderr);
+ t_unbind (fd);
+ t_close (fd);
+ exit (REMANAGE_DISPLAY);
+ }
+#else
+ if ((fd = socket (family, SOCK_STREAM, 0)) == -1)
+ {
+ fprintf (stderr, "Cannot create response socket\n");
+ exit (REMANAGE_DISPLAY);
+ }
+ if (connect (fd, addr, len) == -1)
+ {
+ fprintf (stderr, "Cannot connect to xdm\n");
+ exit (REMANAGE_DISPLAY);
+ }
+#endif
+ buffer.data = (BYTE *) buf;
+ buffer.size = sizeof (buf);
+ buffer.pointer = 0;
+ buffer.count = 0;
+ XdmcpWriteARRAY8 (&buffer, app_resources.clientAddress);
+ XdmcpWriteCARD16 (&buffer, (CARD16) app_resources.connectionType);
+ XdmcpWriteARRAY8 (&buffer, &h->hostaddr);
+#if defined(STREAMSCONN)
+ if( t_snd (fd, (char *)buffer.data, buffer.pointer, 0) < 0 )
+ {
+ fprintf (stderr, "Cannot send to xdm\n");
+ fflush(stderr);
+ t_unbind (fd);
+ t_close (fd);
+ exit (REMANAGE_DISPLAY);
+ }
+ sleep(5); /* Hack because sometimes the connection gets
+ closed before the data arrives on the other end. */
+ t_snddis (fd,NULL);
+ t_unbind (fd);
+ t_close (fd);
+#else
+ write (fd, (char *)buffer.data, buffer.pointer);
+ close (fd);
+#endif
+ }
+ else
+ {
+ int i;
+
+ printf ("%u\n", h->connectionType);
+ for (i = 0; i < (int)h->hostaddr.length; i++)
+ printf ("%u%s", h->hostaddr.data[i],
+ i == h->hostaddr.length - 1 ? "\n" : " ");
+ }
+}
+
+/* ARGSUSED */
+static void
+DoAccept (w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ XawListReturnStruct *r;
+ HostName *h;
+
+ r = XawListShowCurrent (list);
+ if (r->list_index == XAW_LIST_NONE)
+#ifdef XKB
+ XkbStdBell(XtDisplay(toplevel),XtWindow(w),0,XkbBI_MinorError);
+#else
+ XBell (XtDisplay (toplevel), 0);
+#endif
+ else
+ {
+ for (h = hostNamedb; h; h = h->next)
+ if (!strcmp (r->string, h->fullname))
+ {
+ Choose (h);
+ }
+ exit (OBEYSESS_DISPLAY);
+ }
+}
+
+/* ARGSUSED */
+static void
+DoCheckWilling (w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ XawListReturnStruct *r;
+ HostName *h;
+
+ r = XawListShowCurrent (list);
+ if (r->list_index == XAW_LIST_NONE)
+ return;
+ for (h = hostNamedb; h; h = h->next)
+ if (!strcmp (r->string, h->fullname))
+ if (!h->willing)
+ XawListUnhighlight (list);
+}
+
+/* ARGSUSED */
+static void
+DoCancel (w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ exit (OBEYSESS_DISPLAY);
+}
+
+/* ARGSUSED */
+static void
+DoPing (w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ EmptyHostnames ();
+ pingTry = 0;
+ PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL);
+}
+
+static XtActionsRec app_actions[] = {
+ "Accept", DoAccept,
+ "Cancel", DoCancel,
+ "CheckWilling", DoCheckWilling,
+ "Ping", DoPing,
+};
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ Arg position[3];
+ Dimension width, height;
+ Position x, y;
+
+ toplevel = XtInitialize (argv[0], "Chooser", options, XtNumber(options), &argc, argv);
+
+ XtAddConverter(XtRString, XtRARRAY8, CvtStringToARRAY8, NULL, 0);
+
+ XtGetApplicationResources (toplevel, (XtPointer) &app_resources, resources,
+ XtNumber (resources), NULL, (Cardinal) 0);
+
+ XtAddActions (app_actions, XtNumber (app_actions));
+ paned = XtCreateManagedWidget ("paned", panedWidgetClass, toplevel, NULL, 0);
+ label = XtCreateManagedWidget ("label", labelWidgetClass, paned, NULL, 0);
+ viewport = XtCreateManagedWidget ("viewport", viewportWidgetClass, paned, NULL, 0);
+ list = XtCreateManagedWidget ("list", listWidgetClass, viewport, NULL, 0);
+ box = XtCreateManagedWidget ("box", boxWidgetClass, paned, NULL, 0);
+ cancel = XtCreateManagedWidget ("cancel", commandWidgetClass, box, NULL, 0);
+ acceptit = XtCreateManagedWidget ("accept", commandWidgetClass, box, NULL, 0);
+ ping = XtCreateManagedWidget ("ping", commandWidgetClass, box, NULL, 0);
+
+ /*
+ * center ourselves on the screen
+ */
+ XtSetMappedWhenManaged(toplevel, FALSE);
+ XtRealizeWidget (toplevel);
+
+ XtSetArg (position[0], XtNwidth, &width);
+ XtSetArg (position[1], XtNheight, &height);
+ XtGetValues (toplevel, position, (Cardinal) 2);
+ x = (Position)(WidthOfScreen (XtScreen (toplevel)) - width) / 2;
+ y = (Position)(HeightOfScreen (XtScreen (toplevel)) - height) / 3;
+ XtSetArg (position[0], XtNx, x);
+ XtSetArg (position[1], XtNy, y);
+ XtSetValues (toplevel, position, (Cardinal) 2);
+
+ /*
+ * Run
+ */
+ XtMapWidget(toplevel);
+ InitXDMCP (argv + 1);
+ XtMainLoop ();
+ exit(0);
+ /*NOTREACHED*/
+}
+
+/* Converts the hex string s of length len into the byte array d.
+ Returns 0 if s was a legal hex string, 1 otherwise.
+ */
+int
+FromHex (s, d, len)
+ char *s, *d;
+ int len;
+{
+ int t;
+ int ret = len&1; /* odd-length hex strings are illegal */
+ while (len >= 2)
+ {
+#define HexChar(c) ('0' <= (c) && (c) <= '9' ? (c) - '0' : (c) - 'a' + 10)
+
+ if (!ishexdigit(*s))
+ ret = 1;
+ t = HexChar (*s) << 4;
+ s++;
+ if (!ishexdigit(*s))
+ ret = 1;
+ t += HexChar (*s);
+ s++;
+ *d++ = t;
+ len -= 2;
+ }
+ return ret;
+}
+
+/*ARGSUSED*/
+static void
+CvtStringToARRAY8 (args, num_args, fromVal, toVal)
+ XrmValuePtr args;
+ Cardinal *num_args;
+ XrmValuePtr fromVal;
+ XrmValuePtr toVal;
+{
+ static ARRAY8Ptr dest;
+ char *s;
+ int len;
+
+ dest = (ARRAY8Ptr) XtMalloc (sizeof (ARRAY8));
+ len = fromVal->size;
+ s = (char *) fromVal->addr;
+ if (!XdmcpAllocARRAY8 (dest, len >> 1))
+ XtStringConversionWarning ((char *) fromVal->addr, XtRARRAY8);
+ else
+ {
+ FromHex (s, (char *) dest->data, len);
+ }
+ toVal->addr = (caddr_t) &dest;
+ toVal->size = sizeof (ARRAY8Ptr);
+}
diff --git a/config/GiveConsole b/config/GiveConsole
new file mode 100644
index 0000000..ab2dee5
--- /dev/null
+++ b/config/GiveConsole
@@ -0,0 +1,10 @@
+#!/bin/sh
+# Assign ownership of the console to the invoking user
+# $Xorg: GiveConsole,v 1.3 2000/08/17 19:54:17 cpqbld Exp $
+#
+# By convention, both xconsole and xterm -C check that the
+# console is owned by the invoking user and is readable before attaching
+# the console output. This way a random user can invoke xterm -C without
+# causing serious grief.
+#
+chown $USER /dev/console
diff --git a/config/README b/config/README
new file mode 100644
index 0000000..4d49f91
--- /dev/null
+++ b/config/README
@@ -0,0 +1,11 @@
+$Xorg: README,v 1.3 2000/08/17 19:54:17 cpqbld Exp $
+
+Xdm Sample Configuration
+
+This directory contains a collection of files which describe a sample
+configuration of xdm. Choose between the sample Xservers.* files; copy the
+appropriate one to "$(XDMDIR)/Xservers" along with the other
+files in this directory.
+
+Only a few of the many configuration parameters which xdm can be tuned with
+are set in this sample, read the xdm manual page for a complete description.
diff --git a/config/TakeConsole b/config/TakeConsole
new file mode 100644
index 0000000..005c5e0
--- /dev/null
+++ b/config/TakeConsole
@@ -0,0 +1,7 @@
+#!/bin/sh
+# Reassign ownership of the console to root, this should disallow
+# assignment of console output to any random users's xterm
+# $Xorg: TakeConsole,v 1.3 2000/08/17 19:54:17 cpqbld Exp $
+#
+chmod 622 /dev/console
+chown root /dev/console
diff --git a/config/Xaccess b/config/Xaccess
new file mode 100644
index 0000000..b41c4c3
--- /dev/null
+++ b/config/Xaccess
@@ -0,0 +1,68 @@
+# $Xorg: Xaccess,v 1.3 2000/08/17 19:54:17 cpqbld Exp $
+#
+# Access control file for XDMCP connections
+#
+# To control Direct and Broadcast access:
+#
+# pattern
+#
+# To control Indirect queries:
+#
+# pattern list of hostnames and/or macros ...
+#
+# To use the chooser:
+#
+# pattern CHOOSER BROADCAST
+#
+# or
+#
+# pattern CHOOSER list of hostnames and/or macros ...
+#
+# To define macros:
+#
+# %name list of hosts ...
+#
+# The first form tells xdm which displays to respond to itself.
+# The second form tells xdm to forward indirect queries from hosts matching
+# the specified pattern to the indicated list of hosts.
+# The third form tells xdm to handle indirect queries using the chooser;
+# the chooser is directed to send its own queries out via the broadcast
+# address and display the results on the terminal.
+# The fourth form is similar to the third, except instead of using the
+# broadcast address, it sends DirectQuerys to each of the hosts in the list
+#
+# In all cases, xdm uses the first entry which matches the terminal;
+# for IndirectQuery messages only entries with right hand sides can
+# match, for Direct and Broadcast Query messages, only entries without
+# right hand sides can match.
+#
+
+* #any host can get a login window
+
+#
+# To hardwire a specific terminal to a specific host, you can
+# leave the terminal sending indirect queries to this host, and
+# use an entry of the form:
+#
+
+#terminal-a host-a
+
+
+#
+# The nicest way to run the chooser is to just ask it to broadcast
+# requests to the network - that way new hosts show up automatically.
+# Sometimes, however, the chooser can't figure out how to broadcast,
+# so this may not work in all environments.
+#
+
+* CHOOSER BROADCAST #any indirect host can get a chooser
+
+#
+# If you'd prefer to configure the set of hosts each terminal sees,
+# then just uncomment these lines (and comment the CHOOSER line above)
+# and edit the %hostlist line as appropriate
+#
+
+#%hostlist host-a host-b
+
+#* CHOOSER %hostlist #
diff --git a/config/Xservers.fs b/config/Xservers.fs
new file mode 100644
index 0000000..5c1c900
--- /dev/null
+++ b/config/Xservers.fs
@@ -0,0 +1,11 @@
+# $Xorg: Xservers.fs,v 1.3 2000/08/17 19:54:17 cpqbld Exp $
+#
+# Xservers file, fileserver prototype (any machine without a display)
+#
+# Put X terminals which don't support XDMCP in this file; you will
+# want to leave those terminals on and connected to the network, else
+# xdm will have a tougher time managing them.
+#
+# Each line should look like:
+#
+# XterminalName:0 foreign
diff --git a/config/Xservers.ws.cpp b/config/Xservers.ws.cpp
new file mode 100644
index 0000000..6153daf
--- /dev/null
+++ b/config/Xservers.ws.cpp
@@ -0,0 +1,13 @@
+XCOMM $Xorg: Xserv.ws.cpp,v 1.3 2000/08/17 19:54:17 cpqbld Exp $
+XCOMM
+XCOMM Xservers file, workstation prototype
+XCOMM
+XCOMM This file should contain an entry to start the server on the
+XCOMM local display; if you have more than one display (not screen),
+XCOMM you can add entries to the list (one per line). If you also
+XCOMM have some X terminals connected which do not support XDMCP,
+XCOMM you can add them here as well. Each X terminal line should
+XCOMM look like:
+XCOMM XTerminalName:0 foreign
+XCOMM
+:0 local BINDIR/X
diff --git a/config/Xsetup_0 b/config/Xsetup_0
new file mode 100644
index 0000000..8e30694
--- /dev/null
+++ b/config/Xsetup_0
@@ -0,0 +1,3 @@
+#!/bin/sh
+# $Xorg: Xsetup_0,v 1.3 2000/08/17 19:54:17 cpqbld Exp $
+xconsole -geometry 480x130-0-0 -daemon -notify -verbose -fn fixed -exitOnFail
diff --git a/config/xdm-config.cpp b/config/xdm-config.cpp
new file mode 100644
index 0000000..0f81104
--- /dev/null
+++ b/config/xdm-config.cpp
@@ -0,0 +1,19 @@
+! $Xorg: xdm-conf.cpp,v 1.3 2000/08/17 19:54:17 cpqbld Exp $
+DisplayManager.errorLogFile: XDMDIR/xdm-errors
+DisplayManager.pidFile: XDMDIR/xdm-pid
+DisplayManager.keyFile: XDMDIR/xdm-keys
+DisplayManager.servers: XDMDIR/Xservers
+DisplayManager.accessFile: XDMDIR/Xaccess
+! All displays should use authorization, but we cannot be sure
+! X terminals will be configured that way, so by default
+! use authorization only for local displays :0, :1, etc.
+DisplayManager._0.authorize: true
+DisplayManager._1.authorize: true
+! The following three resources set up display :0 as the console.
+DisplayManager._0.setup: XDMDIR/Xsetup_0
+DisplayManager._0.startup: XDMDIR/GiveConsole
+DisplayManager._0.reset: XDMDIR/TakeConsole
+!
+DisplayManager*resources: XDMDIR/Xresources
+DisplayManager*session: XDMDIR/Xsession
+DisplayManager*authComplain: false
diff --git a/daemon.c b/daemon.c
new file mode 100644
index 0000000..937240c
--- /dev/null
+++ b/daemon.c
@@ -0,0 +1,146 @@
+/* $Xorg: daemon.c,v 1.4 2001/02/09 02:05:40 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
+ */
+
+#include <X11/Xos.h>
+
+#if defined(SVR4) || defined(USG)
+#include <termios.h>
+#else
+#include <sys/ioctl.h>
+#endif
+#if defined(__osf__) || defined(linux)
+#define setpgrp setpgid
+#endif
+#ifdef hpux
+#include <sys/ptyio.h>
+#endif
+#include <errno.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+#include <sys/types.h>
+#ifdef X_NOT_POSIX
+#define Pid_t int
+#else
+#define Pid_t pid_t
+#endif
+
+extern void exit ();
+
+BecomeOrphan ()
+{
+ Pid_t child_id;
+ int stat;
+
+ /*
+ * fork so that the process goes into the background automatically. Also
+ * has a nice side effect of having the child process get inherited by
+ * init (pid 1).
+ * Separate the child into its own process group before the parent
+ * exits. This eliminates the possibility that the child might get
+ * killed when the init script that's running xdm exits.
+ */
+
+ child_id = fork();
+ switch (child_id) {
+ case 0:
+ /* child */
+ break;
+ case -1:
+ /* error */
+ LogError("daemon fork failed, errno = %d\n", errno);
+ break;
+
+ default:
+ /* parent */
+
+#if defined(SVR4)
+ stat = setpgid(child_id, child_id);
+ /* This gets error EPERM. Why? */
+#else
+#if defined(SYSV)
+ stat = 0; /* don't know how to set child's process group */
+#else
+ stat = setpgrp(child_id, child_id);
+ if (stat != 0)
+ LogError("setting process grp for daemon failed, errno = %d\n",
+ errno);
+#endif
+#endif
+ exit (0);
+ }
+}
+
+BecomeDaemon ()
+{
+ register int i;
+
+ /*
+ * Close standard file descriptors and get rid of controlling tty
+ */
+
+#if defined(SYSV) || defined(SVR4)
+ setpgrp ();
+#else
+ setpgrp (0, getpid());
+#endif
+
+ close (0);
+ close (1);
+ close (2);
+
+#if !((defined(SYSV) || defined(SVR4)) && defined(i386))
+ if ((i = open ("/dev/tty", O_RDWR)) >= 0) { /* did open succeed? */
+#if defined(USG) && defined(TCCLRCTTY)
+ int zero = 0;
+ (void) ioctl (i, TCCLRCTTY, &zero);
+#else
+#if (defined(SYSV) || defined(SVR4)) && defined(TIOCTTY)
+ int zero = 0;
+ (void) ioctl (i, TIOCTTY, &zero);
+#else
+ (void) ioctl (i, TIOCNOTTY, (char *) 0); /* detach, BSD style */
+#endif
+#endif
+ (void) close (i);
+ }
+#endif /* !i386 */
+
+ /*
+ * Set up the standard file descriptors.
+ */
+ (void) open ("/", O_RDONLY); /* root inode already in core */
+ (void) dup2 (0, 1);
+ (void) dup2 (0, 2);
+}
diff --git a/dm.c b/dm.c
new file mode 100644
index 0000000..4cdbbc0
--- /dev/null
+++ b/dm.c
@@ -0,0 +1,855 @@
+/* $Xorg: dm.c,v 1.5 2001/02/09 02:05:40 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
+ *
+ * display manager
+ */
+
+# include "dm.h"
+
+# include <stdio.h>
+#ifdef X_POSIX_C_SOURCE
+#define _POSIX_C_SOURCE X_POSIX_C_SOURCE
+#include <signal.h>
+#undef _POSIX_C_SOURCE
+#else
+#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
+#include <signal.h>
+#else
+#define _POSIX_SOURCE
+#include <signal.h>
+#undef _POSIX_SOURCE
+#endif
+#endif
+
+#ifndef sigmask
+#define sigmask(m) (1 << ((m - 1)))
+#endif
+
+# include <sys/stat.h>
+# include <errno.h>
+# include <X11/Xfuncproto.h>
+#if NeedVarargsPrototypes
+# include <stdarg.h>
+# define Va_start(a,b) va_start(a,b)
+#else
+# include <varargs.h>
+# define Va_start(a,b) va_start(a)
+#endif
+
+#ifndef F_TLOCK
+#ifndef X_NOT_POSIX
+# include <unistd.h>
+#endif
+#endif
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+
+#ifdef SVR4
+extern FILE *fdopen();
+#endif
+
+static void RescanServers ();
+static void ScanServers ();
+int Rescan;
+static long ServersModTime, ConfigModTime, AccessFileModTime;
+static SIGVAL StopAll (), RescanNotify ();
+void StopDisplay ();
+static void RestartDisplay ();
+static void StartDisplays ();
+
+int nofork_session = 0;
+
+#ifndef NOXDMTITLE
+static char *Title;
+static int TitleLen;
+#endif
+
+#ifndef UNRELIABLE_SIGNALS
+static SIGVAL ChildNotify ();
+#endif
+
+static int parent_pid = -1; /* PID of parent xdm process */
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+ int oldpid, oldumask;
+ char cmdbuf[1024];
+
+ /* make sure at least world write access is disabled */
+ if (((oldumask = umask(022)) & 002) == 002)
+ (void) umask (oldumask);
+#ifndef NOXDMTITLE
+ Title = argv[0];
+ TitleLen = (argv[argc - 1] + strlen(argv[argc - 1])) - Title;
+#endif
+
+ /*
+ * Step 1 - load configuration parameters
+ */
+ InitResources (argc, argv);
+ SetConfigFileTime ();
+ LoadDMResources ();
+ /*
+ * Only allow root to run in non-debug mode to avoid problems
+ */
+ if (debugLevel == 0 && getuid() != 0)
+ {
+ fprintf (stderr, "Only root wants to run %s\n", argv[0]);
+ exit (1);
+ }
+ if (debugLevel == 0 && daemonMode)
+ BecomeOrphan ();
+ if (debugLevel >= 10)
+ nofork_session = 1;
+ if (debugLevel == 0 && daemonMode)
+ BecomeDaemon ();
+ /* SUPPRESS 560 */
+ if ((oldpid = StorePid ()))
+ {
+ if (oldpid == -1)
+ LogError ("Can't create/lock pid file %s\n", pidFile);
+ else
+ LogError ("Can't lock pid file %s, another xdm is running (pid %d)\n",
+ pidFile, oldpid);
+ exit (1);
+ }
+ if (debugLevel == 0)
+ InitErrorLog ();
+
+ if (nofork_session == 0) {
+ /* Clean up any old Authorization files */
+ sprintf(cmdbuf, "/bin/rm -f %s/authdir/authfiles/A*", authDir);
+ system(cmdbuf);
+ }
+
+#ifdef XDMCP
+ init_session_id ();
+ CreateWellKnownSockets ();
+#else
+ Debug ("xdm: not compiled for XDMCP\n");
+#endif
+ parent_pid = getpid ();
+ (void) Signal (SIGTERM, StopAll);
+ (void) Signal (SIGINT, StopAll);
+ /*
+ * Step 2 - Read /etc/Xservers and set up
+ * the socket.
+ *
+ * Keep a sub-daemon running
+ * for each entry
+ */
+ SetAccessFileTime ();
+#ifdef XDMCP
+ ScanAccessDatabase ();
+#endif
+ ScanServers ();
+ StartDisplays ();
+ (void) Signal (SIGHUP, RescanNotify);
+#ifndef UNRELIABLE_SIGNALS
+ (void) Signal (SIGCHLD, ChildNotify);
+#endif
+ while (
+#ifdef XDMCP
+ AnyWellKnownSockets() ||
+#endif
+ AnyDisplaysLeft ())
+ {
+ if (Rescan)
+ {
+ RescanServers ();
+ Rescan = 0;
+ }
+#if defined(UNRELIABLE_SIGNALS) || !defined(XDMCP)
+ WaitForChild ();
+#else
+ WaitForSomething ();
+#endif
+ }
+ Debug ("Nothing left to do, exiting\n");
+ exit(0);
+ /*NOTREACHED*/
+}
+
+/* ARGSUSED */
+static SIGVAL
+RescanNotify (n)
+ int n;
+{
+ Debug ("Caught SIGHUP\n");
+ Rescan = 1;
+#ifdef SIGNALS_RESET_WHEN_CAUGHT
+ (void) Signal (SIGHUP, RescanNotify);
+#endif
+}
+
+static void
+ScanServers ()
+{
+ char lineBuf[10240];
+ int len;
+ FILE *serversFile;
+ struct stat statb;
+ static DisplayType acceptableTypes[] =
+ { { Local, Permanent, FromFile },
+ { Foreign, Permanent, FromFile },
+ };
+
+#define NumTypes (sizeof (acceptableTypes) / sizeof (acceptableTypes[0]))
+
+ if (servers[0] == '/')
+ {
+ serversFile = fopen (servers, "r");
+ if (serversFile == NULL)
+ {
+ LogError ("cannot access servers file %s\n", servers);
+ return;
+ }
+ if (ServersModTime == 0)
+ {
+ fstat (fileno (serversFile), &statb);
+ ServersModTime = statb.st_mtime;
+ }
+ while (fgets (lineBuf, sizeof (lineBuf)-1, serversFile))
+ {
+ len = strlen (lineBuf);
+ if (lineBuf[len-1] == '\n')
+ lineBuf[len-1] = '\0';
+ ParseDisplay (lineBuf, acceptableTypes, NumTypes);
+ }
+ fclose (serversFile);
+ }
+ else
+ {
+ ParseDisplay (servers, acceptableTypes, NumTypes);
+ }
+}
+
+static void
+MarkDisplay (d)
+struct display *d;
+{
+ d->state = MissingEntry;
+}
+
+static void
+RescanServers ()
+{
+ Debug ("rescanning servers\n");
+ LogInfo ("Rescanning both config and servers files\n");
+ ForEachDisplay (MarkDisplay);
+ SetConfigFileTime ();
+ ReinitResources ();
+ LoadDMResources ();
+ ScanServers ();
+ SetAccessFileTime ();
+#ifdef XDMCP
+ ScanAccessDatabase ();
+#endif
+ StartDisplays ();
+}
+
+SetConfigFileTime ()
+{
+ struct stat statb;
+
+ if (stat (config, &statb) != -1)
+ ConfigModTime = statb.st_mtime;
+}
+
+SetAccessFileTime ()
+{
+ struct stat statb;
+
+ if (stat (accessFile, &statb) != -1)
+ AccessFileModTime = statb.st_mtime;
+}
+
+static
+RescanIfMod ()
+{
+ struct stat statb;
+
+ if (config && stat (config, &statb) != -1)
+ {
+ if (statb.st_mtime != ConfigModTime)
+ {
+ Debug ("Config file %s has changed, rereading\n", config);
+ LogInfo ("Rereading configuration file %s\n", config);
+ ConfigModTime = statb.st_mtime;
+ ReinitResources ();
+ LoadDMResources ();
+ }
+ }
+ if (servers[0] == '/' && stat(servers, &statb) != -1)
+ {
+ if (statb.st_mtime != ServersModTime)
+ {
+ Debug ("Servers file %s has changed, rescanning\n", servers);
+ LogInfo ("Rereading servers file %s\n", servers);
+ ServersModTime = statb.st_mtime;
+ ForEachDisplay (MarkDisplay);
+ ScanServers ();
+ }
+ }
+#ifdef XDMCP
+ if (accessFile && accessFile[0] && stat (accessFile, &statb) != -1)
+ {
+ if (statb.st_mtime != AccessFileModTime)
+ {
+ Debug ("Access file %s has changed, rereading\n", accessFile);
+ LogInfo ("Rereading access file %s\n", accessFile);
+ AccessFileModTime = statb.st_mtime;
+ ScanAccessDatabase ();
+ }
+ }
+#endif
+}
+
+/*
+ * catch a SIGTERM, kill all displays and exit
+ */
+
+/* ARGSUSED */
+static SIGVAL
+StopAll (n)
+ int n;
+{
+ if (parent_pid != getpid())
+ {
+ /*
+ * We are a child xdm process that was killed by the
+ * master xdm before we were able to return from fork()
+ * and remove this signal handler.
+ *
+ * See defect XWSog08655 for more information.
+ */
+ Debug ("Child xdm caught SIGTERM before it remove that signal.\n");
+ (void) Signal (n, SIG_DFL);
+ TerminateProcess (getpid(), SIGTERM);
+ return;
+ }
+ Debug ("Shutting down entire manager\n");
+#ifdef XDMCP
+ DestroyWellKnownSockets ();
+#endif
+ ForEachDisplay (StopDisplay);
+#ifdef SIGNALS_RESET_WHEN_CAUGHT
+ /* to avoid another one from killing us unceremoniously */
+ (void) Signal (SIGTERM, StopAll);
+ (void) Signal (SIGINT, StopAll);
+#endif
+}
+
+/*
+ * notice that a child has died and may need another
+ * sub-daemon started
+ */
+
+int ChildReady;
+
+#ifndef UNRELIABLE_SIGNALS
+/* ARGSUSED */
+static SIGVAL
+ChildNotify (n)
+ int n;
+{
+ ChildReady = 1;
+}
+#endif
+
+WaitForChild ()
+{
+ int pid;
+ struct display *d;
+ waitType status;
+#ifndef X_NOT_POSIX
+ sigset_t mask, omask;
+#else
+ int omask;
+#endif
+
+#ifdef UNRELIABLE_SIGNALS
+ /* XXX classic System V signal race condition here with RescanNotify */
+ if ((pid = wait (&status)) != -1)
+#else
+#ifndef X_NOT_POSIX
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ sigaddset(&mask, SIGHUP);
+ sigprocmask(SIG_BLOCK, &mask, &omask);
+#else
+ omask = sigblock (sigmask (SIGCHLD) | sigmask (SIGHUP));
+#endif
+ Debug ("signals blocked, mask was 0x%x\n", omask);
+ if (!ChildReady && !Rescan)
+#ifndef X_NOT_POSIX
+ sigsuspend(&omask);
+#else
+ sigpause (omask);
+#endif
+ ChildReady = 0;
+#ifndef X_NOT_POSIX
+ sigprocmask(SIG_SETMASK, &omask, (sigset_t *)NULL);
+#else
+ sigsetmask (omask);
+#endif
+#ifndef X_NOT_POSIX
+ while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
+#else
+ while ((pid = wait3 (&status, WNOHANG, (struct rusage *) 0)) > 0)
+#endif
+#endif
+ {
+ Debug ("Manager wait returns pid: %d sig %d core %d code %d\n",
+ pid, waitSig(status), waitCore(status), waitCode(status));
+ if (autoRescan)
+ RescanIfMod ();
+ /* SUPPRESS 560 */
+ if ((d = FindDisplayByPid (pid))) {
+ d->pid = -1;
+ switch (waitVal (status)) {
+ case UNMANAGE_DISPLAY:
+ Debug ("Display exited with UNMANAGE_DISPLAY\n");
+ StopDisplay (d);
+ break;
+ case OBEYSESS_DISPLAY:
+ d->startTries = 0;
+ Debug ("Display exited with OBEYSESS_DISPLAY\n");
+ if (d->displayType.lifetime != Permanent ||
+ d->status == zombie)
+ StopDisplay (d);
+ else
+ RestartDisplay (d, FALSE);
+ break;
+ default:
+ Debug ("Display exited with unknown status %d\n", waitVal(status));
+ LogError ("Unknown session exit code %d from process %d\n",
+ waitVal (status), pid);
+ StopDisplay (d);
+ break;
+ case OPENFAILED_DISPLAY:
+ Debug ("Display exited with OPENFAILED_DISPLAY, try %d of %d\n",
+ d->startTries, d->startAttempts);
+ LogError ("Display %s cannot be opened\n", d->name);
+ /*
+ * no display connection was ever made, tell the
+ * terminal that the open attempt failed
+ */
+#ifdef XDMCP
+ if (d->displayType.origin == FromXDMCP)
+ SendFailed (d, "Cannot open display");
+#endif
+ if (d->displayType.origin == FromXDMCP ||
+ d->status == zombie ||
+ ++d->startTries >= d->startAttempts)
+ {
+ LogError ("Display %s is being disabled\n", d->name);
+ StopDisplay (d);
+ }
+ else
+ {
+ RestartDisplay (d, TRUE);
+ }
+ break;
+ case RESERVER_DISPLAY:
+ d->startTries = 0;
+ Debug ("Display exited with RESERVER_DISPLAY\n");
+ if (d->displayType.origin == FromXDMCP || d->status == zombie)
+ StopDisplay(d);
+ else
+ RestartDisplay (d, TRUE);
+ break;
+ case waitCompose (SIGTERM,0,0):
+ d->startTries = 0;
+ Debug ("Display exited on SIGTERM\n");
+ if (d->displayType.origin == FromXDMCP || d->status == zombie)
+ StopDisplay(d);
+ else
+ RestartDisplay (d, TRUE);
+ break;
+ case REMANAGE_DISPLAY:
+ d->startTries = 0;
+ Debug ("Display exited with REMANAGE_DISPLAY\n");
+ /*
+ * XDMCP will restart the session if the display
+ * requests it
+ */
+ if (d->displayType.origin == FromXDMCP || d->status == zombie)
+ StopDisplay(d);
+ else
+ RestartDisplay (d, FALSE);
+ break;
+ }
+ }
+ /* SUPPRESS 560 */
+ else if ((d = FindDisplayByServerPid (pid)))
+ {
+ d->serverPid = -1;
+ switch (d->status)
+ {
+ case zombie:
+ Debug ("Zombie server reaped, removing display %s\n", d->name);
+ RemoveDisplay (d);
+ break;
+ case phoenix:
+ Debug ("Phoenix server arises, restarting display %s\n", d->name);
+ d->status = notRunning;
+ break;
+ case running:
+ Debug ("Server for display %s terminated unexpectedly, status %d\n", d->name, waitVal (status));
+ LogError ("Server for display %s terminated unexpectedly: %d\n", d->name, waitVal (status));
+ if (d->pid != -1)
+ {
+ Debug ("Terminating session pid %d\n", d->pid);
+ TerminateProcess (d->pid, SIGTERM);
+ }
+ break;
+ case notRunning:
+ Debug ("Server exited for notRunning session on display %s\n", d->name);
+ break;
+ }
+ }
+ else
+ {
+ Debug ("Unknown child termination, status %d\n", waitVal (status));
+ }
+ }
+ StartDisplays ();
+}
+
+static void
+CheckDisplayStatus (d)
+struct display *d;
+{
+ if (d->displayType.origin == FromFile)
+ {
+ switch (d->state) {
+ case MissingEntry:
+ StopDisplay (d);
+ break;
+ case NewEntry:
+ d->state = OldEntry;
+ case OldEntry:
+ if (d->status == notRunning)
+ StartDisplay (d);
+ break;
+ }
+ }
+}
+
+static void
+StartDisplays ()
+{
+ ForEachDisplay (CheckDisplayStatus);
+}
+
+void
+StartDisplay (d)
+struct display *d;
+{
+ int pid;
+
+ Debug ("StartDisplay %s\n", d->name);
+ LoadServerResources (d);
+ if (d->displayType.location == Local)
+ {
+ /* don't bother pinging local displays; we'll
+ * certainly notice when they exit
+ */
+ d->pingInterval = 0;
+ if (d->authorize)
+ {
+ Debug ("SetLocalAuthorization %s, auth %s\n",
+ d->name, d->authNames[0]);
+ SetLocalAuthorization (d);
+ /*
+ * reset the server after writing the authorization information
+ * to make it read the file (for compatibility with old
+ * servers which read auth file only on reset instead of
+ * at first connection)
+ */
+ if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
+ kill (d->serverPid, d->resetSignal);
+ }
+ if (d->serverPid == -1 && !StartServer (d))
+ {
+ LogError ("Server for display %s can't be started, session disabled\n", d->name);
+ RemoveDisplay (d);
+ return;
+ }
+ }
+ else
+ {
+ /* this will only happen when using XDMCP */
+ if (d->authorizations)
+ SaveServerAuthorizations (d, d->authorizations, d->authNum);
+ }
+ if (!nofork_session)
+ pid = fork ();
+ else
+ pid = 0;
+ switch (pid)
+ {
+ case 0:
+ if (!nofork_session) {
+ CleanUpChild ();
+ (void) Signal (SIGPIPE, SIG_IGN);
+ }
+ LoadSessionResources (d);
+ SetAuthorization (d);
+ if (!WaitForServer (d))
+ exit (OPENFAILED_DISPLAY);
+#ifdef XDMCP
+ if (d->useChooser)
+ RunChooser (d);
+ else
+#endif
+ ManageSession (d);
+ exit (REMANAGE_DISPLAY);
+ case -1:
+ break;
+ default:
+ Debug ("pid: %d\n", pid);
+ d->pid = pid;
+ d->status = running;
+ break;
+ }
+}
+
+TerminateProcess (pid, signal)
+{
+ kill (pid, signal);
+#ifdef SIGCONT
+ kill (pid, SIGCONT);
+#endif
+}
+
+/*
+ * transition from running to zombie or deleted
+ */
+
+void
+StopDisplay (d)
+ struct display *d;
+{
+ if (d->serverPid != -1)
+ d->status = zombie; /* be careful about race conditions */
+ if (d->pid != -1)
+ TerminateProcess (d->pid, SIGTERM);
+ if (d->serverPid != -1)
+ TerminateProcess (d->serverPid, d->termSignal);
+ else
+ RemoveDisplay (d);
+}
+
+/*
+ * transition from running to phoenix or notRunning
+ */
+
+static void
+RestartDisplay (d, forceReserver)
+ struct display *d;
+ int forceReserver;
+{
+ if (d->serverPid != -1 && (forceReserver || d->terminateServer))
+ {
+ TerminateProcess (d->serverPid, d->termSignal);
+ d->status = phoenix;
+ }
+ else
+ {
+ d->status = notRunning;
+ }
+}
+
+static FD_TYPE CloseMask;
+static int max;
+
+RegisterCloseOnFork (fd)
+int fd;
+{
+ FD_SET (fd, &CloseMask);
+ if (fd > max)
+ max = fd;
+}
+
+ClearCloseOnFork (fd)
+int fd;
+{
+ FD_CLR (fd, &CloseMask);
+ if (fd == max) {
+ while (--fd >= 0)
+ if (FD_ISSET (fd, &CloseMask))
+ break;
+ max = fd;
+ }
+}
+
+CloseOnFork ()
+{
+ int fd;
+
+ for (fd = 0; fd <= max; fd++)
+ if (FD_ISSET (fd, &CloseMask))
+ close (fd);
+ FD_ZERO (&CloseMask);
+ max = 0;
+}
+
+static int pidFd;
+static FILE *pidFilePtr;
+
+StorePid ()
+{
+ int oldpid;
+
+ if (pidFile[0] != '\0') {
+ pidFd = open (pidFile, 2);
+ if (pidFd == -1 && errno == ENOENT)
+ pidFd = open (pidFile, O_RDWR|O_CREAT, 0666);
+ if (pidFd == -1 || !(pidFilePtr = fdopen (pidFd, "r+")))
+ {
+ LogError ("process-id file %s cannot be opened\n",
+ pidFile);
+ return -1;
+ }
+ if (fscanf (pidFilePtr, "%d\n", &oldpid) != 1)
+ oldpid = -1;
+ fseek (pidFilePtr, 0l, 0);
+ if (lockPidFile)
+ {
+#ifdef F_SETLK
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+ struct flock lock_data;
+ lock_data.l_type = F_WRLCK;
+ lock_data.l_whence = SEEK_SET;
+ lock_data.l_start = lock_data.l_len = 0;
+ if (fcntl(pidFd, F_SETLK, &lock_data) == -1)
+ {
+ if (errno == EAGAIN)
+ return oldpid;
+ else
+ return -1;
+ }
+#else
+#ifdef LOCK_EX
+ if (flock (pidFd, LOCK_EX|LOCK_NB) == -1)
+ {
+ if (errno == EWOULDBLOCK)
+ return oldpid;
+ else
+ return -1;
+ }
+#else
+ if (lockf (pidFd, F_TLOCK, 0) == -1)
+ {
+ if (errno == EACCES)
+ return oldpid;
+ else
+ return -1;
+ }
+#endif
+#endif
+ }
+ fprintf (pidFilePtr, "%5d\n", getpid ());
+ (void) fflush (pidFilePtr);
+ RegisterCloseOnFork (pidFd);
+ }
+ return 0;
+}
+
+UnlockPidFile ()
+{
+ if (lockPidFile)
+#ifdef F_SETLK
+ {
+ struct flock lock_data;
+ lock_data.l_type = F_UNLCK;
+ lock_data.l_whence = SEEK_SET;
+ lock_data.l_start = lock_data.l_len = 0;
+ (void) fcntl(pidFd, F_SETLK, &lock_data);
+ }
+#else
+#ifdef F_ULOCK
+ lockf (pidFd, F_ULOCK, 0);
+#else
+ flock (pidFd, LOCK_UN);
+#endif
+#endif
+ close (pidFd);
+ fclose (pidFilePtr);
+}
+
+#if NeedVarargsPrototypes
+SetTitle (char *name, ...)
+#else
+/*VARARGS*/
+SetTitle (name, va_alist)
+char *name;
+va_dcl
+#endif
+{
+#ifndef NOXDMTITLE
+ char *p = Title;
+ int left = TitleLen;
+ char *s;
+ va_list args;
+
+ Va_start(args,name);
+ *p++ = '-';
+ --left;
+ s = name;
+ while (s)
+ {
+ while (*s && left > 0)
+ {
+ *p++ = *s++;
+ left--;
+ }
+ s = va_arg (args, char *);
+ }
+ while (left > 0)
+ {
+ *p++ = ' ';
+ --left;
+ }
+ va_end(args);
+#endif
+}
diff --git a/dm.h b/dm.h
new file mode 100644
index 0000000..801ceab
--- /dev/null
+++ b/dm.h
@@ -0,0 +1,360 @@
+/* $Xorg: dm.h,v 1.4 2001/02/09 02:05:40 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
+ *
+ * dm.h
+ *
+ * public interfaces for greet/verify functionality
+ */
+
+#include <X11/Xos.h>
+#include <X11/Xfuncs.h>
+#include <X11/Xmd.h>
+#include <X11/Xauth.h>
+
+#if defined(X_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE X_POSIX_C_SOURCE
+#include <setjmp.h>
+#include <limits.h>
+#undef _POSIX_C_SOURCE
+#elif defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
+#include <setjmp.h>
+#include <limits.h>
+#else
+#define _POSIX_SOURCE
+#include <setjmp.h>
+#include <limits.h>
+#undef _POSIX_SOURCE
+#endif
+
+/* If XDMCP symbol defined, compile to run XDMCP protocol */
+
+#define XDMCP
+
+#ifdef XDMCP
+#include <X11/Xdmcp.h>
+#endif
+
+#ifdef pegasus
+#undef dirty /* Some bozo put a macro called dirty in sys/param.h */
+#endif /* pegasus */
+
+#ifndef X_NOT_POSIX
+#ifdef _POSIX_SOURCE
+#include <sys/wait.h>
+#else
+#define _POSIX_SOURCE
+#include <sys/wait.h>
+#undef _POSIX_SOURCE
+#endif
+# define waitCode(w) (WIFEXITED(w) ? WEXITSTATUS(w) : 0)
+# define waitSig(w) (WIFSIGNALED(w) ? WTERMSIG(w) : 0)
+# define waitCore(w) 0 /* not in POSIX. so what? */
+typedef int waitType;
+#else /* X_NOT_POSIX */
+#ifdef SYSV
+# define waitCode(w) (((w) >> 8) & 0x7f)
+# define waitSig(w) ((w) & 0xff)
+# define waitCore(w) (((w) >> 15) & 0x01)
+typedef int waitType;
+#else /* SYSV */
+# include <sys/wait.h>
+# define waitCode(w) ((w).w_T.w_Retcode)
+# define waitSig(w) ((w).w_T.w_Termsig)
+# define waitCore(w) ((w).w_T.w_Coredump)
+typedef union wait waitType;
+#endif
+#endif /* X_NOT_POSIX */
+
+# define waitCompose(sig,core,code) ((sig) * 256 + (core) * 128 + (code))
+# define waitVal(w) waitCompose(waitSig(w), waitCore(w), waitCode(w))
+
+typedef enum displayStatus { running, notRunning, zombie, phoenix } DisplayStatus;
+
+#ifndef FD_ZERO
+typedef struct my_fd_set { int fds_bits[1]; } my_fd_set;
+# define FD_ZERO(fdp) bzero ((fdp), sizeof (*(fdp)))
+# define FD_SET(f,fdp) ((fdp)->fds_bits[(f) / (sizeof (int) * 8)] |= (1 << ((f) % (sizeof (int) * 8))))
+# define FD_CLR(f,fdp) ((fdp)->fds_bits[(f) / (sizeof (int) * 8)] &= ~(1 << ((f) % (sizeof (int) * 8))))
+# define FD_ISSET(f,fdp) ((fdp)->fds_bits[(f) / (sizeof (int) * 8)] & (1 << ((f) % (sizeof (int) * 8))))
+# define FD_TYPE my_fd_set
+#else
+# define FD_TYPE fd_set
+#endif
+
+/*
+ * local - server runs on local host
+ * foreign - server runs on remote host
+ * permanent - session restarted when it exits
+ * transient - session not restarted when it exits
+ * fromFile - started via entry in servers file
+ * fromXDMCP - started with XDMCP
+ */
+
+typedef struct displayType {
+ unsigned int location:1;
+ unsigned int lifetime:1;
+ unsigned int origin:1;
+} DisplayType;
+
+# define Local 1
+# define Foreign 0
+
+# define Permanent 1
+# define Transient 0
+
+# define FromFile 1
+# define FromXDMCP 0
+
+extern DisplayType parseDisplayType ();
+
+typedef enum fileState { NewEntry, OldEntry, MissingEntry } FileState;
+
+struct display {
+ struct display *next;
+ /* Xservers file / XDMCP information */
+ char *name; /* DISPLAY name */
+ char *class; /* display class (may be NULL) */
+ DisplayType displayType; /* method to handle with */
+ char **argv; /* program name and arguments */
+
+ /* display state */
+ DisplayStatus status; /* current status */
+ int pid; /* process id of child */
+ int serverPid; /* process id of server (-1 if none) */
+ FileState state; /* state during HUP processing */
+ int startTries; /* current start try */
+
+#ifdef XDMCP
+ /* XDMCP state */
+ CARD32 sessionID; /* ID of active session */
+ XdmcpNetaddr peer; /* display peer address */
+ int peerlen; /* length of peer address */
+ XdmcpNetaddr from; /* XDMCP port of display */
+ int fromlen;
+ CARD16 displayNumber;
+ int useChooser; /* Run the chooser for this display */
+ ARRAY8 clientAddr; /* for chooser picking */
+ CARD16 connectionType; /* ... */
+#endif
+ /* server management resources */
+ int serverAttempts; /* number of attempts at running X */
+ int openDelay; /* open delay time */
+ int openRepeat; /* open attempts to make */
+ int openTimeout; /* abort open attempt timeout */
+ int startAttempts; /* number of attempts at starting */
+ int pingInterval; /* interval between XSync */
+ int pingTimeout; /* timeout for XSync */
+ int terminateServer;/* restart for each session */
+ int grabServer; /* keep server grabbed for Login */
+ int grabTimeout; /* time to wait for grab */
+ int resetSignal; /* signal to reset server */
+ int termSignal; /* signal to terminate server */
+ int resetForAuth; /* server reads auth file at reset */
+ char *keymaps; /* binary compat with DEC */
+ char *greeterLib; /* greeter shared library name */
+
+ /* session resources */
+ char *resources; /* resource file */
+ char *xrdb; /* xrdb program */
+ char *setup; /* Xsetup program */
+ char *startup; /* Xstartup program */
+ char *reset; /* Xreset program */
+ char *session; /* Xsession program */
+ char *userPath; /* path set for session */
+ char *systemPath; /* path set for startup/reset */
+ char *systemShell; /* interpreter for startup/reset */
+ char *failsafeClient;/* a client to start when the session fails */
+ char *chooser; /* chooser program */
+
+ /* authorization resources */
+ int authorize; /* enable authorization */
+ char **authNames; /* authorization protocol names */
+ unsigned short *authNameLens; /* authorization protocol name lens */
+ char *clientAuthFile;/* client specified auth file */
+ char *userAuthDir; /* backup directory for tickets */
+ int authComplain; /* complain when no auth for XDMCP */
+
+ /* information potentially derived from resources */
+ int authNameNum; /* number of protocol names */
+ Xauth **authorizations;/* authorization data */
+ int authNum; /* number of authorizations */
+ char *authFile; /* file to store authorization in */
+
+ int version; /* to keep dynamic greeter clued in */
+ /* add new fields only after here. And preferably at the end. */
+};
+
+#ifdef XDMCP
+
+#define PROTO_TIMEOUT (30 * 60) /* 30 minutes should be long enough */
+
+struct protoDisplay {
+ struct protoDisplay *next;
+ XdmcpNetaddr address; /* UDP address */
+ int addrlen; /* UDP address length */
+ unsigned long date; /* creation date */
+ CARD16 displayNumber;
+ CARD16 connectionType;
+ ARRAY8 connectionAddress;
+ CARD32 sessionID;
+ Xauth *fileAuthorization;
+ Xauth *xdmcpAuthorization;
+ ARRAY8 authenticationName;
+ ARRAY8 authenticationData;
+ XdmAuthKeyRec key;
+};
+#endif /* XDMCP */
+
+struct greet_info {
+ char *name; /* user name */
+ char *password; /* user password */
+ char *string; /* random string */
+ char *passwd; /* binary compat with DEC */
+ int version; /* for dynamic greeter to see */
+ /* add new fields below this line, and preferably at the end */
+};
+
+/* setgroups is not covered by POSIX, arg type varies */
+#if defined(SYSV) || defined(SVR4) || defined(__osf__) || defined(linux)
+#define GID_T gid_t
+#else
+#define GID_T int
+#endif
+
+struct verify_info {
+ int uid; /* user id */
+ int gid; /* group id */
+ char **argv; /* arguments to session */
+ char **userEnviron; /* environment for session */
+ char **systemEnviron;/* environment for startup/reset */
+ int version; /* for dynamic greeter to see */
+ /* add new fields below this line, and preferably at the end */
+};
+
+/* display manager exit status definitions */
+
+# define OBEYSESS_DISPLAY 0 /* obey multipleSessions resource */
+# define REMANAGE_DISPLAY 1 /* force remanage */
+# define UNMANAGE_DISPLAY 2 /* force deletion */
+# define RESERVER_DISPLAY 3 /* force server termination */
+# define OPENFAILED_DISPLAY 4 /* XOpenDisplay failed, retry */
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+extern char *config;
+
+extern char *servers;
+extern int request_port;
+extern int debugLevel;
+extern char *errorLogFile;
+extern int daemonMode;
+extern char *pidFile;
+extern int lockPidFile;
+extern char *authDir;
+extern int autoRescan;
+extern int removeDomainname;
+extern char *keyFile;
+extern char *accessFile;
+extern char **exportList;
+extern char *randomFile;
+extern char *greeterLib;
+extern int choiceTimeout; /* chooser choice timeout */
+
+extern struct display *FindDisplayByName (),
+ *FindDisplayBySessionID (),
+ *FindDisplayByAddress (),
+ *FindDisplayByPid (),
+ *FindDisplayByServerPid (),
+ *NewDisplay ();
+
+extern struct protoDisplay *FindProtoDisplay (),
+ *NewProtoDisplay ();
+
+extern char *localHostname ();
+
+/* in xdmcp.c */
+extern void init_session_id();
+extern void registerHostname();
+
+/* in dm.c */
+extern void StartDisplay();
+
+/* in session.c */
+extern void execute();
+
+/* in auth.c */
+extern void SetLocalAuthorization();
+extern void SetUserAuthorization();
+extern void RemoveUserAuthorization();
+extern void CleanUpFileName();
+
+/* in protodpy.c */
+extern void DisposeProtoDisplay();
+
+/*
+ * CloseOnFork flags
+ */
+
+# define CLOSE_ALWAYS 0
+# define LEAVE_FOR_DISPLAY 1
+
+#ifndef X_NOT_STDC_ENV
+#include <stdlib.h>
+#else
+char *malloc(), *realloc();
+#endif
+
+#if defined(X_NOT_POSIX) && defined(SIGNALRETURNSINT)
+#define SIGVAL int
+#else
+#define SIGVAL void
+#endif
+
+#ifdef X_NOT_POSIX
+#ifdef SYSV
+#define SIGNALS_RESET_WHEN_CAUGHT
+#define UNRELIABLE_SIGNALS
+#endif
+#define Setjmp(e) setjmp(e)
+#define Longjmp(e,v) longjmp(e,v)
+#define Jmp_buf jmp_buf
+#else
+#define Setjmp(e) sigsetjmp(e,1)
+#define Longjmp(e,v) siglongjmp(e,v)
+#define Jmp_buf sigjmp_buf
+#endif
+
+SIGVAL (*Signal())();
diff --git a/dpylist.c b/dpylist.c
new file mode 100644
index 0000000..6dcaafa
--- /dev/null
+++ b/dpylist.c
@@ -0,0 +1,274 @@
+/* $Xorg: dpylist.c,v 1.4 2001/02/09 02:05:40 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
+ *
+ * a simple linked list of known displays
+ */
+
+# include "dm.h"
+
+static struct display *displays;
+
+AnyDisplaysLeft ()
+{
+ return displays != (struct display *) 0;
+}
+
+ForEachDisplay (f)
+ void (*f)();
+{
+ struct display *d, *next;
+
+ for (d = displays; d; d = next) {
+ next = d->next;
+ (*f) (d);
+ }
+}
+
+struct display *
+FindDisplayByName (name)
+char *name;
+{
+ struct display *d;
+
+ for (d = displays; d; d = d->next)
+ if (!strcmp (name, d->name))
+ return d;
+ return 0;
+}
+
+struct display *
+FindDisplayByPid (pid)
+int pid;
+{
+ struct display *d;
+
+ for (d = displays; d; d = d->next)
+ if (pid == d->pid)
+ return d;
+ return 0;
+}
+
+struct display *
+FindDisplayByServerPid (serverPid)
+int serverPid;
+{
+ struct display *d;
+
+ for (d = displays; d; d = d->next)
+ if (serverPid == d->serverPid)
+ return d;
+ return 0;
+}
+
+#ifdef XDMCP
+
+struct display *
+FindDisplayBySessionID (sessionID)
+ CARD32 sessionID;
+{
+ struct display *d;
+
+ for (d = displays; d; d = d->next)
+ if (sessionID == d->sessionID)
+ return d;
+ return 0;
+}
+
+struct display *
+FindDisplayByAddress (addr, addrlen, displayNumber)
+ XdmcpNetaddr addr;
+ int addrlen;
+ CARD16 displayNumber;
+{
+ struct display *d;
+
+ for (d = displays; d; d = d->next)
+ if (d->displayType.origin == FromXDMCP &&
+ d->displayNumber == displayNumber &&
+ addressEqual (d->from, d->fromlen, addr, addrlen))
+ {
+ return d;
+ }
+ return 0;
+}
+
+#endif /* XDMCP */
+
+#define IfFree(x) if (x) free ((char *) x)
+
+RemoveDisplay (old)
+struct display *old;
+{
+ struct display *d, *p;
+ char **x;
+ int i;
+
+ p = 0;
+ for (d = displays; d; d = d->next) {
+ if (d == old) {
+ if (p)
+ p->next = d->next;
+ else
+ displays = d->next;
+ IfFree (d->name);
+ IfFree (d->class);
+ for (x = d->argv; x && *x; x++)
+ IfFree (*x);
+ IfFree (d->argv);
+ IfFree (d->resources);
+ IfFree (d->xrdb);
+ IfFree (d->setup);
+ IfFree (d->startup);
+ IfFree (d->reset);
+ IfFree (d->session);
+ IfFree (d->userPath);
+ IfFree (d->systemPath);
+ IfFree (d->systemShell);
+ IfFree (d->failsafeClient);
+ IfFree (d->chooser);
+ if (d->authorizations)
+ {
+ for (i = 0; i < d->authNum; i++)
+ XauDisposeAuth (d->authorizations[i]);
+ free ((char *) d->authorizations);
+ }
+ IfFree (d->clientAuthFile);
+ if (d->authFile)
+ (void) unlink (d->authFile);
+ IfFree (d->authFile);
+ IfFree (d->userAuthDir);
+ for (x = d->authNames; x && *x; x++)
+ IfFree (*x);
+ IfFree (d->authNames);
+ IfFree (d->authNameLens);
+#ifdef XDMCP
+ IfFree (d->peer);
+ IfFree (d->from);
+ XdmcpDisposeARRAY8 (&d->clientAddr);
+#endif
+ free ((char *) d);
+ break;
+ }
+ p = d;
+ }
+}
+
+struct display *
+NewDisplay (name, class)
+char *name;
+char *class;
+{
+ struct display *d;
+
+ d = (struct display *) malloc (sizeof (struct display));
+ if (!d) {
+ LogOutOfMem ("NewDisplay");
+ return 0;
+ }
+ d->next = displays;
+ d->name = malloc ((unsigned) (strlen (name) + 1));
+ if (!d->name) {
+ LogOutOfMem ("NewDisplay");
+ free ((char *) d);
+ return 0;
+ }
+ strcpy (d->name, name);
+ if (class)
+ {
+ d->class = malloc ((unsigned) (strlen (class) + 1));
+ if (!d->class) {
+ LogOutOfMem ("NewDisplay");
+ free (d->name);
+ free ((char *) d);
+ return 0;
+ }
+ strcpy (d->class, class);
+ }
+ else
+ {
+ d->class = (char *) 0;
+ }
+ /* initialize every field to avoid possible problems */
+ d->argv = 0;
+ d->status = notRunning;
+ d->pid = -1;
+ d->serverPid = -1;
+ d->state = NewEntry;
+ d->resources = NULL;
+ d->xrdb = NULL;
+ d->setup = NULL;
+ d->startup = NULL;
+ d->reset = NULL;
+ d->session = NULL;
+ d->userPath = NULL;
+ d->systemPath = NULL;
+ d->systemShell = NULL;
+ d->failsafeClient = NULL;
+ d->chooser = NULL;
+ d->authorize = FALSE;
+ d->authorizations = NULL;
+ d->authNum = 0;
+ d->authNameNum = 0;
+ d->clientAuthFile = NULL;
+ d->authFile = NULL;
+ d->userAuthDir = NULL;
+ d->authNames = NULL;
+ d->authNameLens = NULL;
+ d->authComplain = 1;
+ d->openDelay = 0;
+ d->openRepeat = 0;
+ d->openTimeout = 0;
+ d->startAttempts = 0;
+ d->startTries = 0;
+ d->terminateServer = 0;
+ d->grabTimeout = 0;
+#ifdef XDMCP
+ d->sessionID = 0;
+ d->peer = 0;
+ d->peerlen = 0;
+ d->from = 0;
+ d->fromlen = 0;
+ d->displayNumber = 0;
+ d->useChooser = 0;
+ d->clientAddr.data = NULL;
+ d->clientAddr.length = 0;
+ d->connectionType = 0;
+#endif
+ d->version = 1; /* registered with The Open Group */
+ displays = d;
+ return d;
+}
+
+
+
+
diff --git a/error.c b/error.c
new file mode 100644
index 0000000..f80468f
--- /dev/null
+++ b/error.c
@@ -0,0 +1,195 @@
+/* $Xorg: error.c,v 1.4 2001/02/09 02:05:40 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
+ *
+ * error.c
+ *
+ * Log display manager errors to a file as
+ * we generally do not have a terminal to talk to
+ */
+
+# include "dm.h"
+# include <stdio.h>
+#if NeedVarargsPrototypes
+# include <stdarg.h>
+#else
+/* this type needs to be big enough to contain int or pointer */
+typedef long Fmtarg_t;
+#endif
+
+/*VARARGS1*/
+LogInfo(
+#if NeedVarargsPrototypes
+ char * fmt, ...)
+#else
+ fmt, arg1, arg2, arg3, arg4, arg5, arg6)
+ char *fmt;
+ Fmtarg_t arg1, arg2, arg3, arg4, arg5, arg6;
+#endif
+{
+ fprintf (stderr, "xdm info (pid %d): ", getpid());
+#if NeedVarargsPrototypes
+ {
+ va_list args;
+ va_start(args, fmt);
+ vfprintf (stderr, fmt, args);
+ va_end(args);
+ }
+#else
+ fprintf (stderr, fmt, arg1, arg2, arg3, arg4, arg5, arg6);
+#endif
+ fflush (stderr);
+}
+
+/*VARARGS1*/
+LogError (
+#if NeedVarargsPrototypes
+ char * fmt, ...)
+#else
+ fmt, arg1, arg2, arg3, arg4, arg5, arg6)
+ char *fmt;
+ Fmtarg_t arg1, arg2, arg3, arg4, arg5, arg6;
+#endif
+{
+ fprintf (stderr, "xdm error (pid %d): ", getpid());
+#if NeedVarargsPrototypes
+ {
+ va_list args;
+ va_start(args, fmt);
+ vfprintf (stderr, fmt, args);
+ va_end(args);
+ }
+#else
+ fprintf (stderr, fmt, arg1, arg2, arg3, arg4, arg5, arg6);
+#endif
+ fflush (stderr);
+}
+
+/*VARARGS1*/
+LogPanic (
+#if NeedVarargsPrototypes
+ char * fmt, ...)
+#else
+ fmt, arg1, arg2, arg3, arg4, arg5, arg6)
+ char *fmt;
+ Fmtarg_t arg1, arg2, arg3, arg4, arg5, arg6;
+#endif
+{
+ fprintf (stderr, "xdm panic (pid %d): ", getpid());
+#if NeedVarargsPrototypes
+ {
+ va_list args;
+ va_start(args, fmt);
+ vfprintf (stderr, fmt, args);
+ va_end(args);
+ }
+#else
+ fprintf (fmt, arg1, arg2, arg3, arg4, arg5, arg6);
+#endif
+ fflush (stderr);
+ exit (1);
+}
+
+/*VARARGS1*/
+LogOutOfMem (
+#if NeedVarargsPrototypes
+ char * fmt, ...)
+#else
+ fmt, arg1, arg2, arg3, arg4, arg5, arg6)
+ char *fmt;
+ Fmtarg_t arg1, arg2, arg3, arg4, arg5, arg6;
+#endif
+{
+ fprintf (stderr, "xdm: out of memory in routine ");
+#if NeedVarargsPrototypes
+ {
+ va_list args;
+ va_start(args, fmt);
+ vfprintf (stderr, fmt, args);
+ va_end(args);
+ }
+#else
+ fprintf (stderr, fmt, arg1, arg2, arg3, arg4, arg5, arg6);
+#endif
+ fflush (stderr);
+}
+
+Panic (mesg)
+char *mesg;
+{
+ int i;
+
+ i = creat ("/dev/console", 0666);
+ write (i, "panic: ", 7);
+ write (i, mesg, strlen (mesg));
+ exit (1);
+}
+
+
+/*VARARGS1*/
+Debug (
+#if NeedVarargsPrototypes
+ char * fmt, ...)
+#else
+ fmt, arg1, arg2, arg3, arg4, arg5, arg6)
+ char *fmt;
+ Fmtarg_t arg1, arg2, arg3, arg4, arg5, arg6;
+#endif
+{
+ if (debugLevel > 0)
+ {
+#if NeedVarargsPrototypes
+ va_list args;
+ va_start(args, fmt);
+ vprintf (fmt, args);
+ va_end(args);
+#else
+ printf (fmt, arg1, arg2, arg3, arg4, arg5, arg6);
+#endif
+ fflush (stdout);
+ }
+}
+
+InitErrorLog ()
+{
+ int i;
+ if (errorLogFile[0]) {
+ i = creat (errorLogFile, 0666);
+ if (i != -1) {
+ if (i != 2) {
+ dup2 (i, 2);
+ close (i);
+ }
+ } else
+ LogError ("Cannot open errorLogFile %s\n", errorLogFile);
+ }
+}
diff --git a/file.c b/file.c
new file mode 100644
index 0000000..547b739
--- /dev/null
+++ b/file.c
@@ -0,0 +1,258 @@
+/* $Xorg: file.c,v 1.5 2001/02/09 02:05:40 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
+ *
+ * file.c
+ */
+
+# include "dm.h"
+# include <ctype.h>
+
+DisplayTypeMatch (d1, d2)
+DisplayType d1, d2;
+{
+ return d1.location == d2.location &&
+ d1.lifetime == d2.lifetime &&
+ d1.origin == d2.origin;
+}
+
+static void
+freeArgs (args)
+ char **args;
+{
+ char **a;
+
+ for (a = args; *a; a++)
+ free (*a);
+ free ((char *) args);
+}
+
+static char **
+splitIntoWords (s)
+ char *s;
+{
+ char **args, **newargs;
+ char *wordStart;
+ int nargs;
+
+ args = 0;
+ nargs = 0;
+ while (*s)
+ {
+ while (*s && isspace (*s))
+ ++s;
+ if (!*s || *s == '#')
+ break;
+ wordStart = s;
+ while (*s && *s != '#' && !isspace (*s))
+ ++s;
+ if (!args)
+ {
+ args = (char **) malloc (2 * sizeof (char *));
+ if (!args)
+ return NULL;
+ }
+ else
+ {
+ newargs = (char **) realloc ((char *) args,
+ (nargs+2)*sizeof (char *));
+ if (!newargs)
+ {
+ freeArgs (args);
+ return NULL;
+ }
+ args = newargs;
+ }
+ args[nargs] = malloc (s - wordStart + 1);
+ if (!args[nargs])
+ {
+ freeArgs (args);
+ return NULL;
+ }
+ strncpy (args[nargs], wordStart, s - wordStart);
+ args[nargs][s-wordStart] = '\0';
+ ++nargs;
+ args[nargs] = NULL;
+ }
+ return args;
+}
+
+static char **
+copyArgs (args)
+ char **args;
+{
+ char **a, **new, **n;
+
+ for (a = args; *a; a++)
+ /* SUPPRESS 530 */
+ ;
+ new = (char **) malloc ((a - args + 1) * sizeof (char *));
+ if (!new)
+ return NULL;
+ n = new;
+ a = args;
+ /* SUPPRESS 560 */
+ while ((*n++ = *a++))
+ /* SUPPRESS 530 */
+ ;
+ return new;
+}
+
+freeSomeArgs (args, n)
+ char **args;
+ int n;
+{
+ char **a;
+
+ a = args;
+ while (n--)
+ free (*a++);
+ free ((char *) args);
+}
+
+ParseDisplay (source, acceptableTypes, numAcceptable)
+char *source;
+DisplayType *acceptableTypes;
+int numAcceptable;
+{
+ char **args, **argv, **a;
+ char *name, *class, *type;
+ struct display *d;
+ int usedDefault;
+ DisplayType displayType;
+
+ args = splitIntoWords (source);
+ if (!args)
+ return;
+ if (!args[0])
+ {
+ LogError ("Missing display name in servers file\n");
+ freeArgs (args);
+ return;
+ }
+ name = args[0];
+ if (!args[1])
+ {
+ LogError ("Missing display type for %s\n", args[0]);
+ freeArgs (args);
+ return;
+ }
+ displayType = parseDisplayType (args[1], &usedDefault);
+ class = NULL;
+ type = args[1];
+ argv = args + 2;
+ /*
+ * extended syntax; if the second argument doesn't
+ * exactly match a legal display type and the third
+ * argument does, use the second argument as the
+ * display class string
+ */
+ if (usedDefault && args[2])
+ {
+ displayType = parseDisplayType (args[2], &usedDefault);
+ if (!usedDefault)
+ {
+ class = args[1];
+ type = args[2];
+ argv = args + 3;
+ }
+ }
+ while (numAcceptable)
+ {
+ if (DisplayTypeMatch (*acceptableTypes, displayType))
+ break;
+ --numAcceptable;
+ ++acceptableTypes;
+ }
+ if (!numAcceptable)
+ {
+ LogError ("Unacceptable display type %s for display %s\n",
+ type, name);
+ }
+ d = FindDisplayByName (name);
+ if (d)
+ {
+ d->state = OldEntry;
+ if (class && strcmp (d->class, class))
+ {
+ char *newclass;
+
+ newclass = malloc ((unsigned) (strlen (class) + 1));
+ if (newclass)
+ {
+ free (d->class);
+ strcpy (newclass, class);
+ d->class = newclass;
+ }
+ }
+ Debug ("Found existing display: %s %s %s", d->name, d->class , type);
+ freeArgs (d->argv);
+ }
+ else
+ {
+ d = NewDisplay (name, class);
+ Debug ("Found new display: %s %s %s",
+ d->name, d->class ? d->class : "", type);
+ }
+ d->displayType = displayType;
+ d->argv = copyArgs (argv);
+ for (a = d->argv; a && *a; a++)
+ Debug (" %s", *a);
+ Debug ("\n");
+ freeSomeArgs (args, argv - args);
+}
+
+static struct displayMatch {
+ char *name;
+ DisplayType type;
+} displayTypes[] = {
+ "local", { Local, Permanent, FromFile },
+ "foreign", { Foreign, Permanent, FromFile },
+ 0, { Local, Permanent, FromFile },
+};
+
+DisplayType
+parseDisplayType (string, usedDefault)
+ char *string;
+ int *usedDefault;
+{
+ struct displayMatch *d;
+
+ for (d = displayTypes; d->name; d++)
+ if (!strcmp (d->name, string))
+ {
+ *usedDefault = 0;
+ return d->type;
+ }
+ *usedDefault = 1;
+ return d->type;
+}
diff --git a/genauth.c b/genauth.c
new file mode 100644
index 0000000..a4f8ced
--- /dev/null
+++ b/genauth.c
@@ -0,0 +1,228 @@
+/* $Xorg: genauth.c,v 1.5 2001/02/09 02:05:40 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
+ */
+
+# include <X11/Xauth.h>
+# include <X11/Xos.h>
+# include "dm.h"
+
+#include <errno.h>
+
+#ifdef X_NOT_STDC_ENV
+#define Time_t long
+extern Time_t time ();
+extern int errno;
+#else
+#include <time.h>
+#define Time_t time_t
+#endif
+
+static unsigned char key[8];
+
+#ifdef HASXDMAUTH
+
+typedef unsigned char auth_cblock[8]; /* block size */
+
+typedef struct auth_ks_struct { auth_cblock _; } auth_wrapper_schedule[16];
+
+extern void _XdmcpWrapperToOddParity();
+
+static
+longtochars (l, c)
+ long l;
+ unsigned char *c;
+{
+ c[0] = (l >> 24) & 0xff;
+ c[1] = (l >> 16) & 0xff;
+ c[2] = (l >> 8) & 0xff;
+ c[3] = l & 0xff;
+}
+
+#endif
+
+# define FILE_LIMIT 1024 /* no more than this many buffers */
+
+static int
+sumFile (name, sum)
+char *name;
+long sum[2];
+{
+ long buf[1024*2];
+ int cnt;
+ int fd;
+ int loops;
+ int reads;
+ int i;
+ int ret_status = 0;
+
+ fd = open (name, 0);
+ if (fd < 0) {
+ LogError("Cannot open randomFile \"%s\", errno = %d\n", name, errno);
+ return 0;
+ }
+#ifdef FRAGILE_DEV_MEM
+ if (strcmp(name, "/dev/mem") == 0) lseek (fd, (off_t) 0x100000, SEEK_SET);
+#endif
+ reads = FILE_LIMIT;
+ sum[0] = 0;
+ sum[1] = 0;
+ while ((cnt = read (fd, (char *) buf, sizeof (buf))) > 0 && --reads > 0) {
+ loops = cnt / (2 * sizeof (long));
+ for (i = 0; i < loops; i+= 2) {
+ sum[0] += buf[i];
+ sum[1] += buf[i+1];
+ ret_status = 1;
+ }
+ }
+ if (cnt < 0)
+ LogError("Cannot read randomFile \"%s\", errno = %d\n", name, errno);
+ close (fd);
+ return ret_status;
+}
+
+#ifdef HASXDMAUTH
+
+static
+InitXdmcpWrapper ()
+{
+ long sum[2];
+ unsigned char tmpkey[8];
+
+ if (!sumFile (randomFile, sum)) {
+ sum[0] = time ((Time_t *) 0);
+ sum[1] = time ((Time_t *) 0);
+ }
+ longtochars (sum[0], tmpkey+0);
+ longtochars (sum[1], tmpkey+4);
+ tmpkey[0] = 0;
+ _XdmcpWrapperToOddParity (tmpkey, key);
+}
+
+#endif
+
+#ifndef HASXDMAUTH
+/* A random number generator that is more unpredictable
+ than that shipped with some systems.
+ This code is taken from the C standard. */
+
+static unsigned long int next = 1;
+
+static int
+xdm_rand()
+{
+ next = next * 1103515245 + 12345;
+ return (unsigned int)(next/65536) % 32768;
+}
+
+static void
+xdm_srand(seed)
+ unsigned int seed;
+{
+ next = seed;
+}
+#endif /* no HASXDMAUTH */
+
+GenerateAuthData (auth, len)
+char *auth;
+int len;
+{
+ long ldata[2];
+
+#ifdef ITIMER_REAL
+ {
+ struct timeval now;
+
+ X_GETTIMEOFDAY (&now);
+ ldata[0] = now.tv_usec;
+ ldata[1] = now.tv_sec;
+ }
+#else
+ {
+ long time ();
+
+ ldata[0] = time ((long *) 0);
+ ldata[1] = getpid ();
+ }
+#endif
+#ifdef HASXDMAUTH
+ {
+ int bit;
+ int i;
+ auth_wrapper_schedule schedule;
+ unsigned char data[8];
+ static int xdmcpAuthInited;
+
+ longtochars (ldata[0], data+0);
+ longtochars (ldata[1], data+4);
+ if (!xdmcpAuthInited)
+ {
+ InitXdmcpWrapper ();
+ xdmcpAuthInited = 1;
+ }
+ _XdmcpAuthSetup (key, schedule);
+ for (i = 0; i < len; i++) {
+ auth[i] = 0;
+ for (bit = 1; bit < 256; bit <<= 1) {
+ _XdmcpAuthDoIt (data, data, schedule, 1);
+ if (data[0] + data[1] & 0x4)
+ auth[i] |= bit;
+ }
+ }
+ }
+#else
+ {
+ int seed;
+ int value;
+ int i;
+ static long localkey[2] = {0,0};
+
+ if ( (localkey[0] == 0) && (localkey[1] == 0) ) {
+ if (!sumFile (randomFile, localkey)) {
+ localkey[0] = 1; /* To keep from continually calling sumFile() */
+ }
+ }
+
+ seed = (ldata[0]+localkey[0]) + ((ldata[1]+localkey[1]) << 16);
+ xdm_srand (seed);
+ for (i = 0; i < len; i++)
+ {
+ value = xdm_rand ();
+ auth[i] = (value & 0xff00) >> 8;
+ }
+ value = len;
+ if (value > sizeof (key))
+ value = sizeof (key);
+ memmove( (char *) key, auth, value);
+ }
+#endif
+}
diff --git a/greet.h b/greet.h
new file mode 100644
index 0000000..a45d971
--- /dev/null
+++ b/greet.h
@@ -0,0 +1,187 @@
+/* $Xorg: greet.h,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */
+/*
+
+Copyright 1994, 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.
+
+*/
+
+/*
+ * greet.h - interface to xdm's dynamically-loadable modular greeter
+ */
+
+#include <X11/Xlib.h>
+
+struct dlfuncs {
+ int (*_PingServer)();
+ int (*_SessionPingFailed)();
+ int (*_Debug)();
+ int (*_RegisterCloseOnFork)();
+ int (*_SecureDisplay)();
+ int (*_UnsecureDisplay)();
+ int (*_ClearCloseOnFork)();
+ int (*_SetupDisplay)();
+ int (*_LogError)();
+ int (*_SessionExit)();
+ int (*_DeleteXloginResources)();
+ int (*_source)();
+ char **(*_defaultEnv)();
+ char **(*_setEnv)();
+ char **(*_parseArgs)();
+ int (*_printEnv)();
+ char **(*_systemEnv)();
+ int (*_LogOutOfMem)();
+ void (*_setgrent)(); /* no longer used */
+ struct group *(*_getgrent)(); /* no longer used */
+ void (*_endgrent)(); /* no longer used */
+#ifdef USESHADOW
+ struct spwd *(*_getspnam)();
+ void (*_endspent)();
+#endif
+ struct passwd *(*_getpwnam)();
+ char *(*_crypt)();
+};
+
+/*
+ * Return values for GreetUser();
+ * Values must be explictly defined because the greet library
+ * may come from a different vendor.
+ * Negative values indicate an error.
+ */
+typedef enum {
+ Greet_Session_Over = 0, /* session managed and over */
+ Greet_Success = 1, /* greet succeeded, session not managed */
+ Greet_Failure = -1 /* greet failed */
+} greet_user_rtn;
+
+/*
+ * GreetUser can either handle the user's session or allow xdm to do it.
+ * The return or exit status of GreetUser indicates to xdm whether it
+ * should start a session.
+ *
+ * GreetUser is passed the xdm struct display pointer, a pointer to a
+ * Display, and pointers to greet and verify structs. If it expectes xdm
+ * to run the session, it fills in the Display pointer and the fields
+ * of the greet and verify structs.
+ *
+ * The verify struct includes the uid, gid, arguments to run the session,
+ * environment for the session, and environment for startup/reset.
+ *
+ * The greet struct includes the user's name and password but these are
+ * really only needed if xdm is compiled with a user-based authorization
+ * option such as SECURE_RPC or K5AUTH.
+ */
+
+extern greet_user_rtn GreetUser(
+#if NeedFunctionPrototypes
+ struct display *d,
+ Display **dpy,
+ struct verify_info *verify,
+ struct greet_info *greet,
+ struct dlfuncs *dlfcns
+#endif
+);
+
+typedef greet_user_rtn (*GreetUserProc)(
+#if NeedFunctionPrototypes
+ struct display *,
+ Display **,
+ struct verify_info *,
+ struct greet_info *,
+ struct dlfuncs *dlfcns
+#endif
+);
+
+#ifdef GREET_LIB
+/*
+ * The greeter uses some symbols from the main xdm executable. Since some
+ * dynamic linkers are broken, we need to fix things up so that the symbols
+ * are referenced indirectly through function pointers. The definitions
+ * here, are used to hold the pointers to the functions in the main xdm
+ * executable. The pointers are filled in when the GreetUser function is
+ * called, with the pointer values passed as a paramter.
+ */
+
+extern int (*__xdm_PingServer)();
+extern int (*__xdm_SessionPingFailed)();
+extern int (*__xdm_Debug)();
+extern int (*__xdm_RegisterCloseOnFork)();
+extern int (*__xdm_SecureDisplay)();
+extern int (*__xdm_UnsecureDisplay)();
+extern int (*__xdm_ClearCloseOnFork)();
+extern int (*__xdm_SetupDisplay)();
+extern int (*__xdm_LogError)();
+extern int (*__xdm_SessionExit)();
+extern int (*__xdm_DeleteXloginResources)();
+extern int (*__xdm_source)();
+extern char **(*__xdm_defaultEnv)();
+extern char **(*__xdm_setEnv)();
+extern char **(*__xdm_parseArgs)();
+extern int (*__xdm_printEnv)();
+extern char **(*__xdm_systemEnv)();
+extern int (*__xdm_LogOutOfMem)();
+extern void (*__xdm_setgrent)();
+extern struct group *(*__xdm_getgrent)();
+extern void (*__xdm_endgrent)();
+#ifdef USESHADOW
+extern struct spwd *(*__xdm_getspnam)();
+extern void (*__xdm_endspent)();
+#endif
+extern struct passwd *(*__xdm_getpwnam)();
+extern char *(*__xdm_crypt)();
+
+/*
+ * Force the shared library to call through the function pointer
+ * initialized during the initial call into the library.
+ */
+
+#define PingServer (*__xdm_PingServer)
+#define SessionPingFailed (*__xdm_SessionPingFailed)
+#define Debug (*__xdm_Debug)
+#define RegisterCloseOnFork (*__xdm_RegisterCloseOnFork)
+#define SecureDisplay (*__xdm_SecureDisplay)
+#define UnsecureDisplay (*__xdm_UnsecureDisplay)
+#define ClearCloseOnFork (*__xdm_ClearCloseOnFork)
+#define SetupDisplay (*__xdm_SetupDisplay)
+#define LogError (*__xdm_LogError)
+#define SessionExit (*__xdm_SessionExit)
+#define DeleteXloginResources (*__xdm_DeleteXloginResources)
+#define source (*__xdm_source)
+#define defaultEnv (*__xdm_defaultEnv)
+#define setEnv (*__xdm_setEnv)
+#define parseArgs (*__xdm_parseArgs)
+#define printEnv (*__xdm_printEnv)
+#define systemEnv (*__xdm_systemEnv)
+#define LogOutOfMem (*__xdm_LogOutOfMem)
+#define setgrent (*__xdm_setgrent)
+#define getgrent (*__xdm_getgrent)
+#define endgrent (*__xdm_endgrent)
+#ifdef USESHADOW
+#define getspnam (*__xdm_getspnam)
+#define endspent (*__xdm_endspent)
+#endif
+#define getpwnam (*__xdm_getpwnam)
+#define crypt (*__xdm_crypt)
+
+#endif /* GREET_LIB */
diff --git a/greeter/Login.c b/greeter/Login.c
new file mode 100644
index 0000000..7650774
--- /dev/null
+++ b/greeter/Login.c
@@ -0,0 +1,904 @@
+/* $Xorg: Login.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
+ *
+ * Login.c
+ */
+
+# include <X11/IntrinsicP.h>
+# include <X11/StringDefs.h>
+# include <X11/keysym.h>
+# include <X11/Xfuncs.h>
+
+# include <stdio.h>
+
+# include "dm.h"
+# include "greet.h"
+# include "LoginP.h"
+
+#define offset(field) XtOffsetOf(LoginRec, login.field)
+#define goffset(field) XtOffsetOf(WidgetRec, core.field)
+
+static XtResource resources[] = {
+ {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ goffset(width), XtRImmediate, (XtPointer) 0},
+ {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
+ goffset(height), XtRImmediate, (XtPointer) 0},
+ {XtNx, XtCX, XtRPosition, sizeof (Position),
+ goffset(x), XtRImmediate, (XtPointer) -1},
+ {XtNy, XtCY, XtRPosition, sizeof (Position),
+ goffset(y), XtRImmediate, (XtPointer) -1},
+ {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(textpixel), XtRString, XtDefaultForeground},
+ {XtNpromptColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(promptpixel), XtRString, XtDefaultForeground},
+ {XtNgreetColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(greetpixel), XtRString, XtDefaultForeground},
+ {XtNfailColor, XtCForeground, XtRPixel, sizeof (Pixel),
+ offset(failpixel), XtRString, XtDefaultForeground},
+ {XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
+ offset (font), XtRString, "*-new century schoolbook-medium-r-normal-*-180-*"},
+ {XtNpromptFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
+ offset (promptFont), XtRString, "*-new century schoolbook-bold-r-normal-*-180-*"},
+ {XtNgreetFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
+ offset (greetFont), XtRString, "*-new century schoolbook-bold-i-normal-*-240-*"},
+ {XtNfailFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
+ offset (failFont), XtRString, "*-new century schoolbook-bold-r-normal-*-180-*"},
+ {XtNgreeting, XtCGreeting, XtRString, sizeof (char *),
+ offset(greeting), XtRString, "X Window System"},
+ {XtNunsecureGreeting, XtCGreeting, XtRString, sizeof (char *),
+ offset(unsecure_greet), XtRString, "This is an unsecure session"},
+ {XtNnamePrompt, XtCNamePrompt, XtRString, sizeof (char *),
+ offset(namePrompt), XtRString, "Login: "},
+ {XtNpasswdPrompt, XtCPasswdPrompt, XtRString, sizeof (char *),
+ offset(passwdPrompt), XtRString, "Password: "},
+ {XtNfail, XtCFail, XtRString, sizeof (char *),
+ offset(fail), XtRString, "Login incorrect"},
+ {XtNfailTimeout, XtCFailTimeout, XtRInt, sizeof (int),
+ offset(failTimeout), XtRImmediate, (XtPointer) 10},
+ {XtNnotifyDone, XtCCallback, XtRFunction, sizeof (XtPointer),
+ offset(notify_done), XtRFunction, (XtPointer) 0},
+ {XtNsessionArgument, XtCSessionArgument, XtRString, sizeof (char *),
+ offset(sessionArg), XtRString, (XtPointer) 0 },
+ {XtNsecureSession, XtCSecureSession, XtRBoolean, sizeof (Boolean),
+ offset(secure_session), XtRImmediate, False },
+ {XtNallowAccess, XtCAllowAccess, XtRBoolean, sizeof (Boolean),
+ offset(allow_access), XtRImmediate, False }
+};
+
+#undef offset
+#undef goffset
+
+# define TEXT_X_INC(w) ((w)->login.font->max_bounds.width)
+# define TEXT_Y_INC(w) ((w)->login.font->max_bounds.ascent +\
+ (w)->login.font->max_bounds.descent)
+# define PROMPT_X_INC(w) ((w)->login.promptFont->max_bounds.width)
+# define PROMPT_Y_INC(w) ((w)->login.promptFont->max_bounds.ascent +\
+ (w)->login.promptFont->max_bounds.descent)
+# define GREET_X_INC(w) ((w)->login.greetFont->max_bounds.width)
+# define GREET_Y_INC(w) ((w)->login.greetFont->max_bounds.ascent +\
+ (w)->login.greetFont->max_bounds.descent)
+# define FAIL_X_INC(w) ((w)->login.failFont->max_bounds.width)
+# define FAIL_Y_INC(w) ((w)->login.failFont->max_bounds.ascent +\
+ (w)->login.failFont->max_bounds.descent)
+
+# define Y_INC(w) max (TEXT_Y_INC(w), PROMPT_Y_INC(w))
+
+# define LOGIN_PROMPT_W(w) (XTextWidth (w->login.promptFont,\
+ w->login.namePrompt,\
+ strlen (w->login.namePrompt)))
+# define PASS_PROMPT_W(w) (XTextWidth (w->login.promptFont,\
+ w->login.passwdPrompt,\
+ strlen (w->login.passwdPrompt)))
+# define PROMPT_W(w) (max(LOGIN_PROMPT_W(w), PASS_PROMPT_W(w)))
+# define GREETING(w) ((w)->login.secure_session && !(w)->login.allow_access ?\
+ (w)->login.greeting : (w)->login.unsecure_greet)
+# define GREET_X(w) ((int)(w->core.width - XTextWidth (w->login.greetFont,\
+ GREETING(w), strlen (GREETING(w)))) / 2)
+# define GREET_Y(w) (GREETING(w)[0] ? 2 * GREET_Y_INC (w) : 0)
+# define GREET_W(w) (max (XTextWidth (w->login.greetFont,\
+ w->login.greeting, strlen (w->login.greeting)), \
+ XTextWidth (w->login.greetFont,\
+ w->login.unsecure_greet, strlen (w->login.unsecure_greet))))
+# define LOGIN_X(w) (2 * PROMPT_X_INC(w))
+# define LOGIN_Y(w) (GREET_Y(w) + GREET_Y_INC(w) +\
+ w->login.greetFont->max_bounds.ascent + Y_INC(w))
+# define LOGIN_W(w) (w->core.width - 6 * TEXT_X_INC(w))
+# define LOGIN_H(w) (3 * Y_INC(w) / 2)
+# define LOGIN_TEXT_X(w)(LOGIN_X(w) + PROMPT_W(w))
+# define PASS_X(w) (LOGIN_X(w))
+# define PASS_Y(w) (LOGIN_Y(w) + 8 * Y_INC(w) / 5)
+# define PASS_W(w) (LOGIN_W(w))
+# define PASS_H(w) (LOGIN_H(w))
+# define PASS_TEXT_X(w) (PASS_X(w) + PROMPT_W(w))
+# define FAIL_X(w) ((int)(w->core.width - XTextWidth (w->login.failFont,\
+ w->login.fail, strlen (w->login.fail))) / 2)
+# define FAIL_Y(w) (PASS_Y(w) + 2 * FAIL_Y_INC (w) +\
+ w->login.failFont->max_bounds.ascent)
+# define FAIL_W(w) (XTextWidth (w->login.failFont,\
+ w->login.fail, strlen (w->login.fail)))
+
+# define PAD_X(w) (2 * (LOGIN_X(w) + max (GREET_X_INC(w), FAIL_X_INC(w))))
+
+# define PAD_Y(w) (max (max (Y_INC(w), GREET_Y_INC(w)),\
+ FAIL_Y_INC(w)))
+
+static void Initialize(), Realize(), Destroy(), Redisplay();
+static Boolean SetValues();
+static void draw_it ();
+
+static int max (a,b) { return a > b ? a : b; }
+
+static void
+EraseName (w, cursor)
+ LoginWidget w;
+ int cursor;
+{
+ int x;
+
+ x = LOGIN_TEXT_X (w);
+ if (cursor > 0)
+ x += XTextWidth (w->login.font, w->login.data.name, cursor);
+ XDrawString (XtDisplay(w), XtWindow (w), w->login.bgGC, x, LOGIN_Y(w),
+ w->login.data.name + cursor, strlen (w->login.data.name + cursor));
+}
+
+static void
+DrawName (w, cursor)
+ LoginWidget w;
+ int cursor;
+{
+ int x;
+
+ x = LOGIN_TEXT_X (w);
+ if (cursor > 0)
+ x += XTextWidth (w->login.font, w->login.data.name, cursor);
+ XDrawString (XtDisplay(w), XtWindow (w), w->login.textGC, x, LOGIN_Y(w),
+ w->login.data.name + cursor, strlen (w->login.data.name + cursor));
+}
+
+static void
+realizeCursor (w, gc)
+ LoginWidget w;
+ GC gc;
+{
+ int x, y;
+ int height, width;
+
+ switch (w->login.state) {
+ case GET_NAME:
+ x = LOGIN_TEXT_X (w);
+ y = LOGIN_Y (w);
+ height = w->login.font->max_bounds.ascent + w->login.font->max_bounds.descent;
+ width = 1;
+ if (w->login.cursor > 0)
+ x += XTextWidth (w->login.font, w->login.data.name, w->login.cursor);
+ break;
+ case GET_PASSWD:
+ x = PASS_TEXT_X (w);
+ y = PASS_Y (w);
+ height = w->login.font->max_bounds.ascent + w->login.font->max_bounds.descent;
+ width = 1;
+ break;
+ default:
+ return;
+ }
+ XFillRectangle (XtDisplay (w), XtWindow (w), gc,
+ x, y - w->login.font->max_bounds.ascent, width, height);
+}
+
+static void
+EraseFail (w)
+ LoginWidget w;
+{
+ int x = FAIL_X(w);
+ int y = FAIL_Y(w);
+
+ XSetForeground (XtDisplay (w), w->login.failGC,
+ w->core.background_pixel);
+ XDrawString (XtDisplay (w), XtWindow (w), w->login.failGC,
+ x, y,
+ w->login.fail, strlen (w->login.fail));
+ w->login.failUp = 0;
+ XSetForeground (XtDisplay (w), w->login.failGC,
+ w->login.failpixel);
+}
+
+static void
+XorCursor (w)
+ LoginWidget w;
+{
+ realizeCursor (w, w->login.xorGC);
+}
+
+static void
+RemoveFail (w)
+ LoginWidget w;
+{
+ if (w->login.failUp)
+ EraseFail (w);
+}
+
+static void
+EraseCursor (w)
+ LoginWidget (w);
+{
+ realizeCursor (w, w->login.bgGC);
+}
+
+/*ARGSUSED*/
+void failTimeout (client_data, id)
+ XtPointer client_data;
+ XtIntervalId * id;
+{
+ LoginWidget w = (LoginWidget)client_data;
+
+ Debug ("failTimeout\n");
+ EraseFail (w);
+}
+
+DrawFail (ctx)
+ Widget ctx;
+{
+ LoginWidget w;
+
+ w = (LoginWidget) ctx;
+ XorCursor (w);
+ ResetLogin (w);
+ XorCursor (w);
+ w->login.failUp = 1;
+ RedrawFail (w);
+ if (w->login.failTimeout > 0) {
+ Debug ("failTimeout: %d\n", w->login.failTimeout);
+ XtAppAddTimeOut(XtWidgetToApplicationContext ((Widget)w),
+ w->login.failTimeout * 1000,
+ failTimeout, (XtPointer) w);
+ }
+}
+
+RedrawFail (w)
+ LoginWidget w;
+{
+ int x = FAIL_X(w);
+ int y = FAIL_Y(w);
+
+ if (w->login.failUp)
+ XDrawString (XtDisplay (w), XtWindow (w), w->login.failGC,
+ x, y,
+ w->login.fail, strlen (w->login.fail));
+}
+
+static void
+draw_it (w)
+ LoginWidget w;
+{
+ EraseCursor (w);
+ if (GREETING(w)[0])
+ XDrawString (XtDisplay (w), XtWindow (w), w->login.greetGC,
+ GREET_X(w), GREET_Y(w),
+ GREETING(w), strlen (GREETING(w)));
+ XDrawString (XtDisplay (w), XtWindow (w), w->login.promptGC,
+ LOGIN_X(w), LOGIN_Y(w),
+ w->login.namePrompt, strlen (w->login.namePrompt));
+ XDrawString (XtDisplay (w), XtWindow (w), w->login.promptGC,
+ PASS_X(w), PASS_Y(w),
+ w->login.passwdPrompt, strlen (w->login.passwdPrompt));
+ RedrawFail (w);
+ DrawName (w, 0);
+ XorCursor (w);
+ /*
+ * The GrabKeyboard here is needed only because of
+ * a bug in the R3 server -- the keyboard is grabbed on
+ * the root window, and the server won't dispatch events
+ * to the focus window unless the focus window is a ancestor
+ * of the grab window. Bug in server already found and fixed,
+ * compatibility until at least R4.
+ */
+ if (XGrabKeyboard (XtDisplay (w), XtWindow (w), False, GrabModeAsync,
+ GrabModeAsync, CurrentTime) != GrabSuccess)
+ {
+ XSetInputFocus (XtDisplay (w), XtWindow (w),
+ RevertToPointerRoot, CurrentTime);
+ }
+}
+
+/*ARGSUSED*/
+static void
+DeleteBackwardChar (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ XorCursor (ctx);
+ RemoveFail (ctx);
+ if (ctx->login.cursor > 0) {
+ ctx->login.cursor--;
+ switch (ctx->login.state) {
+ case GET_NAME:
+ EraseName (ctx, ctx->login.cursor);
+ strcpy (ctx->login.data.name + ctx->login.cursor,
+ ctx->login.data.name + ctx->login.cursor + 1);
+ DrawName (ctx, ctx->login.cursor);
+ break;
+ case GET_PASSWD:
+ strcpy (ctx->login.data.passwd + ctx->login.cursor,
+ ctx->login.data.passwd + ctx->login.cursor + 1);
+ break;
+ }
+ }
+ XorCursor (ctx);
+}
+
+/*ARGSUSED*/
+static void
+DeleteForwardChar (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ XorCursor (ctx);
+ RemoveFail (ctx);
+ switch (ctx->login.state) {
+ case GET_NAME:
+ if (ctx->login.cursor < (int)strlen (ctx->login.data.name)) {
+ EraseName (ctx, ctx->login.cursor);
+ strcpy (ctx->login.data.name + ctx->login.cursor,
+ ctx->login.data.name + ctx->login.cursor + 1);
+ DrawName (ctx, ctx->login.cursor);
+ }
+ break;
+ case GET_PASSWD:
+ if (ctx->login.cursor < (int)strlen (ctx->login.data.passwd)) {
+ strcpy (ctx->login.data.passwd + ctx->login.cursor,
+ ctx->login.data.passwd + ctx->login.cursor + 1);
+ }
+ break;
+ }
+ XorCursor (ctx);
+}
+
+/*ARGSUSED*/
+static void
+MoveBackwardChar (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ XorCursor (ctx);
+ RemoveFail (ctx);
+ if (ctx->login.cursor > 0)
+ ctx->login.cursor--;
+ XorCursor (ctx);
+}
+
+/*ARGSUSED*/
+static void
+MoveForwardChar (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ XorCursor (ctx);
+ RemoveFail (ctx);
+ switch (ctx->login.state) {
+ case GET_NAME:
+ if (ctx->login.cursor < (int)strlen(ctx->login.data.name))
+ ++ctx->login.cursor;
+ break;
+ case GET_PASSWD:
+ if (ctx->login.cursor < (int)strlen(ctx->login.data.passwd))
+ ++ctx->login.cursor;
+ break;
+ }
+ XorCursor (ctx);
+}
+
+/*ARGSUSED*/
+static void
+MoveToBegining (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ XorCursor (ctx);
+ RemoveFail (ctx);
+ ctx->login.cursor = 0;
+ XorCursor (ctx);
+}
+
+/*ARGSUSED*/
+static void
+MoveToEnd (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ XorCursor (ctx);
+ RemoveFail (ctx);
+ switch (ctx->login.state) {
+ case GET_NAME:
+ ctx->login.cursor = strlen (ctx->login.data.name);
+ break;
+ case GET_PASSWD:
+ ctx->login.cursor = strlen (ctx->login.data.passwd);
+ break;
+ }
+ XorCursor (ctx);
+}
+
+/*ARGSUSED*/
+static void
+EraseToEndOfLine (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ XorCursor (ctx);
+ RemoveFail (ctx);
+ switch (ctx->login.state) {
+ case GET_NAME:
+ EraseName (ctx, ctx->login.cursor);
+ ctx->login.data.name[ctx->login.cursor] = '\0';
+ break;
+ case GET_PASSWD:
+ ctx->login.data.passwd[ctx->login.cursor] = '\0';
+ break;
+ }
+ XorCursor (ctx);
+}
+
+/*ARGSUSED*/
+static void
+EraseLine (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ MoveToBegining (ctxw, event, params, num_params);
+ EraseToEndOfLine (ctxw, event, params, num_params);
+}
+
+/*ARGSUSED*/
+static void
+FinishField (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ XorCursor (ctx);
+ RemoveFail (ctx);
+ switch (ctx->login.state) {
+ case GET_NAME:
+ ctx->login.state = GET_PASSWD;
+ ctx->login.cursor = 0;
+ break;
+ case GET_PASSWD:
+ ctx->login.state = DONE;
+ ctx->login.cursor = 0;
+ (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_OK);
+ break;
+ }
+ XorCursor (ctx);
+}
+
+/*ARGSUSED*/
+static void
+AllowAccess (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+ Arg arglist[1];
+ Boolean allow;
+
+ RemoveFail (ctx);
+ XtSetArg (arglist[0], XtNallowAccess, (char *) &allow);
+ XtGetValues ((Widget) ctx, arglist, 1);
+ XtSetArg (arglist[0], XtNallowAccess, !allow);
+ XtSetValues ((Widget) ctx, arglist, 1);
+}
+
+/*ARGSUSED*/
+static void
+SetSessionArgument (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ RemoveFail (ctx);
+ if (ctx->login.sessionArg)
+ XtFree (ctx->login.sessionArg);
+ ctx->login.sessionArg = 0;
+ if (*num_params > 0) {
+ ctx->login.sessionArg = XtMalloc (strlen (params[0]) + 1);
+ if (ctx->login.sessionArg)
+ strcpy (ctx->login.sessionArg, params[0]);
+ else
+ LogOutOfMem ("set session argument");
+ }
+}
+
+/*ARGSUSED*/
+static void
+RestartSession (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ XorCursor (ctx);
+ RemoveFail (ctx);
+ ctx->login.state = DONE;
+ ctx->login.cursor = 0;
+ (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_RESTART);
+ XorCursor (ctx);
+}
+
+/*ARGSUSED*/
+static void
+AbortSession (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ XorCursor (ctx);
+ RemoveFail (ctx);
+ ctx->login.state = DONE;
+ ctx->login.cursor = 0;
+ (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_ABORT);
+ XorCursor (ctx);
+}
+
+/*ARGSUSED*/
+static void
+AbortDisplay (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ XorCursor (ctx);
+ RemoveFail (ctx);
+ ctx->login.state = DONE;
+ ctx->login.cursor = 0;
+ (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_ABORT_DISPLAY);
+ XorCursor (ctx);
+}
+
+ResetLogin (w)
+ LoginWidget w;
+{
+ EraseName (w, 0);
+ w->login.cursor = 0;
+ w->login.data.name[0] = '\0';
+ w->login.data.passwd[0] = '\0';
+ w->login.state = GET_NAME;
+}
+
+/* ARGSUSED */
+static void
+InsertChar (ctxw, event, params, num_params)
+ Widget ctxw;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ LoginWidget ctx = (LoginWidget)ctxw;
+
+ char strbuf[128];
+ int len;
+
+ len = XLookupString (&event->xkey, strbuf, sizeof (strbuf), 0, 0);
+ strbuf[len] = '\0';
+ switch (ctx->login.state) {
+ case GET_NAME:
+ if (len + (int)strlen(ctx->login.data.name) >= NAME_LEN - 1)
+ len = NAME_LEN - strlen(ctx->login.data.name) - 2;
+ case GET_PASSWD:
+ if (len + (int)strlen(ctx->login.data.passwd) >= NAME_LEN - 1)
+ len = NAME_LEN - strlen(ctx->login.data.passwd) - 2;
+ }
+ if (len == 0)
+ return;
+ XorCursor (ctx);
+ RemoveFail (ctx);
+ switch (ctx->login.state) {
+ case GET_NAME:
+ EraseName (ctx, ctx->login.cursor);
+ memmove( ctx->login.data.name + ctx->login.cursor + len,
+ ctx->login.data.name + ctx->login.cursor,
+ strlen (ctx->login.data.name + ctx->login.cursor) + 1);
+ memmove( ctx->login.data.name + ctx->login.cursor, strbuf, len);
+ DrawName (ctx, ctx->login.cursor);
+ ctx->login.cursor += len;
+ break;
+ case GET_PASSWD:
+ memmove( ctx->login.data.passwd + ctx->login.cursor + len,
+ ctx->login.data.passwd + ctx->login.cursor,
+ strlen (ctx->login.data.passwd + ctx->login.cursor) + 1);
+ memmove( ctx->login.data.passwd + ctx->login.cursor, strbuf, len);
+ ctx->login.cursor += len;
+ break;
+ }
+ XorCursor (ctx);
+}
+
+/* ARGSUSED */
+static void Initialize (greq, gnew, args, num_args)
+ Widget greq, gnew;
+ ArgList args;
+ Cardinal *num_args;
+{
+ LoginWidget w = (LoginWidget)gnew;
+ XtGCMask valuemask, xvaluemask;
+ XGCValues myXGCV;
+ Arg position[2];
+ Position x, y;
+
+ myXGCV.foreground = w->login.textpixel;
+ myXGCV.background = w->core.background_pixel;
+ valuemask = GCForeground | GCBackground;
+ if (w->login.font) {
+ myXGCV.font = w->login.font->fid;
+ valuemask |= GCFont;
+ }
+ w->login.textGC = XtGetGC(gnew, valuemask, &myXGCV);
+ myXGCV.foreground = w->core.background_pixel;
+ w->login.bgGC = XtGetGC(gnew, valuemask, &myXGCV);
+
+ myXGCV.foreground = w->login.textpixel ^ w->core.background_pixel;
+ myXGCV.function = GXxor;
+ xvaluemask = valuemask | GCFunction;
+ w->login.xorGC = XtGetGC (gnew, xvaluemask, &myXGCV);
+
+ /*
+ * Note that the second argument is a GCid -- QueryFont accepts a GCid and
+ * returns the curently contained font.
+ */
+
+ if (w->login.font == NULL)
+ w->login.font = XQueryFont (XtDisplay (w),
+ XGContextFromGC (XDefaultGCOfScreen (XtScreen (w))));
+
+ xvaluemask = valuemask;
+ if (w->login.promptFont == NULL)
+ w->login.promptFont = w->login.font;
+ else
+ xvaluemask |= GCFont;
+
+ myXGCV.foreground = w->login.promptpixel;
+ myXGCV.font = w->login.promptFont->fid;
+ w->login.promptGC = XtGetGC (gnew, xvaluemask, &myXGCV);
+
+ xvaluemask = valuemask;
+ if (w->login.greetFont == NULL)
+ w->login.greetFont = w->login.font;
+ else
+ xvaluemask |= GCFont;
+
+ myXGCV.foreground = w->login.greetpixel;
+ myXGCV.font = w->login.greetFont->fid;
+ w->login.greetGC = XtGetGC (gnew, xvaluemask, &myXGCV);
+
+ xvaluemask = valuemask;
+ if (w->login.failFont == NULL)
+ w->login.failFont = w->login.font;
+ else
+ xvaluemask |= GCFont;
+
+ myXGCV.foreground = w->login.failpixel;
+ myXGCV.font = w->login.failFont->fid;
+ w->login.failGC = XtGetGC (gnew, xvaluemask, &myXGCV);
+
+ w->login.data.name[0] = '\0';
+ w->login.data.passwd[0] = '\0';
+ w->login.state = GET_NAME;
+ w->login.cursor = 0;
+ w->login.failUp = 0;
+ if (w->core.width == 0)
+ w->core.width = max (GREET_W(w), FAIL_W(w)) + PAD_X(w);
+ if (w->core.height == 0) {
+ int fy = FAIL_Y(w);
+ int pady = PAD_Y(w);
+
+ w->core.height = fy + pady; /* for stupid compilers */
+ }
+ if ((x = w->core.x) == -1)
+ x = (int)(XWidthOfScreen (XtScreen (w)) - w->core.width) / 2;
+ if ((y = w->core.y) == -1)
+ y = (int)(XHeightOfScreen (XtScreen (w)) - w->core.height) / 3;
+ XtSetArg (position[0], XtNx, x);
+ XtSetArg (position[1], XtNy, y);
+ XtSetValues (XtParent (w), position, (Cardinal) 2);
+}
+
+
+static void Realize (gw, valueMask, attrs)
+ Widget gw;
+ XtValueMask *valueMask;
+ XSetWindowAttributes *attrs;
+{
+ XtCreateWindow( gw, (unsigned)InputOutput, (Visual *)CopyFromParent,
+ *valueMask, attrs );
+}
+
+static void Destroy (gw)
+ Widget gw;
+{
+ LoginWidget w = (LoginWidget)gw;
+ bzero (w->login.data.name, NAME_LEN);
+ bzero (w->login.data.passwd, NAME_LEN);
+ XtReleaseGC(gw, w->login.textGC);
+ XtReleaseGC(gw, w->login.bgGC);
+ XtReleaseGC(gw, w->login.xorGC);
+ XtReleaseGC(gw, w->login.promptGC);
+ XtReleaseGC(gw, w->login.greetGC);
+ XtReleaseGC(gw, w->login.failGC);
+}
+
+/* ARGSUSED */
+static void Redisplay(gw, event, region)
+ Widget gw;
+ XEvent *event;
+ Region region;
+{
+ draw_it ((LoginWidget) gw);
+}
+
+/*ARGSUSED*/
+static Boolean SetValues (current, request, new, args, num_args)
+ Widget current, request, new;
+ ArgList args;
+ Cardinal *num_args;
+{
+ LoginWidget currentL, newL;
+
+ currentL = (LoginWidget) current;
+ newL = (LoginWidget) new;
+ if (GREETING (currentL) != GREETING (newL))
+ return True;
+ return False;
+}
+
+char defaultLoginTranslations [] =
+"\
+Ctrl<Key>H: delete-previous-character() \n\
+Ctrl<Key>D: delete-character() \n\
+Ctrl<Key>B: move-backward-character() \n\
+Ctrl<Key>F: move-forward-character() \n\
+Ctrl<Key>A: move-to-begining() \n\
+Ctrl<Key>E: move-to-end() \n\
+Ctrl<Key>K: erase-to-end-of-line() \n\
+Ctrl<Key>U: erase-line() \n\
+Ctrl<Key>X: erase-line() \n\
+Ctrl<Key>C: restart-session() \n\
+Ctrl<Key>\\\\: abort-session() \n\
+:Ctrl<Key>plus: allow-all-access() \n\
+<Key>BackSpace: delete-previous-character() \n\
+<Key>Delete: delete-previous-character() \n\
+<Key>Return: finish-field() \n\
+<Key>: insert-char() \
+";
+
+XtActionsRec loginActionsTable [] = {
+ {"delete-previous-character", DeleteBackwardChar},
+ {"delete-character", DeleteForwardChar},
+ {"move-backward-character", MoveBackwardChar},
+ {"move-forward-character", MoveForwardChar},
+ {"move-to-begining", MoveToBegining},
+ {"move-to-end", MoveToEnd},
+ {"erase-to-end-of-line", EraseToEndOfLine},
+ {"erase-line", EraseLine},
+ {"finish-field", FinishField},
+ {"abort-session", AbortSession},
+ {"abort-display", AbortDisplay},
+ {"restart-session", RestartSession},
+ {"insert-char", InsertChar},
+ {"set-session-argument", SetSessionArgument},
+ {"allow-all-access", AllowAccess},
+};
+
+LoginClassRec loginClassRec = {
+ { /* core fields */
+ /* superclass */ &widgetClassRec,
+ /* class_name */ "Login",
+ /* size */ sizeof(LoginRec),
+ /* class_initialize */ NULL,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ loginActionsTable,
+ /* num_actions */ XtNumber (loginActionsTable),
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ Destroy,
+ /* resize */ NULL,
+ /* expose */ Redisplay,
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ NULL,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultLoginTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ }
+};
+
+WidgetClass loginWidgetClass = (WidgetClass) &loginClassRec;
diff --git a/greeter/Login.h b/greeter/Login.h
new file mode 100644
index 0000000..d2b88f4
--- /dev/null
+++ b/greeter/Login.h
@@ -0,0 +1,106 @@
+/* $Xorg: Login.h,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
+ */
+
+
+#ifndef _XtLogin_h
+#define _XtLogin_h
+
+/***********************************************************************
+ *
+ * Login Widget
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background pixel White
+ border BorderColor pixel Black
+ borderWidth BorderWidth int 1
+ foreground Foreground Pixel Black
+ height Height int 120
+ mappedWhenManaged MappedWhenManaged Boolean True
+ width Width int 120
+ x Position int 0
+ y Position int 0
+
+*/
+
+# define XtNgreeting "greeting"
+# define XtNunsecureGreeting "unsecureGreeting"
+# define XtNnamePrompt "namePrompt"
+# define XtNpasswdPrompt "passwdPrompt"
+# define XtNfail "fail"
+# define XtNnotifyDone "notifyDone"
+# define XtNpromptColor "promptColor"
+# define XtNgreetColor "greetColor"
+# define XtNfailColor "failColor"
+# define XtNpromptFont "promptFont"
+# define XtNgreetFont "greetFont"
+# define XtNfailFont "failFont"
+# define XtNfailTimeout "failTimeout"
+# define XtNsessionArgument "sessionArgument"
+# define XtNsecureSession "secureSession"
+# define XtNallowAccess "allowAccess"
+
+# define XtCGreeting "Greeting"
+# define XtCNamePrompt "NamePrompt"
+# define XtCPasswdPrompt "PasswdPrompt"
+# define XtCFail "Fail"
+# define XtCFailTimeout "FailTimeout"
+# define XtCSessionArgument "SessionArgument"
+# define XtCSecureSession "SecureSession"
+# define XtCAllowAccess "AllowAccess"
+
+/* notifyDone interface definition */
+
+#define NAME_LEN 32
+
+typedef struct _LoginData {
+ char name[NAME_LEN], passwd[NAME_LEN];
+} LoginData;
+
+# define NOTIFY_OK 0
+# define NOTIFY_ABORT 1
+# define NOTIFY_RESTART 2
+# define NOTIFY_ABORT_DISPLAY 3
+
+typedef struct _LoginRec *LoginWidget; /* completely defined in LoginPrivate.h */
+typedef struct _LoginClassRec *LoginWidgetClass; /* completely defined in LoginPrivate.h */
+
+extern WidgetClass loginWidgetClass;
+
+#endif /* _XtLogin_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/greeter/LoginP.h b/greeter/LoginP.h
new file mode 100644
index 0000000..8a8f467
--- /dev/null
+++ b/greeter/LoginP.h
@@ -0,0 +1,96 @@
+/* $Xorg: LoginP.h,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
+ */
+
+#ifndef _LoginP_h
+#define _LoginP_h
+
+#include "Login.h"
+#include <X11/CoreP.h>
+
+#define GET_NAME 0
+#define GET_PASSWD 1
+#define DONE 2
+
+/* New fields for the login widget instance record */
+typedef struct {
+ Pixel textpixel; /* foreground pixel */
+ Pixel promptpixel; /* prompt pixel */
+ Pixel greetpixel; /* greeting pixel */
+ Pixel failpixel; /* failure pixel */
+ GC textGC; /* pointer to GraphicsContext */
+ GC bgGC; /* pointer to GraphicsContext */
+ GC xorGC; /* pointer to GraphicsContext */
+ GC promptGC;
+ GC greetGC;
+ GC failGC;
+ char *greeting; /* greeting */
+ char *unsecure_greet;/* message displayed when insecure */
+ char *namePrompt; /* name prompt */
+ char *passwdPrompt; /* password prompt */
+ char *fail; /* failure message */
+ XFontStruct *font; /* font for text */
+ XFontStruct *promptFont; /* font for prompts */
+ XFontStruct *greetFont; /* font for greeting */
+ XFontStruct *failFont; /* font for failure message */
+ int state; /* state */
+ int cursor; /* current cursor position */
+ int failUp; /* failure message displayed */
+ LoginData data; /* name/passwd */
+ char *sessionArg; /* argument passed to session */
+ void (*notify_done)();/* proc to call when done */
+ int failTimeout; /* seconds til drop fail msg */
+ XtIntervalId interval_id; /* drop fail message note */
+ Boolean secure_session; /* session is secured */
+ Boolean allow_access; /* disable access control on login */
+ } LoginPart;
+
+/* Full instance record declaration */
+typedef struct _LoginRec {
+ CorePart core;
+ LoginPart login;
+ } LoginRec;
+
+/* New fields for the Login widget class record */
+typedef struct {int dummy;} LoginClassPart;
+
+/* Full class record declaration. */
+typedef struct _LoginClassRec {
+ CoreClassPart core_class;
+ LoginClassPart login_class;
+ } LoginClassRec;
+
+/* Class pointer. */
+extern LoginClassRec loginClassRec;
+
+#endif /* _LoginP_h */
diff --git a/greeter/greet.c b/greeter/greet.c
new file mode 100644
index 0000000..93c64a6
--- /dev/null
+++ b/greeter/greet.c
@@ -0,0 +1,410 @@
+/* $Xorg: greet.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, X Consortium
+ *
+ * widget to get username/password
+ *
+ */
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/XKBlib.h>
+
+#include "dm.h"
+#include "greet.h"
+#include "Login.h"
+
+#if GREET_LIB
+/*
+ * Function pointers filled in by the initial call ito the library
+ */
+
+int (*__xdm_PingServer)() = NULL;
+int (*__xdm_SessionPingFailed)() = NULL;
+int (*__xdm_Debug)() = NULL;
+int (*__xdm_RegisterCloseOnFork)() = NULL;
+int (*__xdm_SecureDisplay)() = NULL;
+int (*__xdm_UnsecureDisplay)() = NULL;
+int (*__xdm_ClearCloseOnFork)() = NULL;
+int (*__xdm_SetupDisplay)() = NULL;
+int (*__xdm_LogError)() = NULL;
+int (*__xdm_SessionExit)() = NULL;
+int (*__xdm_DeleteXloginResources)() = NULL;
+int (*__xdm_source)() = NULL;
+char **(*__xdm_defaultEnv)() = NULL;
+char **(*__xdm_setEnv)() = NULL;
+char **(*__xdm_parseArgs)() = NULL;
+int (*__xdm_printEnv)() = NULL;
+char **(*__xdm_systemEnv)() = NULL;
+int (*__xdm_LogOutOfMem)() = NULL;
+void (*__xdm_setgrent)() = NULL;
+struct group *(*__xdm_getgrent)() = NULL;
+void (*__xdm_endgrent)() = NULL;
+#ifdef USESHADOW
+struct spwd *(*__xdm_getspnam)() = NULL;
+void (*__xdm_endspent)() = NULL;
+#endif
+struct passwd *(*__xdm_getpwnam)() = NULL;
+char *(*__xdm_crypt)() = NULL;
+
+#endif
+
+#ifdef SECURE_RPC
+#include <rpc/rpc.h>
+#include <rpc/key_prot.h>
+#endif
+
+#ifdef K5AUTH
+#include <krb5/krb5.h>
+#endif
+
+extern Display *dpy;
+
+static int done, code;
+static char name[128], password[128];
+static Widget toplevel;
+static Widget login;
+static XtAppContext context;
+static XtIntervalId pingTimeout;
+
+/*ARGSUSED*/
+static void
+GreetPingServer (closure, intervalId)
+ XtPointer closure;
+ XtIntervalId *intervalId;
+{
+ struct display *d;
+
+ d = (struct display *) closure;
+ if (!PingServer (d, XtDisplay (toplevel)))
+ SessionPingFailed (d);
+ pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000,
+ GreetPingServer, (closure));
+}
+
+/*ARGSUSED*/
+static void
+GreetDone (w, data, status)
+ Widget w;
+ LoginData *data;
+ int status;
+{
+ Debug ("GreetDone: %s, (password is %d long)\n",
+ data->name, strlen (data->passwd));
+ switch (status) {
+ case NOTIFY_OK:
+ strcpy (name, data->name);
+ strcpy (password, data->passwd);
+ bzero (data->passwd, NAME_LEN);
+ code = 0;
+ done = 1;
+ break;
+ case NOTIFY_ABORT:
+ Debug ("RESERVER_DISPLAY\n");
+ code = RESERVER_DISPLAY;
+ done = 1;
+ break;
+ case NOTIFY_RESTART:
+ Debug ("REMANAGE_DISPLAY\n");
+ code = REMANAGE_DISPLAY;
+ done = 1;
+ break;
+ case NOTIFY_ABORT_DISPLAY:
+ Debug ("UNMANAGE_DISPLAY\n");
+ code = UNMANAGE_DISPLAY;
+ done = 1;
+ break;
+ }
+}
+
+static Display *
+InitGreet (d)
+ struct display *d;
+{
+ Arg arglist[10];
+ int i;
+ static int argc;
+ Screen *scrn;
+ static char *argv[] = { "xlogin", 0 };
+ Display *dpy;
+
+ Debug ("greet %s\n", d->name);
+ argc = 1;
+ XtToolkitInitialize ();
+ context = XtCreateApplicationContext();
+ dpy = XtOpenDisplay (context, d->name, "xlogin", "Xlogin", 0,0,
+ &argc, argv);
+
+ if (!dpy)
+ return 0;
+
+ {
+ int opcode, evbase, errbase, majret, minret;
+ unsigned int value = XkbPCF_GrabsUseXKBStateMask;
+ if (XkbQueryExtension (dpy, &opcode, &evbase, &errbase, &majret, &minret)) {
+ if (XkbSetPerClientControls (dpy, XkbPCF_GrabsUseXKBStateMask, &value))
+ LogError ("%s\n", "SetPerClientControls failed");
+ }
+ }
+
+ RegisterCloseOnFork (ConnectionNumber (dpy));
+
+ SecureDisplay (d, dpy);
+
+ i = 0;
+ scrn = XDefaultScreenOfDisplay(dpy);
+ XtSetArg(arglist[i], XtNscreen, scrn); i++;
+ XtSetArg(arglist[i], XtNargc, argc); i++;
+ XtSetArg(arglist[i], XtNargv, argv); i++;
+
+ toplevel = XtAppCreateShell ((String) NULL, "Xlogin",
+ applicationShellWidgetClass, dpy, arglist, i);
+
+ i = 0;
+ XtSetArg (arglist[i], XtNnotifyDone, (XtPointer)GreetDone); i++;
+ if (!d->authorize || d->authorizations || !d->authComplain)
+ {
+ XtSetArg (arglist[i], XtNsecureSession, True); i++;
+ }
+ login = XtCreateManagedWidget ("login", loginWidgetClass, toplevel,
+ arglist, i);
+ XtRealizeWidget (toplevel);
+
+ XWarpPointer(dpy, None, XRootWindowOfScreen (scrn),
+ 0, 0, 0, 0,
+ XWidthOfScreen(scrn) / 2,
+ XHeightOfScreen(scrn) / 2);
+
+ if (d->pingInterval)
+ {
+ pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000,
+ GreetPingServer, (XtPointer) d);
+ }
+ return dpy;
+}
+
+static
+CloseGreet (d)
+ struct display *d;
+{
+ Boolean allow;
+ Arg arglist[1];
+ Display *dpy = XtDisplay(toplevel);
+
+ if (pingTimeout)
+ {
+ XtRemoveTimeOut (pingTimeout);
+ pingTimeout = 0;
+ }
+ UnsecureDisplay (d, dpy);
+ XtSetArg (arglist[0], XtNallowAccess, (char *) &allow);
+ XtGetValues (login, arglist, 1);
+ if (allow)
+ {
+ Debug ("Disabling access control\n");
+ XSetAccessControl (dpy, DisableAccess);
+ }
+ XtDestroyWidget (toplevel);
+ ClearCloseOnFork (XConnectionNumber (dpy));
+ XCloseDisplay (dpy);
+ Debug ("Greet connection closed\n");
+}
+
+static int
+Greet (d, greet)
+ struct display *d;
+ struct greet_info *greet;
+{
+ XEvent event;
+ Arg arglist[1];
+
+ XtSetArg (arglist[0], XtNallowAccess, False);
+ XtSetValues (login, arglist, 1);
+
+ Debug ("dispatching %s\n", d->name);
+ done = 0;
+ while (!done) {
+ XtAppNextEvent (context, &event);
+ XtDispatchEvent (&event);
+ }
+ XFlush (XtDisplay (toplevel));
+ Debug ("Done dispatch %s\n", d->name);
+ if (code == 0)
+ {
+ greet->name = name;
+ greet->password = password;
+ XtSetArg (arglist[0], XtNsessionArgument, (char *) &(greet->string));
+ XtGetValues (login, arglist, 1);
+ Debug ("sessionArgument: %s\n", greet->string ? greet->string : "<NULL>");
+ }
+ return code;
+}
+
+
+static void
+FailedLogin (d, greet)
+ struct display *d;
+ struct greet_info *greet;
+{
+ DrawFail (login);
+ bzero (greet->name, strlen(greet->name));
+ bzero (greet->password, strlen(greet->password));
+}
+
+
+greet_user_rtn GreetUser(d, dpy, verify, greet, dlfuncs)
+ struct display *d;
+ Display ** dpy;
+ struct verify_info *verify;
+ struct greet_info *greet;
+ struct dlfuncs *dlfuncs;
+{
+ int i;
+
+#ifdef GREET_LIB
+/*
+ * These must be set before they are used.
+ */
+ __xdm_PingServer = dlfuncs->_PingServer;
+ __xdm_SessionPingFailed = dlfuncs->_SessionPingFailed;
+ __xdm_Debug = dlfuncs->_Debug;
+ __xdm_RegisterCloseOnFork = dlfuncs->_RegisterCloseOnFork;
+ __xdm_SecureDisplay = dlfuncs->_SecureDisplay;
+ __xdm_UnsecureDisplay = dlfuncs->_UnsecureDisplay;
+ __xdm_ClearCloseOnFork = dlfuncs->_ClearCloseOnFork;
+ __xdm_SetupDisplay = dlfuncs->_SetupDisplay;
+ __xdm_LogError = dlfuncs->_LogError;
+ __xdm_SessionExit = dlfuncs->_SessionExit;
+ __xdm_DeleteXloginResources = dlfuncs->_DeleteXloginResources;
+ __xdm_source = dlfuncs->_source;
+ __xdm_defaultEnv = dlfuncs->_defaultEnv;
+ __xdm_setEnv = dlfuncs->_setEnv;
+ __xdm_parseArgs = dlfuncs->_parseArgs;
+ __xdm_printEnv = dlfuncs->_printEnv;
+ __xdm_systemEnv = dlfuncs->_systemEnv;
+ __xdm_LogOutOfMem = dlfuncs->_LogOutOfMem;
+ __xdm_setgrent = dlfuncs->_setgrent;
+ __xdm_getgrent = dlfuncs->_getgrent;
+ __xdm_endgrent = dlfuncs->_endgrent;
+#ifdef USESHADOW
+ __xdm_getspnam = dlfuncs->_getspnam;
+ __xdm_endspent = dlfuncs->_endspent;
+#endif
+ __xdm_getpwnam = dlfuncs->_getpwnam;
+ __xdm_crypt = dlfuncs->_crypt;
+#endif
+
+ *dpy = InitGreet (d);
+ /*
+ * Run the setup script - note this usually will not work when
+ * the server is grabbed, so we don't even bother trying.
+ */
+ if (!d->grabServer)
+ SetupDisplay (d);
+ if (!*dpy) {
+ LogError ("Cannot reopen display %s for greet window\n", d->name);
+ exit (RESERVER_DISPLAY);
+ }
+ for (;;) {
+ /*
+ * Greet user, requesting name/password
+ */
+ code = Greet (d, greet);
+ if (code != 0)
+ {
+ CloseGreet (d);
+ SessionExit (d, code, FALSE);
+ }
+ /*
+ * Verify user
+ */
+ if (Verify (d, greet, verify))
+ break;
+ else
+ FailedLogin (d, greet);
+ }
+ DeleteXloginResources (d, *dpy);
+ CloseGreet (d);
+ Debug ("Greet loop finished\n");
+ /*
+ * Run system-wide initialization file
+ */
+ if (source (verify->systemEnviron, d->startup) != 0)
+ {
+ Debug ("Startup program %s exited with non-zero status\n",
+ d->startup);
+ SessionExit (d, OBEYSESS_DISPLAY, FALSE);
+ }
+ /*
+ * for user-based authorization schemes,
+ * add the user to the server's allowed "hosts" list.
+ */
+ for (i = 0; i < d->authNum; i++)
+ {
+#ifdef SECURE_RPC
+ if (d->authorizations[i]->name_length == 9 &&
+ memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0)
+ {
+ XHostAddress addr;
+ char netname[MAXNETNAMELEN+1];
+ char domainname[MAXNETNAMELEN+1];
+
+ getdomainname(domainname, sizeof domainname);
+ user2netname (netname, verify->uid, domainname);
+ addr.family = FamilyNetname;
+ addr.length = strlen (netname);
+ addr.address = netname;
+ XAddHost (*dpy, &addr);
+ }
+#endif
+#ifdef K5AUTH
+ if (d->authorizations[i]->name_length == 14 &&
+ memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0)
+ {
+ /* Update server's auth file with user-specific info.
+ * Don't need to AddHost because X server will do that
+ * automatically when it reads the cache we are about
+ * to point it at.
+ */
+ extern Xauth *Krb5GetAuthFor();
+
+ XauDisposeAuth (d->authorizations[i]);
+ d->authorizations[i] =
+ Krb5GetAuthFor(14, "MIT-KERBEROS-5", d->name);
+ SaveServerAuthorizations (d, d->authorizations, d->authNum);
+ }
+#endif
+ }
+
+ return Greet_Success;
+}
diff --git a/greeter/verify.c b/greeter/verify.c
new file mode 100644
index 0000000..52b8138
--- /dev/null
+++ b/greeter/verify.c
@@ -0,0 +1,173 @@
+/* $Xorg: verify.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
+ *
+ * verify.c
+ *
+ * typical unix verification routine.
+ */
+
+# include "dm.h"
+# include <pwd.h>
+#ifdef USESHADOW
+# include <shadow.h>
+# include <errno.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+#endif
+
+# include "greet.h"
+
+#ifdef X_NOT_STDC_ENV
+char *getenv();
+#endif
+
+static char *envvars[] = {
+ "TZ", /* SYSV and SVR4, but never hurts */
+#if defined(sony) && !defined(SYSTYPE_SYSV) && !defined(_SYSTYPE_SYSV)
+ "bootdev",
+ "boothowto",
+ "cputype",
+ "ioptype",
+ "machine",
+ "model",
+ "CONSDEVTYPE",
+ "SYS_LANGUAGE",
+ "SYS_CODE",
+#endif
+#if (defined(SVR4) || defined(SYSV)) && defined(i386) && !defined(sun)
+ "XLOCAL",
+#endif
+ NULL
+};
+
+static char **
+userEnv (d, useSystemPath, user, home, shell)
+struct display *d;
+int useSystemPath;
+char *user, *home, *shell;
+{
+ char **env;
+ char **envvar;
+ char *str;
+ extern char **defaultEnv (), **setEnv ();
+
+ env = defaultEnv ();
+ env = setEnv (env, "DISPLAY", d->name);
+ env = setEnv (env, "HOME", home);
+ env = setEnv (env, "LOGNAME", user); /* POSIX, System V */
+ env = setEnv (env, "USER", user); /* BSD */
+ env = setEnv (env, "PATH", useSystemPath ? d->systemPath : d->userPath);
+ env = setEnv (env, "SHELL", shell);
+ for (envvar = envvars; *envvar; envvar++)
+ {
+ str = getenv(*envvar);
+ if (str)
+ env = setEnv (env, *envvar, str);
+ }
+ return env;
+}
+
+int
+Verify (d, greet, verify)
+struct display *d;
+struct greet_info *greet;
+struct verify_info *verify;
+{
+ struct passwd *p;
+#ifdef USESHADOW
+ struct spwd *sp;
+#endif
+ char *user_pass;
+#if !defined(SVR4) || !defined(GREET_LIB) /* shared lib decls handle this */
+ char *crypt ();
+ char **systemEnv (), **parseArgs ();
+#endif
+ char *shell, *home;
+ char **argv;
+
+ Debug ("Verify %s ...\n", greet->name);
+ p = getpwnam (greet->name);
+ if (!p || strlen (greet->name) == 0) {
+ Debug ("getpwnam() failed.\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ } else {
+ user_pass = p->pw_passwd;
+ }
+#ifdef USESHADOW
+ errno = 0;
+ sp = getspnam(greet->name);
+ if (sp == NULL) {
+ Debug ("getspnam() failed, errno=%d. Are you root?\n", errno);
+ } else {
+ user_pass = sp->sp_pwdp;
+ }
+ endspent();
+#endif
+#if defined(ultrix) || defined(__ultrix__)
+ if (authenticate_user(p, greet->password, NULL) < 0)
+#else
+ if (strcmp (crypt (greet->password, user_pass), user_pass))
+#endif
+ {
+ Debug ("password verify failed\n");
+ bzero(greet->password, strlen(greet->password));
+ return 0;
+ }
+ Debug ("verify succeeded\n");
+ bzero(user_pass, strlen(user_pass)); /* in case shadow password */
+ /* The password is passed to StartClient() for use by user-based
+ authorization schemes. It is zeroed there. */
+ verify->uid = p->pw_uid;
+ verify->gid = p->pw_gid;
+ home = p->pw_dir;
+ shell = p->pw_shell;
+ argv = 0;
+ if (d->session)
+ argv = parseArgs (argv, d->session);
+ if (greet->string)
+ argv = parseArgs (argv, greet->string);
+ if (!argv)
+ argv = parseArgs (argv, "xsession");
+ verify->argv = argv;
+ verify->userEnviron = userEnv (d, p->pw_uid == 0,
+ greet->name, home, shell);
+ Debug ("user environment:\n");
+ printEnv (verify->userEnviron);
+ verify->systemEnviron = systemEnv (d, greet->name, home);
+ Debug ("system environment:\n");
+ printEnv (verify->systemEnviron);
+ Debug ("end of environments\n");
+ return 1;
+}
diff --git a/krb5auth.c b/krb5auth.c
new file mode 100644
index 0000000..5451430
--- /dev/null
+++ b/krb5auth.c
@@ -0,0 +1,266 @@
+/* $Xorg: krb5auth.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */
+/*
+
+Copyright 1994, 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: Stephen Gildea, The Open Group
+ */
+
+/*
+ * krb5auth
+ *
+ * generate Kerberos Version 5 authorization records
+ */
+
+#include "dm.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <krb5/krb5.h>
+#include <krb5/kdb.h> /* for TGTNAME */
+
+/*ARGSUSED*/
+Krb5InitAuth (name_len, name)
+ unsigned short name_len;
+ char *name;
+{
+ krb5_init_ets(); /* initialize error_message() tables */
+}
+
+/*
+ * Returns malloc'ed string that is the credentials cache name.
+ * name should be freed by caller.
+ */
+char *
+Krb5CCacheName(dname)
+ char *dname;
+{
+ char *name;
+ char *tmpdir;
+
+ tmpdir = getenv("TMPDIR");
+ if (!tmpdir)
+ tmpdir = "/tmp";
+ name = malloc(strlen(tmpdir) + strlen(dname) + 20);
+ if (!name)
+ return NULL;
+ sprintf(name, "FILE:%s/K5C", tmpdir);
+ CleanUpFileName(dname, name+strlen(name), strlen(dname)+1);
+ return name;
+}
+
+krb5_error_code
+Krb5DisplayCCache(dname, ccache_return)
+ char *dname;
+ krb5_ccache *ccache_return;
+{
+ krb5_error_code code;
+ char *name;
+
+ name = Krb5CCacheName(dname);
+ if (!name)
+ return ENOMEM;
+ Debug("resolving Kerberos cache %s\n", name);
+ code = krb5_cc_resolve(name, ccache_return);
+ free(name);
+ return code;
+}
+
+Xauth *
+Krb5GetAuthFor(namelen, name, dname)
+ unsigned short namelen;
+ char *name;
+ char *dname;
+{
+ Xauth *new;
+ char *filename;
+ struct stat statbuf;
+
+ new = (Xauth *) malloc (sizeof *new);
+ if (!new)
+ return (Xauth *) 0;
+ new->family = FamilyWild;
+ new->address_length = 0;
+ new->address = 0;
+ new->number_length = 0;
+ new->number = 0;
+
+ if (dname)
+ {
+ filename = Krb5CCacheName(dname);
+ new->data = (char *) malloc (3 + strlen(filename) + 1);
+ if (!new->data)
+ {
+ free (filename);
+ free ((char *) new);
+ return (Xauth *) 0;
+ }
+ strcpy(new->data, "UU:");
+ strcat(new->data, filename);
+ free (filename);
+ new->data_length = strlen(new->data);
+ }
+ else
+ {
+ new->data = NULL;
+ new->data_length = 0;
+ }
+
+ new->name = (char *) malloc (namelen);
+ if (!new->name)
+ {
+ free ((char *) new->data);
+ free ((char *) new);
+ return (Xauth *) 0;
+ }
+ memmove( new->name, name, namelen);
+ new->name_length = namelen;
+ return new;
+}
+
+
+Xauth *
+Krb5GetAuth (namelen, name)
+ unsigned short namelen;
+ char *name;
+{
+ return Krb5GetAuthFor(namelen, name, NULL);
+}
+
+int preauth_search_list[] = {
+ 0,
+ KRB5_PADATA_ENC_TIMESTAMP,
+ -1
+ };
+
+/*
+ * Krb5Init - lifted from kinit.c
+ * Get TGT.
+ * Returns 0 if successful, 1 if not.
+ */
+int
+Krb5Init(name, passwd, d)
+ char *name;
+ char *passwd;
+ struct display *d; /* k5_ccache filled in if successful */
+{
+ krb5_ccache ccache;
+ krb5_error_code code;
+ krb5_principal me;
+ krb5_creds my_creds;
+ krb5_principal server;
+ krb5_address **my_addresses;
+ krb5_timestamp now;
+ int i;
+
+ if (code = Krb5DisplayCCache(d->name, &ccache)) {
+ LogError("%s while getting Krb5 ccache for \"%s\"\n",
+ error_message(code), d->name);
+ return 1;
+ }
+
+ if (code = krb5_parse_name (name, &me)) {
+ LogError("%s while parsing Krb5 name \"%s\"\n",
+ error_message(code), name);
+ return 1;
+ }
+
+ code = krb5_cc_initialize (ccache, me);
+ if (code != 0) {
+ LogError("%s while initializing Krb5 cache \"%s\"\n",
+ error_message(code), krb5_cc_default_name());
+ return 1;
+ }
+
+ memset((char *)&my_creds, 0, sizeof(my_creds));
+
+ my_creds.client = me;
+
+ if (code = krb5_build_principal_ext(&server,
+ krb5_princ_realm(me)->length,
+ krb5_princ_realm(me)->data,
+ 6, "krbtgt",
+ krb5_princ_realm(me)->length,
+ krb5_princ_realm(me)->data,
+ 0)) {
+ LogError("%s while building Krb5 TGT server name\n",
+ error_message(code));
+ return 1;
+ }
+
+ my_creds.server = server;
+
+ code = krb5_os_localaddr(&my_addresses);
+ if (code != 0) {
+ LogError("%s while getting my address for Krb5\n",
+ error_message(code));
+ return 1;
+ }
+ if (code = krb5_timeofday(&now)) {
+ LogError("%s while getting time of day for Krb5\n",
+ error_message(code));
+ return 1;
+ }
+ my_creds.times.starttime = 0; /* start timer when request
+ gets to KDC */
+ my_creds.times.endtime = now + 60*60*8; /* 8 hours */
+ my_creds.times.renew_till = 0;
+
+ for (i = 0; preauth_search_list[i] >= 0; i++) {
+ code = krb5_get_in_tkt_with_password(0, my_addresses,
+ preauth_search_list[i],
+ ETYPE_DES_CBC_CRC,
+ KEYTYPE_DES,
+ passwd,
+ ccache,
+ &my_creds, 0);
+ if (code != KRB5KDC_PREAUTH_FAILED &&
+ code != KRB5KRB_ERR_GENERIC)
+ break;
+ }
+
+ krb5_free_principal(server);
+ krb5_free_addresses(my_addresses);
+
+ if (code) {
+ char *my_name = NULL;
+ int code2 = krb5_unparse_name(me, &my_name);
+ if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
+ LogError ("password incorrect for Krb5 principal \"%s\"\n",
+ code2 ? name : my_name);
+ }
+ else
+ LogError("%s while getting initial Krb5 credentials for \"%s\"\n",
+ error_message(code), code2 ? name : my_name);
+ if (my_name)
+ free (my_name);
+ return 1;
+ }
+ krb5_cc_close(ccache);
+ return 0;
+}
diff --git a/mitauth.c b/mitauth.c
new file mode 100644
index 0000000..1eee630
--- /dev/null
+++ b/mitauth.c
@@ -0,0 +1,91 @@
+/* $Xorg: mitauth.c,v 1.4 2001/02/09 02:05:40 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
+ *
+ * mitauth
+ *
+ * generate authorization keys
+ * for MIT-MAGIC-COOKIE-1 type authorization
+ */
+
+# include <X11/Xos.h>
+# include "dm.h"
+
+# define AUTH_DATA_LEN 16 /* bytes of authorization data */
+static char auth_name[256];
+static int auth_name_len;
+
+MitInitAuth (name_len, name)
+ unsigned short name_len;
+ char *name;
+{
+ if (name_len > 256)
+ name_len = 256;
+ auth_name_len = name_len;
+ memmove( auth_name, name, name_len);
+}
+
+Xauth *
+MitGetAuth (namelen, name)
+ unsigned short namelen;
+ char *name;
+{
+ Xauth *new;
+ new = (Xauth *) malloc (sizeof (Xauth));
+
+ if (!new)
+ return (Xauth *) 0;
+ new->family = FamilyWild;
+ new->address_length = 0;
+ new->address = 0;
+ new->number_length = 0;
+ new->number = 0;
+
+ new->data = (char *) malloc (AUTH_DATA_LEN);
+ if (!new->data)
+ {
+ free ((char *) new);
+ return (Xauth *) 0;
+ }
+ new->name = (char *) malloc (namelen);
+ if (!new->name)
+ {
+ free ((char *) new->data);
+ free ((char *) new);
+ return (Xauth *) 0;
+ }
+ memmove( (char *)new->name, name, namelen);
+ new->name_length = namelen;
+ GenerateAuthData (new->data, AUTH_DATA_LEN);
+ new->data_length = AUTH_DATA_LEN;
+ return new;
+}
diff --git a/netaddr.c b/netaddr.c
new file mode 100644
index 0000000..7053780
--- /dev/null
+++ b/netaddr.c
@@ -0,0 +1,242 @@
+/* $Xorg: netaddr.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */
+/*
+
+Copyright 1991, 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 - X display manager
+ *
+ * netaddr.c - Interpretation of XdmcpNetaddr object.
+ */
+
+#include "dm.h"
+
+#include <X11/X.h> /* FamilyInternet, etc. */
+
+#ifdef XDMCP
+
+#include <sys/socket.h> /* struct sockaddr */
+#include <netinet/in.h> /* struct sockaddr_in */
+
+#ifdef UNIXCONN
+#include <sys/un.h> /* struct sockaddr_un */
+#endif
+#ifdef DNETCONN
+#include <netdnet/dn.h> /* struct sockaddr_dn */
+#endif
+
+/* given an XdmcpNetaddr, returns the socket protocol family used,
+ e.g., AF_INET */
+
+int NetaddrFamily(netaddrp)
+ XdmcpNetaddr netaddrp;
+{
+#ifdef STREAMSCONN
+ short family = *(short *)netaddrp;
+ return family;
+#else
+ return ((struct sockaddr *)netaddrp)->sa_family;
+#endif
+}
+
+
+/* given an XdmcpNetaddr, returns a pointer to the TCP/UDP port used
+ and sets *lenp to the length of the address
+ or 0 if not using TCP or UDP. */
+
+char * NetaddrPort(netaddrp, lenp)
+ XdmcpNetaddr netaddrp;
+ int *lenp; /* return */
+{
+#ifdef STREAMSCONN
+ *lenp = 2;
+ return netaddrp+2;
+#else
+ switch (NetaddrFamily(netaddrp))
+ {
+ case AF_INET:
+ *lenp = 2;
+ return (char *)&(((struct sockaddr_in *)netaddrp)->sin_port);
+ default:
+ *lenp = 0;
+ return NULL;
+ }
+#endif
+}
+
+
+/* given an XdmcpNetaddr, returns a pointer to the network address
+ and sets *lenp to the length of the address */
+
+char * NetaddrAddress(netaddrp, lenp)
+ XdmcpNetaddr netaddrp;
+ int *lenp; /* return */
+{
+#ifdef STREAMSCONN
+ *lenp = 4;
+ return netaddrp+4;
+#else
+ switch (NetaddrFamily(netaddrp)) {
+#ifdef UNIXCONN
+ case AF_UNIX:
+ *lenp = strlen(((struct sockaddr_un *)netaddrp)->sun_path);
+ return (char *) (((struct sockaddr_un *)netaddrp)->sun_path);
+#endif
+#ifdef TCPCONN
+ case AF_INET:
+ *lenp = sizeof (struct in_addr);
+ return (char *) &(((struct sockaddr_in *)netaddrp)->sin_addr);
+#endif
+#ifdef DNETCONN
+ case AF_DECnet:
+ *lenp = sizeof (struct dn_naddr);
+ return (char *) &(((struct sockaddr_dn *)netaddrp)->sdn_add);
+#endif
+#ifdef AF_CHAOS
+ case AF_CHAOS:
+#endif
+ default:
+ *lenp = 0;
+ return NULL;
+ }
+#endif /* STREAMSCONN else */
+}
+
+
+/* given an XdmcpNetaddr, sets *addr to the network address used and
+ sets *len to the number of bytes in addr.
+ Returns the X protocol family used, e.g., FamilyInternet */
+
+int ConvertAddr (saddr, len, addr)
+ XdmcpNetaddr saddr;
+ int *len; /* return */
+ char **addr; /* return */
+{
+ int retval;
+
+ if (len == NULL)
+ return -1;
+ *addr = NetaddrAddress(saddr, len);
+#ifdef STREAMSCONN
+ /* kludge */
+ if (NetaddrFamily(saddr) == 2)
+ retval = FamilyInternet;
+#else
+ switch (NetaddrFamily(saddr))
+ {
+#ifdef AF_UNSPEC
+ case AF_UNSPEC:
+ retval = FamilyLocal;
+ break;
+#endif
+#ifdef AF_UNIX
+#ifndef hpux
+ case AF_UNIX:
+ retval = FamilyLocal;
+ break;
+#endif
+#endif
+#ifdef TCPCONN
+ case AF_INET:
+ retval = FamilyInternet;
+ break;
+#endif
+#ifdef DNETCONN
+ case AF_DECnet:
+ retval = FamilyDECnet;
+ break;
+#endif
+#ifdef AF_CHAOS
+ case AF_CHAOS:
+ retval = FamilyChaos;
+ break;
+#endif
+ default:
+ retval = -1;
+ break;
+ }
+#endif /* STREAMSCONN else */
+ Debug ("ConvertAddr returning %d for family %d\n", retval,
+ NetaddrFamily(saddr));
+ return retval;
+}
+
+addressEqual (a1, len1, a2, len2)
+ XdmcpNetaddr a1, a2;
+ int len1, len2;
+{
+ int partlen1, partlen2;
+ char *part1, *part2;
+
+ if (len1 != len2)
+ {
+ return FALSE;
+ }
+ if (NetaddrFamily(a1) != NetaddrFamily(a2))
+ {
+ return FALSE;
+ }
+ part1 = NetaddrPort(a1, &partlen1);
+ part2 = NetaddrPort(a2, &partlen2);
+ if (partlen1 != partlen2 || memcmp(part1, part2, partlen1) != 0)
+ {
+ return FALSE;
+ }
+ part1 = NetaddrAddress(a1, &partlen1);
+ part2 = NetaddrAddress(a2, &partlen2);
+ if (partlen1 != partlen2 || memcmp(part1, part2, partlen1) != 0)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#ifdef DEBUG
+/*ARGSUSED*/
+PrintSockAddr (a, len) /* Debugging routine */
+ struct sockaddr *a;
+ int len;
+{
+ unsigned char *t, *p;
+
+ Debug ("family %d, ", a->sa_family);
+ switch (a->sa_family) {
+#ifdef AF_INET
+ case AF_INET:
+
+ p = (unsigned char *) &((struct sockaddr_in *) a)->sin_port;
+ t = (unsigned char *) &((struct sockaddr_in *) a)->sin_addr;
+
+ Debug ("port %d, host %d.%d.%d.%d\n",
+ (p[0] << 8) + p[1], t[0], t[1], t[2], t[3]);
+ break;
+ }
+#endif
+}
+#endif
+
+#endif /* XDMCP */
diff --git a/policy.c b/policy.c
new file mode 100644
index 0000000..3cffa90
--- /dev/null
+++ b/policy.c
@@ -0,0 +1,162 @@
+/* $Xorg: policy.c,v 1.4 2001/02/09 02:05:40 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
+ *
+ * policy.c. Implement site-dependent policy for XDMCP connections
+ */
+
+# include "dm.h"
+
+#ifdef XDMCP
+
+# include <X11/X.h>
+# include <sys/socket.h>
+#ifdef AF_INET
+# include <netinet/in.h>
+#endif
+
+static ARRAY8 noAuthentication = { (CARD16) 0, (CARD8Ptr) 0 };
+
+typedef struct _XdmAuth {
+ ARRAY8 authentication;
+ ARRAY8 authorization;
+} XdmAuthRec, *XdmAuthPtr;
+
+static XdmAuthRec auth[] = {
+#ifdef HASXDMAUTH
+{ {(CARD16) 20, (CARD8 *) "XDM-AUTHENTICATION-1"},
+ {(CARD16) 19, (CARD8 *) "XDM-AUTHORIZATION-1"},
+},
+#endif
+{ {(CARD16) 0, (CARD8 *) 0},
+ {(CARD16) 0, (CARD8 *) 0},
+}
+};
+
+#define NumAuth (sizeof auth / sizeof auth[0])
+
+ARRAY8Ptr
+ChooseAuthentication (authenticationNames)
+ ARRAYofARRAY8Ptr authenticationNames;
+{
+ int i, j;
+
+ for (i = 0; i < (int)authenticationNames->length; i++)
+ for (j = 0; j < NumAuth; j++)
+ if (XdmcpARRAY8Equal (&authenticationNames->data[i],
+ &auth[j].authentication))
+ return &authenticationNames->data[i];
+ return &noAuthentication;
+}
+
+CheckAuthentication (pdpy, displayID, name, data)
+ struct protoDisplay *pdpy;
+ ARRAY8Ptr displayID, name, data;
+{
+#ifdef HASXDMAUTH
+ if (name->length && !strncmp ((char *)name->data, "XDM-AUTHENTICATION-1", 20))
+ return XdmCheckAuthentication (pdpy, displayID, name, data);
+#endif
+ return TRUE;
+}
+
+int
+SelectAuthorizationTypeIndex (authenticationName, authorizationNames)
+ ARRAY8Ptr authenticationName;
+ ARRAYofARRAY8Ptr authorizationNames;
+{
+ int i, j;
+
+ for (j = 0; j < NumAuth; j++)
+ if (XdmcpARRAY8Equal (authenticationName,
+ &auth[j].authentication))
+ break;
+ if (j < NumAuth)
+ {
+ for (i = 0; i < (int)authorizationNames->length; i++)
+ if (XdmcpARRAY8Equal (&authorizationNames->data[i],
+ &auth[j].authorization))
+ return i;
+ }
+ for (i = 0; i < (int)authorizationNames->length; i++)
+ if (ValidAuthorization (authorizationNames->data[i].length,
+ (char *) authorizationNames->data[i].data))
+ return i;
+ return -1;
+}
+
+/*ARGSUSED*/
+int
+Willing (addr, connectionType, authenticationName, status, type)
+ ARRAY8Ptr addr;
+ CARD16 connectionType;
+ ARRAY8Ptr authenticationName;
+ ARRAY8Ptr status;
+ xdmOpCode type;
+{
+ char statusBuf[256];
+ int ret;
+
+ ret = AcceptableDisplayAddress (addr, connectionType, type);
+ if (!ret)
+ sprintf (statusBuf, "Display not authorized to connect");
+ else
+ sprintf (statusBuf, "Willing to manage");
+ status->length = strlen (statusBuf);
+ status->data = (CARD8Ptr) malloc (status->length);
+ if (!status->data)
+ status->length = 0;
+ else
+ memmove( status->data, statusBuf, status->length);
+ return ret;
+}
+
+/*ARGSUSED*/
+ARRAY8Ptr
+Accept (from, fromlen, displayNumber)
+ struct sockaddr *from;
+ int fromlen;
+ CARD16 displayNumber;
+{
+ return 0;
+}
+
+/*ARGSUSED*/
+int
+SelectConnectionTypeIndex (connectionTypes, connectionAddresses)
+ ARRAY16Ptr connectionTypes;
+ ARRAYofARRAY8Ptr connectionAddresses;
+{
+ return 0;
+}
+
+#endif /* XDMCP */
diff --git a/protodpy.c b/protodpy.c
new file mode 100644
index 0000000..4672f77
--- /dev/null
+++ b/protodpy.c
@@ -0,0 +1,173 @@
+/*
+ * $Xorg: protodpy.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $
+ *
+Copyright 1989, 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.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+/*
+ * protodpy.c
+ *
+ * manage a collection of proto-displays. These are displays for
+ * which sessionID's have been generated, but no session has been
+ * started.
+ */
+
+#include "dm.h"
+
+#ifdef XDMCP
+
+#include <sys/types.h>
+#ifdef X_NOT_STDC_ENV
+#define Time_t long
+extern Time_t time ();
+#else
+#include <time.h>
+#define Time_t time_t
+#endif
+
+static struct protoDisplay *protoDisplays;
+
+#ifdef DEBUG
+static
+PrintProtoDisplay (pdpy)
+ struct protoDisplay *pdpy;
+{
+ Debug ("ProtoDisplay 0x%x\n", pdpy);
+ Debug ("\taddress: ");
+ PrintSockAddr (pdpy->address, pdpy->addrlen);
+ Debug ("\tdate %d (%d from now)\n", pdpy->date, time(0) - pdpy->date);
+ Debug ("\tdisplay Number %d\n", pdpy->displayNumber);
+ Debug ("\tsessionID %d\n", pdpy->sessionID);
+}
+#endif
+
+struct protoDisplay *
+FindProtoDisplay (address, addrlen, displayNumber)
+ XdmcpNetaddr address;
+ int addrlen;
+ CARD16 displayNumber;
+{
+ struct protoDisplay *pdpy;
+
+ Debug ("FindProtoDisplay\n");
+ for (pdpy = protoDisplays; pdpy; pdpy=pdpy->next)
+ {
+ if (pdpy->displayNumber == displayNumber &&
+ addressEqual (address, addrlen, pdpy->address, pdpy->addrlen))
+ {
+ return pdpy;
+ }
+ }
+ return (struct protoDisplay *) 0;
+}
+
+static
+TimeoutProtoDisplays (now)
+ Time_t now;
+{
+ struct protoDisplay *pdpy, *next;
+
+ for (pdpy = protoDisplays; pdpy; pdpy = next)
+ {
+ next = pdpy->next;
+ if (pdpy->date < now - PROTO_TIMEOUT)
+ DisposeProtoDisplay (pdpy);
+ }
+}
+
+struct protoDisplay *
+NewProtoDisplay (address, addrlen, displayNumber,
+ connectionType, connectionAddress, sessionID)
+ XdmcpNetaddr address;
+ int addrlen;
+ CARD16 displayNumber;
+ CARD16 connectionType;
+ ARRAY8Ptr connectionAddress;
+ CARD32 sessionID;
+{
+ struct protoDisplay *pdpy;
+ Time_t date;
+
+ Debug ("NewProtoDisplay\n");
+ time (&date);
+ TimeoutProtoDisplays (date);
+ pdpy = (struct protoDisplay *) malloc (sizeof *pdpy);
+ if (!pdpy)
+ return NULL;
+ pdpy->address = (XdmcpNetaddr) malloc (addrlen);
+ if (!pdpy->address)
+ {
+ free ((char *) pdpy);
+ return NULL;
+ }
+ pdpy->addrlen = addrlen;
+ memmove( pdpy->address, address, addrlen);
+ pdpy->displayNumber = displayNumber;
+ pdpy->connectionType = connectionType;
+ pdpy->date = date;
+ if (!XdmcpCopyARRAY8 (connectionAddress, &pdpy->connectionAddress))
+ {
+ free ((char *) pdpy->address);
+ free ((char *) pdpy);
+ return NULL;
+ }
+ pdpy->sessionID = sessionID;
+ pdpy->fileAuthorization = (Xauth *) NULL;
+ pdpy->xdmcpAuthorization = (Xauth *) NULL;
+ pdpy->next = protoDisplays;
+ protoDisplays = pdpy;
+ return pdpy;
+}
+
+void
+DisposeProtoDisplay (pdpy)
+ struct protoDisplay *pdpy;
+{
+ struct protoDisplay *p, *prev;
+
+ prev = 0;
+ for (p = protoDisplays; p; p=p->next)
+ {
+ if (p == pdpy)
+ break;
+ prev = p;
+ }
+ if (!p)
+ return;
+ if (prev)
+ prev->next = pdpy->next;
+ else
+ protoDisplays = pdpy->next;
+ bzero(&pdpy->key, sizeof(pdpy->key));
+ if (pdpy->fileAuthorization)
+ XauDisposeAuth (pdpy->fileAuthorization);
+ if (pdpy->xdmcpAuthorization)
+ XauDisposeAuth (pdpy->xdmcpAuthorization);
+ XdmcpDisposeARRAY8 (&pdpy->connectionAddress);
+ free ((char *) pdpy->address);
+ free ((char *) pdpy);
+}
+
+#endif /* XDMCP */
diff --git a/reset.c b/reset.c
new file mode 100644
index 0000000..76dfb9d
--- /dev/null
+++ b/reset.c
@@ -0,0 +1,116 @@
+/* $Xorg: reset.c,v 1.4 2001/02/09 02:05:40 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
+ *
+ * pseudoReset -- pretend to reset the server by killing all clients
+ * with windows. It will reset the server most of the time, unless
+ * a client remains connected with no windows.
+ */
+
+# include "dm.h"
+# include <X11/Xlib.h>
+# include <signal.h>
+
+/*ARGSUSED*/
+static int
+ignoreErrors (dpy, event)
+Display *dpy;
+XErrorEvent *event;
+{
+ Debug ("ignoring error\n");
+}
+
+/*
+ * this is mostly bogus -- but quite useful. I wish the protocol
+ * had some way of enumerating and identifying clients, that way
+ * this code wouldn't have to be this kludgy.
+ */
+
+static
+killWindows (dpy, window)
+Display *dpy;
+Window window;
+{
+ Window root, parent, *children;
+ int child;
+ unsigned int nchildren = 0;
+
+ while (XQueryTree (dpy, window, &root, &parent, &children, &nchildren)
+ && nchildren > 0)
+ {
+ for (child = 0; child < nchildren; child++) {
+ Debug ("XKillClient 0x%x\n", children[child]);
+ XKillClient (dpy, children[child]);
+ }
+ XFree ((char *)children);
+ }
+}
+
+static Jmp_buf resetJmp;
+
+/* ARGSUSED */
+static SIGVAL
+abortReset (n)
+ int n;
+{
+ Longjmp (resetJmp, 1);
+}
+
+/*
+ * this display connection better not have any windows...
+ */
+
+pseudoReset (dpy)
+Display *dpy;
+{
+ Window root;
+ int screen;
+
+ if (Setjmp (resetJmp)) {
+ LogError ("pseudoReset timeout\n");
+ } else {
+ (void) Signal (SIGALRM, abortReset);
+ (void) alarm (30);
+ XSetErrorHandler (ignoreErrors);
+ for (screen = 0; screen < ScreenCount (dpy); screen++) {
+ Debug ("pseudoReset screen %d\n", screen);
+ root = RootWindow (dpy, screen);
+ killWindows (dpy, root);
+ }
+ Debug ("before XSync\n");
+ XSync (dpy, False);
+ (void) alarm (0);
+ }
+ Signal (SIGALRM, SIG_DFL);
+ XSetErrorHandler ((int (*)()) 0);
+ Debug ("pseudoReset done\n");
+}
diff --git a/resource.c b/resource.c
new file mode 100644
index 0000000..5745ae6
--- /dev/null
+++ b/resource.c
@@ -0,0 +1,472 @@
+/* $Xorg: resource.c,v 1.4 2001/02/09 02:05:40 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
+ *
+ * resource.c
+ */
+
+# include "dm.h"
+# include <X11/Intrinsic.h>
+# include <X11/Xmu/CharSet.h>
+
+char *config;
+
+char *servers;
+int request_port;
+int debugLevel;
+char *errorLogFile;
+int daemonMode;
+char *pidFile;
+int lockPidFile;
+char *authDir;
+int autoRescan;
+int removeDomainname;
+char *keyFile;
+char *accessFile;
+char **exportList;
+char *randomFile;
+char *greeterLib;
+int choiceTimeout; /* chooser choice timeout */
+
+# define DM_STRING 0
+# define DM_INT 1
+# define DM_BOOL 2
+# define DM_ARGV 3
+
+/*
+ * the following constants are supposed to be set in the makefile from
+ * parameters set util/imake.includes/site.def (or *.macros in that directory
+ * if it is server-specific). DO NOT CHANGE THESE DEFINITIONS!
+ */
+#ifndef DEF_SERVER_LINE
+#define DEF_SERVER_LINE ":0 local /usr/bin/X11/X :0"
+#endif
+#ifndef XRDB_PROGRAM
+#define XRDB_PROGRAM "/usr/bin/X11/xrdb"
+#endif
+#ifndef DEF_SESSION
+#define DEF_SESSION "/usr/bin/X11/xterm -ls"
+#endif
+#ifndef DEF_USER_PATH
+#define DEF_USER_PATH ":/bin:/usr/bin:/usr/bin/X11:/usr/ucb"
+#endif
+#ifndef DEF_SYSTEM_PATH
+#define DEF_SYSTEM_PATH "/etc:/bin:/usr/bin:/usr/bin/X11:/usr/ucb"
+#endif
+#ifndef DEF_SYSTEM_SHELL
+#define DEF_SYSTEM_SHELL "/bin/sh"
+#endif
+#ifndef DEF_FAILSAFE_CLIENT
+#define DEF_FAILSAFE_CLIENT "/usr/bin/X11/xterm"
+#endif
+#ifndef DEF_XDM_CONFIG
+#define DEF_XDM_CONFIG "/usr/lib/X11/xdm/xdm-config"
+#endif
+#ifndef DEF_CHOOSER
+#define DEF_CHOOSER "/usr/lib/X11/xdm/chooser"
+#endif
+#ifndef DEF_AUTH_NAME
+#ifdef HASXDMAUTH
+#define DEF_AUTH_NAME "XDM-AUTHORIZATION-1 MIT-MAGIC-COOKIE-1"
+#else
+#define DEF_AUTH_NAME "MIT-MAGIC-COOKIE-1"
+#endif
+#endif
+#ifndef DEF_AUTH_DIR
+#define DEF_AUTH_DIR "/usr/lib/X11/xdm"
+#endif
+#ifndef DEF_USER_AUTH_DIR
+#define DEF_USER_AUTH_DIR "/tmp"
+#endif
+#ifndef DEF_KEY_FILE
+#define DEF_KEY_FILE ""
+#endif
+#ifndef DEF_ACCESS_FILE
+#define DEF_ACCESS_FILE ""
+#endif
+#ifndef DEF_RANDOM_FILE
+#define DEF_RANDOM_FILE "/dev/mem"
+#endif
+#ifndef DEF_GREETER_LIB
+#define DEF_GREETER_LIB "/X11/lib/X11/xdm/libXdmGreet.so"
+#endif
+
+#define DEF_UDP_PORT "177" /* registered XDMCP port, dont change */
+
+struct dmResources {
+ char *name, *class;
+ int type;
+ char **dm_value;
+ char *default_value;
+} DmResources[] = {
+"servers", "Servers", DM_STRING, &servers,
+ DEF_SERVER_LINE,
+"requestPort", "RequestPort", DM_INT, (char **) &request_port,
+ DEF_UDP_PORT,
+"debugLevel", "DebugLevel", DM_INT, (char **) &debugLevel,
+ "0",
+"errorLogFile", "ErrorLogFile", DM_STRING, &errorLogFile,
+ "",
+"daemonMode", "DaemonMode", DM_BOOL, (char **) &daemonMode,
+ "true",
+"pidFile", "PidFile", DM_STRING, &pidFile,
+ "",
+"lockPidFile", "LockPidFile", DM_BOOL, (char **) &lockPidFile,
+ "true",
+"authDir", "authDir", DM_STRING, &authDir,
+ DEF_AUTH_DIR,
+"autoRescan", "AutoRescan", DM_BOOL, (char **) &autoRescan,
+ "true",
+"removeDomainname","RemoveDomainname",DM_BOOL, (char **) &removeDomainname,
+ "true",
+"keyFile", "KeyFile", DM_STRING, &keyFile,
+ DEF_KEY_FILE,
+"accessFile", "AccessFile", DM_STRING, &accessFile,
+ DEF_ACCESS_FILE,
+"exportList", "ExportList", DM_ARGV, (char **) &exportList,
+ "",
+"randomFile", "RandomFile", DM_STRING, &randomFile,
+ DEF_RANDOM_FILE,
+"greeterLib", "GreeterLib", DM_STRING, &greeterLib,
+ DEF_GREETER_LIB,
+"choiceTimeout","ChoiceTimeout",DM_INT, (char **) &choiceTimeout,
+ "15",
+};
+
+# define NUM_DM_RESOURCES (sizeof DmResources / sizeof DmResources[0])
+
+# define boffset(f) XtOffsetOf(struct display, f)
+
+struct displayResource {
+ char *name, *class;
+ int type;
+ int offset;
+ char *default_value;
+};
+
+/* resources for managing the server */
+
+struct displayResource serverResources[] = {
+"serverAttempts","ServerAttempts",DM_INT, boffset(serverAttempts),
+ "1",
+"openDelay", "OpenDelay", DM_INT, boffset(openDelay),
+ "15",
+"openRepeat", "OpenRepeat", DM_INT, boffset(openRepeat),
+ "5",
+"openTimeout", "OpenTimeout", DM_INT, boffset(openTimeout),
+ "30",
+"startAttempts","StartAttempts",DM_INT, boffset(startAttempts),
+ "4",
+"pingInterval", "PingInterval", DM_INT, boffset(pingInterval),
+ "5",
+"pingTimeout", "PingTimeout", DM_INT, boffset(pingTimeout),
+ "5",
+"terminateServer","TerminateServer",DM_BOOL, boffset(terminateServer),
+ "false",
+"grabServer", "GrabServer", DM_BOOL, boffset(grabServer),
+ "false",
+"grabTimeout", "GrabTimeout", DM_INT, boffset(grabTimeout),
+ "3",
+"resetSignal", "Signal", DM_INT, boffset(resetSignal),
+ "1", /* SIGHUP */
+"termSignal", "Signal", DM_INT, boffset(termSignal),
+ "15", /* SIGTERM */
+"resetForAuth", "ResetForAuth", DM_BOOL, boffset(resetForAuth),
+ "false",
+"authorize", "Authorize", DM_BOOL, boffset(authorize),
+ "true",
+"authComplain", "AuthComplain", DM_BOOL, boffset(authComplain),
+ "true",
+"authName", "AuthName", DM_ARGV, boffset(authNames),
+ DEF_AUTH_NAME,
+"authFile", "AuthFile", DM_STRING, boffset(clientAuthFile),
+ "",
+};
+
+# define NUM_SERVER_RESOURCES (sizeof serverResources/\
+ sizeof serverResources[0])
+
+/* resources which control the session behaviour */
+
+struct displayResource sessionResources[] = {
+"resources", "Resources", DM_STRING, boffset(resources),
+ "",
+"xrdb", "Xrdb", DM_STRING, boffset(xrdb),
+ XRDB_PROGRAM,
+"setup", "Setup", DM_STRING, boffset(setup),
+ "",
+"startup", "Startup", DM_STRING, boffset(startup),
+ "",
+"reset", "Reset", DM_STRING, boffset(reset),
+ "",
+"session", "Session", DM_STRING, boffset(session),
+ DEF_SESSION,
+"userPath", "Path", DM_STRING, boffset(userPath),
+ DEF_USER_PATH,
+"systemPath", "Path", DM_STRING, boffset(systemPath),
+ DEF_SYSTEM_PATH,
+"systemShell", "Shell", DM_STRING, boffset(systemShell),
+ DEF_SYSTEM_SHELL,
+"failsafeClient","FailsafeClient", DM_STRING, boffset(failsafeClient),
+ DEF_FAILSAFE_CLIENT,
+"userAuthDir", "UserAuthDir", DM_STRING, boffset(userAuthDir),
+ DEF_USER_AUTH_DIR,
+"chooser", "Chooser", DM_STRING, boffset(chooser),
+ DEF_CHOOSER,
+};
+
+# define NUM_SESSION_RESOURCES (sizeof sessionResources/\
+ sizeof sessionResources[0])
+
+XrmDatabase DmResourceDB;
+
+GetResource (name, class, valueType, valuep, default_value)
+ char *name, *class;
+ int valueType;
+ char **valuep;
+ char *default_value;
+{
+ char *type;
+ XrmValue value;
+ char *string, *new_string;
+ char str_buf[50];
+ int len;
+ extern char **parseArgs();
+
+ if (DmResourceDB && XrmGetResource (DmResourceDB,
+ name, class,
+ &type, &value))
+ {
+ string = value.addr;
+ len = value.size;
+ }
+ else
+ {
+ string = default_value;
+ len = strlen (string);
+ }
+
+ Debug ("%s/%s value %*.*s\n", name, class, len, len, string);
+
+ if (valueType == DM_STRING && *valuep)
+ {
+ if (strlen (*valuep) == len && !strncmp (*valuep, string, len))
+ return;
+ else
+ free (*valuep);
+ }
+
+ switch (valueType) {
+ case DM_STRING:
+ new_string = malloc ((unsigned) (len+1));
+ if (!new_string) {
+ LogOutOfMem ("GetResource");
+ return;
+ }
+ strncpy (new_string, string, len);
+ new_string[len] = '\0';
+ *(valuep) = new_string;
+ break;
+ case DM_INT:
+ strncpy (str_buf, string, sizeof (str_buf));
+ str_buf[sizeof (str_buf)-1] = '\0';
+ *((int *) valuep) = atoi (str_buf);
+ break;
+ case DM_BOOL:
+ strncpy (str_buf, string, sizeof (str_buf));
+ str_buf[sizeof (str_buf)-1] = '\0';
+ XmuCopyISOLatin1Lowered (str_buf, str_buf);
+ if (!strcmp (str_buf, "true") ||
+ !strcmp (str_buf, "on") ||
+ !strcmp (str_buf, "yes"))
+ *((int *) valuep) = 1;
+ else if (!strcmp (str_buf, "false") ||
+ !strcmp (str_buf, "off") ||
+ !strcmp (str_buf, "no"))
+ *((int *) valuep) = 0;
+ break;
+ case DM_ARGV:
+ freeArgs (*(char ***) valuep);
+ *((char ***) valuep) = parseArgs ((char **) 0, string);
+ break;
+ }
+}
+
+XrmOptionDescRec configTable [] = {
+{"-server", NULL, XrmoptionSkipArg, (caddr_t) NULL },
+{"-udpPort", NULL, XrmoptionSkipArg, (caddr_t) NULL },
+{"-error", NULL, XrmoptionSkipArg, (caddr_t) NULL },
+{"-resources", NULL, XrmoptionSkipArg, (caddr_t) NULL },
+{"-session", NULL, XrmoptionSkipArg, (caddr_t) NULL },
+{"-debug", NULL, XrmoptionSkipArg, (caddr_t) NULL },
+{"-xrm", NULL, XrmoptionSkipArg, (caddr_t) NULL },
+{"-config", ".configFile", XrmoptionSepArg, (caddr_t) NULL }
+};
+
+XrmOptionDescRec optionTable [] = {
+{"-server", ".servers", XrmoptionSepArg, (caddr_t) NULL },
+{"-udpPort", ".requestPort", XrmoptionSepArg, (caddr_t) NULL },
+{"-error", ".errorLogFile", XrmoptionSepArg, (caddr_t) NULL },
+{"-resources", "*resources", XrmoptionSepArg, (caddr_t) NULL },
+{"-session", "*session", XrmoptionSepArg, (caddr_t) NULL },
+{"-debug", "*debugLevel", XrmoptionSepArg, (caddr_t) NULL },
+{"-xrm", NULL, XrmoptionResArg, (caddr_t) NULL },
+{"-daemon", ".daemonMode", XrmoptionNoArg, "true" },
+{"-nodaemon", ".daemonMode", XrmoptionNoArg, "false" }
+};
+
+static int originalArgc;
+static char **originalArgv;
+
+InitResources (argc, argv)
+int argc;
+char **argv;
+{
+ XrmInitialize ();
+ originalArgc = argc;
+ originalArgv = argv;
+ ReinitResources ();
+}
+
+ReinitResources ()
+{
+ int argc;
+ char **a;
+ char **argv;
+ XrmDatabase newDB;
+
+ argv = (char **) malloc ((originalArgc + 1) * sizeof (char *));
+ if (!argv)
+ LogPanic ("no space for argument realloc\n");
+ for (argc = 0; argc < originalArgc; argc++)
+ argv[argc] = originalArgv[argc];
+ argv[argc] = 0;
+ if (DmResourceDB)
+ XrmDestroyDatabase (DmResourceDB);
+ DmResourceDB = XrmGetStringDatabase ("");
+ /* pre-parse the command line to get the -config option, if any */
+ XrmParseCommand (&DmResourceDB, configTable,
+ sizeof (configTable) / sizeof (configTable[0]),
+ "DisplayManager", &argc, argv);
+ GetResource ("DisplayManager.configFile", "DisplayManager.ConfigFile",
+ DM_STRING, &config, DEF_XDM_CONFIG);
+ newDB = XrmGetFileDatabase ( config );
+ if (newDB)
+ {
+ if (DmResourceDB)
+ XrmDestroyDatabase (DmResourceDB);
+ DmResourceDB = newDB;
+ }
+ else if (argc != originalArgc)
+ LogError ("Can't open configuration file %s\n", config );
+ XrmParseCommand (&DmResourceDB, optionTable,
+ sizeof (optionTable) / sizeof (optionTable[0]),
+ "DisplayManager", &argc, argv);
+ if (argc > 1)
+ {
+ LogError ("extra arguments on command line:");
+ for (a = argv + 1; *a; a++)
+ LogError (" \"%s\"", *a);
+ LogError ("\n");
+ }
+ free (argv);
+}
+
+LoadDMResources ()
+{
+ int i;
+ char name[1024], class[1024];
+
+ for (i = 0; i < NUM_DM_RESOURCES; i++) {
+ sprintf (name, "DisplayManager.%s", DmResources[i].name);
+ sprintf (class, "DisplayManager.%s", DmResources[i].class);
+ GetResource (name, class, DmResources[i].type,
+ (char **) DmResources[i].dm_value,
+ DmResources[i].default_value);
+ }
+}
+
+static
+CleanUpName (src, dst, len)
+char *src, *dst;
+int len;
+{
+ while (*src) {
+ if (--len <= 0)
+ break;
+ switch (*src)
+ {
+ case ':':
+ case '.':
+ *dst++ = '_';
+ break;
+ default:
+ *dst++ = *src;
+ }
+ ++src;
+ }
+ *dst = '\0';
+}
+
+LoadDisplayResources (d, resources, numResources)
+ struct display *d;
+ struct displayResource *resources;
+ int numResources;
+{
+ int i;
+ char name[1024], class[1024];
+ char dpyName[512], dpyClass[512];
+
+ CleanUpName (d->name, dpyName, sizeof (dpyName));
+ CleanUpName (d->class ? d->class : d->name, dpyClass, sizeof (dpyClass));
+ for (i = 0; i < numResources; i++) {
+ sprintf (name, "DisplayManager.%s.%s",
+ dpyName, resources[i].name);
+ sprintf (class, "DisplayManager.%s.%s",
+ dpyClass, resources[i].class);
+ GetResource (name, class, resources[i].type,
+ (char **) (((char *) d) + resources[i].offset),
+ resources[i].default_value);
+ }
+}
+
+LoadServerResources (d)
+ struct display *d;
+{
+ LoadDisplayResources (d, serverResources, NUM_SERVER_RESOURCES);
+}
+
+LoadSessionResources (d)
+ struct display *d;
+{
+ LoadDisplayResources (d, sessionResources, NUM_SESSION_RESOURCES);
+}
diff --git a/rpcauth.c b/rpcauth.c
new file mode 100644
index 0000000..7c94652
--- /dev/null
+++ b/rpcauth.c
@@ -0,0 +1,88 @@
+/* $Xorg: rpcauth.c,v 1.4 2001/02/09 02:05:40 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
+ *
+ * rpcauth
+ *
+ * generate SecureRPC authorization records
+ */
+
+# include <X11/Xos.h>
+# include <rpc/rpc.h>
+# include <rpc/key_prot.h>
+# include "dm.h"
+
+/*ARGSUSED*/
+SecureRPCInitAuth (name_len, name)
+ unsigned short name_len;
+ char *name;
+{
+}
+
+Xauth *
+SecureRPCGetAuth (namelen, name)
+ unsigned short namelen;
+ char *name;
+{
+ char key[MAXNETNAMELEN+1];
+ Xauth *new;
+
+ new = (Xauth *) malloc (sizeof *new);
+ if (!new)
+ return (Xauth *) 0;
+ new->family = FamilyWild;
+ new->address_length = 0;
+ new->address = 0;
+ new->number_length = 0;
+ new->number = 0;
+
+ getnetname (key);
+ Debug ("System netname %s\n", key);
+ new->data_length = strlen(key);
+ new->data = (char *) malloc (new->data_length);
+ if (!new->data)
+ {
+ free ((char *) new);
+ return (Xauth *) 0;
+ }
+ new->name = (char *) malloc (namelen);
+ if (!new->name)
+ {
+ free ((char *) new->data);
+ free ((char *) new);
+ return (Xauth *) 0;
+ }
+ memmove( new->name, name, namelen);
+ new->name_length = namelen;
+ memmove( new->data, key, new->data_length);
+ return new;
+}
diff --git a/server.c b/server.c
new file mode 100644
index 0000000..76c17d7
--- /dev/null
+++ b/server.c
@@ -0,0 +1,419 @@
+/* $Xorg: server.c,v 1.5 2001/02/09 02:05:40 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
+ *
+ * server.c - manage the X server
+ */
+
+# include "dm.h"
+# include <X11/Xlib.h>
+# include <X11/Xos.h>
+# include <stdio.h>
+# include <signal.h>
+# include <errno.h>
+# include <sys/socket.h>
+
+static receivedUsr1;
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+static serverPause ();
+
+static Display *dpy;
+
+/* ARGSUSED */
+static SIGVAL
+CatchUsr1 (n)
+ int n;
+{
+#ifdef SIGNALS_RESET_WHEN_CAUGHT
+ (void) Signal (SIGUSR1, CatchUsr1);
+#endif
+ Debug ("display manager caught SIGUSR1\n");
+ ++receivedUsr1;
+}
+
+char *_SysErrorMsg (n)
+ int n;
+{
+ char *s = strerror(n);
+ return (s ? s : "unknown error");
+}
+
+StartServerOnce (d)
+struct display *d;
+{
+ char **f;
+ char **argv;
+ char arg[1024];
+ char **parseArgs ();
+ int pid;
+
+ Debug ("StartServer for %s\n", d->name);
+ receivedUsr1 = 0;
+ (void) Signal (SIGUSR1, CatchUsr1);
+ argv = d->argv;
+ switch (pid = fork ()) {
+ case 0:
+ CleanUpChild ();
+ if (d->authFile) {
+ sprintf (arg, "-auth %s", d->authFile);
+ argv = parseArgs (argv, arg);
+ }
+ if (!argv) {
+ LogError ("StartServer: no arguments\n");
+ sleep ((unsigned) d->openDelay);
+ exit (UNMANAGE_DISPLAY);
+ }
+ for (f = argv; *f; f++)
+ Debug ("'%s' ", *f);
+ Debug ("\n");
+ /*
+ * give the server SIGUSR1 ignored,
+ * it will notice that and send SIGUSR1
+ * when ready
+ */
+ (void) Signal (SIGUSR1, SIG_IGN);
+ (void) execv (argv[0], argv);
+ LogError ("server %s cannot be executed\n",
+ argv[0]);
+ sleep ((unsigned) d->openDelay);
+ exit (REMANAGE_DISPLAY);
+ case -1:
+ LogError ("fork failed, sleeping\n");
+ return 0;
+ default:
+ break;
+ }
+ Debug ("Server Started %d\n", pid);
+ d->serverPid = pid;
+ if (serverPause ((unsigned) d->openDelay, pid))
+ return FALSE;
+ return TRUE;
+}
+
+StartServer (d)
+struct display *d;
+{
+ int i;
+ int ret = FALSE;
+
+ i = 0;
+ while (d->serverAttempts == 0 || i < d->serverAttempts)
+ {
+ if ((ret = StartServerOnce (d)) == TRUE)
+ break;
+ sleep (d->openDelay);
+ i++;
+ }
+ return ret;
+}
+
+/*
+ * sleep for t seconds, return 1 if the server is dead when
+ * the sleep finishes, 0 else
+ */
+
+static Jmp_buf pauseAbort;
+static int serverPauseRet;
+
+/* ARGSUSED */
+static SIGVAL
+serverPauseAbort (n)
+ int n;
+{
+ Longjmp (pauseAbort, 1);
+}
+
+/* ARGSUSED */
+static SIGVAL
+serverPauseUsr1 (n)
+ int n;
+{
+ Debug ("display manager paused til SIGUSR1\n");
+ ++receivedUsr1;
+ Longjmp (pauseAbort, 1);
+}
+
+static
+serverPause (t, serverPid)
+unsigned t;
+int serverPid;
+{
+ int pid;
+
+ serverPauseRet = 0;
+ if (!Setjmp (pauseAbort)) {
+ (void) Signal (SIGALRM, serverPauseAbort);
+ (void) Signal (SIGUSR1, serverPauseUsr1);
+#ifdef SYSV
+ if (receivedUsr1)
+ (void) alarm ((unsigned) 1);
+ else
+ (void) alarm (t);
+#else
+ if (!receivedUsr1)
+ (void) alarm (t);
+ else
+ Debug ("Already received USR1\n");
+#endif
+ for (;;) {
+#if defined(SYSV) && defined(X_NOT_POSIX)
+ pid = wait ((waitType *) 0);
+#else
+ if (!receivedUsr1)
+ pid = wait ((waitType *) 0);
+ else
+#ifndef X_NOT_POSIX
+ pid = waitpid (-1, (int *) 0, WNOHANG);
+#else
+ pid = wait3 ((waitType *) 0, WNOHANG,
+ (struct rusage *) 0);
+#endif /* X_NOT_POSIX */
+#endif /* SYSV */
+ if (pid == serverPid ||
+ pid == -1 && errno == ECHILD)
+ {
+ Debug ("Server dead\n");
+ serverPauseRet = 1;
+ break;
+ }
+#if !defined(SYSV) || !defined(X_NOT_POSIX)
+ if (pid == 0) {
+ Debug ("Server alive and kicking\n");
+ break;
+ }
+#endif
+ }
+ }
+ (void) alarm ((unsigned) 0);
+ (void) Signal (SIGALRM, SIG_DFL);
+ (void) Signal (SIGUSR1, CatchUsr1);
+ if (serverPauseRet) {
+ Debug ("Server died\n");
+ LogError ("server unexpectedly died\n");
+ }
+ return serverPauseRet;
+}
+
+
+/*
+ * this code is complicated by some TCP failings. On
+ * many systems, the connect will occasionally hang forever,
+ * this trouble is avoided by setting up a timeout to Longjmp
+ * out of the connect (possibly leaving piles of garbage around
+ * inside Xlib) and give up, terminating the server.
+ */
+
+static Jmp_buf openAbort;
+
+/* ARGSUSED */
+static SIGVAL
+abortOpen (n)
+ int n;
+{
+ Longjmp (openAbort, 1);
+}
+
+#ifdef XDMCP
+
+#ifdef STREAMSCONN
+#include <tiuser.h>
+#endif
+
+static
+GetRemoteAddress (d, fd)
+ struct display *d;
+ int fd;
+{
+ char buf[512];
+ int len = sizeof (buf);
+#ifdef STREAMSCONN
+ struct netbuf netb;
+#endif
+
+ if (d->peer)
+ free ((char *) d->peer);
+#ifdef STREAMSCONN
+ netb.maxlen = sizeof(buf);
+ netb.buf = buf;
+ t_getname(fd, &netb, REMOTENAME);
+ len = 8;
+ /* lucky for us, t_getname returns something that looks like a sockaddr */
+#else
+ getpeername (fd, (struct sockaddr *) buf, &len);
+#endif
+ d->peerlen = 0;
+ if (len)
+ {
+ d->peer = (XdmcpNetaddr) malloc (len);
+ if (d->peer)
+ {
+ memmove( (char *) d->peer, buf, len);
+ d->peerlen = len;
+ }
+ }
+ Debug ("Got remote address %s %d\n", d->name, d->peerlen);
+}
+
+#endif /* XDMCP */
+
+static int
+openErrorHandler (dpy)
+ Display *dpy;
+{
+ LogError ("IO Error in XOpenDisplay\n");
+ exit (OPENFAILED_DISPLAY);
+}
+
+int
+WaitForServer (d)
+ struct display *d;
+{
+ int i;
+
+ for (i = 0; i < (d->openRepeat > 0 ? d->openRepeat : 1); i++) {
+ (void) Signal (SIGALRM, abortOpen);
+ (void) alarm ((unsigned) d->openTimeout);
+ if (!Setjmp (openAbort)) {
+ Debug ("Before XOpenDisplay(%s)\n", d->name);
+ errno = 0;
+ (void) XSetIOErrorHandler (openErrorHandler);
+ dpy = XOpenDisplay (d->name);
+#ifdef STREAMSCONN
+ {
+ /* For some reason, the next XOpenDisplay we do is
+ going to fail, so we might as well get that out
+ of the way. There is something broken here. */
+ Display *bogusDpy = XOpenDisplay (d->name);
+ Debug ("bogus XOpenDisplay %s\n",
+ bogusDpy ? "succeeded" : "failed");
+ if (bogusDpy) XCloseDisplay(bogusDpy); /* just in case */
+ }
+#endif
+ (void) alarm ((unsigned) 0);
+ (void) Signal (SIGALRM, SIG_DFL);
+ (void) XSetIOErrorHandler ((int (*)()) 0);
+ Debug ("After XOpenDisplay(%s)\n", d->name);
+ if (dpy) {
+#ifdef XDMCP
+ if (d->displayType.location == Foreign)
+ GetRemoteAddress (d, ConnectionNumber (dpy));
+#endif
+ RegisterCloseOnFork (ConnectionNumber (dpy));
+ (void) fcntl (ConnectionNumber (dpy), F_SETFD, 0);
+ return 1;
+ } else {
+ Debug ("OpenDisplay failed %d (%s) on \"%s\"\n",
+ errno, _SysErrorMsg (errno), d->name);
+ }
+ Debug ("waiting for server to start %d\n", i);
+ sleep ((unsigned) d->openDelay);
+ } else {
+ Debug ("hung in open, aborting\n");
+ LogError ("Hung in XOpenDisplay(%s), aborting\n", d->name);
+ (void) Signal (SIGALRM, SIG_DFL);
+ break;
+ }
+ }
+ Debug ("giving up on server\n");
+ LogError ("server open failed for %s, giving up\n", d->name);
+ return 0;
+}
+
+ResetServer (d)
+ struct display *d;
+{
+ if (dpy && d->displayType.origin != FromXDMCP)
+ pseudoReset (dpy);
+}
+
+static Jmp_buf pingTime;
+
+static void
+PingLost ()
+{
+ Longjmp (pingTime, 1);
+}
+
+/* ARGSUSED */
+static int
+PingLostIOErr (dpy)
+ Display *dpy;
+{
+ PingLost();
+}
+
+/* ARGSUSED */
+static SIGVAL
+PingLostSig (n)
+ int n;
+{
+ PingLost();
+}
+
+PingServer (d, alternateDpy)
+ struct display *d;
+ Display *alternateDpy;
+{
+ int (*oldError)();
+ SIGVAL (*oldSig)();
+ int oldAlarm;
+
+ if (!alternateDpy)
+ alternateDpy = dpy;
+ oldError = XSetIOErrorHandler (PingLostIOErr);
+ oldAlarm = alarm (0);
+ oldSig = Signal (SIGALRM, PingLostSig);
+ (void) alarm (d->pingTimeout * 60);
+ if (!Setjmp (pingTime))
+ {
+ Debug ("Ping server\n");
+ XSync (alternateDpy, 0);
+ }
+ else
+ {
+ Debug ("Server dead\n");
+ (void) alarm (0);
+ (void) Signal (SIGALRM, SIG_DFL);
+ XSetIOErrorHandler (oldError);
+ return 0;
+ }
+ (void) alarm (0);
+ (void) Signal (SIGALRM, oldSig);
+ (void) alarm (oldAlarm);
+ Debug ("Server alive\n");
+ XSetIOErrorHandler (oldError);
+ return 1;
+}
diff --git a/session.c b/session.c
new file mode 100644
index 0000000..9eae405
--- /dev/null
+++ b/session.c
@@ -0,0 +1,878 @@
+/* $Xorg: session.c,v 1.8 2001/02/09 02:05:40 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
+ *
+ * session.c
+ */
+
+#include "dm.h"
+#include "greet.h"
+#include <X11/Xlib.h>
+#include <signal.h>
+#include <X11/Xatom.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#ifdef AIXV3
+# include <usersec.h>
+#endif
+#ifdef SECURE_RPC
+# include <rpc/rpc.h>
+# include <rpc/key_prot.h>
+#endif
+#ifdef K5AUTH
+# include <krb5/krb5.h>
+#endif
+
+#ifndef GREET_USER_STATIC
+#include <dlfcn.h>
+#ifndef RTLD_NOW
+#define RTLD_NOW 1
+#endif
+#endif
+
+#ifdef CSRG_BASED
+#include <sys/param.h>
+#ifdef HAS_SETUSERCONTEXT
+#include <login_cap.h>
+#include <pwd.h>
+#endif
+#endif
+
+extern int PingServer();
+extern int SessionPingFailed();
+extern int Debug();
+extern int RegisterCloseOnFork();
+extern int SecureDisplay();
+extern int UnsecureDisplay();
+extern int ClearCloseOnFork();
+extern int SetupDisplay();
+extern int LogError();
+extern int SessionExit();
+extern int DeleteXloginResources();
+extern int source();
+extern char **defaultEnv();
+extern char **setEnv();
+extern char **parseArgs();
+extern int printEnv();
+extern char **systemEnv();
+extern int LogOutOfMem();
+extern void setgrent();
+extern struct group *getgrent();
+extern void endgrent();
+#ifdef USESHADOW
+extern struct spwd *getspnam();
+extern void endspent();
+#endif
+extern struct passwd *getpwnam();
+extern char *crypt();
+
+static struct dlfuncs dlfuncs = {
+ PingServer,
+ SessionPingFailed,
+ Debug,
+ RegisterCloseOnFork,
+ SecureDisplay,
+ UnsecureDisplay,
+ ClearCloseOnFork,
+ SetupDisplay,
+ LogError,
+ SessionExit,
+ DeleteXloginResources,
+ source,
+ defaultEnv,
+ setEnv,
+ parseArgs,
+ printEnv,
+ systemEnv,
+ LogOutOfMem,
+ setgrent,
+ getgrent,
+ endgrent,
+#ifdef USESHADOW
+ getspnam,
+ endspent,
+#endif
+ getpwnam,
+ crypt,
+ };
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+static Bool StartClient();
+
+static int clientPid;
+static struct greet_info greet;
+static struct verify_info verify;
+
+static Jmp_buf abortSession;
+
+/* ARGSUSED */
+static SIGVAL
+catchTerm (n)
+ int n;
+{
+ Longjmp (abortSession, 1);
+}
+
+static Jmp_buf pingTime;
+
+/* ARGSUSED */
+static SIGVAL
+catchAlrm (n)
+ int n;
+{
+ Longjmp (pingTime, 1);
+}
+
+static Jmp_buf tenaciousClient;
+
+/* ARGSUSED */
+static SIGVAL
+waitAbort (n)
+ int n;
+{
+ Longjmp (tenaciousClient, 1);
+}
+
+#if defined(_POSIX_SOURCE) || defined(SYSV) || defined(SVR4)
+#define killpg(pgrp, sig) kill(-(pgrp), sig)
+#endif
+
+static void
+AbortClient (pid)
+ int pid;
+{
+ int sig = SIGTERM;
+#ifdef __STDC__
+ volatile int i;
+#else
+ int i;
+#endif
+ int retId;
+ for (i = 0; i < 4; i++) {
+ if (killpg (pid, sig) == -1) {
+ switch (errno) {
+ case EPERM:
+ LogError ("xdm can't kill client\n");
+ case EINVAL:
+ case ESRCH:
+ return;
+ }
+ }
+ if (!Setjmp (tenaciousClient)) {
+ (void) Signal (SIGALRM, waitAbort);
+ (void) alarm ((unsigned) 10);
+ retId = wait ((waitType *) 0);
+ (void) alarm ((unsigned) 0);
+ (void) Signal (SIGALRM, SIG_DFL);
+ if (retId == pid)
+ break;
+ } else
+ (void) Signal (SIGALRM, SIG_DFL);
+ sig = SIGKILL;
+ }
+}
+
+SessionPingFailed (d)
+ struct display *d;
+{
+ if (clientPid > 1)
+ {
+ AbortClient (clientPid);
+ source (verify.systemEnviron, d->reset);
+ }
+ SessionExit (d, RESERVER_DISPLAY, TRUE);
+}
+
+/*
+ * We need our own error handlers because we can't be sure what exit code Xlib
+ * will use, and our Xlib does exit(1) which matches REMANAGE_DISPLAY, which
+ * can cause a race condition leaving the display wedged. We need to use
+ * RESERVER_DISPLAY for IO errors, to ensure that the manager waits for the
+ * server to terminate. For other X errors, we should give up.
+ */
+
+/*ARGSUSED*/
+static
+IOErrorHandler (dpy)
+ Display *dpy;
+{
+ LogError("fatal IO error %d (%s)\n", errno, _SysErrorMsg(errno));
+ exit(RESERVER_DISPLAY);
+}
+
+static int
+ErrorHandler(dpy, event)
+ Display *dpy;
+ XErrorEvent *event;
+{
+ LogError("X error\n");
+ if (XmuPrintDefaultErrorMessage (dpy, event, stderr) == 0) return 0;
+ exit(UNMANAGE_DISPLAY);
+ /*NOTREACHED*/
+}
+
+ManageSession (d)
+struct display *d;
+{
+ int pid;
+ Display *dpy;
+ greet_user_rtn greet_stat;
+ static GreetUserProc greet_user_proc = NULL;
+#ifndef GREET_USER_STATIC
+ void *greet_lib_handle;
+#endif
+
+ Debug ("ManageSession %s\n", d->name);
+ (void)XSetIOErrorHandler(IOErrorHandler);
+ (void)XSetErrorHandler(ErrorHandler);
+ SetTitle(d->name, (char *) 0);
+ /*
+ * Load system default Resources
+ */
+ LoadXloginResources (d);
+
+#ifdef GREET_USER_STATIC
+ greet_user_proc = GreetUser;
+#else
+ Debug("ManageSession: loading greeter library %s\n", greeterLib);
+ greet_lib_handle = dlopen(greeterLib, RTLD_NOW);
+ if (greet_lib_handle != NULL)
+ greet_user_proc = (GreetUserProc)dlsym(greet_lib_handle, "GreetUser");
+ if (greet_user_proc == NULL)
+ {
+ LogError("%s while loading %s\n", dlerror(), greeterLib);
+ exit(UNMANAGE_DISPLAY);
+ }
+#endif
+
+ /* tell the possibly dynamically loaded greeter function
+ * what data structure formats to expect.
+ * These version numbers are registered with The Open Group. */
+ verify.version = 1;
+ greet.version = 1;
+ greet_stat = (*greet_user_proc)(d, &dpy, &verify, &greet, &dlfuncs);
+
+ if (greet_stat == Greet_Success)
+ {
+ clientPid = 0;
+ if (!Setjmp (abortSession)) {
+ (void) Signal (SIGTERM, catchTerm);
+ /*
+ * Start the clients, changing uid/groups
+ * setting up environment and running the session
+ */
+ if (StartClient (&verify, d, &clientPid, greet.name, greet.password)) {
+ Debug ("Client Started\n");
+
+#ifndef GREET_USER_STATIC
+ /* Save memory; close library */
+ dlclose(greet_lib_handle);
+#endif
+
+ /*
+ * Wait for session to end,
+ */
+ for (;;) {
+ if (d->pingInterval)
+ {
+ if (!Setjmp (pingTime))
+ {
+ (void) Signal (SIGALRM, catchAlrm);
+ (void) alarm (d->pingInterval * 60);
+ pid = wait ((waitType *) 0);
+ (void) alarm (0);
+ }
+ else
+ {
+ (void) alarm (0);
+ if (!PingServer (d, (Display *) NULL))
+ SessionPingFailed (d);
+ }
+ }
+ else
+ {
+ pid = wait ((waitType *) 0);
+ }
+ if (pid == clientPid)
+ break;
+ }
+ } else {
+ LogError ("session start failed\n");
+ }
+ } else {
+ /*
+ * when terminating the session, nuke
+ * the child and then run the reset script
+ */
+ AbortClient (clientPid);
+ }
+ }
+ /*
+ * run system-wide reset file
+ */
+ Debug ("Source reset program %s\n", d->reset);
+ source (verify.systemEnviron, d->reset);
+ SessionExit (d, OBEYSESS_DISPLAY, TRUE);
+}
+
+LoadXloginResources (d)
+struct display *d;
+{
+ char **args, **parseArgs();
+ char **env = 0, **setEnv(), **systemEnv();
+
+ if (d->resources[0] && access (d->resources, 4) == 0) {
+ env = systemEnv (d, (char *) 0, (char *) 0);
+ args = parseArgs ((char **) 0, d->xrdb);
+ args = parseArgs (args, d->resources);
+ Debug ("Loading resource file: %s\n", d->resources);
+ (void) runAndWait (args, env);
+ freeArgs (args);
+ freeEnv (env);
+ }
+}
+
+SetupDisplay (d)
+struct display *d;
+{
+ char **env = 0, **setEnv(), **systemEnv();
+
+ if (d->setup && d->setup[0])
+ {
+ env = systemEnv (d, (char *) 0, (char *) 0);
+ (void) source (env, d->setup);
+ freeEnv (env);
+ }
+}
+
+/*ARGSUSED*/
+DeleteXloginResources (d, dpy)
+struct display *d;
+Display *dpy;
+{
+ int i;
+ Atom prop = XInternAtom(dpy, "SCREEN_RESOURCES", True);
+
+ XDeleteProperty(dpy, RootWindow (dpy, 0), XA_RESOURCE_MANAGER);
+ if (prop) {
+ for (i = ScreenCount(dpy); --i >= 0; )
+ XDeleteProperty(dpy, RootWindow (dpy, i), prop);
+ }
+}
+
+static Jmp_buf syncJump;
+
+/* ARGSUSED */
+static SIGVAL
+syncTimeout (n)
+ int n;
+{
+ Longjmp (syncJump, 1);
+}
+
+SecureDisplay (d, dpy)
+struct display *d;
+Display *dpy;
+{
+ Debug ("SecureDisplay %s\n", d->name);
+ (void) Signal (SIGALRM, syncTimeout);
+ if (Setjmp (syncJump)) {
+ LogError ("WARNING: display %s could not be secured\n",
+ d->name);
+ SessionExit (d, RESERVER_DISPLAY, FALSE);
+ }
+ (void) alarm ((unsigned) d->grabTimeout);
+ Debug ("Before XGrabServer %s\n", d->name);
+ XGrabServer (dpy);
+ if (XGrabKeyboard (dpy, DefaultRootWindow (dpy), True, GrabModeAsync,
+ GrabModeAsync, CurrentTime) != GrabSuccess)
+ {
+ (void) alarm (0);
+ (void) Signal (SIGALRM, SIG_DFL);
+ LogError ("WARNING: keyboard on display %s could not be secured\n",
+ d->name);
+ SessionExit (d, RESERVER_DISPLAY, FALSE);
+ }
+ Debug ("XGrabKeyboard succeeded %s\n", d->name);
+ (void) alarm (0);
+ (void) Signal (SIGALRM, SIG_DFL);
+ pseudoReset (dpy);
+ if (!d->grabServer)
+ {
+ XUngrabServer (dpy);
+ XSync (dpy, 0);
+ }
+ Debug ("done secure %s\n", d->name);
+}
+
+UnsecureDisplay (d, dpy)
+struct display *d;
+Display *dpy;
+{
+ Debug ("Unsecure display %s\n", d->name);
+ if (d->grabServer)
+ {
+ XUngrabServer (dpy);
+ XSync (dpy, 0);
+ }
+}
+
+SessionExit (d, status, removeAuth)
+ struct display *d;
+{
+ /* make sure the server gets reset after the session is over */
+ if (d->serverPid >= 2 && d->resetSignal)
+ kill (d->serverPid, d->resetSignal);
+ else
+ ResetServer (d);
+ if (removeAuth)
+ {
+ setgid (verify.gid);
+ setuid (verify.uid);
+ RemoveUserAuthorization (d, &verify);
+#ifdef K5AUTH
+ /* do like "kdestroy" program */
+ {
+ krb5_error_code code;
+ krb5_ccache ccache;
+
+ code = Krb5DisplayCCache(d->name, &ccache);
+ if (code)
+ LogError("%s while getting Krb5 ccache to destroy\n",
+ error_message(code));
+ else {
+ code = krb5_cc_destroy(ccache);
+ if (code) {
+ if (code == KRB5_FCC_NOFILE) {
+ Debug ("No Kerberos ccache file found to destroy\n");
+ } else
+ LogError("%s while destroying Krb5 credentials cache\n",
+ error_message(code));
+ } else
+ Debug ("Kerberos ccache destroyed\n");
+ krb5_cc_close(ccache);
+ }
+ }
+#endif /* K5AUTH */
+ }
+ Debug ("Display %s exiting with status %d\n", d->name, status);
+ exit (status);
+}
+
+static Bool
+StartClient (verify, d, pidp, name, passwd)
+ struct verify_info *verify;
+ struct display *d;
+ int *pidp;
+ char *name;
+ char *passwd;
+{
+ char **f, *home, *getEnv ();
+ char *failsafeArgv[2];
+ int pid;
+#ifdef HAS_SETUSERCONTEXT
+ struct passwd* pwd;
+#endif
+
+ if (verify->argv) {
+ Debug ("StartSession %s: ", verify->argv[0]);
+ for (f = verify->argv; *f; f++)
+ Debug ("%s ", *f);
+ Debug ("; ");
+ }
+ if (verify->userEnviron) {
+ for (f = verify->userEnviron; *f; f++)
+ Debug ("%s ", *f);
+ Debug ("\n");
+ }
+ switch (pid = fork ()) {
+ case 0:
+ CleanUpChild ();
+
+ /* Do system-dependent login setup here */
+
+#ifndef AIXV3
+#ifndef HAS_SETUSERCONTEXT
+ if (setgid(verify->gid) < 0)
+ {
+ LogError("setgid %d (user \"%s\") failed, errno=%d\n",
+ verify->gid, name, errno);
+ return (0);
+ }
+#if (BSD >= 199103)
+ if (setlogin(name) < 0)
+ {
+ LogError("setlogin for \"%s\" failed, errno=%d", name, errno);
+ return(0);
+ }
+#endif
+ if (initgroups(name, verify->gid) < 0)
+ {
+ LogError("initgroups for \"%s\" failed, errno=%d\n", name, errno);
+ return (0);
+ }
+ if (setuid(verify->uid) < 0)
+ {
+ LogError("setuid %d (user \"%s\") failed, errno=%d\n",
+ verify->uid, name, errno);
+ return (0);
+ }
+#else /* HAS_SETUSERCONTEXT */
+ /*
+ * Set the user's credentials: uid, gid, groups,
+ * environment variables, resource limits, and umask.
+ */
+ pwd = getpwnam(name);
+ if (pwd)
+ {
+ if (setusercontext(NULL, pwd, pwd->pw_uid, LOGIN_SETALL) < 0)
+ {
+ LogError("setusercontext for \"%s\" failed, errno=%d\n", name,
+ errno);
+ return (0);
+ }
+ endpwent();
+ }
+ else
+ {
+ LogError("getpwnam for \"%s\" failed, errno=%d\n", name, errno);
+ return (0);
+ }
+#endif /* HAS_SETUSERCONTEXT */
+#else /* AIXV3 */
+ /*
+ * Set the user's credentials: uid, gid, groups,
+ * audit classes, user limits, and umask.
+ */
+ if (setpcred(name, NULL) == -1)
+ {
+ LogError("setpcred for \"%s\" failed, errno=%d\n", name, errno);
+ return (0);
+ }
+#endif /* AIXV3 */
+
+ /*
+ * for user-based authorization schemes,
+ * use the password to get the user's credentials.
+ */
+#ifdef SECURE_RPC
+ /* do like "keylogin" program */
+ {
+ char netname[MAXNETNAMELEN+1], secretkey[HEXKEYBYTES+1];
+ int nameret, keyret;
+ int len;
+ int key_set_ok = 0;
+
+ nameret = getnetname (netname);
+ Debug ("User netname: %s\n", netname);
+ len = strlen (passwd);
+ if (len > 8)
+ bzero (passwd + 8, len - 8);
+ keyret = getsecretkey(netname,secretkey,passwd);
+ Debug ("getsecretkey returns %d, key length %d\n",
+ keyret, strlen (secretkey));
+ /* is there a key, and do we have the right password? */
+ if (keyret == 1)
+ {
+ if (*secretkey)
+ {
+ keyret = key_setsecret(secretkey);
+ Debug ("key_setsecret returns %d\n", keyret);
+ if (keyret == -1)
+ LogError ("failed to set NIS secret key\n");
+ else
+ key_set_ok = 1;
+ }
+ else
+ {
+ /* found a key, but couldn't interpret it */
+ LogError ("password incorrect for NIS principal \"%s\"\n",
+ nameret ? netname : name);
+ }
+ }
+ if (!key_set_ok)
+ {
+ /* remove SUN-DES-1 from authorizations list */
+ int i, j;
+ for (i = 0; i < d->authNum; i++)
+ {
+ if (d->authorizations[i]->name_length == 9 &&
+ memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0)
+ {
+ for (j = i+1; j < d->authNum; j++)
+ d->authorizations[j-1] = d->authorizations[j];
+ d->authNum--;
+ break;
+ }
+ }
+ }
+ bzero(secretkey, strlen(secretkey));
+ }
+#endif
+#ifdef K5AUTH
+ /* do like "kinit" program */
+ {
+ int i, j;
+ int result;
+ extern char *Krb5CCacheName();
+
+ result = Krb5Init(name, passwd, d);
+ if (result == 0) {
+ /* point session clients at the Kerberos credentials cache */
+ verify->userEnviron =
+ setEnv(verify->userEnviron,
+ "KRB5CCNAME", Krb5CCacheName(d->name));
+ } else {
+ for (i = 0; i < d->authNum; i++)
+ {
+ if (d->authorizations[i]->name_length == 14 &&
+ memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0)
+ {
+ /* remove Kerberos from authorizations list */
+ for (j = i+1; j < d->authNum; j++)
+ d->authorizations[j-1] = d->authorizations[j];
+ d->authNum--;
+ break;
+ }
+ }
+ }
+ }
+#endif /* K5AUTH */
+ bzero(passwd, strlen(passwd));
+ SetUserAuthorization (d, verify);
+ home = getEnv (verify->userEnviron, "HOME");
+ if (home)
+ if (chdir (home) == -1) {
+ LogError ("user \"%s\": cannot chdir to home \"%s\" (err %d), using \"/\"\n",
+ getEnv (verify->userEnviron, "USER"), home, errno);
+ chdir ("/");
+ verify->userEnviron = setEnv(verify->userEnviron, "HOME", "/");
+ }
+ if (verify->argv) {
+ Debug ("executing session %s\n", verify->argv[0]);
+ execute (verify->argv, verify->userEnviron);
+ LogError ("Session \"%s\" execution failed (err %d)\n", verify->argv[0], errno);
+ } else {
+ LogError ("Session has no command/arguments\n");
+ }
+ failsafeArgv[0] = d->failsafeClient;
+ failsafeArgv[1] = 0;
+ execute (failsafeArgv, verify->userEnviron);
+ exit (1);
+ case -1:
+ bzero(passwd, strlen(passwd));
+ Debug ("StartSession, fork failed\n");
+ LogError ("can't start session on \"%s\", fork failed, errno=%d\n",
+ d->name, errno);
+ return 0;
+ default:
+ bzero(passwd, strlen(passwd));
+ Debug ("StartSession, fork succeeded %d\n", pid);
+ *pidp = pid;
+ return 1;
+ }
+}
+
+int
+source (environ, file)
+char **environ;
+char *file;
+{
+ char **args, *args_safe[2];
+ extern char **parseArgs ();
+ int ret;
+
+ if (file && file[0]) {
+ Debug ("source %s\n", file);
+ args = parseArgs ((char **) 0, file);
+ if (!args)
+ {
+ args = args_safe;
+ args[0] = file;
+ args[1] = NULL;
+ }
+ ret = runAndWait (args, environ);
+ freeArgs (args);
+ return ret;
+ }
+ return 0;
+}
+
+int
+runAndWait (args, environ)
+ char **args;
+ char **environ;
+{
+ int pid;
+ waitType result;
+
+ switch (pid = fork ()) {
+ case 0:
+ CleanUpChild ();
+ execute (args, environ);
+ LogError ("can't execute \"%s\" (err %d)\n", args[0], errno);
+ exit (1);
+ case -1:
+ Debug ("fork failed\n");
+ LogError ("can't fork to execute \"%s\" (err %d)\n", args[0], errno);
+ return 1;
+ default:
+ while (wait (&result) != pid)
+ /* SUPPRESS 530 */
+ ;
+ break;
+ }
+ return waitVal (result);
+}
+
+void
+execute (argv, environ)
+ char **argv;
+ char **environ;
+{
+ /* give /dev/null as stdin */
+ (void) close (0);
+ open ("/dev/null", 0);
+ /* make stdout follow stderr to the log file */
+ dup2 (2,1);
+ execve (argv[0], argv, environ);
+ /*
+ * In case this is a shell script which hasn't been
+ * made executable (or this is a SYSV box), do
+ * a reasonable thing
+ */
+ if (errno != ENOENT) {
+ char program[1024], *e, *p, *optarg;
+ FILE *f;
+ char **newargv, **av;
+ int argc;
+
+ /*
+ * emulate BSD kernel behaviour -- read
+ * the first line; check if it starts
+ * with "#!", in which case it uses
+ * the rest of the line as the name of
+ * program to run. Else use "/bin/sh".
+ */
+ f = fopen (argv[0], "r");
+ if (!f)
+ return;
+ if (fgets (program, sizeof (program) - 1, f) == NULL)
+ {
+ fclose (f);
+ return;
+ }
+ fclose (f);
+ e = program + strlen (program) - 1;
+ if (*e == '\n')
+ *e = '\0';
+ if (!strncmp (program, "#!", 2)) {
+ p = program + 2;
+ while (*p && isspace (*p))
+ ++p;
+ optarg = p;
+ while (*optarg && !isspace (*optarg))
+ ++optarg;
+ if (*optarg) {
+ *optarg = '\0';
+ do
+ ++optarg;
+ while (*optarg && isspace (*optarg));
+ } else
+ optarg = 0;
+ } else {
+ p = "/bin/sh";
+ optarg = 0;
+ }
+ Debug ("Shell script execution: %s (optarg %s)\n",
+ p, optarg ? optarg : "(null)");
+ for (av = argv, argc = 0; *av; av++, argc++)
+ /* SUPPRESS 530 */
+ ;
+ newargv = (char **) malloc ((argc + (optarg ? 3 : 2)) * sizeof (char *));
+ if (!newargv)
+ return;
+ av = newargv;
+ *av++ = p;
+ if (optarg)
+ *av++ = optarg;
+ /* SUPPRESS 560 */
+ while ((*av++ = *argv++))
+ /* SUPPRESS 530 */
+ ;
+ execve (newargv[0], newargv, environ);
+ }
+}
+
+extern char **setEnv ();
+
+char **
+defaultEnv ()
+{
+ char **env, **exp, *value;
+
+ env = 0;
+ for (exp = exportList; exp && *exp; ++exp)
+ {
+ value = getenv (*exp);
+ if (value)
+ env = setEnv (env, *exp, value);
+ }
+ return env;
+}
+
+char **
+systemEnv (d, user, home)
+struct display *d;
+char *user, *home;
+{
+ char **env;
+
+ env = defaultEnv ();
+ env = setEnv (env, "DISPLAY", d->name);
+ if (home)
+ env = setEnv (env, "HOME", home);
+ if (user)
+ {
+ env = setEnv (env, "USER", user);
+ env = setEnv (env, "LOGNAME", user);
+ }
+ env = setEnv (env, "PATH", d->systemPath);
+ env = setEnv (env, "SHELL", d->systemShell);
+ if (d->authFile)
+ env = setEnv (env, "XAUTHORITY", d->authFile);
+ return env;
+}
diff --git a/socket.c b/socket.c
new file mode 100644
index 0000000..47b0c79
--- /dev/null
+++ b/socket.c
@@ -0,0 +1,123 @@
+/* $Xorg: socket.c,v 1.4 2001/02/09 02:05:40 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
+ *
+ * socket.c - Support for BSD sockets
+ */
+
+#include "dm.h"
+
+#ifdef XDMCP
+#ifndef STREAMSCONN
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <netdb.h>
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+
+extern int xdmcpFd;
+extern int chooserFd;
+
+extern FD_TYPE WellKnownSocketsMask;
+extern int WellKnownSocketsMax;
+
+CreateWellKnownSockets ()
+{
+ struct sockaddr_in sock_addr;
+ char *name, *localHostname();
+
+ if (request_port == 0)
+ return;
+ Debug ("creating socket %d\n", request_port);
+ xdmcpFd = socket (AF_INET, SOCK_DGRAM, 0);
+ if (xdmcpFd == -1) {
+ LogError ("XDMCP socket creation failed, errno %d\n", errno);
+ return;
+ }
+ name = localHostname ();
+ registerHostname (name, strlen (name));
+ RegisterCloseOnFork (xdmcpFd);
+ /* zero out the entire structure; this avoids 4.4 incompatibilities */
+ bzero ((char *) &sock_addr, sizeof (sock_addr));
+#ifdef BSD44SOCKETS
+ sock_addr.sin_len = sizeof(sock_addr);
+#endif
+ sock_addr.sin_family = AF_INET;
+ sock_addr.sin_port = htons ((short) request_port);
+ sock_addr.sin_addr.s_addr = htonl (INADDR_ANY);
+ if (bind (xdmcpFd, (struct sockaddr *)&sock_addr, sizeof (sock_addr)) == -1)
+ {
+ LogError ("error %d binding socket address %d\n", errno, request_port);
+ close (xdmcpFd);
+ xdmcpFd = -1;
+ return;
+ }
+ WellKnownSocketsMax = xdmcpFd;
+ FD_SET (xdmcpFd, &WellKnownSocketsMask);
+
+ chooserFd = socket (AF_INET, SOCK_STREAM, 0);
+ Debug ("Created chooser socket %d\n", chooserFd);
+ if (chooserFd == -1)
+ {
+ LogError ("chooser socket creation failed, errno %d\n", errno);
+ return;
+ }
+ listen (chooserFd, 5);
+ if (chooserFd > WellKnownSocketsMax)
+ WellKnownSocketsMax = chooserFd;
+ FD_SET (chooserFd, &WellKnownSocketsMask);
+}
+
+GetChooserAddr (addr, lenp)
+ char *addr;
+ int *lenp;
+{
+ struct sockaddr_in in_addr;
+ int len;
+
+ len = sizeof in_addr;
+ if (getsockname (chooserFd, (struct sockaddr *)&in_addr, &len) < 0)
+ return -1;
+ Debug ("Chooser socket port: %d\n", ntohs(in_addr.sin_port));
+ memmove( addr, (char *) &in_addr, len);
+ *lenp = len;
+ return 0;
+}
+
+#endif /* !STREAMSCONN */
+#endif /* XDMCP */
diff --git a/streams.c b/streams.c
new file mode 100644
index 0000000..585fe90
--- /dev/null
+++ b/streams.c
@@ -0,0 +1,147 @@
+/* $Xorg: streams.c,v 1.4 2001/02/09 02:05:40 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
+ *
+ * streams.c - Support for STREAMS
+ */
+
+#include "dm.h"
+
+#ifdef XDMCP
+#ifdef STREAMSCONN
+
+#include <fcntl.h>
+#include <tiuser.h>
+#include <netconfig.h>
+#include <netdir.h>
+
+extern int xdmcpFd;
+extern int chooserFd;
+
+extern FD_TYPE WellKnownSocketsMask;
+extern int WellKnownSocketsMax;
+
+CreateWellKnownSockets ()
+{
+ struct t_bind bind_addr;
+ struct netconfig *nconf;
+ struct nd_hostserv service;
+ struct nd_addrlist *servaddrs;
+ char *name, *localHostname();
+ char bindbuf[15];
+ int it;
+
+ if (request_port == 0)
+ return;
+ Debug ("creating UDP stream %d\n", request_port);
+
+ nconf = getnetconfigent("udp");
+ if (!nconf) {
+ t_error("getnetconfigent udp");
+ return;
+ }
+
+ xdmcpFd = t_open(nconf->nc_device, O_RDWR, NULL);
+ if (xdmcpFd == -1) {
+ LogError ("XDMCP stream creation failed\n");
+ t_error ("CreateWellKnownSockets(xdmcpFd): t_open failed");
+ return;
+ }
+ name = localHostname ();
+ registerHostname (name, strlen (name));
+ RegisterCloseOnFork (xdmcpFd);
+
+ service.h_host = HOST_SELF;
+ sprintf(bindbuf, "%d", request_port);
+ service.h_serv = bindbuf;
+ netdir_getbyname(nconf, &service, &servaddrs);
+ freenetconfigent(nconf);
+
+ bind_addr.qlen = 5;
+ bind_addr.addr.buf = servaddrs->n_addrs[0].buf;
+ bind_addr.addr.len = servaddrs->n_addrs[0].len;
+ bind_addr.addr.maxlen = servaddrs->n_addrs[0].len;
+ it = t_bind(xdmcpFd, &bind_addr, &bind_addr);
+ netdir_free((char *)servaddrs, ND_ADDRLIST);
+ if (it < 0)
+ {
+ LogError ("error binding STREAMS address %d\n", request_port);
+ t_error("CreateWellKNowSocket(xdmcpFd): t_bind failed");
+ t_close (xdmcpFd);
+ xdmcpFd = -1;
+ return;
+ }
+ WellKnownSocketsMax = xdmcpFd;
+ FD_SET (xdmcpFd, &WellKnownSocketsMask);
+
+ chooserFd = t_open ("/dev/tcp", O_RDWR, NULL);
+ Debug ("Created chooser fd %d\n", chooserFd);
+ if (chooserFd == -1)
+ {
+ LogError ("chooser stream creation failed\n");
+ t_error("CreateWellKnowSockets(chooserFd): t_open failed");
+ return;
+ }
+ bind_addr.qlen = 5;
+ bind_addr.addr.len = 0;
+ bind_addr.addr.maxlen = 0;
+ if( t_bind( chooserFd, &bind_addr, NULL ) < 0 )
+ {
+ t_error("CreateWellKnowSockets(chooserFd): t_bind failed");
+ }
+
+ if (chooserFd > WellKnownSocketsMax)
+ WellKnownSocketsMax = chooserFd;
+ FD_SET (chooserFd, &WellKnownSocketsMask);
+}
+
+GetChooserAddr (addr, lenp)
+ char *addr; /* return */
+ int *lenp; /* size of addr, returned as amt used */
+{
+ struct netbuf nbuf;
+ int retval;
+
+ nbuf.buf = addr;
+ nbuf.len = *lenp;
+ nbuf.maxlen = *lenp;
+ retval = t_getname (chooserFd, &nbuf, LOCALNAME);
+ if (retval < 0) {
+ if (debugLevel > 0)
+ t_error("t_getname on chooser fd");
+ }
+ *lenp = nbuf.len;
+ return retval;
+}
+
+#endif /* STREAMSCONN */
+#endif /* XDMCP */
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..372f372
--- /dev/null
+++ b/util.c
@@ -0,0 +1,263 @@
+/* $Xorg: util.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */
+/*
+
+Copyright 1989, 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
+ *
+ * util.c
+ *
+ * various utility routines
+ */
+
+# include "dm.h"
+#ifdef X_POSIX_C_SOURCE
+#define _POSIX_C_SOURCE X_POSIX_C_SOURCE
+#include <signal.h>
+#undef _POSIX_C_SOURCE
+#else
+#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
+#include <signal.h>
+#else
+#define _POSIX_SOURCE
+#include <signal.h>
+#undef _POSIX_SOURCE
+#endif
+#endif
+#if defined(__osf__) || defined(linux)
+#define setpgrp setpgid
+#endif
+
+printEnv (e)
+char **e;
+{
+ while (*e)
+ Debug ("%s\n", *e++);
+}
+
+static char *
+makeEnv (name, value)
+char *name;
+char *value;
+{
+ char *result;
+
+ result = malloc ((unsigned) (strlen (name) + strlen (value) + 2));
+ if (!result) {
+ LogOutOfMem ("makeEnv");
+ return 0;
+ }
+ sprintf (result, "%s=%s", name, value);
+ return result;
+}
+
+char *
+getEnv (e, name)
+ char **e;
+ char *name;
+{
+ int l = strlen (name);
+
+ if (!e) return 0;
+
+ while (*e) {
+ if ((int)strlen (*e) > l && !strncmp (*e, name, l) &&
+ (*e)[l] == '=')
+ return (*e) + l + 1;
+ ++e;
+ }
+ return 0;
+}
+
+char **
+setEnv (e, name, value)
+ char **e;
+ char *name;
+ char *value;
+{
+ char **new, **old;
+ char *newe;
+ int envsize;
+ int l;
+
+ l = strlen (name);
+ newe = makeEnv (name, value);
+ if (!newe) {
+ LogOutOfMem ("setEnv");
+ return e;
+ }
+ if (e) {
+ for (old = e; *old; old++)
+ if ((int)strlen (*old) > l && !strncmp (*old, name, l) && (*old)[l] == '=')
+ break;
+ if (*old) {
+ free (*old);
+ *old = newe;
+ return e;
+ }
+ envsize = old - e;
+ new = (char **) realloc ((char *) e,
+ (unsigned) ((envsize + 2) * sizeof (char *)));
+ } else {
+ envsize = 0;
+ new = (char **) malloc (2 * sizeof (char *));
+ }
+ if (!new) {
+ LogOutOfMem ("setEnv");
+ free (newe);
+ return e;
+ }
+ new[envsize] = newe;
+ new[envsize+1] = 0;
+ return new;
+}
+
+freeEnv (env)
+ char **env;
+{
+ char **e;
+
+ if (env)
+ {
+ for (e = env; *e; e++)
+ free (*e);
+ free (env);
+ }
+}
+
+# define isblank(c) ((c) == ' ' || c == '\t')
+
+char **
+parseArgs (argv, string)
+char **argv;
+char *string;
+{
+ char *word;
+ char *save;
+ int i;
+
+ i = 0;
+ while (argv && argv[i])
+ ++i;
+ if (!argv) {
+ argv = (char **) malloc (sizeof (char *));
+ if (!argv) {
+ LogOutOfMem ("parseArgs");
+ return 0;
+ }
+ }
+ word = string;
+ for (;;) {
+ if (!*string || isblank (*string)) {
+ if (word != string) {
+ argv = (char **) realloc ((char *) argv,
+ (unsigned) ((i + 2) * sizeof (char *)));
+ save = malloc ((unsigned) (string - word + 1));
+ if (!argv || !save) {
+ LogOutOfMem ("parseArgs");
+ if (argv)
+ free ((char *) argv);
+ if (save)
+ free (save);
+ return 0;
+ }
+ argv[i] = strncpy (save, word, string-word);
+ argv[i][string-word] = '\0';
+ i++;
+ }
+ if (!*string)
+ break;
+ word = string + 1;
+ }
+ ++string;
+ }
+ argv[i] = 0;
+ return argv;
+}
+
+freeArgs (argv)
+ char **argv;
+{
+ char **a;
+
+ if (!argv)
+ return;
+
+ for (a = argv; *a; a++)
+ free (*a);
+ free ((char *) argv);
+}
+
+CleanUpChild ()
+{
+#if defined(SYSV) || defined(SVR4)
+ setpgrp ();
+#else
+ setpgrp (0, getpid ());
+ sigsetmask (0);
+#endif
+#ifdef SIGCHLD
+ (void) Signal (SIGCHLD, SIG_DFL);
+#endif
+ (void) Signal (SIGTERM, SIG_DFL);
+ (void) Signal (SIGPIPE, SIG_DFL);
+ (void) Signal (SIGALRM, SIG_DFL);
+ (void) Signal (SIGHUP, SIG_DFL);
+ CloseOnFork ();
+}
+
+static char localHostbuf[256];
+static int gotLocalHostname;
+
+char *
+localHostname ()
+{
+ if (!gotLocalHostname)
+ {
+ XmuGetHostname (localHostbuf, sizeof (localHostbuf) - 1);
+ gotLocalHostname = 1;
+ }
+ return localHostbuf;
+}
+
+SIGVAL (*Signal (sig, handler))()
+ int sig;
+ SIGVAL (*handler)();
+{
+#ifndef X_NOT_POSIX
+ struct sigaction sigact, osigact;
+ sigact.sa_handler = handler;
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = 0;
+ sigaction(sig, &sigact, &osigact);
+ return osigact.sa_handler;
+#else
+ return signal(sig, handler);
+#endif
+}
diff --git a/xdm.man.cpp b/xdm.man.cpp
new file mode 100644
index 0000000..45f8a90
--- /dev/null
+++ b/xdm.man.cpp
@@ -0,0 +1,1258 @@
+.\" $Xorg: xdm.man,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $
+.\" Copyright 1988, 1994, 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.
+.TH XDM 1 "Release 6.4" "X Version 11"
+.SH NAME
+xdm \- X Display Manager with support for XDMCP, host chooser
+.SH SYNOPSIS
+.B xdm
+[
+.B \-config
+.I configuration_file
+] [
+.B \-nodaemon
+] [
+.B \-debug
+.I debug_level
+] [
+.B \-error
+.I error_log_file
+] [
+.B \-resources
+.I resource_file
+] [
+.B \-server
+.I server_entry
+] [
+.B \-session
+.I session_program
+]
+.SH DESCRIPTION
+.I Xdm
+manages a collection of X displays, which may be on the local host
+or remote servers. The design of
+.I xdm
+was guided by the needs of X terminals as well as The Open Group standard
+XDMCP, the \fIX Display Manager Control Protocol\fP.
+.I Xdm
+provides services similar to those provided by \fIinit\fP, \fIgetty\fP
+and \fIlogin\fP on character terminals: prompting for login name and password,
+authenticating the user, and running a ``session.''
+.PP
+A ``session'' is defined by the lifetime of a particular process; in the
+traditional character-based terminal world, it is the user's login shell.
+In the
+.I xdm
+context, it is an arbitrary session manager. This is because in a windowing
+environment, a user's login shell process does not necessarily have any
+terminal-like interface with which to connect.
+When a real session manager is not available, a window manager or terminal
+emulator is typically used as the ``session manager,'' meaning that
+termination of this process terminates the user's session.
+.PP
+When the session is terminated, \fIxdm\fP
+resets the X server and (optionally) restarts the whole process.
+.PP
+When \fIxdm\fP receives an Indirect query via XDMCP, it can run a
+\fIchooser\fP process to
+perform an XDMCP BroadcastQuery (or an XDMCP Query to specified hosts)
+on behalf of the display and
+offer a menu of possible hosts that offer XDMCP display management.
+This feature is useful with X terminals that do not offer a host
+menu themselves.
+.PP
+Because
+.I xdm
+provides the first interface that users will see, it is designed to be
+simple to use and easy to customize to the needs of a particular site.
+.I Xdm
+has many options, most of which have reasonable defaults. Browse through the
+various sections of this manual,
+picking and choosing the things you want to change.
+Pay particular attention to the
+.B "Session Program"
+section, which will describe how to
+set up the style of session desired.
+.SH "OVERVIEW"
+\fIxdm\fP is highly configurable, and most of its behavior can be
+controlled by resource files and shell scripts. The names of these
+files themselves are resources read from the file \fIxdm-config\fP or
+the file named by the \fB\-config\fP option.
+.PP
+\fIxdm\fP offers display management two different ways. It can manage
+X servers running on the local machine and specified in
+\fIXservers\fP, and it can manage remote X servers (typically X
+terminals) using XDMCP (the XDM Control Protocol)
+as specified in the \fIXaccess\fP file.
+.PP
+The resources of the X clients run by \fIxdm\fP outside the user's
+session, including \fIxdm\fP's own login window, can be
+affected by setting resources in the \fIXresources\fP file.
+.PP
+For X terminals that do not offer a menu of hosts to get display
+management from, \fIxdm\fP can collect willing hosts and run the
+\fIchooser\fP program to offer the user a menu.
+For X displays attached to a host, this step is typically not used, as
+the local host does the display management.
+.PP
+After resetting the X server, \fIxdm\fP runs the \fIXsetup\fP script
+to assist in setting up the screen the user sees along with the
+\fIxlogin\fP widget.
+.PP
+The \fIxlogin\fP widget, which \fIxdm\fP presents,
+offers the familiar login and password prompts.
+.PP
+After the user logs in, \fIxdm\fP runs the \fIXstartup\fP script as
+root.
+.PP
+Then \fIxdm\fP runs the \fIXsession\fP script as the user. This
+system session file may do some additional startup and typically runs
+the \fI.xsession\fP script in the user's home directory.
+When the \fIXsession\fP script exits, the session is over.
+.PP
+At the end of the session, the \fIXreset\fP script is run to clean up,
+the X server is reset, and the cycle starts over.
+.PP
+The file \fI/usr/X11R6/lib/X11/xdm/xdm-errors\fP will contain error
+messages from
+.I xdm
+and anything output to stderr by \fIXsetup, Xstartup, Xsession\fP
+or \fIXreset\fP.
+When you have trouble getting
+.I xdm
+working, check this file to see if
+.I xdm
+has any clues to the trouble.
+.SH OPTIONS
+.PP
+All of these options, except \fB\-config\fP itself,
+specify values that can also be specified in the configuration file
+as resources.
+.IP "\fB\-config\fP \fIconfiguration_file\fP"
+Names the configuration file, which specifies resources to control
+the behavior of
+.I xdm.
+.I <XRoot>/lib/X11/xdm/xdm-config
+is the default.
+See the section \fBConfiguration File\fP.
+.IP "\fB\-nodaemon\fP"
+Specifies ``false'' as the value for the \fBDisplayManager.daemonMode\fP
+resource.
+This suppresses the normal daemon behavior, which is for
+.I xdm
+to close all file descriptors, disassociate itself from
+the controlling terminal, and put
+itself in the background when it first starts up.
+.IP "\fB\-debug\fP \fIdebug_level\fP"
+Specifies the numeric value for the \fBDisplayManager.debugLevel\fP
+resource. A non-zero value causes
+.I xdm
+to print lots of debugging statements to the terminal; it also disables the
+\fBDisplayManager.daemonMode\fP resource, forcing
+.I xdm
+to run synchronously. To interpret these debugging messages, a copy
+of the source code for
+.I xdm
+is almost a necessity. No attempt has been
+made to rationalize or standardize the output.
+.IP "\fB\-error\fP \fIerror_log_file\fP"
+Specifies the value for the \fBDisplayManager.errorLogFile\fP resource.
+This file contains errors from
+.I xdm
+as well as anything written to stderr by the various scripts and programs
+run during the progress of the session.
+.IP "\fB\-resources\fP \fIresource_file\fP"
+Specifies the value for the \fBDisplayManager*resources\fP resource. This file
+is loaded using
+.I xrdb
+to specify configuration parameters for the
+authentication widget.
+.IP "\fB\-server\fP \fIserver_entry\fP"
+Specifies the value for the \fBDisplayManager.servers\fP resource.
+See the section
+.B "Local Server Specification"
+for a description of this resource.
+.IP "\fB\-udpPort\fP \fIport_number\fP"
+Specifies the value for the \fBDisplayManager.requestPort\fP resource. This
+sets the port-number which
+.I xdm
+will monitor for XDMCP requests. As XDMCP
+uses the registered well-known UDP port 177, this resource should
+not be changed except for debugging.
+.IP "\fB\-session\fP \fIsession_program\fP"
+Specifies the value for the \fBDisplayManager*session\fP resource. This
+indicates the program to run as the session after the user has logged in.
+.IP "\fB\-xrm\fP \fIresource_specification\fP"
+Allows an arbitrary resource to be specified, as in most
+X Toolkit applications.
+.SH RESOURCES
+At many stages the actions of
+.I xdm
+can be controlled through the use of its configuration file, which is in the
+X resource format.
+Some resources modify the behavior of
+.I xdm
+on all displays,
+while others modify its behavior on a single display. Where actions relate
+to a specific display,
+the display name is inserted into the resource name between
+``DisplayManager'' and the final resource name segment.
+.PP
+For local displays, the resource name and class are as read from the
+\fIXservers\fP file.
+.PP
+For remote displays, the resource name is what the network address of
+the display resolves to. See the \fBremoveDomain\fP resource. The
+name must match exactly; \fIxdm\fP is not aware of
+all the network aliases that might reach a given display.
+If the name resolve fails, the address is
+used. The resource class is as sent by the display in the XDMCP
+Manage request.
+.PP
+Because the resource
+manager uses colons to separate the name of the resource from its value and
+dots to separate resource name parts,
+.I xdm
+substitutes underscores for both dots and colons when generating the resource
+name.
+For example, \fBDisplayManager.expo_x_org_0.startup\fP is the name of the
+resource which defines the startup shell file for the ``expo.x.org:0'' display.
+.\"
+.IP "\fBDisplayManager.servers\fP"
+This resource either specifies a file name full of server entries, one per
+line (if the value starts with a slash), or a single server entry.
+See the section \fBLocal Server Specification\fP for the details.
+.IP "\fBDisplayManager.requestPort\fP"
+This indicates the UDP port number which
+.I xdm
+uses to listen for incoming XDMCP requests. Unless you need to debug the
+system, leave this with its default value of 177.
+.IP "\fBDisplayManager.errorLogFile\fP"
+Error output is normally directed at the system console. To redirect it,
+set this resource to a file name. A method to send these messages to
+.I syslog
+should be developed for systems which support it; however, the
+wide variety of interfaces precludes any system-independent
+implementation. This file also contains any output directed to stderr
+by the \fIXsetup, Xstartup, Xsession\fP and \fIXreset\fP files,
+so it will contain descriptions
+of problems in those scripts as well.
+.IP "\fBDisplayManager.debugLevel\fP"
+If the integer value of this resource is greater than zero,
+reams of
+debugging information will be printed. It also disables daemon mode, which
+would redirect the information into the bit-bucket, and
+allows non-root users to run
+.I xdm,
+which would normally not be useful.
+.IP "\fBDisplayManager.daemonMode\fP"
+Normally,
+.I xdm
+attempts to make itself into a daemon process unassociated with any terminal.
+This is
+accomplished by forking and leaving the parent process to exit, then closing
+file descriptors and releasing the controlling terminal. In some
+environments this is not desired (in particular, when debugging). Setting
+this resource to ``false'' will disable this feature.
+.IP "\fBDisplayManager.pidFile\fP"
+The filename specified will be created to contain an ASCII
+representation of the process-id of the main
+.I xdm
+process.
+.I Xdm
+also uses file locking on this file
+to attempt to eliminate multiple daemons running on
+the same machine, which would cause quite a bit of havoc.
+.IP "\fBDisplayManager.lockPidFile\fP"
+This is the resource which controls whether
+.I xdm
+uses file locking to keep multiple display managers from running amok.
+On System V, this
+uses the \fIlockf\fP library call, while on BSD it uses \fIflock.\fP
+.IP "\fBDisplayManager.authDir\fP"
+This names a directory under which
+.I xdm
+stores authorization files while initializing the session. The
+default value is \fI<XRoot>/lib/X11/xdm.\fP
+Can be overridden for specific displays by
+DisplayManager.\fIDISPLAY\fP.authFile.
+.IP \fBDisplayManager.autoRescan\fP
+This boolean controls whether
+.I xdm
+rescans the configuration, servers, access control and authentication keys
+files after a session terminates and the files have changed. By default it
+is ``true.'' You can force
+.I xdm
+to reread these files by sending a SIGHUP to the main process.
+.IP "\fBDisplayManager.removeDomainname\fP"
+When computing the display name for XDMCP clients, the name resolver will
+typically create a fully qualified host name for the terminal. As this is
+sometimes confusing,
+.I xdm
+will remove the domain name portion of the host name if it is the same as the
+domain name of the local host when this variable is set. By default the
+value is ``true.''
+.IP "\fBDisplayManager.keyFile\fP"
+XDM-AUTHENTICATION-1 style XDMCP authentication requires that a private key
+be shared between
+.I xdm
+and the terminal. This resource specifies the file containing those
+values. Each entry in the file consists of a display name and the shared
+key. By default,
+.I xdm
+does not include support for XDM-AUTHENTICATION-1, as it requires DES which
+is not generally distributable because of United States export restrictions.
+.IP \fBDisplayManager.accessFile\fP
+To prevent unauthorized XDMCP service and to allow forwarding of XDMCP
+IndirectQuery requests, this file contains a database of hostnames which are
+either allowed direct access to this machine, or have a list of hosts to
+which queries should be forwarded to. The format of this file is described
+in the section
+.B "XDMCP Access Control."
+.IP \fBDisplayManager.exportList\fP
+A list of additional environment variables, separated by white space,
+to pass on to the \fIXsetup\fP,
+\fIXstartup\fP, \fIXsession\fP, and \fIXreset\fP programs.
+.IP \fBDisplayManager.randomFile\fP
+A file to checksum to generate the seed of authorization keys.
+This should be a file that changes frequently.
+The default is \fI/dev/mem\fP.
+.IP \fBDisplayManager.greeterLib\fP
+On systems that support a dynamically-loadable greeter library, the
+name of the library. Default is \fI<XRoot>/lib/X11/xdm/libXdmGreet.so\fP.
+.IP \fBDisplayManager.choiceTimeout\fP
+Number of seconds to wait for display to respond after user has
+selected a host from the chooser. If the display sends an XDMCP
+IndirectQuery within this time, the request is forwarded to the chosen
+host. Otherwise, it is assumed to be from a new session and the
+chooser is offered again.
+Default is 15.
+.\"
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.resources\fP"
+This resource specifies the name of the file to be loaded by \fIxrdb\fP
+as the resource database onto the root window of screen 0 of the display.
+The \fIXsetup\fP program, the Login widget, and \fIchooser\fP will use
+the resources set in this file.
+This resource data base is loaded just before the authentication procedure
+is started, so it can control the appearance of the login window. See the
+section
+.B "Authentication Widget,"
+which describes the various
+resources that are appropriate to place in this file.
+There is no default value for this resource, but
+\fI<XRoot>/lib/X11/xdm/Xresources\fP
+is the conventional name.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.chooser\fP"
+Specifies the program run to offer a host menu for Indirect queries
+redirected to the special host name CHOOSER.
+\fI<XRoot>/lib/X11/xdm/chooser\fP is the default.
+See the sections \fBXDMCP Access Control\fP and \fBChooser\fP.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.xrdb\fP"
+Specifies the program used to load the resources. By default,
+.I xdm
+uses \fI<XRoot>/bin/xrdb\fP.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.cpp\fP"
+This specifies the name of the C preprocessor which is used by \fIxrdb\fP.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.setup\fP"
+This specifies a program which is run (as root) before offering the
+Login window. This may be used to change the appearance of the screen
+around the Login window or to put up other windows (e.g., you may want
+to run \fIxconsole\fP here).
+By default, no program is run. The conventional name for a
+file used here is \fIXsetup\fP.
+See the section \fBSetup Program.\fP
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.startup\fP"
+This specifies a program which is run (as root) after the authentication
+process succeeds. By default, no program is run. The conventional name for a
+file used here is \fIXstartup\fP.
+See the section \fBStartup Program.\fP
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.session\fP"
+This specifies the session to be executed (not running as root).
+By default, \fI<XRoot>/bin/xterm\fP is
+run. The conventional name is \fIXsession\fP.
+See the section
+.B "Session Program."
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.reset\fP"
+This specifies a program which is run (as root) after the session terminates.
+By default, no program is run.
+The conventional name is \fIXreset\fP.
+See the section
+.B "Reset Program."
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.openDelay\fP"
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.openRepeat\fP"
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.openTimeout\fP"
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.startAttempts\fP"
+These numeric resources control the behavior of
+.I xdm
+when attempting to open intransigent servers. \fBopenDelay\fP is
+the length of the
+pause (in seconds) between successive attempts, \fBopenRepeat\fP is the
+number of attempts to make, \fBopenTimeout\fP is the amount of time
+to wait while actually
+attempting the open (i.e., the maximum time spent in the
+.IR connect (2)
+system call) and \fBstartAttempts\fP is the number of times this entire process
+is done before giving up on the server. After \fBopenRepeat\fP attempts have been made,
+or if \fBopenTimeout\fP seconds elapse in any particular attempt,
+.I xdm
+terminates and restarts the server, attempting to connect again.
+This
+process is repeated \fBstartAttempts\fP times, at which point the display is
+declared dead and disabled. Although
+this behavior may seem arbitrary, it has been empirically developed and
+works quite well on most systems. The default values are
+5 for \fBopenDelay\fP, 5 for \fBopenRepeat\fP, 30 for \fBopenTimeout\fP and
+4 for \fBstartAttempts\fP.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.pingInterval\fP"
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.pingTimeout\fP"
+To discover when remote displays disappear,
+.I xdm
+occasionally pings them, using an X connection and \fIXSync\fP
+calls. \fBpingInterval\fP specifies the time (in minutes) between each
+ping attempt, \fBpingTimeout\fP specifies the maximum amount of time (in
+minutes) to wait for the terminal to respond to the request. If the
+terminal does not respond, the session is declared dead and terminated. By
+default, both are set to 5 minutes. If you frequently use X terminals which
+can become isolated from the managing host, you may wish to increase this
+value. The only worry is that sessions will continue to exist after the
+terminal has been accidentally disabled.
+.I xdm
+will not ping local displays. Although it would seem harmless, it is
+unpleasant when the workstation session is terminated as a result of the
+server hanging for NFS service and not responding to the ping.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.terminateServer\fP"
+This boolean resource specifies whether the X server should be terminated
+when a session terminates (instead of resetting it). This option can be
+used when the server tends to grow without bound over time, in order to limit
+the amount of time the server is run. The default value is ``false.''
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.userPath\fP"
+.I Xdm
+sets the PATH environment variable for the session to this value. It should
+be a colon separated list of directories; see
+.IR sh (1)
+for a full description.
+``:/bin:/usr/bin:/usr/X11R6/bin:/usr/ucb''
+is a common setting.
+The default value can be specified at build time in the X system
+configuration file with DefaultUserPath.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.systemPath\fP"
+.I Xdm
+sets the PATH environment variable for the startup and reset scripts to the
+value of this resource. The default for this resource is specified
+at build time by the DefaultSystemPath entry in the system configuration file;
+``/etc:/bin:/usr/bin:/usr/X11R6/bin:/usr/ucb'' is a common choice.
+Note the absence of ``.'' from this entry. This is a good practice to
+follow for root; it avoids many common Trojan Horse system penetration
+schemes.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.systemShell\fP"
+.I Xdm
+sets the SHELL environment variable for the startup and reset scripts to the
+value of this resource. It is \fI/bin/sh\fP by default.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.failsafeClient\fP"
+If the default session fails to execute,
+.I xdm
+will fall back to this program. This program is executed with no
+arguments, but executes using the same environment variables as
+the session would have had (see the section \fBSession Program\fP).
+By default, \fI<XRoot>/bin/xterm\fP is used.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.grabServer\fP"
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.grabTimeout\fP"
+To improve security,
+.I xdm
+grabs the server and keyboard while reading the login name and password.
+The
+\fBgrabServer\fP resource specifies if the server should be held for the
+duration of the name/password reading. When ``false,'' the server is ungrabbed
+after the keyboard grab succeeds, otherwise the server is grabbed until just
+before the session begins. The default is ``false.''
+The \fBgrabTimeout\fP resource specifies the maximum time
+.I xdm
+will wait for the grab to succeed. The grab may fail if some other
+client has the server grabbed, or possibly if the network latencies
+are very high. This resource has a default value of 3 seconds; you
+should be cautious when raising it, as a user can be spoofed by a
+look-alike window on the display. If the grab fails,
+.I xdm
+kills and restarts the server (if possible) and the session.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.authorize\fP"
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.authName\fP"
+\fBauthorize\fP is a boolean resource which controls whether
+.I xdm
+generates and uses authorization for the local server connections. If
+authorization is used, \fBauthName\fP is a list
+of authorization mechanisms to use, separated by white space.
+XDMCP connections dynamically specify which
+authorization mechanisms are supported, so
+\fBauthName\fP is ignored in this case. When \fBauthorize\fP is set for a
+display and authorization is not available, the user is informed by having a
+different message displayed in the login widget. By default, \fBauthorize\fP
+is ``true.'' \fBauthName\fP is ``MIT-MAGIC-COOKIE-1,'' or, if
+XDM-AUTHORIZATION-1 is available, ``XDM-AUTHORIZATION-1\0MIT-MAGIC-COOKIE-1.''
+.IP \fBDisplayManager.\fP\fIDISPLAY\fP\fB.authFile\fP
+This file is used to communicate the authorization data from
+.I xdm
+to the server, using the \fB\-auth\fP server command line option.
+It should be
+kept in a directory which is not world-writable as it could easily be
+removed, disabling the authorization mechanism in the server.
+If not specified, a name is generated from DisplayManager.authDir and
+the name of the display.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.authComplain\fP"
+If set to ``false,'' disables the use of the \fBunsecureGreeting\fP
+in the login window.
+See the section \fBAuthentication Widget.\fP
+The default is ``true.''
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.resetSignal\fP"
+The number of the signal \fIxdm\fP sends to reset the server.
+See the section \fBControlling the Server.\fP
+The default is 1 (SIGHUP).
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.termSignal\fP"
+The number of the signal \fIxdm\fP sends to terminate the server.
+See the section \fBControlling the Server.\fP
+The default is 15 (SIGTERM).
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.resetForAuth\fP"
+The original implementation of authorization in the sample server reread the
+authorization file at server reset time, instead of when checking the
+initial connection. As
+.I xdm
+generates the authorization information just before connecting to the
+display, an old server would not get up-to-date authorization information.
+This resource causes
+.I xdm
+to send SIGHUP to the server after setting up the file, causing an
+additional server reset to occur, during which time the new authorization
+information will be read.
+The default is ``false,'' which will work for all MIT servers.
+.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.userAuthDir\fP"
+When
+.I xdm
+is unable to write to the usual user authorization file ($HOME/.Xauthority),
+it creates a unique file name in this directory and points the environment
+variable XAUTHORITY at the created file. It uses \fI/tmp\fP by default.
+.SH "CONFIGURATION FILE"
+First, the
+.I xdm
+configuration file should be set up.
+Make a directory (usually \fI<XRoot>/lib/X11/xdm\fP, where <XRoot>
+refers to the root of the X11 install tree) to contain all of the relevant
+files. In the examples that follow, we use /usr/X11R6 as the value of
+<XRoot>.
+.LP
+Here is a reasonable configuration file, which could be
+named \fIxdm-config\fP:
+.nf
+
+.ta .5i 4i
+
+ DisplayManager.servers: /usr/X11R6/lib/X11/xdm/Xservers
+ DisplayManager.errorLogFile: /usr/X11R6/lib/X11/xdm/xdm-errors
+ DisplayManager*resources: /usr/X11R6/lib/X11/xdm/Xresources
+ DisplayManager*startup: /usr/X11R6/lib/X11/xdm/Xstartup
+ DisplayManager*session: /usr/X11R6/lib/X11/xdm/Xsession
+ DisplayManager.pidFile: /usr/X11R6/lib/X11/xdm/xdm-pid
+ DisplayManager._0.authorize: true
+ DisplayManager*authorize: false
+
+.fi
+.PP
+Note that this file mostly contains references to other files. Note also
+that some of the resources are specified with ``*'' separating the
+components. These resources can be made unique for each different display,
+by replacing the ``*'' with the display-name, but normally this is not very
+useful. See the \fBResources\fP section for a complete discussion.
+.SH "XDMCP ACCESS CONTROL"
+.PP
+The database file specified by the \fBDisplayManager.accessFile\fP provides
+information which
+.I xdm
+uses to control access from displays requesting XDMCP service. This file
+contains three types of entries: entries which control the response to
+Direct and Broadcast queries, entries which control the response to
+Indirect queries, and macro definitions.
+.PP
+The format of the Direct entries is simple, either a host name or a
+pattern, which is distinguished from a host name by the inclusion of
+one or more meta characters (`*' matches any sequence of 0 or more
+characters, and `?' matches any single character) which are compared against
+the host name of the display device.
+If the entry is a host name, all comparisons are done using
+network addresses, so any name which converts to the correct network address
+may be used.
+For patterns, only canonical host names are used
+in the comparison, so ensure that you do not attempt to match
+aliases.
+Preceding either a host name or a pattern with a `!' character
+causes hosts which
+match that entry to be excluded.
+.PP
+An Indirect entry also contains a host name or pattern,
+but follows it with a list of
+host names or macros to which indirect queries should be sent.
+.PP
+A macro definition contains a macro name and a list of host names and
+other macros that
+the macro expands to. To distinguish macros from hostnames, macro
+names start with a `%' character. Macros may be nested.
+.PP
+Indirect entries
+may also specify to have \fIxdm\fP run \fIchooser\fP to offer a menu
+of hosts to connect to. See the section \fBChooser\fP.
+.PP
+When checking access for a particular display host, each entry is scanned in
+turn and the first matching entry determines the response. Direct and
+Broadcast
+entries are ignored when scanning for an Indirect entry and vice-versa.
+.PP
+Blank lines are ignored, `#' is treated as a comment
+delimiter causing the rest of that line to be ignored,
+and `\e\fInewline\fP'
+causes the newline to be ignored, allowing indirect host lists to span
+multiple lines.
+.PP
+Here is an example Xaccess file:
+.LP
+.ta 2i 4i
+.nf
+#
+# Xaccess \- XDMCP access control file
+#
+
+#
+# Direct/Broadcast query entries
+#
+
+!xtra.lcs.mit.edu # disallow direct/broadcast service for xtra
+bambi.ogi.edu # allow access from this particular display
+*.lcs.mit.edu # allow access from any display in LCS
+
+#
+# Indirect query entries
+#
+
+%HOSTS expo.lcs.mit.edu xenon.lcs.mit.edu \\
+ excess.lcs.mit.edu kanga.lcs.mit.edu
+
+extract.lcs.mit.edu xenon.lcs.mit.edu #force extract to contact xenon
+!xtra.lcs.mit.edu dummy #disallow indirect access
+*.lcs.mit.edu %HOSTS #all others get to choose
+.fi
+.SH CHOOSER
+.PP
+For X terminals that do not offer a host menu for use with Broadcast
+or Indirect queries, the \fIchooser\fP program can do this for them.
+In the \fIXaccess\fP file, specify ``CHOOSER'' as the first entry in
+the Indirect host list. \fIChooser\fP will send a Query request to
+each of the remaining host names in the list and offer a menu of all
+the hosts that respond.
+.PP
+The list may consist of the word ``BROADCAST,'' in which case
+\fIchooser\fP will send a Broadcast instead, again offering a menu of
+all hosts that respond. Note that on some operating systems, UDP
+packets cannot be broadcast, so this feature will not work.
+.PP
+Example \fIXaccess\fP file using \fIchooser\fP:
+
+.nf
+extract.lcs.mit.edu CHOOSER %HOSTS #offer a menu of these hosts
+xtra.lcs.mit.edu CHOOSER BROADCAST #offer a menu of all hosts
+.fi
+.PP
+The program to use for \fIchooser\fP is specified by the
+\fBDisplayManager.\fP\fIDISPLAY\fP\fB.chooser\fP resource. For more
+flexibility at this step, the chooser could be a shell script.
+\fIChooser\fP is the session manager here; it is run instead of a
+child \fIxdm\fP to manage the display.
+.PP
+Resources for this program
+can be put into the file named by
+\fBDisplayManager.\fP\fIDISPLAY\fP\fB.resources\fP.
+.PP
+When the user selects a host, \fIchooser\fP prints the host chosen,
+which is read by the parent \fIxdm\fP, and exits.
+\fIxdm\fP closes its connection to the X server, and the server resets
+and sends another \fBIndirect\fP XDMCP request.
+\fIxdm\fP remembers the user's choice (for
+\fBDisplayManager.choiceTimeout\fP seconds) and forwards the request
+to the chosen host, which starts a session on that display.
+.\"
+.SH "LOCAL SERVER SPECIFICATION"
+.PP
+The resource \fBDisplayManager.servers\fP gives a server specification
+or, if the values starts with a slash (/), the name of a file
+containing server specifications, one per line.
+.PP
+Each specification
+indicates a display which should constantly be managed and which is
+not using XDMCP.
+This method is used typically for local servers only. If the resource
+or the file named by the resource is empty, \fIxdm\fP will offer XDMCP
+service only.
+.PP
+Each specification consists of at least three parts: a display
+name, a display class, a display type, and (for local servers) a command
+line to start the server. A typical entry for local display number 0 would
+be:
+.nf
+
+ :0 Digital-QV local /usr/X11R6/bin/X :0
+
+.fi
+The display types are:
+.ta 1i
+.nf
+
+local local display: \fIxdm\fP must run the server
+foreign remote display: \fIxdm\fP opens an X connection to a running server
+
+.fi
+.PP
+The display name must be something that can be passed in the \fB\-display\fP
+option to an X program. This string is used to generate the display-specific
+resource names, so be careful to match the
+names (e.g., use ``:0 Sun-CG3 local /usr/X11R6/bin/X :0'' instead of
+``localhost:0 Sun-CG3 local /usr/X11R6/bin/X :0''
+if your other resources are specified as
+``DisplayManager._0.session''). The display class portion is also used in the
+display-specific resources, as the class of the resource. This is
+useful if you have a large collection of similar displays (such as a corral of
+X terminals) and would like to set resources for groups of them. When using
+XDMCP, the display is required to specify the display class, so the manual
+for your particular X terminal should document the display class
+string for your device. If it doesn't, you can run
+.I xdm
+in debug mode and
+look at the resource strings which it generates for that device, which will
+include the class string.
+.PP
+When \fIxdm\fP starts a session, it sets up authorization data for the
+server. For local servers, \fIxdm\fP passes
+``\fB\-auth\fP \fIfilename\fP'' on the server's command line to point
+it at its authorization data.
+For XDMCP servers, \fIxdm\fP passes the
+authorization data to the server via the \fBAccept\fP XDMCP request.
+.SH RESOURCES FILE
+The \fIXresources\fP file is
+loaded onto the display as a resource database using
+.I xrdb.
+As the authentication
+widget reads this database before starting up, it usually contains
+parameters for that widget:
+.nf
+.ta .5i 1i
+
+ xlogin*login.translations: #override\\
+ Ctrl<Key>R: abort-display()\\n\\
+ <Key>F1: set-session-argument(failsafe) finish-field()\\n\\
+ <Key>Return: set-session-argument() finish-field()
+ xlogin*borderWidth: 3
+ xlogin*greeting: CLIENTHOST
+ #ifdef COLOR
+ xlogin*greetColor: CadetBlue
+ xlogin*failColor: red
+ #endif
+
+.fi
+.PP
+Please note the translations entry; it specifies
+a few new translations for the widget which allow users to escape from the
+default session (and avoid troubles that may occur in it). Note that if
+#override is not specified, the default translations are removed and replaced
+by the new value, not a very useful result as some of the default translations
+are quite useful (such as ``<Key>: insert-char ()'' which responds to normal
+typing).
+.PP
+This file may also contain resources for the setup program and \fIchooser\fP.
+.SH "SETUP PROGRAM"
+The \fIXsetup\fP file is run after
+the server is reset, but before the Login window is offered.
+The file is typically a shell script.
+It is run as root, so should be careful about security.
+This is the place to change the root background or bring up other
+windows that should appear on the screen along with the Login widget.
+.PP
+In addition to any specified by \fBDisplayManager.exportList\fP,
+the following environment variables are passed:
+.nf
+.ta .5i 2i
+
+ DISPLAY the associated display name
+ PATH the value of \fBDisplayManager.\fP\fIDISPLAY\fP\fB.systemPath\fP
+ SHELL the value of \fBDisplayManager.\fP\fIDISPLAY\fP\fB.systemShell\fP
+ XAUTHORITY may be set to an authority file
+.fi
+.PP
+Note that since \fIxdm\fP grabs the keyboard, any other windows will not be
+able to receive keyboard input. They will be able to interact with
+the mouse, however; beware of potential security holes here.
+If \fBDisplayManager.\fP\fIDISPLAY\fP\fB.grabServer\fP is set,
+\fIXsetup\fP will not be able to connect
+to the display at all.
+Resources for this program
+can be put into the file named by
+\fBDisplayManager.\fP\fIDISPLAY\fP\fB.resources\fP.
+.PP
+Here is a sample \fIXsetup\fP script:
+.nf
+
+ #!/bin/sh
+ # Xsetup_0 \- setup script for one workstation
+ xcmsdb < /usr/X11R6/lib/monitors/alex.0
+ xconsole\0\-geometry\0480x130\-0\-0\0\-notify\0\-verbose\0\-exitOnFail &
+
+.fi
+.SH "AUTHENTICATION WIDGET"
+The authentication widget reads a name/password pair
+from the keyboard. Nearly every imaginable
+parameter can be controlled with a resource. Resources for this widget
+should be put into the file named by
+\fBDisplayManager.\fP\fIDISPLAY\fP\fB.resources\fP. All of these have reasonable
+default values, so it is not necessary to specify any of them.
+.IP "\fBxlogin.Login.width, xlogin.Login.height, xlogin.Login.x, xlogin.Login.y\fP"
+The geometry of the Login widget is normally computed automatically. If you
+wish to position it elsewhere, specify each of these resources.
+.IP "\fBxlogin.Login.foreground\fP"
+The color used to display the typed-in user name.
+.IP "\fBxlogin.Login.font\fP"
+The font used to display the typed-in user name.
+.IP "\fBxlogin.Login.greeting\fP"
+A string which identifies this window.
+The default is ``X Window System.''
+.IP "\fBxlogin.Login.unsecureGreeting\fP"
+When X authorization is requested in the configuration file for this
+display and none is in use, this greeting replaces the standard
+greeting. The default is ``This is an unsecure session''
+.IP "\fBxlogin.Login.greetFont\fP"
+The font used to display the greeting.
+.IP "\fBxlogin.Login.greetColor\fP"
+The color used to display the greeting.
+.IP "\fBxlogin.Login.namePrompt\fP"
+The string displayed to prompt for a user name.
+.I Xrdb
+strips trailing white space from resource values, so to add spaces at
+the end of the prompt (usually a nice thing), add spaces escaped with
+backslashes. The default is ``Login: ''
+.IP "\fBxlogin.Login.passwdPrompt\fP"
+The string displayed to prompt for a password.
+The default is ``Password: ''
+.IP "\fBxlogin.Login.promptFont\fP"
+The font used to display both prompts.
+.IP "\fBxlogin.Login.promptColor\fP"
+The color used to display both prompts.
+.IP "\fBxlogin.Login.fail\fP"
+A message which is displayed when the authentication fails.
+The default is ``Login incorrect''
+.IP "\fBxlogin.Login.failFont\fP"
+The font used to display the failure message.
+.IP "\fBxlogin.Login.failColor\fP"
+The color used to display the failure message.
+.IP "\fBxlogin.Login.failTimeout\fP"
+The number of seconds that the failure message is displayed.
+The default is 30.
+.IP "\fBxlogin.Login.translations\fP"
+This specifies the translations used for the login widget. Refer to the X
+Toolkit documentation for a complete discussion on translations. The default
+translation table is:
+.nf
+.ta .5i 2i
+
+ Ctrl<Key>H: delete-previous-character() \\n\\
+ Ctrl<Key>D: delete-character() \\n\\
+ Ctrl<Key>B: move-backward-character() \\n\\
+ Ctrl<Key>F: move-forward-character() \\n\\
+ Ctrl<Key>A: move-to-begining() \\n\\
+ Ctrl<Key>E: move-to-end() \\n\\
+ Ctrl<Key>K: erase-to-end-of-line() \\n\\
+ Ctrl<Key>U: erase-line() \\n\\
+ Ctrl<Key>X: erase-line() \\n\\
+ Ctrl<Key>C: restart-session() \\n\\
+ Ctrl<Key>\\\\: abort-session() \\n\\
+ <Key>BackSpace: delete-previous-character() \\n\\
+ <Key>Delete: delete-previous-character() \\n\\
+ <Key>Return: finish-field() \\n\\
+ <Key>: insert-char() \\
+
+.fi
+.PP
+The actions which are supported by the widget are:
+.IP "delete-previous-character"
+Erases the character before the cursor.
+.IP "delete-character"
+Erases the character after the cursor.
+.IP "move-backward-character"
+Moves the cursor backward.
+.IP "move-forward-character"
+Moves the cursor forward.
+.IP "move-to-begining"
+(Apologies about the spelling error.)
+Moves the cursor to the beginning of the editable text.
+.IP "move-to-end"
+Moves the cursor to the end of the editable text.
+.IP "erase-to-end-of-line"
+Erases all text after the cursor.
+.IP "erase-line"
+Erases the entire text.
+.IP "finish-field"
+If the cursor is in the name field, proceeds to the password field; if the
+cursor is in the password field, checks the current name/password pair. If
+the name/password pair is valid, \fIxdm\fP
+starts the session. Otherwise the failure message is displayed and
+the user is prompted again.
+.IP "abort-session"
+Terminates and restarts the server.
+.IP "abort-display"
+Terminates the server, disabling it. This action
+is not accessible in the default configuration.
+There are various reasons to stop \fIxdm\fP on a system console, such as
+when shutting the system down, when using \fIxdmshell\fP,
+to start another type of server, or to generally access the console.
+Sending \fIxdm\fP a SIGHUP will restart the display. See the section
+\fBControlling XDM\fP.
+.IP "restart-session"
+Resets the X server and starts a new session. This can be used when
+the resources have been changed and you want to test them or when
+the screen has been overwritten with system messages.
+.IP "insert-char"
+Inserts the character typed.
+.IP "set-session-argument"
+Specifies a single word argument which is passed to the session at startup.
+See the section \fBSession Program\fP.
+.IP "allow-all-access"
+Disables access control in the server. This can be used when
+the .Xauthority file cannot be created by
+.I xdm.
+Be very careful using this;
+it might be better to disconnect the machine from the network
+before doing this.
+.SH "STARTUP PROGRAM"
+.PP
+The \fIXstartup\fP program is run as
+root when the user logs in.
+It is typically a shell script.
+Since it is run as root, \fIXstartup\fP should be
+very careful about security. This is the place to put commands which add
+entries to \fI/etc/utmp\fP
+(the \fIsessreg\fP program may be useful here),
+mount users' home directories from file servers,
+or abort the session if logins are not
+allowed.
+.PP
+In addition to any specified by \fBDisplayManager.exportList\fP,
+the following environment variables are passed:
+.nf
+.ta .5i 2i
+
+ DISPLAY the associated display name
+ HOME the initial working directory of the user
+ LOGNAME the user name
+ USER the user name
+ PATH the value of \fBDisplayManager.\fP\fIDISPLAY\fP\fB.systemPath\fP
+ SHELL the value of \fBDisplayManager.\fP\fIDISPLAY\fP\fB.systemShell\fP
+ XAUTHORITY may be set to an authority file
+
+.fi
+.PP
+No arguments are passed to the script.
+.I Xdm
+waits until this script exits before starting the user session. If the
+exit value of this script is non-zero,
+.I xdm
+discontinues the session and starts another authentication
+cycle.
+.PP
+The sample \fIXstartup\fP file shown here prevents login while the
+file \fI/etc/nologin\fP
+exists.
+Thus this is not a complete example, but
+simply a demonstration of the available functionality.
+.PP
+Here is a sample \fIXstartup\fP script:
+.nf
+.ta .5i 1i
+
+ #!/bin/sh
+ #
+ # Xstartup
+ #
+ # This program is run as root after the user is verified
+ #
+ if [ \-f /etc/nologin ]; then
+ xmessage\0\-file /etc/nologin\0\-timeout 30\0\-center
+ exit 1
+ fi
+ sessreg\0\-a\0\-l $DISPLAY\0\-x /usr/X11R6/lib/xdm/Xservers $LOGNAME
+ /usr/X11R6/lib/xdm/GiveConsole
+ exit 0
+.fi
+.SH "SESSION PROGRAM"
+.PP
+The \fIXsession\fP program is the command which is run as the user's session.
+It is run with
+the permissions of the authorized user.
+.PP
+In addition to any specified by \fBDisplayManager.exportList\fP,
+the following environment variables are passed:
+.nf
+.ta .5i 2i
+
+ DISPLAY the associated display name
+ HOME the initial working directory of the user
+ LOGNAME the user name
+ USER the user name
+ PATH the value of \fBDisplayManager.\fP\fIDISPLAY\fP\fB.userPath\fP
+ SHELL the user's default shell (from \fIgetpwnam\fP)
+ XAUTHORITY may be set to a non-standard authority file
+ KRB5CCNAME may be set to a Kerberos credentials cache name
+
+.fi
+.PP
+At most installations, \fIXsession\fP should look in $HOME for
+a file \fI\.xsession,\fP
+which contains commands that each user would like to use as a session.
+\fIXsession\fP should also
+implement a system default session if no user-specified session exists.
+See the section \fBTypical Usage\fP.
+.PP
+An argument may be passed to this program from the authentication widget
+using the `set-session-argument' action. This can be used to select
+different styles of session. One good use of this feature is to allow
+the user to escape from the ordinary session when it fails. This
+allows users to repair their own \fI.xsession\fP if it fails,
+without requiring administrative intervention.
+The example following
+demonstrates this feature.
+.PP
+This example recognizes
+the special
+``failsafe'' mode, specified in the translations
+in the \fIXresources\fP file, to provide an escape
+from the ordinary session. It also requires that the .xsession file
+be executable so we don't have to guess what shell it wants to use.
+.nf
+.ta .5i 1i 1.5i
+
+ #!/bin/sh
+ #
+ # Xsession
+ #
+ # This is the program that is run as the client
+ # for the display manager.
+
+ case $# in
+ 1)
+ case $1 in
+ failsafe)
+ exec xterm \-geometry 80x24\-0\-0
+ ;;
+ esac
+ esac
+
+ startup=$HOME/.xsession
+ resources=$HOME/.Xresources
+
+ if [ \-f "$startup" ]; then
+ exec "$startup"
+ else
+ if [ \-f "$resources" ]; then
+ xrdb \-load "$resources"
+ fi
+ twm &
+ xman \-geometry +10\-10 &
+ exec xterm \-geometry 80x24+10+10 \-ls
+ fi
+
+.fi
+.PP
+The user's \fI.xsession\fP file might look something like this
+example. Don't forget that the file must have execute permission.
+.nf
+ #! /bin/csh
+ # no \-f in the previous line so .cshrc gets run to set $PATH
+ twm &
+ xrdb \-merge "$HOME/.Xresources"
+ emacs \-geometry +0+50 &
+ xbiff \-geometry \-430+5 &
+ xterm \-geometry \-0+50 -ls
+.fi
+.SH "RESET PROGRAM"
+.PP
+Symmetrical with \fIXstartup\fP,
+the \fIXreset\fP script is run after the user session has
+terminated. Run as root, it should contain commands that undo
+the effects of commands in \fIXstartup,\fP removing entries
+from \fI/etc/utmp\fP
+or unmounting directories from file servers. The environment
+variables that were passed to \fIXstartup\fP are also
+passed to \fIXreset\fP.
+.PP
+A sample \fIXreset\fP script:
+.nf
+.ta .5i 1i
+ #!/bin/sh
+ #
+ # Xreset
+ #
+ # This program is run as root after the session ends
+ #
+ sessreg\0\-d\0\-l $DISPLAY\0\-x /usr/X11R6/lib/xdm/Xservers $LOGNAME
+ /usr/X11R6/lib/xdm/TakeConsole
+ exit 0
+.fi
+.SH "CONTROLLING THE SERVER"
+.I Xdm
+controls local servers using POSIX signals. SIGHUP is expected to reset the
+server, closing all client connections and performing other cleanup
+duties. SIGTERM is expected to terminate the server.
+If these signals do not perform the expected actions,
+the resources \fBDisplayManager.\fP\fIDISPLAY\fP\fB.resetSignal\fP and
+\fBDisplayManager.\fP\fIDISPLAY\fP\fB.termSignal\fP can specify alternate signals.
+.PP
+To control remote terminals not using XDMCP,
+.I xdm
+searches the window hierarchy on the display and uses the protocol request
+KillClient in an attempt to clean up the terminal for the next session. This
+may not actually kill all of the clients, as only those which have created
+windows will be noticed. XDMCP provides a more sure mechanism; when
+.I xdm
+closes its initial connection, the session is over and the terminal is
+required to close all other connections.
+.SH "CONTROLLING XDM"
+.PP
+.I Xdm
+responds to two signals: SIGHUP and SIGTERM. When sent a SIGHUP,
+.I xdm
+rereads the configuration file, the access control file, and the servers
+file. For the servers file, it notices if entries have been added or
+removed. If a new entry has been added,
+.I xdm
+starts a session on the associated display. Entries which have been removed
+are disabled immediately, meaning that any session in progress will be
+terminated without notice and no new session will be started.
+.PP
+When sent a SIGTERM,
+.I xdm
+terminates all sessions in progress and exits. This can be used when
+shutting down the system.
+.PP
+.I Xdm
+attempts to mark its various sub-processes for
+.IR ps (1)
+by editing the
+command line argument list in place. Because
+.I xdm
+can't allocate additional
+space for this task, it is useful to start
+.I xdm
+with a reasonably long
+command line (using the full path name should be enough).
+Each process which is
+servicing a display is marked \fB\-\fP\fIdisplay.\fP
+.SH "ADDITIONAL LOCAL DISPLAYS"
+.PP
+To add an additional local display, add a line for it to the
+\fIXservers\fP file.
+(See the section \fBLocal Server Specification\fP.)
+.PP
+Examine the display-specific resources in \fIxdm-config\fP
+(e.g., \fBDisplayManager._0.authorize\fP)
+and consider which of them should be copied for the new display.
+The default \fIxdm-config\fP has all the appropriate lines for
+displays \fB:0\fP and \fB:1\fP.
+.SH "OTHER POSSIBILITIES"
+.PP
+You can use \fIxdm\fP
+to run a single session at a time, using the 4.3 \fIinit\fP
+options or other suitable daemon by specifying the server on the command
+line:
+.nf
+.ta .5i
+
+ xdm \-server ":0 SUN-3/60CG4 local /usr/X11R6/bin/X :0"
+
+.fi
+.PP
+Or, you might have a file server and a collection of X terminals. The
+configuration for this is identical to the sample above,
+except the \fIXservers\fP file would look like
+.nf
+.ta .5i
+
+ extol:0 VISUAL-19 foreign
+ exalt:0 NCD-19 foreign
+ explode:0 NCR-TOWERVIEW3000 foreign
+
+.fi
+.PP
+This directs
+.I xdm
+to manage sessions on all three of these terminals. See the section
+\fBControlling Xdm\fP for a description of using signals to enable
+and disable these terminals in a manner reminiscent of
+.IR init (8).
+.SH LIMITATIONS
+One thing that
+.I xdm
+isn't very good at doing is coexisting with other window systems. To use
+multiple window systems on the same hardware, you'll probably be more
+interested in
+.I xinit.
+.SH FILES
+.TP 20
+.I <XRoot>/lib/X11/xdm/xdm-config
+the default configuration file
+.TP 20
+.I $HOME/.Xauthority
+user authorization file where \fIxdm\fP stores keys for clients to read
+.TP 20
+.I <XRoot>/lib/X11/xdm/chooser
+the default chooser
+.TP 20
+.I <XRoot>/bin/xrdb
+the default resource database loader
+.TP 20
+.I <XRoot>/bin/X
+the default server
+.TP 20
+.I <XRoot>/bin/xterm
+the default session program and failsafe client
+.TP 20
+.I <XRoot>/lib/X11/xdm/A<display>\-<suffix>
+the default place for authorization files
+.TP 20
+.I /tmp/K5C<display>
+Kerberos credentials cache
+.LP
+Note: <XRoot> refers to the root of the X11 install tree.
+.SH "SEE ALSO"
+.IR X (1),
+.IR xinit (1),
+.IR xauth (1),
+.IR Xsecurity (1),
+.IR sessreg (1),
+.IR Xserver (1),
+.\" .IR chooser (1), \" except that there isn't a manual for it yet
+.\" .IR xdmshell (1), \" except that there isn't a manual for it yet
+.br
+.I "X Display Manager Control Protocol"
+.SH AUTHOR
+Keith Packard, MIT X Consortium
diff --git a/xdmauth.c b/xdmauth.c
new file mode 100644
index 0000000..cd4d221
--- /dev/null
+++ b/xdmauth.c
@@ -0,0 +1,301 @@
+/* $Xorg: xdmauth.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
+ *
+ * xdmauth
+ *
+ * generate authorization data for XDM-AUTHORIZATION-1 as per XDMCP spec
+ */
+
+#include "dm.h"
+
+#ifdef HASXDMAUTH
+
+static char auth_name[256];
+static int auth_name_len;
+
+XdmPrintDataHex (s, a, l)
+ char *s;
+ char *a;
+ int l;
+{
+ int i;
+
+ Debug ("%s", s);
+ for (i = 0; i < l; i++)
+ Debug (" %02x", a[i] & 0xff);
+ Debug ("\n");
+}
+
+#ifdef notdef /* not used */
+XdmPrintKey (s, k)
+ char *s;
+ XdmAuthKeyRec *k;
+{
+ XdmPrintDataHex (s, (char *) k->data, 8);
+}
+#endif
+
+#ifdef XDMCP
+XdmPrintArray8Hex (s, a)
+ char *s;
+ ARRAY8Ptr a;
+{
+ XdmPrintDataHex (s, (char *) a->data, a->length);
+}
+#endif
+
+XdmInitAuth (name_len, name)
+ unsigned short name_len;
+ char *name;
+{
+ if (name_len > 256)
+ name_len = 256;
+ auth_name_len = name_len;
+ memmove( auth_name, name, name_len);
+}
+
+/*
+ * Generate authorization for XDM-AUTHORIZATION-1
+ *
+ * When being used with XDMCP, 8 bytes are generated for the session key
+ * (sigma), as the random number (rho) is already shared between xdm and
+ * the server. Otherwise, we'll prepend a random number to pass in the file
+ * between xdm and the server (16 bytes total)
+ */
+
+Xauth *
+XdmGetAuthHelper (namelen, name, includeRho)
+ unsigned short namelen;
+ char *name;
+ int includeRho;
+{
+ Xauth *new;
+ new = (Xauth *) malloc (sizeof (Xauth));
+
+ if (!new)
+ return (Xauth *) 0;
+ new->family = FamilyWild;
+ new->address_length = 0;
+ new->address = 0;
+ new->number_length = 0;
+ new->number = 0;
+ if (includeRho)
+ new->data_length = 16;
+ else
+ new->data_length = 8;
+
+ new->data = (char *) malloc (new->data_length);
+ if (!new->data)
+ {
+ free ((char *) new);
+ return (Xauth *) 0;
+ }
+ new->name = (char *) malloc (namelen);
+ if (!new->name)
+ {
+ free ((char *) new->data);
+ free ((char *) new);
+ return (Xauth *) 0;
+ }
+ memmove( (char *)new->name, name, namelen);
+ new->name_length = namelen;
+ GenerateAuthData ((char *)new->data, new->data_length);
+ /*
+ * set the first byte of the session key to zero as it
+ * is a DES key and only uses 56 bits
+ */
+ ((char *)new->data)[new->data_length - 8] = '\0';
+ XdmPrintDataHex ("Local server auth", (char *)new->data, new->data_length);
+ return new;
+}
+
+Xauth *
+XdmGetAuth (namelen, name)
+ unsigned short namelen;
+ char *name;
+{
+ return XdmGetAuthHelper (namelen, name, TRUE);
+}
+
+#ifdef XDMCP
+
+void
+XdmGetXdmcpAuth (pdpy,authorizationNameLen, authorizationName)
+ struct protoDisplay *pdpy;
+ unsigned short authorizationNameLen;
+ char *authorizationName;
+{
+ Xauth *fileauth, *xdmcpauth;
+
+ if (pdpy->fileAuthorization && pdpy->xdmcpAuthorization)
+ return;
+ xdmcpauth = XdmGetAuthHelper (authorizationNameLen, authorizationName, FALSE);
+ if (!xdmcpauth)
+ return;
+ fileauth = (Xauth *) malloc (sizeof (Xauth));
+ if (!fileauth)
+ {
+ XauDisposeAuth(xdmcpauth);
+ return;
+ }
+ /* build the file auth from the XDMCP auth */
+ *fileauth = *xdmcpauth;
+ fileauth->name = malloc (xdmcpauth->name_length);
+ fileauth->data = malloc (16);
+ fileauth->data_length = 16;
+ if (!fileauth->name || !fileauth->data)
+ {
+ XauDisposeAuth (xdmcpauth);
+ if (fileauth->name)
+ free ((char *) fileauth->name);
+ if (fileauth->data)
+ free ((char *) fileauth->data);
+ free ((char *) fileauth);
+ return;
+ }
+ /*
+ * for the file authorization, prepend the random number (rho)
+ * which is simply the number we've been passing back and
+ * forth via XDMCP
+ */
+ memmove( fileauth->name, xdmcpauth->name, xdmcpauth->name_length);
+ memmove( fileauth->data, pdpy->authenticationData.data, 8);
+ memmove( fileauth->data + 8, xdmcpauth->data, 8);
+ XdmPrintDataHex ("Accept packet auth", xdmcpauth->data, xdmcpauth->data_length);
+ XdmPrintDataHex ("Auth file auth", fileauth->data, fileauth->data_length);
+ /* encrypt the session key for its trip back to the server */
+ XdmcpWrap (xdmcpauth->data, &pdpy->key, xdmcpauth->data, 8);
+ pdpy->fileAuthorization = fileauth;
+ pdpy->xdmcpAuthorization = xdmcpauth;
+}
+
+#define atox(c) ('0' <= c && c <= '9' ? c - '0' : \
+ 'a' <= c && c <= 'f' ? c - 'a' + 10 : \
+ 'A' <= c && c <= 'F' ? c - 'A' + 10 : -1)
+
+static
+HexToBinary (key)
+ char *key;
+{
+ char *out, *in;
+ int top, bottom;
+
+ in = key + 2;
+ out= key;
+ while (in[0] && in[1])
+ {
+ top = atox(in[0]);
+ if (top == -1)
+ return 0;
+ bottom = atox(in[1]);
+ if (bottom == -1)
+ return 0;
+ *out++ = (top << 4) | bottom;
+ in += 2;
+ }
+ if (in[0])
+ return 0;
+ *out++ = '\0';
+ return 1;
+}
+
+/*
+ * Search the Keys file for the entry matching this display. This
+ * routine accepts either plain ascii strings for keys, or hex-encoded numbers
+ */
+
+XdmGetKey (pdpy, displayID)
+ struct protoDisplay *pdpy;
+ ARRAY8Ptr displayID;
+{
+ FILE *keys;
+ char line[1024], id[1024], key[1024];
+ int keylen;
+
+ Debug ("Lookup key for %*.*s\n", displayID->length, displayID->length, displayID->data);
+ keys = fopen (keyFile, "r");
+ if (!keys)
+ return FALSE;
+ while (fgets (line, sizeof (line) - 1, keys))
+ {
+ if (line[0] == '#' || sscanf (line, "%s %s", id, key) != 2)
+ continue;
+ bzero(line, sizeof(line));
+ Debug ("Key entry for \"%s\" %d bytes\n", id, strlen(key));
+ if (strlen (id) == displayID->length &&
+ !strncmp (id, (char *)displayID->data, displayID->length))
+ {
+ if (!strncmp (key, "0x", 2) || !strncmp (key, "0X", 2))
+ if (!HexToBinary (key))
+ break;
+ keylen = strlen (key);
+ while (keylen < 7)
+ key[keylen++] = '\0';
+ pdpy->key.data[0] = '\0';
+ memmove( pdpy->key.data + 1, key, 7);
+ bzero(key, sizeof(key));
+ fclose (keys);
+ return TRUE;
+ }
+ }
+ bzero(line, sizeof(line));
+ bzero(key, sizeof(key));
+ fclose (keys);
+ return FALSE;
+}
+
+/*ARGSUSED*/
+XdmCheckAuthentication (pdpy, displayID, authenticationName, authenticationData)
+ struct protoDisplay *pdpy;
+ ARRAY8Ptr displayID, authenticationName, authenticationData;
+{
+ XdmAuthKeyPtr incoming;
+
+ if (!XdmGetKey (pdpy, displayID))
+ return FALSE;
+ if (authenticationData->length != 8)
+ return FALSE;
+ XdmcpUnwrap (authenticationData->data, &pdpy->key,
+ authenticationData->data, 8);
+ XdmPrintArray8Hex ("Request packet auth", authenticationData);
+ if (!XdmcpCopyARRAY8(authenticationData, &pdpy->authenticationData))
+ return FALSE;
+ incoming = (XdmAuthKeyPtr) authenticationData->data;
+ XdmcpIncrementKey (incoming);
+ XdmcpWrap (authenticationData->data, &pdpy->key,
+ authenticationData->data, 8);
+ return TRUE;
+}
+
+#endif /* XDMCP */
+#endif /* HASXDMAUTH (covering the entire file) */
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 */
diff --git a/xdmshell.c b/xdmshell.c
new file mode 100644
index 0000000..166e689
--- /dev/null
+++ b/xdmshell.c
@@ -0,0 +1,222 @@
+/* $Xorg: xdmshell.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */
+/*
+ * xdmshell - simple program for running xdm from login
+ *
+ *
+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.
+ * *
+ * Author: Jim Fulton, MIT X Consortium
+ *
+ * This program should probably be setuid to root. On the macII, it must be
+ * run from the console so that getty doesn't get confused about zero-length
+ * reads.
+ *
+ * WARNING: Make sure that you tailor your Xresources file to have a
+ * way of invoking the abort-display() action. Otherwise, you won't be able
+ * bring down X when you are finished.
+ */
+
+#include <stdio.h>
+#include "dm.h"
+#include <errno.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#ifdef macII
+#define ON_CONSOLE_ONLY
+#endif
+
+#ifdef ON_CONSOLE_ONLY
+#include <sys/ioctl.h>
+#endif
+
+#ifndef BINDIR
+#define BINDIR "/usr/bin/X11"
+#endif
+
+/*
+ * HP-UX does have vfork, but A/UX doesn't
+ */
+#ifndef HAS_VFORK
+#define vfork() fork()
+#endif
+
+char *ProgramName;
+
+static char *SysErrorMsg (n)
+ int n;
+{
+ char *s = strerror(n);
+ return (s ? s : "unknown error");
+}
+
+
+static int exec_args (filename, args)
+ char *filename;
+ char **args;
+{
+ int pid;
+ waitType status;
+
+ if (!filename) return -1;
+
+ if (filename[0] != '/') {
+ fprintf (stderr,
+ "%s: attempt to execute program with relative pathname: %s\n",
+ ProgramName, filename);
+ return -1;
+ }
+
+ if (access (filename, X_OK) != 0) return -1;
+
+ switch (pid = vfork ()) {
+ case -1: /* error */
+ return -1;
+ case 0: /* child */
+ execv (filename, args);
+ _exit (1);
+ /* NOTREACHED */
+ default: /* parent */
+ while (wait (&status) != pid) ;
+ }
+ return waitCode (status);
+}
+
+static int exec_one_arg (filename, arg)
+ char *filename;
+ char *arg;
+{
+ char *argv[3];
+
+ argv[0] = filename;
+ argv[1] = arg;
+ argv[2] = NULL;
+ return exec_args (filename, argv);
+}
+
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ttyfd;
+ char cmdbuf[256];
+ char *args[10];
+#ifdef ON_CONSOLE_ONLY
+ int consfd;
+ int ttypgrp, conspgrp;
+ char *ttyName;
+ extern char *ttyname();
+#endif
+
+ ProgramName = argv[0];
+
+ if (argc > 1) {
+ fprintf (stderr, "usage: %s\r\n", ProgramName);
+ exit (1);
+ }
+
+ ttyfd = open ("/dev/tty", O_RDWR, 0);
+ if (ttyfd < 3) { /* stdin = 0, stdout = 1, stderr = 2 */
+ fprintf (stderr,
+ "%s: must be run directly from the console.\r\n",
+ ProgramName);
+ exit (1);
+ }
+#ifdef ON_CONSOLE_ONLY
+ if (ioctl (ttyfd, TIOCGPGRP, (char *)&ttypgrp) != 0) {
+ fprintf (stderr, "%s: unable to get process group of /dev/tty\r\n",
+ ProgramName);
+ (void) close (ttyfd);
+ exit (1);
+ }
+#endif
+ (void) close (ttyfd);
+
+#ifdef ON_CONSOLE_ONLY
+ ttyName = ttyname (0);
+ if (!ttyName || strcmp (ttyName, "/dev/console") != 0) {
+ fprintf (stderr, "%s: must login on /dev/console instead of %s\r\n",
+ ProgramName, ttyName ? ttyName : "non-terminal device");
+ exit (1);
+ }
+
+ consfd = open ("/dev/console", O_RDWR, 0);
+ if (consfd < 3) { /* stdin = 0, stdout = 1, stderr = 2 */
+ fprintf (stderr, "%s: unable to open /dev/console\r\n",
+ ProgramName);
+ exit (1);
+ }
+
+ if (ioctl (consfd, TIOCGPGRP, (char *)&conspgrp) != 0) {
+ fprintf (stderr,
+ "%s: unable to get process group of /dev/console\r\n",
+ ProgramName);
+ (void) close (consfd);
+ exit (1);
+ }
+ (void) close (consfd);
+
+ if (ttypgrp != conspgrp) {
+ fprintf (stderr, "%s: must be run from /dev/console\r\n",
+ ProgramName);
+ exit (1);
+ }
+#endif
+
+ /* make xdm run in a non-setuid environment */
+ setuid (geteuid());
+
+ /*
+ * exec /usr/bin/X11/xdm -nodaemon -udpPort 0
+ */
+ strcpy (cmdbuf, BINDIR);
+ strcat (cmdbuf, "/xdm");
+ args[0] = cmdbuf;
+ args[1] = "-nodaemon";
+ args[2] = "-udpPort";
+ args[3] = "0";
+ args[4] = NULL;
+ if (exec_args (cmdbuf, args) == -1) {
+ fprintf (stderr, "%s: unable to execute %s (error %d, %s)\r\n",
+ ProgramName, cmdbuf, errno, SysErrorMsg(errno));
+ exit (1);
+ }
+
+#ifdef macII
+ strcpy (cmdbuf, BINDIR);
+ strcat (cmdbuf, "/Xrepair");
+ (void) exec_one_arg (cmdbuf, NULL);
+ (void) exec_one_arg ("/usr/bin/screenrestore", NULL);
+#endif
+
+#ifdef sun
+ strcpy (cmdbuf, BINDIR);
+ strcat (cmdbuf, "/kbd_mode");
+ (void) exec_one_arg (cmdbuf, "-a");
+#endif
+
+ exit (0);
+ /*NOTREACHED*/
+}
+