summaryrefslogtreecommitdiff
path: root/os
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:54 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:54 +0000
commitded6147bfb5d75ff1e67c858040a628b61bc17d1 (patch)
tree82355105e93cdac89ef7d987424351c77545faf0 /os
parentcb6ef07bf01e72d1a6e6e83ceb7f76d6534da941 (diff)
R6.6 is the Xorg base-line
Diffstat (limited to 'os')
-rw-r--r--os/WaitFor.c613
-rw-r--r--os/access.c1232
-rw-r--r--os/auth.c411
-rw-r--r--os/connection.c1281
-rw-r--r--os/io.c1262
-rw-r--r--os/k5auth.c796
-rw-r--r--os/lbxio.c585
-rw-r--r--os/mitauth.c193
-rw-r--r--os/oscolor.c294
-rw-r--r--os/osdep.h186
-rw-r--r--os/osinit.c200
-rw-r--r--os/rpcauth.c202
-rw-r--r--os/secauth.c201
-rw-r--r--os/utils.c1105
-rw-r--r--os/xdmauth.c518
-rw-r--r--os/xdmcp.c1341
16 files changed, 10420 insertions, 0 deletions
diff --git a/os/WaitFor.c b/os/WaitFor.c
new file mode 100644
index 000000000..fbc05399c
--- /dev/null
+++ b/os/WaitFor.c
@@ -0,0 +1,613 @@
+/***********************************************************
+
+Copyright 1987, 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.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/* $Xorg: WaitFor.c,v 1.4 2001/02/09 02:05:22 xorgcvs Exp $ */
+
+/*****************************************************************
+ * OS Dependent input routines:
+ *
+ * WaitForSomething
+ * TimerForce, TimerSet, TimerCheck, TimerFree
+ *
+ *****************************************************************/
+
+#ifdef WIN32
+#include <X11/Xwinsock.h>
+#endif
+#include "Xos.h" /* for strings, fcntl, time */
+
+#include <errno.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#include <stdio.h>
+#include "X.h"
+#include "misc.h"
+
+#include <X11/Xpoll.h>
+#include "osdep.h"
+#include "dixstruct.h"
+#include "opaque.h"
+
+#ifdef DPMSExtension
+#include "dpms.h"
+extern void DPMSSet();
+extern void DPMSGet();
+extern CARD32 DPMSStandbyTime;
+extern CARD32 DPMSSuspendTime;
+extern CARD32 DPMSOffTime;
+extern BOOL DPMSEnabled;
+extern CARD16 DPMSPowerLevel;
+#endif
+
+extern fd_set AllSockets;
+extern fd_set AllClients;
+extern fd_set LastSelectMask;
+extern fd_set WellKnownConnections;
+extern fd_set EnabledDevices;
+extern fd_set ClientsWithInput;
+extern fd_set ClientsWriteBlocked;
+extern fd_set OutputPending;
+
+extern int ConnectionTranslation[];
+
+extern Bool NewOutputPending;
+extern Bool AnyClientsWriteBlocked;
+
+extern WorkQueuePtr workQueue;
+
+
+#ifdef XTESTEXT1
+/*
+ * defined in xtestext1dd.c
+ */
+extern int playback_on;
+#endif /* XTESTEXT1 */
+
+struct _OsTimerRec {
+ OsTimerPtr next;
+ CARD32 expires;
+ OsTimerCallback callback;
+ pointer arg;
+};
+
+static void DoTimer();
+static OsTimerPtr timers;
+
+/*****************
+ * WaitForSomething:
+ * Make the server suspend until there is
+ * 1. data from clients or
+ * 2. input events available or
+ * 3. ddx notices something of interest (graphics
+ * queue ready, etc.) or
+ * 4. clients that have buffered replies/events are ready
+ *
+ * If the time between INPUT events is
+ * greater than ScreenSaverTime, the display is turned off (or
+ * saved, depending on the hardware). So, WaitForSomething()
+ * has to handle this also (that's why the select() has a timeout.
+ * For more info on ClientsWithInput, see ReadRequestFromClient().
+ * pClientsReady is an array to store ready client->index values into.
+ *****************/
+
+static INT32 timeTilFrob = 0; /* while screen saving */
+
+int
+WaitForSomething(pClientsReady)
+ int *pClientsReady;
+{
+ int i;
+ struct timeval waittime, *wt;
+ INT32 timeout;
+#ifdef DPMSExtension
+ INT32 standbyTimeout, suspendTimeout, offTimeout;
+#endif
+ fd_set clientsReadable;
+ fd_set clientsWritable;
+ int curclient;
+ int selecterr;
+ int nready;
+ fd_set devicesReadable;
+ CARD32 now;
+
+ FD_ZERO(&clientsReadable);
+
+ /* We need a while loop here to handle
+ crashed connections and the screen saver timeout */
+ while (1)
+ {
+ /* deal with any blocked jobs */
+ if (workQueue)
+ ProcessWorkQueue();
+
+ if (XFD_ANYSET (&ClientsWithInput))
+ {
+ XFD_COPYSET (&ClientsWithInput, &clientsReadable);
+ break;
+ }
+#ifdef DPMSExtension
+ if (ScreenSaverTime > 0 || DPMSEnabled || timers)
+#else
+ if (ScreenSaverTime > 0 || timers)
+#endif
+ now = GetTimeInMillis();
+ wt = NULL;
+ if (timers)
+ {
+ while (timers && timers->expires <= now)
+ DoTimer(timers, now, &timers);
+ if (timers)
+ {
+ timeout = timers->expires - now;
+ waittime.tv_sec = timeout / MILLI_PER_SECOND;
+ waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
+ (1000000 / MILLI_PER_SECOND);
+ wt = &waittime;
+ }
+ }
+ if (ScreenSaverTime > 0
+#ifdef DPMSExtension
+ || (DPMSEnabled &&
+ (DPMSStandbyTime > 0 || DPMSSuspendTime > 0 || DPMSOffTime > 0))
+#endif
+ ) {
+#ifdef DPMSExtension
+ if (ScreenSaverTime > 0)
+#endif
+ timeout = (ScreenSaverTime -
+ (now - lastDeviceEventTime.milliseconds));
+#ifdef DPMSExtension
+ if (DPMSStandbyTime > 0)
+ standbyTimeout = (DPMSStandbyTime -
+ (now - lastDeviceEventTime.milliseconds));
+ if (DPMSSuspendTime > 0)
+ suspendTimeout = (DPMSSuspendTime -
+ (now - lastDeviceEventTime.milliseconds));
+ if (DPMSOffTime > 0)
+ offTimeout = (DPMSOffTime -
+ (now - lastDeviceEventTime.milliseconds));
+#endif /* DPMSExtension */
+
+ if (timeout <= 0
+#ifdef DPMSExtension
+ && ScreenSaverTime > 0
+#endif /* DPMSExtension */
+ ) {
+ INT32 timeSinceSave;
+
+ timeSinceSave = -timeout;
+ if (timeSinceSave >= timeTilFrob && timeTilFrob >= 0)
+ {
+ ResetOsBuffers(); /* not ideal, but better than nothing */
+ SaveScreens(SCREEN_SAVER_ON, ScreenSaverActive);
+#ifdef DPMSExtension
+ if (ScreenSaverInterval > 0 &&
+ DPMSPowerLevel == DPMSModeOn)
+#else
+ if (ScreenSaverInterval)
+#endif /* DPMSExtension */
+ /* round up to the next ScreenSaverInterval */
+ timeTilFrob = ScreenSaverInterval *
+ ((timeSinceSave + ScreenSaverInterval) /
+ ScreenSaverInterval);
+ else
+ timeTilFrob = -1;
+ }
+ timeout = timeTilFrob - timeSinceSave;
+ }
+ else
+ {
+ if (ScreenSaverTime > 0 && timeout > ScreenSaverTime)
+ timeout = ScreenSaverTime;
+ timeTilFrob = 0;
+ }
+#ifdef DPMSExtension
+ if (DPMSEnabled)
+ {
+ if (standbyTimeout > 0 && timeout > standbyTimeout)
+ timeout = standbyTimeout;
+ if (suspendTimeout > 0 && timeout > suspendTimeout)
+ timeout = suspendTimeout;
+ if (offTimeout > 0 && timeout > offTimeout)
+ timeout = offTimeout;
+ }
+#endif
+ if (timeout > 0 && (!wt || timeout < (timers->expires - now)))
+ {
+ waittime.tv_sec = timeout / MILLI_PER_SECOND;
+ waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
+ (1000000 / MILLI_PER_SECOND);
+ wt = &waittime;
+ }
+#ifdef DPMSExtension
+ /* don't bother unless it's switched on */
+ if (DPMSEnabled) {
+ /*
+ * If this mode's enabled, and if the time's come
+ * and if we're still at a lesser mode, do it now.
+ */
+ if (DPMSStandbyTime > 0) {
+ if (standbyTimeout <= 0) {
+ if (DPMSPowerLevel < DPMSModeStandby) {
+ DPMSSet(DPMSModeStandby);
+ }
+ }
+ }
+ /*
+ * and ditto. Note that since these modes can have the
+ * same timeouts, they can happen at the same time.
+ */
+ if (DPMSSuspendTime > 0) {
+ if (suspendTimeout <= 0) {
+ if (DPMSPowerLevel < DPMSModeSuspend) {
+ DPMSSet(DPMSModeSuspend);
+ }
+ }
+ }
+ if (DPMSOffTime > 0) {
+ if (offTimeout <= 0) {
+ if (DPMSPowerLevel < DPMSModeOff) {
+ DPMSSet(DPMSModeOff);
+ }
+ }
+ }
+ }
+#endif
+ }
+ XFD_COPYSET(&AllSockets, &LastSelectMask);
+ BlockHandler((pointer)&wt, (pointer)&LastSelectMask);
+ if (NewOutputPending)
+ FlushAllOutput();
+#ifdef XTESTEXT1
+ /* XXX how does this interact with new write block handling? */
+ if (playback_on) {
+ wt = &waittime;
+ XTestComputeWaitTime (&waittime);
+ }
+#endif /* XTESTEXT1 */
+ /* keep this check close to select() call to minimize race */
+ if (dispatchException)
+ i = -1;
+ else if (AnyClientsWriteBlocked)
+ {
+ XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable);
+ i = Select (MAXSOCKS, &LastSelectMask, &clientsWritable, NULL, wt);
+ }
+ else
+ i = Select (MAXSOCKS, &LastSelectMask, NULL, NULL, wt);
+ selecterr = errno;
+ WakeupHandler(i, (pointer)&LastSelectMask);
+#ifdef XTESTEXT1
+ if (playback_on) {
+ i = XTestProcessInputAction (i, &waittime);
+ }
+#endif /* XTESTEXT1 */
+ if (i <= 0) /* An error or timeout occurred */
+ {
+
+ if (dispatchException)
+ return 0;
+ FD_ZERO(&clientsWritable);
+ if (i < 0)
+ if (selecterr == EBADF) /* Some client disconnected */
+ {
+ CheckConnections ();
+ if (! XFD_ANYSET (&AllClients))
+ return 0;
+ }
+ else if (selecterr == EINVAL)
+ {
+ FatalError("WaitForSomething(): select: errno=%d\n",
+ selecterr);
+ }
+ else if (selecterr != EINTR)
+ {
+ ErrorF("WaitForSomething(): select: errno=%d\n",
+ selecterr);
+ }
+ if (timers)
+ {
+ now = GetTimeInMillis();
+ while (timers && timers->expires <= now)
+ DoTimer(timers, now, &timers);
+ }
+ if (*checkForInput[0] != *checkForInput[1])
+ return 0;
+ }
+ else
+ {
+#ifdef WIN32
+ fd_set tmp_set;
+#endif
+ if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable))
+ {
+ NewOutputPending = TRUE;
+ XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
+ XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
+ if (! XFD_ANYSET(&ClientsWriteBlocked))
+ AnyClientsWriteBlocked = FALSE;
+ }
+
+ XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices);
+ XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
+#ifndef WIN32
+ if (LastSelectMask.fds_bits[0] & WellKnownConnections.fds_bits[0])
+#else
+ XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections);
+ if (XFD_ANYSET(&tmp_set))
+#endif
+ QueueWorkProc(EstablishNewConnections, NULL,
+ (pointer)&LastSelectMask);
+#ifdef DPMSExtension
+ if (XFD_ANYSET (&devicesReadable) && (DPMSPowerLevel != DPMSModeOn))
+ DPMSSet(DPMSModeOn);
+#endif
+ if (XFD_ANYSET (&devicesReadable) || XFD_ANYSET (&clientsReadable))
+ break;
+ }
+ }
+
+ nready = 0;
+ if (XFD_ANYSET (&clientsReadable))
+ {
+#ifndef WIN32
+ for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++)
+ {
+ int highest_priority;
+
+ while (clientsReadable.fds_bits[i])
+ {
+ int client_priority, client_index;
+
+ curclient = ffs (clientsReadable.fds_bits[i]) - 1;
+ client_index = ConnectionTranslation[curclient + (i << 5)];
+#else
+ int highest_priority;
+ fd_set savedClientsReadable;
+ XFD_COPYSET(&clientsReadable, &savedClientsReadable);
+ for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++)
+ {
+ int client_priority, client_index;
+
+ curclient = XFD_FD(&savedClientsReadable, i);
+ client_index = ConnectionTranslation[curclient];
+#endif
+#ifdef XSYNC
+ /* We implement "strict" priorities.
+ * Only the highest priority client is returned to
+ * dix. If multiple clients at the same priority are
+ * ready, they are all returned. This means that an
+ * aggressive client could take over the server.
+ * This was not considered a big problem because
+ * aggressive clients can hose the server in so many
+ * other ways :)
+ */
+ client_priority = clients[client_index]->priority;
+ if (nready == 0 || client_priority > highest_priority)
+ {
+ /* Either we found the first client, or we found
+ * a client whose priority is greater than all others
+ * that have been found so far. Either way, we want
+ * to initialize the list of clients to contain just
+ * this client.
+ */
+ pClientsReady[0] = client_index;
+ highest_priority = client_priority;
+ nready = 1;
+ }
+ /* the following if makes sure that multiple same-priority
+ * clients get batched together
+ */
+ else if (client_priority == highest_priority)
+#endif
+ {
+ pClientsReady[nready++] = client_index;
+ }
+#ifndef WIN32
+ clientsReadable.fds_bits[i] &= ~(((fd_mask)1) << curclient);
+ }
+#else
+ FD_CLR(curclient, &clientsReadable);
+#endif
+ }
+ }
+ return nready;
+}
+
+#if 0
+/*
+ * This is not always a macro.
+ */
+ANYSET(src)
+ FdMask *src;
+{
+ int i;
+
+ for (i=0; i<mskcnt; i++)
+ if (src[ i ])
+ return (TRUE);
+ return (FALSE);
+}
+#endif
+
+static void
+DoTimer(timer, now, prev)
+ register OsTimerPtr timer;
+ CARD32 now;
+ OsTimerPtr *prev;
+{
+ CARD32 newTime;
+
+ *prev = timer->next;
+ timer->next = NULL;
+ newTime = (*timer->callback)(timer, now, timer->arg);
+ if (newTime)
+ TimerSet(timer, 0, newTime, timer->callback, timer->arg);
+}
+
+OsTimerPtr
+TimerSet(timer, flags, millis, func, arg)
+ register OsTimerPtr timer;
+ int flags;
+ CARD32 millis;
+ OsTimerCallback func;
+ pointer arg;
+{
+ register OsTimerPtr *prev;
+ CARD32 now = GetTimeInMillis();
+
+ if (!timer)
+ {
+ timer = (OsTimerPtr)xalloc(sizeof(struct _OsTimerRec));
+ if (!timer)
+ return NULL;
+ }
+ else
+ {
+ for (prev = &timers; *prev; prev = &(*prev)->next)
+ {
+ if (*prev == timer)
+ {
+ *prev = timer->next;
+ if (flags & TimerForceOld)
+ (void)(*timer->callback)(timer, now, timer->arg);
+ break;
+ }
+ }
+ }
+ if (!millis)
+ return timer;
+ if (!(flags & TimerAbsolute))
+ millis += now;
+ timer->expires = millis;
+ timer->callback = func;
+ timer->arg = arg;
+ if (millis <= now)
+ {
+ timer->next = NULL;
+ millis = (*timer->callback)(timer, now, timer->arg);
+ if (!millis)
+ return timer;
+ }
+ for (prev = &timers;
+ *prev && millis > (*prev)->expires;
+ prev = &(*prev)->next)
+ ;
+ timer->next = *prev;
+ *prev = timer;
+ return timer;
+}
+
+Bool
+TimerForce(timer)
+ register OsTimerPtr timer;
+{
+ register OsTimerPtr *prev;
+ register CARD32 newTime;
+
+ for (prev = &timers; *prev; prev = &(*prev)->next)
+ {
+ if (*prev == timer)
+ {
+ DoTimer(timer, GetTimeInMillis(), prev);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+void
+TimerCancel(timer)
+ register OsTimerPtr timer;
+{
+ register OsTimerPtr *prev;
+
+ if (!timer)
+ return;
+ for (prev = &timers; *prev; prev = &(*prev)->next)
+ {
+ if (*prev == timer)
+ {
+ *prev = timer->next;
+ break;
+ }
+ }
+}
+
+void
+TimerFree(timer)
+ register OsTimerPtr timer;
+{
+ if (!timer)
+ return;
+ TimerCancel(timer);
+ xfree(timer);
+}
+
+void
+TimerCheck()
+{
+ register CARD32 now = GetTimeInMillis();
+
+ while (timers && timers->expires <= now)
+ DoTimer(timers, now, &timers);
+}
+
+void
+TimerInit()
+{
+ OsTimerPtr timer;
+
+ while (timer = timers)
+ {
+ timers = timer->next;
+ xfree(timer);
+ }
+}
diff --git a/os/access.c b/os/access.c
new file mode 100644
index 000000000..abca79e9d
--- /dev/null
+++ b/os/access.c
@@ -0,0 +1,1232 @@
+/* $Xorg: access.c,v 1.5 2001/02/09 02:05:23 xorgcvs Exp $ */
+/***********************************************************
+
+Copyright 1987, 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.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+#ifdef WIN32
+#include <X11/Xwinsock.h>
+#endif
+
+#include <stdio.h>
+#include <X11/Xtrans.h>
+#include <X11/Xauth.h>
+#include "X.h"
+#include "Xproto.h"
+#include "misc.h"
+#include "site.h"
+#include <errno.h>
+
+#ifndef WIN32
+#ifdef ESIX
+#include <lan/socket.h>
+#else
+#include <sys/socket.h>
+#endif
+#include <sys/ioctl.h>
+#include <ctype.h>
+
+#if defined(TCPCONN) || defined(STREAMSCONN) || defined(ISC)
+#include <netinet/in.h>
+#endif /* TCPCONN || STREAMSCONN || ISC */
+#ifdef DNETCONN
+#include <netdnet/dn.h>
+#include <netdnet/dnetdb.h>
+#endif
+
+#ifdef hpux
+# include <sys/utsname.h>
+# ifdef HAS_IFREQ
+# include <net/if.h>
+# endif
+#else
+#if defined(SVR4) || (defined(SYSV) && defined(i386))
+# include <sys/utsname.h>
+#endif
+#if defined(SYSV) && defined(i386)
+# include <sys/stream.h>
+#endif
+#ifdef ESIX
+# include <lan/if.h>
+#else
+# include <net/if.h>
+#endif
+#endif /* hpux */
+
+#ifdef SVR4
+#include <sys/sockio.h>
+#endif
+
+#ifdef ESIX
+#include <lan/netdb.h>
+#else
+#include <netdb.h>
+#endif
+
+#endif /* WIN32 */
+
+#define X_INCLUDE_NETDB_H
+#include <X11/Xos_r.h>
+
+#include "dixstruct.h"
+#include "osdep.h"
+
+#ifdef XCSECURITY
+#define _SECURITY_SERVER
+#include "extensions/security.h"
+#endif
+
+Bool defeatAccessControl = FALSE;
+
+#define acmp(a1, a2, len) memcmp((char *)(a1), (char *)(a2), len)
+#define acopy(a1, a2, len) memmove((char *)(a2), (char *)(a1), len)
+#define addrEqual(fam, address, length, host) \
+ ((fam) == (host)->family &&\
+ (length) == (host)->len &&\
+ !acmp (address, (host)->addr, length))
+
+static int ConvertAddr(
+#if NeedFunctionPrototypes
+ struct sockaddr */*saddr*/,
+ int */*len*/,
+ pointer */*addr*/
+#endif
+);
+
+static int CheckAddr(
+#if NeedFunctionPrototypes
+ int /*family*/,
+ pointer /*pAddr*/,
+ unsigned /*length*/
+#endif
+);
+
+static Bool NewHost(
+#if NeedFunctionPrototypes
+ int /*family*/,
+ pointer /*addr*/,
+ int /*len*/
+#endif
+);
+
+typedef struct _host {
+ short family;
+ short len;
+ unsigned char *addr;
+ struct _host *next;
+} HOST;
+
+#define MakeHost(h,l) (h)=(HOST *) xalloc(sizeof *(h)+(l));\
+ if((h))\
+ (h)->addr=(unsigned char *) ((h) + 1);
+#define FreeHost(h) xfree(h)
+static HOST *selfhosts = NULL;
+static HOST *validhosts = NULL;
+static int AccessEnabled = DEFAULT_ACCESS_CONTROL;
+static int LocalHostEnabled = FALSE;
+static int UsingXdmcp = FALSE;
+
+
+/*
+ * called when authorization is not enabled to add the
+ * local host to the access list
+ */
+
+void
+EnableLocalHost ()
+{
+ if (!UsingXdmcp)
+ {
+ LocalHostEnabled = TRUE;
+ AddLocalHosts ();
+ }
+}
+
+/*
+ * called when authorization is enabled to keep us secure
+ */
+void
+DisableLocalHost ()
+{
+ HOST *self;
+
+ LocalHostEnabled = FALSE;
+ for (self = selfhosts; self; self = self->next)
+ (void) RemoveHost ((ClientPtr)NULL, self->family, self->len, (pointer)self->addr);
+}
+
+/*
+ * called at init time when XDMCP will be used; xdmcp always
+ * adds local hosts manually when needed
+ */
+
+void
+AccessUsingXdmcp ()
+{
+ UsingXdmcp = TRUE;
+ LocalHostEnabled = FALSE;
+}
+
+
+/*
+ * DefineSelf (fd):
+ *
+ * Define this host for access control. Find all the hosts the OS knows about
+ * for this fd and add them to the selfhosts list.
+ */
+
+#ifdef WINTCP /* NCR Wollongong based 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>
+
+void
+DefineSelf (fd)
+ int fd;
+{
+ /*
+ * 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;
+ register HOST *host;
+ int family, len;
+
+ if ((fd = open ("/dev/ip", O_RDWR, 0 )) < 0)
+ Error ("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 (fd, (int) I_STR, (char *) &str) < 0)
+ {
+ close (fd);
+ Error ("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 (fd, (int) I_STR, (char *) &str) < 0)
+ {
+ close (fd);
+ Error ("Getting interface configuration");
+ }
+
+ len = sizeof(struct sockaddr_in);
+ family = ConvertAddr (IA_SIN(&ifaddr), &len, (pointer *)&addr);
+ if (family == -1 || family == FamilyLocal)
+ continue;
+ for (host = selfhosts;
+ host && !addrEqual (family, addr, len, host);
+ host = host->next)
+ ;
+ if (host)
+ continue;
+ MakeHost(host,len)
+ if (host)
+ {
+ host->family = family;
+ host->len = len;
+ acopy(addr, host->addr, len);
+ host->next = selfhosts;
+ selfhosts = host;
+ }
+#ifdef XDMCP
+ {
+ struct sockaddr broad_addr;
+
+ /*
+ * If this isn't an Internet Address, don't register it.
+ */
+ if (family != FamilyInternet)
+ continue;
+
+ /*
+ * ignore 'localhost' entries as they're not useful
+ * on the other end of the wire
+ */
+ if (len == 4 &&
+ addr[0] == 127 && addr[1] == 0 &&
+ addr[2] == 0 && addr[3] == 1)
+ continue;
+
+ XdmcpRegisterConnection (family, (char *)addr, len);
+
+
+#define IA_BROADADDR(ia) ((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_broadaddr))
+
+ XdmcpRegisterBroadcastAddress (
+ (struct sockaddr_in *) IA_BROADADDR(&ifaddr));
+
+#undef IA_BROADADDR
+ }
+#endif /* XDMCP */
+ }
+
+ close(fd);
+
+ /*
+ * add something of FamilyLocalHost
+ */
+ for (host = selfhosts;
+ host && !addrEqual(FamilyLocalHost, "", 0, host);
+ host = host->next);
+ if (!host)
+ {
+ MakeHost(host, 0);
+ if (host)
+ {
+ host->family = FamilyLocalHost;
+ host->len = 0;
+ acopy("", host->addr, 0);
+ host->next = selfhosts;
+ selfhosts = host;
+ }
+ }
+}
+
+#else /* WINTCP */
+
+#if !defined(SIOCGIFCONF) || (defined (hpux) && ! defined (HAS_IFREQ))
+void
+DefineSelf (fd)
+ int fd;
+{
+#if !defined(TCPCONN) && !defined(UNIXCONN)
+ return;
+#else
+ register int n;
+ int len;
+ caddr_t addr;
+ int family;
+ register HOST *host;
+
+#if defined(__386BSD__) || defined(__NetBSD__) || defined(__FreeBSD__) \
+ || defined(WIN32)
+ char name[100];
+#else
+ struct utsname name;
+#endif
+ register struct hostent *hp;
+
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+ } saddr;
+
+ struct sockaddr_in *inetaddr;
+ struct sockaddr_in broad_addr;
+ _Xgethostbynameparams hparams;
+
+#if defined(__386BSD__) || defined(__NetBSD__) || defined(__FreeBSD__) \
+ || defined(WIN32)
+ if (gethostname (name, sizeof name) < 0)
+ hp = NULL;
+ else
+ hp = _XGethostbyname(name, hparams);
+#else
+ /* 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 = _XGethostbyname(name.nodename, hparams);
+#endif
+ if (hp != NULL)
+ {
+ saddr.sa.sa_family = hp->h_addrtype;
+ inetaddr = (struct sockaddr_in *) (&(saddr.sa));
+ acopy ( hp->h_addr, &(inetaddr->sin_addr), hp->h_length);
+ len = sizeof(saddr.sa);
+ family = ConvertAddr ( &(saddr.sa), &len, (pointer *)&addr);
+ if ( family != -1 && family != FamilyLocal )
+ {
+ for (host = selfhosts;
+ host && !addrEqual (family, addr, len, host);
+ host = host->next) ;
+ if (!host)
+ {
+ /* add this host to the host list. */
+ MakeHost(host,len)
+ if (host)
+ {
+ host->family = family;
+ host->len = len;
+ acopy ( addr, host->addr, len);
+ host->next = selfhosts;
+ selfhosts = host;
+ }
+#ifdef XDMCP
+ /*
+ * If this is an Internet Address, but not the localhost
+ * address (127.0.0.1), register it.
+ */
+ if (family == FamilyInternet &&
+ !(len == 4 && addr[0] == 127 && addr[1] == 0 &&
+ addr[2] == 0 && addr[3] == 1)
+ )
+ {
+ XdmcpRegisterConnection (family, (char *)addr, len);
+ broad_addr = *inetaddr;
+ ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr =
+ htonl (INADDR_BROADCAST);
+ XdmcpRegisterBroadcastAddress ((struct sockaddr_in *)
+ &broad_addr);
+ }
+#endif /* XDMCP */
+ }
+ }
+ }
+ /*
+ * now add a host of family FamilyLocalHost...
+ */
+ for (host = selfhosts;
+ host && !addrEqual(FamilyLocalHost, "", 0, host);
+ host = host->next);
+ if (!host)
+ {
+ MakeHost(host, 0);
+ if (host)
+ {
+ host->family = FamilyLocalHost;
+ host->len = 0;
+ acopy("", host->addr, 0);
+ host->next = selfhosts;
+ selfhosts = host;
+ }
+ }
+#endif /* !TCPCONN && !UNIXCONN */
+}
+
+#else
+void
+DefineSelf (fd)
+ int fd;
+{
+ char buf[2048];
+ struct ifconf ifc;
+ register int n;
+ int len;
+ unsigned char * addr;
+ int family;
+ register HOST *host;
+ register struct ifreq *ifr;
+
+#ifdef DNETCONN
+ struct dn_naddr *dnaddr = getnodeadd();
+ /*
+ * AF_DECnet may not be listed in the interface list. Instead use
+ * the supported library call to find out the local address (if any).
+ */
+ if (dnaddr)
+ {
+ addr = (unsigned char *) dnaddr;
+ len = dnaddr->a_len + sizeof(dnaddr->a_len);
+ family = FamilyDECnet;
+ for (host = selfhosts;
+ host && !addrEqual (family, addr, len, host);
+ host = host->next)
+ ;
+ if (!host)
+ {
+ MakeHost(host,len)
+ if (host)
+ {
+ host->family = family;
+ host->len = len;
+ acopy(addr, host->addr, len);
+ host->next = selfhosts;
+ selfhosts = host;
+ }
+ }
+ }
+#endif
+ ifc.ifc_len = sizeof (buf);
+ ifc.ifc_buf = buf;
+ if (ioctl (fd, (int) SIOCGIFCONF, (pointer) &ifc) < 0)
+ Error ("Getting 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
+ )
+ {
+ len = sizeof(ifr->ifr_addr);
+#ifdef DNETCONN
+ /*
+ * DECnet was handled up above.
+ */
+ if (ifr->ifr_addr.sa_family == AF_DECnet)
+ continue;
+#endif /* DNETCONN */
+ family = ConvertAddr (&ifr->ifr_addr, &len, (pointer *)&addr);
+ if (family == -1 || family == FamilyLocal)
+ continue;
+ for (host = selfhosts;
+ host && !addrEqual (family, addr, len, host);
+ host = host->next)
+ ;
+ if (host)
+ continue;
+ MakeHost(host,len)
+ if (host)
+ {
+ host->family = family;
+ host->len = len;
+ acopy(addr, host->addr, len);
+ host->next = selfhosts;
+ selfhosts = host;
+ }
+#ifdef XDMCP
+ {
+ struct sockaddr broad_addr;
+
+ /*
+ * If this isn't an Internet Address, don't register it.
+ */
+ if (family != FamilyInternet)
+ continue;
+
+ /*
+ * ignore 'localhost' entries as they're not useful
+ * on the other end of the wire
+ */
+ if (len == 4 &&
+ addr[0] == 127 && addr[1] == 0 &&
+ addr[2] == 0 && addr[3] == 1)
+ continue;
+
+ XdmcpRegisterConnection (family, (char *)addr, len);
+ 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;
+ if (ioctl (fd, SIOCGIFFLAGS, (char *) &broad_req) != -1 &&
+ (broad_req.ifr_flags & IFF_BROADCAST) &&
+ (broad_req.ifr_flags & IFF_UP)
+ )
+ {
+ broad_req = *ifr;
+ if (ioctl (fd, SIOCGIFBRDADDR, &broad_req) != -1)
+ broad_addr = broad_req.ifr_addr;
+ else
+ continue;
+ }
+ else
+ continue;
+ }
+#endif
+ XdmcpRegisterBroadcastAddress ((struct sockaddr_in *) &broad_addr);
+ }
+#endif
+ }
+ /*
+ * add something of FamilyLocalHost
+ */
+ for (host = selfhosts;
+ host && !addrEqual(FamilyLocalHost, "", 0, host);
+ host = host->next);
+ if (!host)
+ {
+ MakeHost(host, 0);
+ if (host)
+ {
+ host->family = FamilyLocalHost;
+ host->len = 0;
+ acopy("", host->addr, 0);
+ host->next = selfhosts;
+ selfhosts = host;
+ }
+ }
+}
+#endif /* hpux && !HAS_IFREQ */
+#endif /* WINTCP */
+
+#ifdef XDMCP
+void
+AugmentSelf(from, len)
+ pointer from;
+ int len;
+{
+ int family;
+ pointer addr;
+ register HOST *host;
+
+ family = ConvertAddr(from, &len, (pointer *)&addr);
+ if (family == -1 || family == FamilyLocal)
+ return;
+ for (host = selfhosts; host; host = host->next)
+ {
+ if (addrEqual(family, addr, len, host))
+ return;
+ }
+ MakeHost(host,len)
+ if (!host)
+ return;
+ host->family = family;
+ host->len = len;
+ acopy(addr, host->addr, len);
+ host->next = selfhosts;
+ selfhosts = host;
+}
+#endif
+
+void
+AddLocalHosts ()
+{
+ HOST *self;
+
+ for (self = selfhosts; self; self = self->next)
+ (void) NewHost (self->family, self->addr, self->len);
+}
+
+static char* etcx_hosts = NULL;
+
+/* Reset access control list to initial hosts */
+void
+ResetHosts (display)
+ char *display;
+{
+ register HOST *host;
+ char lhostname[120], ohostname[120];
+ char *hostname = ohostname;
+ int fnamelen;
+ char* etcstr = "/etc/X";
+ char* dothoststr = ".hosts";
+ FILE *fd;
+ char *ptr;
+ int i, hostlen;
+ union {
+ struct sockaddr sa;
+#if defined(TCPCONN) || defined(STREAMSCONN)
+ struct sockaddr_in in;
+#endif /* TCPCONN || STREAMSCONN */
+#ifdef DNETCONN
+ struct sockaddr_dn dn;
+#endif
+ } saddr;
+#ifdef DNETCONN
+ struct nodeent *np;
+ struct dn_naddr dnaddr, *dnaddrp, *dnet_addr();
+#endif
+#ifdef K5AUTH
+ krb5_principal princ;
+ krb5_data kbuf;
+#endif
+ int family;
+ pointer addr;
+ int len;
+ register struct hostent *hp;
+
+ AccessEnabled = defeatAccessControl ? FALSE : DEFAULT_ACCESS_CONTROL;
+ LocalHostEnabled = FALSE;
+ while (host = validhosts)
+ {
+ validhosts = host->next;
+ FreeHost (host);
+ }
+ if (etcx_hosts == NULL) {
+ fnamelen = strlen (display);
+ fnamelen += strlen (etcstr);
+ fnamelen += strlen (dothoststr);
+ etcx_hosts = (char*) xalloc (fnamelen + 1); /* A memory leak? No! */
+ /* eventually could use snprintf, when more systems have it */
+ sprintf (etcx_hosts, "%s%s%s", etcstr, display, dothoststr);
+#ifndef WIN32
+#ifdef PATH_MAX
+ if (fnamelen > PATH_MAX) {
+ /* punish stupid hackers */
+ strcpy (etcx_hosts, "/dev/zero");
+ }
+#endif
+#endif
+ }
+ if (fd = fopen (etcx_hosts, "r"))
+ {
+ while (fgets (ohostname, sizeof (ohostname), fd))
+ {
+ if (*ohostname == '#')
+ continue;
+ if (ptr = strchr(ohostname, '\n'))
+ *ptr = 0;
+ hostlen = strlen(ohostname) + 1;
+ for (i = 0; i < hostlen; i++)
+ lhostname[i] = tolower(ohostname[i]);
+ hostname = ohostname;
+ if (!strncmp("local:", lhostname, 6))
+ {
+ family = FamilyLocalHost;
+ NewHost(family, "", 0);
+ }
+#if defined(TCPCONN) || defined(STREAMSCONN)
+ else if (!strncmp("inet:", lhostname, 5))
+ {
+ family = FamilyInternet;
+ hostname = ohostname + 5;
+ }
+#endif
+#ifdef DNETCONN
+ else if (!strncmp("dnet:", lhostname, 5))
+ {
+ family = FamilyDECnet;
+ hostname = ohostname + 5;
+ }
+#endif
+#ifdef SECURE_RPC
+ else if (!strncmp("nis:", lhostname, 4))
+ {
+ family = FamilyNetname;
+ hostname = ohostname + 4;
+ }
+#endif
+#ifdef K5AUTH
+ else if (!strncmp("krb:", lhostname, 4))
+ {
+ family = FamilyKrb5Principal;
+ hostname = ohostname + 4;
+ }
+#endif
+#ifdef DNETCONN
+ if ((family == FamilyDECnet) ||
+ (ptr = strchr(hostname, ':')) && (*(ptr + 1) == ':') &&
+ !(*ptr = '\0')) /* bash trailing colons if necessary */
+ {
+ /* node name (DECnet names end in "::") */
+ dnaddrp = dnet_addr(hostname);
+ if (!dnaddrp && (np = getnodebyname (hostname)))
+ {
+ /* node was specified by name */
+ saddr.sa.sa_family = np->n_addrtype;
+ len = sizeof(saddr.sa);
+ if (ConvertAddr (&saddr.sa, &len, (pointer *)&addr) == FamilyDECnet)
+ {
+ bzero ((char *) &dnaddr, sizeof (dnaddr));
+ dnaddr.a_len = np->n_length;
+ acopy (np->n_addr, dnaddr.a_addr, np->n_length);
+ dnaddrp = &dnaddr;
+ }
+ }
+ if (dnaddrp)
+ (void) NewHost(FamilyDECnet, (pointer)dnaddrp,
+ (int)(dnaddrp->a_len + sizeof(dnaddrp->a_len)));
+ }
+ else
+#endif /* DNETCONN */
+#ifdef K5AUTH
+ if (family == FamilyKrb5Principal)
+ {
+ krb5_parse_name(hostname, &princ);
+ XauKrb5Encode(princ, &kbuf);
+ (void) NewHost(FamilyKrb5Principal, kbuf.data, kbuf.length);
+ krb5_free_principal(princ);
+ }
+ else
+#endif
+#ifdef SECURE_RPC
+ if ((family == FamilyNetname) || (strchr(hostname, '@')))
+ {
+ SecureRPCInit ();
+ (void) NewHost (FamilyNetname, hostname, strlen (hostname));
+ }
+ else
+#endif /* SECURE_RPC */
+#if defined(TCPCONN) || defined(STREAMSCONN)
+ {
+ _Xgethostbynameparams hparams;
+
+ /* host name */
+ if (family == FamilyInternet &&
+ (hp = _XGethostbyname(hostname, hparams)) ||
+ (hp = _XGethostbyname(hostname, hparams)))
+ {
+ saddr.sa.sa_family = hp->h_addrtype;
+ len = sizeof(saddr.sa);
+ if ((family = ConvertAddr (&saddr.sa, &len, (pointer *)&addr)) != -1)
+ {
+#ifdef h_addr /* new 4.3bsd version of gethostent */
+ char **list;
+
+ /* iterate over the addresses */
+ for (list = hp->h_addr_list; *list; list++)
+ (void) NewHost (family, (pointer)*list, len);
+#else
+ (void) NewHost (family, (pointer)hp->h_addr, len);
+#endif
+ }
+ }
+ }
+#endif /* TCPCONN || STREAMSCONN */
+ family = FamilyWild;
+ }
+ fclose (fd);
+ }
+}
+
+/* Is client on the local host */
+Bool LocalClient(client)
+ ClientPtr client;
+{
+ int alen, family, notused;
+ Xtransaddr *from = NULL;
+ pointer addr;
+ register HOST *host;
+
+#ifdef XCSECURITY
+ /* untrusted clients can't change host access */
+ if (client->trustLevel != XSecurityClientTrusted)
+ {
+ SecurityAudit("client %d attempted to change host access\n",
+ client->index);
+ return FALSE;
+ }
+#endif
+#ifdef LBX
+ if (!((OsCommPtr)client->osPrivate)->trans_conn)
+ return FALSE;
+#endif
+ if (!_XSERVTransGetPeerAddr (((OsCommPtr)client->osPrivate)->trans_conn,
+ &notused, &alen, &from))
+ {
+ family = ConvertAddr ((struct sockaddr *) from,
+ &alen, (pointer *)&addr);
+ if (family == -1)
+ {
+ xfree ((char *) from);
+ return FALSE;
+ }
+ if (family == FamilyLocal)
+ {
+ xfree ((char *) from);
+ return TRUE;
+ }
+ for (host = selfhosts; host; host = host->next)
+ {
+ if (addrEqual (family, addr, alen, host))
+ return TRUE;
+ }
+ xfree ((char *) from);
+ }
+ return FALSE;
+}
+
+static Bool
+AuthorizedClient(client)
+ ClientPtr client;
+{
+ if (!client || defeatAccessControl)
+ return TRUE;
+ return LocalClient(client);
+}
+
+/* Add a host to the access control list. This is the external interface
+ * called from the dispatcher */
+
+int
+AddHost (client, family, length, pAddr)
+ ClientPtr client;
+ int family;
+ unsigned length; /* of bytes in pAddr */
+ pointer pAddr;
+{
+ int len;
+
+ if (!AuthorizedClient(client))
+ return(BadAccess);
+ switch (family) {
+ case FamilyLocalHost:
+ len = length;
+ LocalHostEnabled = TRUE;
+ break;
+#ifdef K5AUTH
+ case FamilyKrb5Principal:
+ len = length;
+ break;
+#endif
+#ifdef SECURE_RPC
+ case FamilyNetname:
+ len = length;
+ SecureRPCInit ();
+ break;
+#endif
+ case FamilyInternet:
+ case FamilyDECnet:
+ case FamilyChaos:
+ if ((len = CheckAddr (family, pAddr, length)) < 0)
+ {
+ client->errorValue = length;
+ return (BadValue);
+ }
+ break;
+ case FamilyLocal:
+ default:
+ client->errorValue = family;
+ return (BadValue);
+ }
+ if (NewHost (family, pAddr, len))
+ return Success;
+ return BadAlloc;
+}
+
+Bool
+ForEachHostInFamily (family, func, closure)
+ int family;
+ Bool (*func)();
+ pointer closure;
+{
+ HOST *host;
+
+ for (host = validhosts; host; host = host->next)
+ if (family == host->family && func (host->addr, host->len, closure))
+ return TRUE;
+ return FALSE;
+}
+
+/* Add a host to the access control list. This is the internal interface
+ * called when starting or resetting the server */
+static Bool
+NewHost (family, addr, len)
+ int family;
+ pointer addr;
+ int len;
+{
+ register HOST *host;
+
+ for (host = validhosts; host; host = host->next)
+ {
+ if (addrEqual (family, addr, len, host))
+ return TRUE;
+ }
+ MakeHost(host,len)
+ if (!host)
+ return FALSE;
+ host->family = family;
+ host->len = len;
+ acopy(addr, host->addr, len);
+ host->next = validhosts;
+ validhosts = host;
+ return TRUE;
+}
+
+/* Remove a host from the access control list */
+
+int
+RemoveHost (client, family, length, pAddr)
+ ClientPtr client;
+ int family;
+ unsigned length; /* of bytes in pAddr */
+ pointer pAddr;
+{
+ int len;
+ register HOST *host, **prev;
+
+ if (!AuthorizedClient(client))
+ return(BadAccess);
+ switch (family) {
+ case FamilyLocalHost:
+ len = length;
+ LocalHostEnabled = FALSE;
+ break;
+#ifdef K5AUTH
+ case FamilyKrb5Principal:
+ len = length;
+ break;
+#endif
+#ifdef SECURE_RPC
+ case FamilyNetname:
+ len = length;
+ break;
+#endif
+ case FamilyInternet:
+ case FamilyDECnet:
+ case FamilyChaos:
+ if ((len = CheckAddr (family, pAddr, length)) < 0)
+ {
+ client->errorValue = length;
+ return(BadValue);
+ }
+ break;
+ case FamilyLocal:
+ default:
+ client->errorValue = family;
+ return(BadValue);
+ }
+ for (prev = &validhosts;
+ (host = *prev) && (!addrEqual (family, pAddr, len, host));
+ prev = &host->next)
+ ;
+ if (host)
+ {
+ *prev = host->next;
+ FreeHost (host);
+ }
+ return (Success);
+}
+
+/* Get all hosts in the access control list */
+int
+GetHosts (data, pnHosts, pLen, pEnabled)
+ pointer *data;
+ int *pnHosts;
+ int *pLen;
+ BOOL *pEnabled;
+{
+ int len;
+ register int n = 0;
+ register unsigned char *ptr;
+ register HOST *host;
+ int nHosts = 0;
+
+ *pEnabled = AccessEnabled ? EnableAccess : DisableAccess;
+ for (host = validhosts; host; host = host->next)
+ {
+ nHosts++;
+ n += (((host->len + 3) >> 2) << 2) + sizeof(xHostEntry);
+ }
+ if (n)
+ {
+ *data = ptr = (pointer) xalloc (n);
+ if (!ptr)
+ {
+ return(BadAlloc);
+ }
+ for (host = validhosts; host; host = host->next)
+ {
+ len = host->len;
+ ((xHostEntry *)ptr)->family = host->family;
+ ((xHostEntry *)ptr)->length = len;
+ ptr += sizeof(xHostEntry);
+ acopy (host->addr, ptr, len);
+ ptr += ((len + 3) >> 2) << 2;
+ }
+ } else {
+ *data = NULL;
+ }
+ *pnHosts = nHosts;
+ *pLen = n;
+ return(Success);
+}
+
+/* Check for valid address family and length, and return address length. */
+
+/*ARGSUSED*/
+static int
+CheckAddr (family, pAddr, length)
+ int family;
+ pointer pAddr;
+ unsigned length;
+{
+ int len;
+
+ switch (family)
+ {
+#if defined(TCPCONN) || defined(STREAMSCONN)
+ case FamilyInternet:
+ if (length == sizeof (struct in_addr))
+ len = length;
+ else
+ len = -1;
+ break;
+#endif
+#ifdef DNETCONN
+ case FamilyDECnet:
+ {
+ struct dn_naddr *dnaddr = (struct dn_naddr *) pAddr;
+
+ if ((length < sizeof(dnaddr->a_len)) ||
+ (length < dnaddr->a_len + sizeof(dnaddr->a_len)))
+ len = -1;
+ else
+ len = dnaddr->a_len + sizeof(dnaddr->a_len);
+ if (len > sizeof(struct dn_naddr))
+ len = -1;
+ }
+ break;
+#endif
+ default:
+ len = -1;
+ }
+ return (len);
+}
+
+/* Check if a host is not in the access control list.
+ * Returns 1 if host is invalid, 0 if we've found it. */
+
+InvalidHost (saddr, len)
+ register struct sockaddr *saddr;
+ int len;
+{
+ int family;
+ pointer addr;
+ register HOST *selfhost, *host;
+
+ if (!AccessEnabled) /* just let them in */
+ return(0);
+ family = ConvertAddr (saddr, &len, (pointer *)&addr);
+ if (family == -1)
+ return 1;
+ if (family == FamilyLocal)
+ {
+ if (!LocalHostEnabled)
+ {
+ /*
+ * check to see if any local address is enabled. This
+ * implicitly enables local connections.
+ */
+ for (selfhost = selfhosts; selfhost; selfhost=selfhost->next)
+ {
+ for (host = validhosts; host; host=host->next)
+ {
+ if (addrEqual (selfhost->family, selfhost->addr,
+ selfhost->len, host))
+ return 0;
+ }
+ }
+ return 1;
+ } else
+ return 0;
+ }
+ for (host = validhosts; host; host = host->next)
+ {
+ if (addrEqual (family, addr, len, host))
+ return (0);
+ }
+ return (1);
+}
+
+static int
+ConvertAddr (saddr, len, addr)
+ register struct sockaddr *saddr;
+ int *len;
+ pointer *addr;
+{
+ if (*len == 0)
+ return (FamilyLocal);
+ switch (saddr->sa_family)
+ {
+ case AF_UNSPEC:
+#if defined(UNIXCONN) || defined(LOCALCONN)
+ case AF_UNIX:
+#endif
+ return FamilyLocal;
+#if defined(TCPCONN) || defined(STREAMSCONN)
+ case AF_INET:
+ *len = sizeof (struct in_addr);
+ *addr = (pointer) &(((struct sockaddr_in *) saddr)->sin_addr);
+ return FamilyInternet;
+#endif
+#ifdef DNETCONN
+ case AF_DECnet:
+ {
+ struct sockaddr_dn *sdn = (struct sockaddr_dn *) saddr;
+ *len = sdn->sdn_nodeaddrl + sizeof(sdn->sdn_nodeaddrl);
+ *addr = (pointer) &(sdn->sdn_add);
+ }
+ return FamilyDECnet;
+#endif
+#ifdef CHAOSCONN
+ case AF_CHAOS:
+ {
+ not implemented
+ }
+ return FamilyChaos;
+#endif
+ default:
+ return -1;
+ }
+}
+
+int
+ChangeAccessControl(client, fEnabled)
+ ClientPtr client;
+ int fEnabled;
+{
+ if (!AuthorizedClient(client))
+ return BadAccess;
+ AccessEnabled = fEnabled;
+ return Success;
+}
+
+/* returns FALSE if xhost + in effect, else TRUE */
+int
+GetAccessControl()
+{
+ return AccessEnabled;
+}
+
diff --git a/os/auth.c b/os/auth.c
new file mode 100644
index 000000000..7b914bb28
--- /dev/null
+++ b/os/auth.c
@@ -0,0 +1,411 @@
+/* $Xorg: auth.c,v 1.5 2001/02/09 02:05:23 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.
+
+*/
+
+/*
+ * authorization hooks for the server
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+#ifdef K5AUTH
+# include <krb5/krb5.h>
+#endif
+# include "X.h"
+# include "Xauth.h"
+# include "misc.h"
+# include "dixstruct.h"
+# include <sys/types.h>
+# include <sys/stat.h>
+#ifdef XCSECURITY
+#define _SECURITY_SERVER
+# include "extensions/security.h"
+#endif
+#ifdef WIN32
+#include "Xw32defs.h"
+#endif
+
+struct protocol {
+ unsigned short name_length;
+ char *name;
+ int (*Add)(); /* new authorization data */
+ XID (*Check)(); /* verify client authorization data */
+ int (*Reset)(); /* delete all authorization data entries */
+ XID (*ToID)(); /* convert cookie to ID */
+ int (*FromID)(); /* convert ID to cookie */
+ int (*Remove)(); /* remove a specific cookie */
+#ifdef XCSECURITY
+ XID (*Generate)();
+#endif
+};
+
+extern int MitAddCookie ();
+extern XID MitCheckCookie ();
+extern int MitResetCookie ();
+extern XID MitToID ();
+extern int MitFromID (), MitRemoveCookie ();
+extern XID MitGenerateCookie();
+
+#ifdef HASXDMAUTH
+extern int XdmAddCookie ();
+extern XID XdmCheckCookie ();
+extern int XdmResetCookie ();
+extern XID XdmToID ();
+extern int XdmFromID (), XdmRemoveCookie ();
+#endif
+
+#ifdef SECURE_RPC
+extern int SecureRPCAdd();
+extern XID SecureRPCCheck();
+extern int SecureRPCReset();
+extern XID SecureRPCToID();
+extern int SecureRPCFromID(), SecureRPCRemove();
+#endif
+
+#ifdef K5AUTH
+extern int K5Add();
+extern XID K5Check();
+extern int K5Reset();
+extern XID K5ToID();
+extern int K5FromID(), K5Remove();
+#endif
+
+extern XID AuthSecurityCheck();
+
+static struct protocol protocols[] = {
+{ (unsigned short) 18, "MIT-MAGIC-COOKIE-1",
+ MitAddCookie, MitCheckCookie, MitResetCookie,
+ MitToID, MitFromID, MitRemoveCookie,
+#ifdef XCSECURITY
+ MitGenerateCookie
+#endif
+},
+#ifdef HASXDMAUTH
+{ (unsigned short) 19, "XDM-AUTHORIZATION-1",
+ XdmAddCookie, XdmCheckCookie, XdmResetCookie,
+ XdmToID, XdmFromID, XdmRemoveCookie,
+#ifdef XCSECURITY
+ NULL
+#endif
+},
+#endif
+#ifdef SECURE_RPC
+{ (unsigned short) 9, "SUN-DES-1",
+ SecureRPCAdd, SecureRPCCheck, SecureRPCReset,
+ SecureRPCToID, SecureRPCFromID,SecureRPCRemove,
+#ifdef XCSECURITY
+ NULL
+#endif
+},
+#endif
+#ifdef K5AUTH
+{ (unsigned short) 14, "MIT-KERBEROS-5",
+ K5Add, K5Check, K5Reset,
+ K5ToID, K5FromID, K5Remove,
+#ifdef XCSECURITY
+ NULL
+#endif
+},
+#endif
+#ifdef XCSECURITY
+{ (unsigned short) XSecurityAuthorizationNameLen,
+ XSecurityAuthorizationName,
+ NULL, AuthSecurityCheck, NULL,
+ NULL, NULL, NULL,
+ NULL
+},
+#endif
+};
+
+# define NUM_AUTHORIZATION (sizeof (protocols) /\
+ sizeof (struct protocol))
+
+/*
+ * Initialize all classes of authorization by reading the
+ * specified authorization file
+ */
+
+static char *authorization_file = (char *)NULL;
+
+static Bool ShouldLoadAuth = TRUE;
+
+void
+InitAuthorization (file_name)
+char *file_name;
+{
+ authorization_file = file_name;
+}
+
+int
+LoadAuthorization ()
+{
+ FILE *f;
+ Xauth *auth;
+ int i;
+ int count = 0;
+
+ ShouldLoadAuth = FALSE;
+ if (!authorization_file)
+ return 0;
+ f = fopen (authorization_file, "r");
+ if (!f)
+ return 0;
+ while (auth = XauReadAuth (f)) {
+ for (i = 0; i < NUM_AUTHORIZATION; i++) {
+ if (protocols[i].name_length == auth->name_length &&
+ memcmp (protocols[i].name, auth->name, (int) auth->name_length) == 0 &&
+ protocols[i].Add)
+ {
+ ++count;
+ (*protocols[i].Add) (auth->data_length, auth->data,
+ FakeClientID(0));
+ }
+ }
+ XauDisposeAuth (auth);
+ }
+ fclose (f);
+ return count;
+}
+
+#ifdef XDMCP
+/*
+ * XdmcpInit calls this function to discover all authorization
+ * schemes supported by the display
+ */
+void
+RegisterAuthorizations ()
+{
+ int i;
+
+ for (i = 0; i < NUM_AUTHORIZATION; i++)
+ XdmcpRegisterAuthorization (protocols[i].name,
+ (int)protocols[i].name_length);
+}
+#endif
+
+XID
+CheckAuthorization (name_length, name, data_length, data, client, reason)
+ unsigned int name_length;
+ char *name;
+ unsigned int data_length;
+ char *data;
+ ClientPtr client;
+ char **reason; /* failure message. NULL for default msg */
+{
+ int i;
+ struct stat buf;
+ static time_t lastmod = 0;
+
+ if (!authorization_file || stat(authorization_file, &buf))
+ {
+ if (lastmod != 0) {
+ lastmod = 0;
+ ShouldLoadAuth = TRUE; /* stat lost, so force reload */
+ }
+ }
+ else if (buf.st_mtime > lastmod)
+ {
+ lastmod = buf.st_mtime;
+ ShouldLoadAuth = TRUE;
+ }
+ if (ShouldLoadAuth)
+ {
+ if (LoadAuthorization())
+ DisableLocalHost(); /* got at least one */
+ else
+ EnableLocalHost ();
+ }
+ if (name_length)
+ for (i = 0; i < NUM_AUTHORIZATION; i++) {
+ if (protocols[i].name_length == name_length &&
+ memcmp (protocols[i].name, name, (int) name_length) == 0)
+ {
+ return (*protocols[i].Check) (data_length, data, client, reason);
+ }
+ }
+ return (XID) ~0L;
+}
+
+void
+ResetAuthorization ()
+{
+ int i;
+
+ for (i = 0; i < NUM_AUTHORIZATION; i++)
+ if (protocols[i].Reset)
+ (*protocols[i].Reset)();
+ ShouldLoadAuth = TRUE;
+}
+
+XID
+AuthorizationToID (name_length, name, data_length, data)
+unsigned short name_length;
+char *name;
+unsigned short data_length;
+char *data;
+{
+ int i;
+
+ for (i = 0; i < NUM_AUTHORIZATION; i++) {
+ if (protocols[i].name_length == name_length &&
+ memcmp (protocols[i].name, name, (int) name_length) == 0 &&
+ protocols[i].ToID)
+ {
+ return (*protocols[i].ToID) (data_length, data);
+ }
+ }
+ return (XID) ~0L;
+}
+
+int
+AuthorizationFromID (id, name_lenp, namep, data_lenp, datap)
+XID id;
+unsigned short *name_lenp;
+char **namep;
+unsigned short *data_lenp;
+char **datap;
+{
+ int i;
+
+ for (i = 0; i < NUM_AUTHORIZATION; i++) {
+ if (protocols[i].FromID &&
+ (*protocols[i].FromID) (id, data_lenp, datap)) {
+ *name_lenp = protocols[i].name_length;
+ *namep = protocols[i].name;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+RemoveAuthorization (name_length, name, data_length, data)
+unsigned short name_length;
+char *name;
+unsigned short data_length;
+char *data;
+{
+ int i;
+
+ for (i = 0; i < NUM_AUTHORIZATION; i++) {
+ if (protocols[i].name_length == name_length &&
+ memcmp (protocols[i].name, name, (int) name_length) == 0 &&
+ protocols[i].Remove)
+ {
+ return (*protocols[i].Remove) (data_length, data);
+ }
+ }
+ return 0;
+}
+
+int
+AddAuthorization (name_length, name, data_length, data)
+unsigned int name_length;
+char *name;
+unsigned int data_length;
+char *data;
+{
+ int i;
+
+ for (i = 0; i < NUM_AUTHORIZATION; i++) {
+ if (protocols[i].name_length == name_length &&
+ memcmp (protocols[i].name, name, (int) name_length) == 0 &&
+ protocols[i].Add)
+ {
+ return (*protocols[i].Add) (data_length, data, FakeClientID(0));
+ }
+ }
+ return 0;
+}
+
+#ifdef XCSECURITY
+
+XID
+GenerateAuthorization(name_length, name, data_length, data,
+ data_length_return, data_return)
+unsigned int name_length;
+char *name;
+unsigned int data_length;
+char *data;
+unsigned int *data_length_return;
+char **data_return;
+{
+ int i;
+
+ for (i = 0; i < NUM_AUTHORIZATION; i++) {
+ if (protocols[i].name_length == name_length &&
+ memcmp (protocols[i].name, name, (int) name_length) == 0 &&
+ protocols[i].Generate)
+ {
+ return (*protocols[i].Generate) (data_length, data,
+ FakeClientID(0), data_length_return, data_return);
+ }
+ }
+ return -1;
+}
+
+/* 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;
+}
+
+void
+GenerateRandomData (len, buf)
+int len;
+char *buf;
+{
+ static int seed;
+ int value;
+ int i;
+
+ seed += GetTimeInMillis();
+ xdm_srand (seed);
+ for (i = 0; i < len; i++)
+ {
+ value = xdm_rand ();
+ buf[i] ^= (value & 0xff00) >> 8;
+ }
+
+ /* XXX add getrusage, popen("ps -ale") */
+}
+
+#endif /* XCSECURITY */
diff --git a/os/connection.c b/os/connection.c
new file mode 100644
index 000000000..7c4b9fef3
--- /dev/null
+++ b/os/connection.c
@@ -0,0 +1,1281 @@
+/* $Xorg: connection.c,v 1.6 2001/02/09 02:05:23 xorgcvs Exp $ */
+/***********************************************************
+
+Copyright 1987, 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.
+
+
+Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/*****************************************************************
+ * Stuff to create connections --- OS dependent
+ *
+ * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets,
+ * CloseDownConnection, CheckConnections, AddEnabledDevice,
+ * RemoveEnabledDevice, OnlyListToOneClient,
+ * ListenToAllClients,
+ *
+ * (WaitForSomething is in its own file)
+ *
+ * In this implementation, a client socket table is not kept.
+ * Instead, what would be the index into the table is just the
+ * file descriptor of the socket. This won't work for if the
+ * socket ids aren't small nums (0 - 2^8)
+ *
+ *****************************************************************/
+
+#ifdef WIN32
+#include <X11/Xwinsock.h>
+#endif
+#include "X.h"
+#include "Xproto.h"
+#include <X11/Xtrans.h>
+#include <errno.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+
+#ifndef WIN32
+#include <sys/socket.h>
+
+#ifdef hpux
+#include <sys/utsname.h>
+#include <sys/ioctl.h>
+#endif
+
+#ifdef AIXV3
+#include <sys/ioctl.h>
+#endif
+
+#if defined(TCPCONN) || defined(STREAMSCONN)
+# include <netinet/in.h>
+# ifndef hpux
+# ifdef apollo
+# ifndef NO_TCP_H
+# include <netinet/tcp.h>
+# endif
+# else
+# include <netinet/tcp.h>
+# endif
+# endif
+#endif
+
+#include <sys/uio.h>
+#endif /* WIN32 */
+#include "misc.h" /* for typedef of pointer */
+#include <X11/Xpoll.h>
+#include "osdep.h"
+#include "opaque.h"
+#include "dixstruct.h"
+#ifdef XAPPGROUP
+#include "extensions/Xagsrv.h"
+#endif
+#ifdef XCSECURITY
+#define _SECURITY_SERVER
+#include "extensions/security.h"
+#endif
+#ifdef LBX
+#include "lbxserve.h"
+#endif
+
+#ifdef X_NOT_POSIX
+#define Pid_t int
+#else
+#define Pid_t pid_t
+#endif
+
+#ifdef DNETCONN
+#include <netdnet/dn.h>
+#endif /* DNETCONN */
+
+extern char *display; /* The display number */
+int lastfdesc; /* maximum file descriptor */
+
+fd_set WellKnownConnections; /* Listener mask */
+fd_set EnabledDevices; /* mask for input devices that are on */
+fd_set AllSockets; /* select on this */
+fd_set AllClients; /* available clients */
+fd_set LastSelectMask; /* mask returned from last select call */
+fd_set ClientsWithInput; /* clients with FULL requests in buffer */
+fd_set ClientsWriteBlocked; /* clients who cannot receive output */
+fd_set OutputPending; /* clients with reply/event data ready to go */
+#ifndef _SC_OPEN_MAX
+int MaxClients = MAXSOCKS; /* use MAXSOCKS if sysconf(_SC_OPEN_MAX) is not supported */
+#else
+int MaxClients = 0;
+#endif
+Bool NewOutputPending; /* not yet attempted to write some new output */
+Bool AnyClientsWriteBlocked; /* true if some client blocked on write */
+
+Bool RunFromSmartParent; /* send SIGUSR1 to parent process */
+Bool PartialNetwork; /* continue even if unable to bind all addrs */
+static Pid_t ParentProcess;
+
+static Bool debug_conns = FALSE;
+
+fd_set IgnoredClientsWithInput;
+static fd_set GrabImperviousClients;
+static fd_set SavedAllClients;
+static fd_set SavedAllSockets;
+static fd_set SavedClientsWithInput;
+int GrabInProgress = 0;
+
+#ifndef WIN32
+int ConnectionTranslation[MAXSOCKS];
+#else
+/* SPAM ALERT !!!
+ * On NT fds are not between 0 and MAXSOCKS, they are unrelated, and there is
+ * not even a known maximum value, so use something quite arbitrary for now.
+ * This is clearly boggus and another form of storage which doesn't use the fd
+ * as a direct index should really be implemented for NT.
+ */
+#define MAXFD 500
+int ConnectionTranslation[MAXFD];
+#endif
+
+XtransConnInfo *ListenTransConns = NULL;
+int *ListenTransFds = NULL;
+int ListenTransCount;
+
+extern int auditTrailLevel;
+
+static void ErrorConnMax(
+#if NeedFunctionPrototypes
+XtransConnInfo /* trans_conn */
+#endif
+);
+
+#ifndef LBX
+static
+#endif
+void CloseDownFileDescriptor(
+#if NeedFunctionPrototypes
+#ifdef LBX
+ ClientPtr client
+#else
+ register OsCommPtr /*oc*/
+#endif
+#endif
+);
+
+#ifdef LBX
+extern int LbxFlushClient();
+extern void LbxCloseClient();
+#endif /* LBX */
+
+static XtransConnInfo
+lookup_trans_conn (fd)
+ int fd;
+{
+ if (ListenTransFds)
+ {
+ int i;
+ for (i = 0; i < ListenTransCount; i++)
+ if (ListenTransFds[i] == fd)
+ return ListenTransConns[i];
+ }
+
+ return (NULL);
+}
+
+#ifdef XDMCP
+void XdmcpOpenDisplay(), XdmcpInit(), XdmcpReset(), XdmcpCloseDisplay();
+#endif
+
+/*****************
+ * CreateWellKnownSockets
+ * At initialization, create the sockets to listen on for new clients.
+ *****************/
+
+void
+CreateWellKnownSockets()
+{
+ int request, i;
+ int partial;
+ char port[20];
+
+ FD_ZERO(&AllSockets);
+ FD_ZERO(&AllClients);
+ FD_ZERO(&LastSelectMask);
+ FD_ZERO(&ClientsWithInput);
+
+#ifndef WIN32
+ for (i=0; i<MAXSOCKS; i++) ConnectionTranslation[i] = 0;
+#else
+ for (i=0; i<MAXFD; i++) ConnectionTranslation[i] = 0;
+#endif
+#ifdef XNO_SYSCONF /* should only be on FreeBSD 1.x and NetBSD 0.x */
+#undef _SC_OPEN_MAX
+#endif
+#ifdef _SC_OPEN_MAX
+ lastfdesc = sysconf(_SC_OPEN_MAX) - 1;
+#else
+#ifdef hpux
+ lastfdesc = _NFILE - 1;
+#else
+ lastfdesc = getdtablesize() - 1;
+#endif
+#endif
+
+ if (lastfdesc > MAXSOCKS)
+ {
+ lastfdesc = MAXSOCKS;
+ }
+
+ FD_ZERO (&WellKnownConnections);
+
+ sprintf (port, "%d", atoi (display));
+
+ if ((_XSERVTransMakeAllCOTSServerListeners (port, &partial,
+ &ListenTransCount, &ListenTransConns) >= 0) &&
+ (ListenTransCount >= 1))
+ {
+ if (!PartialNetwork && partial)
+ {
+ FatalError ("Failed to establish all listening sockets");
+ }
+ else
+ {
+ ListenTransFds = (int *) malloc (ListenTransCount * sizeof (int));
+
+ for (i = 0; i < ListenTransCount; i++)
+ {
+ int fd = _XSERVTransGetConnectionNumber (ListenTransConns[i]);
+
+ ListenTransFds[i] = fd;
+ FD_SET (fd, &WellKnownConnections);
+
+ if (!_XSERVTransIsLocal (ListenTransConns[i]))
+ {
+ DefineSelf (fd);
+ }
+ }
+ }
+ }
+
+ if (!XFD_ANYSET (&WellKnownConnections))
+ FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running");
+#ifndef WIN32
+ OsSignal (SIGPIPE, SIG_IGN);
+ OsSignal (SIGHUP, AutoResetServer);
+#endif
+ OsSignal (SIGINT, GiveUp);
+ OsSignal (SIGTERM, GiveUp);
+ XFD_COPYSET (&WellKnownConnections, &AllSockets);
+ ResetHosts(display);
+ /*
+ * Magic: If SIGUSR1 was set to SIG_IGN when
+ * the server started, assume that either
+ *
+ * a- The parent process is ignoring SIGUSR1
+ *
+ * or
+ *
+ * b- The parent process is expecting a SIGUSR1
+ * when the server is ready to accept connections
+ *
+ * In the first case, the signal will be harmless,
+ * in the second case, the signal will be quite
+ * useful
+ */
+#ifndef WIN32
+ if (OsSignal (SIGUSR1, SIG_IGN) == SIG_IGN)
+ RunFromSmartParent = TRUE;
+ ParentProcess = getppid ();
+ if (RunFromSmartParent) {
+ if (ParentProcess > 0) {
+ kill (ParentProcess, SIGUSR1);
+ }
+ }
+#endif
+#ifdef XDMCP
+ XdmcpInit ();
+#endif
+}
+
+void
+ResetWellKnownSockets ()
+{
+ int i;
+
+ ResetOsBuffers();
+
+ for (i = 0; i < ListenTransCount; i++)
+ {
+ int status = _XSERVTransResetListener (ListenTransConns[i]);
+
+ if (status != TRANS_RESET_NOOP)
+ {
+ if (status == TRANS_RESET_FAILURE)
+ {
+ /*
+ * ListenTransConns[i] freed by xtrans.
+ * Remove it from out list.
+ */
+
+ FD_CLR (ListenTransFds[i], &WellKnownConnections);
+ ListenTransFds[i] = ListenTransFds[ListenTransCount - 1];
+ ListenTransConns[i] = ListenTransConns[ListenTransCount - 1];
+ ListenTransCount -= 1;
+ i -= 1;
+ }
+ else if (status == TRANS_RESET_NEW_FD)
+ {
+ /*
+ * A new file descriptor was allocated (the old one was closed)
+ */
+
+ int newfd = _XSERVTransGetConnectionNumber (ListenTransConns[i]);
+
+ FD_CLR (ListenTransFds[i], &WellKnownConnections);
+ ListenTransFds[i] = newfd;
+ FD_SET(newfd, &WellKnownConnections);
+ }
+ }
+ }
+
+ ResetAuthorization ();
+ ResetHosts(display);
+ /*
+ * See above in CreateWellKnownSockets about SIGUSR1
+ */
+#ifndef WIN32
+ if (RunFromSmartParent) {
+ if (ParentProcess > 0) {
+ kill (ParentProcess, SIGUSR1);
+ }
+ }
+#endif
+ /*
+ * restart XDMCP
+ */
+#ifdef XDMCP
+ XdmcpReset ();
+#endif
+}
+
+static void
+AuthAudit (client, letin, saddr, len, proto_n, auth_proto, auth_id)
+ ClientPtr client;
+ Bool letin;
+ struct sockaddr *saddr;
+ int len;
+ unsigned short proto_n;
+ char *auth_proto;
+ int auth_id;
+{
+ char addr[128];
+ char *out = addr;
+
+ if (!((OsCommPtr)client->osPrivate)->trans_conn) {
+ strcpy(addr, "LBX proxy at ");
+ out += strlen(addr);
+ }
+ if (!len)
+ strcpy(out, "local host");
+ else
+ switch (saddr->sa_family)
+ {
+ case AF_UNSPEC:
+#if defined(UNIXCONN) || defined(LOCALCONN)
+ case AF_UNIX:
+#endif
+ strcpy(out, "local host");
+ break;
+#if defined(TCPCONN) || defined(STREAMSCONN)
+ case AF_INET:
+ sprintf(out, "IP %s port %d",
+ inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr),
+ ((struct sockaddr_in *) saddr)->sin_port);
+ break;
+#endif
+#ifdef DNETCONN
+ case AF_DECnet:
+ sprintf(out, "DN %s",
+ dnet_ntoa(&((struct sockaddr_dn *) saddr)->sdn_add));
+ break;
+#endif
+ default:
+ strcpy(out, "unknown address");
+ }
+ if (letin)
+ AuditF("client %d connected from %s\n", client->index, addr);
+ else
+ AuditF("client %d rejected from %s\n", client->index, addr);
+ if (proto_n)
+ AuditF(" Auth name: %.*s ID: %d\n", proto_n, auth_proto, auth_id);
+}
+
+XID
+AuthorizationIDOfClient(client)
+ ClientPtr client;
+{
+ if (client->osPrivate)
+ return ((OsCommPtr)client->osPrivate)->auth_id;
+ else
+ return None;
+}
+
+
+/*****************************************************************
+ * ClientAuthorized
+ *
+ * Sent by the client at connection setup:
+ * typedef struct _xConnClientPrefix {
+ * CARD8 byteOrder;
+ * BYTE pad;
+ * CARD16 majorVersion, minorVersion;
+ * CARD16 nbytesAuthProto;
+ * CARD16 nbytesAuthString;
+ * } xConnClientPrefix;
+ *
+ * It is hoped that eventually one protocol will be agreed upon. In the
+ * mean time, a server that implements a different protocol than the
+ * client expects, or a server that only implements the host-based
+ * mechanism, will simply ignore this information.
+ *
+ *****************************************************************/
+
+char *
+ClientAuthorized(client, proto_n, auth_proto, string_n, auth_string)
+ ClientPtr client;
+ char *auth_proto, *auth_string;
+ unsigned int proto_n, string_n;
+{
+ register OsCommPtr priv;
+ Xtransaddr *from = NULL;
+ int family;
+ int fromlen;
+ XID auth_id;
+ char *reason = NULL;
+ XtransConnInfo trans_conn;
+ int restore_trans_conn = 0;
+ ClientPtr lbxpc;
+
+ priv = (OsCommPtr)client->osPrivate;
+ trans_conn = priv->trans_conn;
+
+#ifdef LBX
+ if (!trans_conn) {
+ /*
+ * Since trans_conn is NULL, this must be a proxy's client for
+ * which we have NO address. Therefore, we will temporarily
+ * set the client's trans_conn to the proxy's trans_conn and
+ * after CheckAuthorization the client's trans_conn will be
+ * restored.
+ *
+ * If XDM-AUTHORIZATION-1 is being used, CheckAuthorization
+ * will eventually call XdmAuthorizationValidate and this
+ * later function may use the client's trans_conn to get the
+ * client's address. Since a XDM-AUTH-1 auth string includes
+ * the client's address, this address is compared to the address
+ * in the client's trans_conn. If the proxy and client are
+ * on the same host, the comparison will fail; otherwise the
+ * comparison will fail and the client will not be authorized
+ * to connect to the server.
+ *
+ * The basis for this additional code is to prevent a
+ * NULL pointer dereference of the client's trans_conn.
+ * The fundamental problem - the fact that the client's
+ * trans_conn is NULL - is because the NewClient
+ * request in version 1.0 of the LBX protocol does not
+ * send the client's address to the server. When the
+ * spec is changed and the client's address is sent to
+ * server in the NewClient request, this additional code
+ * should be removed.
+ *
+ * See defect number XWSog08218 for more information.
+ */
+ lbxpc = LbxProxyClient(priv->proxy);
+ trans_conn = ((OsCommPtr)lbxpc->osPrivate)->trans_conn;
+ priv->trans_conn = trans_conn;
+ restore_trans_conn = 1;
+ }
+#endif
+
+ auth_id = CheckAuthorization (proto_n, auth_proto,
+ string_n, auth_string, client, &reason);
+
+#ifdef LBX
+ if (restore_trans_conn) {
+ /*
+ * Restore client's trans_conn state
+ */
+ priv = (OsCommPtr)client->osPrivate;
+ priv->trans_conn = NULL;
+
+ trans_conn = NULL;
+ }
+
+#endif
+
+#ifdef LBX
+ if (!trans_conn) {
+ /*
+ * Use the proxy's trans_conn
+ */
+ trans_conn = ((OsCommPtr)lbxpc->osPrivate)->trans_conn;
+ if (auth_id == (XID) ~0L && !GetAccessControl())
+ auth_id = ((OsCommPtr)lbxpc->osPrivate)->auth_id;
+#ifdef XCSECURITY
+ else if (auth_id != (XID) ~0L && !SecuritySameLevel(lbxpc, auth_id)) {
+ auth_id = (XID) ~0L;
+ reason = "Client trust level differs from that of LBX Proxy";
+ }
+#endif
+ }
+#endif
+ if (auth_id == (XID) ~0L)
+ {
+ if (
+#ifdef XCSECURITY
+ (proto_n == 0 ||
+ strncmp (auth_proto, XSecurityAuthorizationName, proto_n) != 0) &&
+#endif
+ _XSERVTransGetPeerAddr (trans_conn,
+ &family, &fromlen, &from) != -1)
+ {
+ if (
+#ifdef LBX
+ !priv->trans_conn ||
+#endif
+ InvalidHost ((struct sockaddr *) from, fromlen))
+ AuthAudit(client, FALSE, (struct sockaddr *) from,
+ fromlen, proto_n, auth_proto, auth_id);
+ else
+ {
+ auth_id = (XID) 0;
+ if (auditTrailLevel > 1)
+ AuthAudit(client, TRUE,
+ (struct sockaddr *) from, fromlen,
+ proto_n, auth_proto, auth_id);
+ }
+
+ free ((char *) from);
+ }
+
+ if (auth_id == (XID) ~0L)
+ if (reason)
+ return reason;
+ else
+ return "Client is not authorized to connect to Server";
+ }
+ else if (auditTrailLevel > 1)
+ {
+ if (_XSERVTransGetPeerAddr (trans_conn,
+ &family, &fromlen, &from) != -1)
+ {
+ AuthAudit(client, TRUE, (struct sockaddr *) from, fromlen,
+ proto_n, auth_proto, auth_id);
+
+ free ((char *) from);
+ }
+ }
+ priv->auth_id = auth_id;
+ priv->conn_time = 0;
+
+#ifdef XDMCP
+ /* indicate to Xdmcp protocol that we've opened new client */
+ XdmcpOpenDisplay(priv->fd);
+#endif /* XDMCP */
+#ifdef XAPPGROUP
+ if (ClientStateCallback)
+ XagCallClientStateChange (client);
+#endif
+ /* At this point, if the client is authorized to change the access control
+ * list, we should getpeername() information, and add the client to
+ * the selfhosts list. It's not really the host machine, but the
+ * true purpose of the selfhosts list is to see who may change the
+ * access control list.
+ */
+ return((char *)NULL);
+}
+
+static ClientPtr
+#ifdef LBX
+AllocNewConnection (trans_conn, fd, conn_time, Flush, Close, proxy)
+#else
+AllocNewConnection (trans_conn, fd, conn_time)
+#endif
+ XtransConnInfo trans_conn;
+ int fd;
+ CARD32 conn_time;
+#ifdef LBX
+ int (*Flush)();
+ void (*Close)();
+ LbxProxyPtr proxy;
+#endif
+{
+ OsCommPtr oc;
+ ClientPtr client;
+
+ if (
+#ifdef LBX
+ trans_conn &&
+#endif
+#ifndef WIN32
+ fd >= lastfdesc
+#else
+ XFD_SETCOUNT(&AllClients) >= MaxClients
+#endif
+ )
+ return NullClient;
+ oc = (OsCommPtr)xalloc(sizeof(OsCommRec));
+ if (!oc)
+ return NullClient;
+ oc->trans_conn = trans_conn;
+ oc->fd = fd;
+ oc->input = (ConnectionInputPtr)NULL;
+ oc->output = (ConnectionOutputPtr)NULL;
+ oc->auth_id = None;
+ oc->conn_time = conn_time;
+#ifdef LBX
+ oc->proxy = proxy;
+ oc->Flush = Flush;
+ oc->Close = Close;
+ oc->largereq = (ConnectionInputPtr) NULL;
+#endif
+ if (!(client = NextAvailableClient((pointer)oc)))
+ {
+ xfree (oc);
+ return NullClient;
+ }
+#ifdef LBX
+ if (trans_conn)
+#endif
+ {
+ ConnectionTranslation[fd] = client->index;
+ if (GrabInProgress)
+ {
+ FD_SET(fd, &SavedAllClients);
+ FD_SET(fd, &SavedAllSockets);
+ }
+ else
+ {
+ FD_SET(fd, &AllClients);
+ FD_SET(fd, &AllSockets);
+ }
+ }
+ return client;
+}
+
+#ifdef LBX
+
+int
+ClientConnectionNumber (client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr) client->osPrivate;
+
+ return oc->fd;
+}
+
+ClientPtr
+AllocLbxClientConnection (client, proxy)
+ ClientPtr client;
+ LbxProxyPtr proxy;
+{
+ OsCommPtr oc = (OsCommPtr) client->osPrivate;
+
+ return AllocNewConnection ((XtransConnInfo)NULL, oc->fd, GetTimeInMillis(),
+ LbxFlushClient, LbxCloseClient, proxy);
+}
+
+void
+LbxProxyConnection (client, proxy)
+ ClientPtr client;
+ LbxProxyPtr proxy;
+{
+ OsCommPtr oc = (OsCommPtr) client->osPrivate;
+
+ FlushClient(client, oc, (char *)NULL, 0);
+ oc->proxy = proxy;
+ oc->Flush = LbxFlushClient;
+ oc->Close = LbxCloseClient;
+ LbxPrimeInput(client, proxy);
+}
+
+#endif
+
+/*****************
+ * EstablishNewConnections
+ * If anyone is waiting on listened sockets, accept them.
+ * Returns a mask with indices of new clients. Updates AllClients
+ * and AllSockets.
+ *****************/
+
+/*ARGSUSED*/
+Bool
+EstablishNewConnections(clientUnused, closure)
+ ClientPtr clientUnused;
+ pointer closure;
+{
+#ifndef WIN32
+ fd_mask readyconnections; /* mask of listeners that are ready */
+#else
+ fd_set readyconnections; /* set of listeners that are ready */
+#endif
+ int curconn; /* fd of listener that's ready */
+ register int newconn; /* fd of new client */
+ CARD32 connect_time;
+ register int i;
+ register ClientPtr client;
+ register OsCommPtr oc;
+ fd_set tmask;
+
+ XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections);
+#ifndef WIN32
+ readyconnections = tmask.fds_bits[0];
+ if (!readyconnections)
+ return TRUE;
+#else
+ XFD_COPYSET(&tmask, &readyconnections);
+ if (!XFD_ANYSET(&readyconnections))
+ return TRUE;
+#endif
+ connect_time = GetTimeInMillis();
+ /* kill off stragglers */
+ for (i=1; i<currentMaxClients; i++)
+ {
+ if (client = clients[i])
+ {
+ oc = (OsCommPtr)(client->osPrivate);
+ if (oc && (oc->conn_time != 0) &&
+ (connect_time - oc->conn_time) >= TimeOutValue ||
+ client->noClientException != Success && !client->clientGone)
+ CloseDownClient(client);
+ }
+ }
+#ifndef WIN32
+ while (readyconnections)
+#else
+ for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++)
+#endif
+ {
+ XtransConnInfo trans_conn, new_trans_conn;
+ int status;
+
+#ifndef WIN32
+ curconn = ffs (readyconnections) - 1;
+ readyconnections &= ~(1 << curconn);
+#else
+ curconn = XFD_FD(&readyconnections, i);
+#endif
+
+ if ((trans_conn = lookup_trans_conn (curconn)) == NULL)
+ continue;
+
+ if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL)
+ continue;
+
+ newconn = _XSERVTransGetConnectionNumber (new_trans_conn);
+
+ if (newconn < lastfdesc)
+ {
+ int clientid;
+ clientid = ConnectionTranslation[newconn];
+ if(clientid && (client = clients[clientid]))
+ CloseDownClient(client);
+ }
+
+ _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1);
+
+ if (!AllocNewConnection (new_trans_conn, newconn, connect_time
+#ifdef LBX
+ , StandardFlushClient,
+ CloseDownFileDescriptor, (LbxProxyPtr)NULL
+#endif
+ ))
+ {
+ ErrorConnMax(new_trans_conn);
+ _XSERVTransClose(new_trans_conn);
+ }
+ }
+ return TRUE;
+}
+
+#define NOROOM "Maximum number of clients reached"
+
+/************
+ * ErrorConnMax
+ * Fail a connection due to lack of client or file descriptor space
+ ************/
+
+static void
+ErrorConnMax(trans_conn)
+XtransConnInfo trans_conn;
+{
+ register int fd = _XSERVTransGetConnectionNumber (trans_conn);
+ xConnSetupPrefix csp;
+ char pad[3];
+ struct iovec iov[3];
+ char byteOrder = 0;
+ int whichbyte = 1;
+ struct timeval waittime;
+ fd_set mask;
+
+ /* if these seems like a lot of trouble to go to, it probably is */
+ waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND;
+ waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) *
+ (1000000 / MILLI_PER_SECOND);
+ FD_ZERO(&mask);
+ FD_SET(fd, &mask);
+ (void)Select(fd + 1, &mask, NULL, NULL, &waittime);
+ /* try to read the byte-order of the connection */
+ (void)_XSERVTransRead(trans_conn, &byteOrder, 1);
+ if ((byteOrder == 'l') || (byteOrder == 'B'))
+ {
+ csp.success = xFalse;
+ csp.lengthReason = sizeof(NOROOM) - 1;
+ csp.length = (sizeof(NOROOM) + 2) >> 2;
+ csp.majorVersion = X_PROTOCOL;
+ csp.minorVersion = X_PROTOCOL_REVISION;
+ if (((*(char *) &whichbyte) && (byteOrder == 'B')) ||
+ (!(*(char *) &whichbyte) && (byteOrder == 'l')))
+ {
+ swaps(&csp.majorVersion, whichbyte);
+ swaps(&csp.minorVersion, whichbyte);
+ swaps(&csp.length, whichbyte);
+ }
+ iov[0].iov_len = sz_xConnSetupPrefix;
+ iov[0].iov_base = (char *) &csp;
+ iov[1].iov_len = csp.lengthReason;
+ iov[1].iov_base = NOROOM;
+ iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3;
+ iov[2].iov_base = pad;
+ (void)_XSERVTransWritev(trans_conn, iov, 3);
+ }
+}
+
+/************
+ * CloseDownFileDescriptor:
+ * Remove this file descriptor and it's I/O buffers, etc.
+ ************/
+
+#ifdef LBX
+void
+CloseDownFileDescriptor(client)
+ ClientPtr client;
+#else
+static void
+CloseDownFileDescriptor(oc)
+ register OsCommPtr oc;
+#endif
+{
+#ifdef LBX
+ register OsCommPtr oc = (OsCommPtr) client->osPrivate;
+#endif
+ int connection = oc->fd;
+
+ if (oc->trans_conn) {
+ _XSERVTransDisconnect(oc->trans_conn);
+ _XSERVTransClose(oc->trans_conn);
+ }
+#ifdef LBX
+ ConnectionTranslation[connection] = 0;
+#else
+ FreeOsBuffers(oc);
+#endif
+ FD_CLR(connection, &AllSockets);
+ FD_CLR(connection, &AllClients);
+ FD_CLR(connection, &ClientsWithInput);
+ FD_CLR(connection, &GrabImperviousClients);
+ if (GrabInProgress)
+ {
+ FD_CLR(connection, &SavedAllSockets);
+ FD_CLR(connection, &SavedAllClients);
+ FD_CLR(connection, &SavedClientsWithInput);
+ }
+ FD_CLR(connection, &ClientsWriteBlocked);
+ if (!XFD_ANYSET(&ClientsWriteBlocked))
+ AnyClientsWriteBlocked = FALSE;
+ FD_CLR(connection, &OutputPending);
+#ifndef LBX
+ xfree(oc);
+#endif
+}
+
+/*****************
+ * CheckConections
+ * Some connection has died, go find which one and shut it down
+ * The file descriptor has been closed, but is still in AllClients.
+ * If would truly be wonderful if select() would put the bogus
+ * file descriptors in the exception mask, but nooooo. So we have
+ * to check each and every socket individually.
+ *****************/
+
+void
+CheckConnections()
+{
+#ifndef WIN32
+ fd_mask mask;
+#endif
+ fd_set tmask;
+ register int curclient, curoff;
+ int i;
+ struct timeval notime;
+ int r;
+#ifdef WIN32
+ fd_set savedAllClients;
+#endif
+
+ notime.tv_sec = 0;
+ notime.tv_usec = 0;
+
+#ifndef WIN32
+ for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++)
+ {
+ mask = AllClients.fds_bits[i];
+ while (mask)
+ {
+ curoff = ffs (mask) - 1;
+ curclient = curoff + (i << 5);
+ FD_ZERO(&tmask);
+ FD_SET(curclient, &tmask);
+ r = Select (curclient + 1, &tmask, NULL, NULL, &notime);
+ if (r < 0)
+ CloseDownClient(clients[ConnectionTranslation[curclient]]);
+ mask &= ~(1 << curoff);
+ }
+ }
+#else
+ XFD_COPYSET(&AllClients, &savedAllClients);
+ for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++)
+ {
+ curclient = XFD_FD(&savedAllClients, i);
+ FD_ZERO(&tmask);
+ FD_SET(curclient, &tmask);
+ r = Select (curclient + 1, &tmask, NULL, NULL, &notime);
+ if (r < 0)
+ CloseDownClient(clients[ConnectionTranslation[curclient]]);
+ }
+#endif
+}
+
+
+/*****************
+ * CloseDownConnection
+ * Delete client from AllClients and free resources
+ *****************/
+
+void
+CloseDownConnection(client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+
+ if (oc->output && oc->output->count)
+ FlushClient(client, oc, (char *)NULL, 0);
+#ifdef XDMCP
+ XdmcpCloseDisplay(oc->fd);
+#endif
+#ifndef LBX
+ CloseDownFileDescriptor(oc);
+#else
+ (*oc->Close) (client);
+ FreeOsBuffers(oc);
+ xfree(oc);
+#endif
+ client->osPrivate = (pointer)NULL;
+ if (auditTrailLevel > 1)
+ AuditF("client %d disconnected\n", client->index);
+}
+
+
+AddEnabledDevice(fd)
+ int fd;
+{
+ FD_SET(fd, &EnabledDevices);
+ FD_SET(fd, &AllSockets);
+}
+
+
+RemoveEnabledDevice(fd)
+ int fd;
+{
+ FD_CLR(fd, &EnabledDevices);
+ FD_CLR(fd, &AllSockets);
+}
+
+/*****************
+ * OnlyListenToOneClient:
+ * Only accept requests from one client. Continue to handle new
+ * connections, but don't take any protocol requests from the new
+ * ones. Note that if GrabInProgress is set, EstablishNewConnections
+ * needs to put new clients into SavedAllSockets and SavedAllClients.
+ * Note also that there is no timeout for this in the protocol.
+ * This routine is "undone" by ListenToAllClients()
+ *****************/
+
+OnlyListenToOneClient(client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ int connection = oc->fd;
+
+ if (! GrabInProgress)
+ {
+ XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput);
+ XFD_ANDSET(&ClientsWithInput,
+ &ClientsWithInput, &GrabImperviousClients);
+ if (FD_ISSET(connection, &SavedClientsWithInput))
+ {
+ FD_CLR(connection, &SavedClientsWithInput);
+ FD_SET(connection, &ClientsWithInput);
+ }
+ XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients);
+ XFD_COPYSET(&AllSockets, &SavedAllSockets);
+ XFD_COPYSET(&AllClients, &SavedAllClients);
+ XFD_UNSET(&AllSockets, &AllClients);
+ XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients);
+ FD_SET(connection, &AllClients);
+ XFD_ORSET(&AllSockets, &AllSockets, &AllClients);
+ GrabInProgress = client->index;
+ }
+}
+
+/****************
+ * ListenToAllClients:
+ * Undoes OnlyListentToOneClient()
+ ****************/
+
+ListenToAllClients()
+{
+ if (GrabInProgress)
+ {
+ XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets);
+ XFD_ORSET(&AllClients, &AllClients, &SavedAllClients);
+ XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput);
+ GrabInProgress = 0;
+ }
+}
+
+/****************
+ * IgnoreClient
+ * Removes one client from input masks.
+ * Must have cooresponding call to AttendClient.
+ ****************/
+
+IgnoreClient (client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ int connection = oc->fd;
+#ifdef LBX
+ LbxClientPtr lbxClient = LbxClient(client);
+#endif
+
+ isItTimeToYield = TRUE;
+#ifdef LBX
+ if (lbxClient) {
+ lbxClient->ignored = TRUE;
+ return;
+ }
+#endif
+ if (!GrabInProgress || FD_ISSET(connection, &AllClients))
+ {
+ if (FD_ISSET (connection, &ClientsWithInput))
+ FD_SET(connection, &IgnoredClientsWithInput);
+ else
+ FD_CLR(connection, &IgnoredClientsWithInput);
+ FD_CLR(connection, &ClientsWithInput);
+ FD_CLR(connection, &AllSockets);
+ FD_CLR(connection, &AllClients);
+ FD_CLR(connection, &LastSelectMask);
+ }
+ else
+ {
+ if (FD_ISSET (connection, &SavedClientsWithInput))
+ FD_SET(connection, &IgnoredClientsWithInput);
+ else
+ FD_CLR(connection, &IgnoredClientsWithInput);
+ FD_CLR(connection, &SavedClientsWithInput);
+ FD_CLR(connection, &SavedAllSockets);
+ FD_CLR(connection, &SavedAllClients);
+ }
+}
+
+/****************
+ * AttendClient
+ * Adds one client back into the input masks.
+ ****************/
+
+AttendClient (client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ int connection = oc->fd;
+#ifdef LBX
+ LbxClientPtr lbxClient = LbxClient(client);
+
+ if (lbxClient) {
+ lbxClient->ignored = FALSE;
+ return;
+ }
+#endif
+ if (!GrabInProgress || GrabInProgress == client->index ||
+ FD_ISSET(connection, &GrabImperviousClients))
+ {
+ FD_SET(connection, &AllClients);
+ FD_SET(connection, &AllSockets);
+ FD_SET(connection, &LastSelectMask);
+ if (FD_ISSET (connection, &IgnoredClientsWithInput))
+ FD_SET(connection, &ClientsWithInput);
+ }
+ else
+ {
+ FD_SET(connection, &SavedAllClients);
+ FD_SET(connection, &SavedAllSockets);
+ if (FD_ISSET(connection, &IgnoredClientsWithInput))
+ FD_SET(connection, &SavedClientsWithInput);
+ }
+}
+
+/* make client impervious to grabs; assume only executing client calls this */
+
+MakeClientGrabImpervious(client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ int connection = oc->fd;
+
+ FD_SET(connection, &GrabImperviousClients);
+
+ if (ServerGrabCallback)
+ {
+ ServerGrabInfoRec grabinfo;
+ grabinfo.client = client;
+ grabinfo.grabstate = CLIENT_IMPERVIOUS;
+ CallCallbacks(&ServerGrabCallback, &grabinfo);
+ }
+}
+
+/* make client pervious to grabs; assume only executing client calls this */
+
+MakeClientGrabPervious(client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ int connection = oc->fd;
+
+ FD_CLR(connection, &GrabImperviousClients);
+ if (GrabInProgress && (GrabInProgress != client->index))
+ {
+ if (FD_ISSET(connection, &ClientsWithInput))
+ {
+ FD_SET(connection, &SavedClientsWithInput);
+ FD_CLR(connection, &ClientsWithInput);
+ }
+ FD_CLR(connection, &AllSockets);
+ FD_CLR(connection, &AllClients);
+ isItTimeToYield = TRUE;
+ }
+
+ if (ServerGrabCallback)
+ {
+ ServerGrabInfoRec grabinfo;
+ grabinfo.client = client;
+ grabinfo.grabstate = CLIENT_PERVIOUS;
+ CallCallbacks(&ServerGrabCallback, &grabinfo);
+ }
+}
+
+#ifdef AIXV3
+
+static fd_set pendingActiveClients;
+static BOOL reallyGrabbed;
+
+/****************
+* DontListenToAnybody:
+* Don't listen to requests from any clients. Continue to handle new
+* connections, but don't take any protocol requests from anybody.
+* We have to take care if there is already a grab in progress, though.
+* Undone by PayAttentionToClientsAgain. We also have to be careful
+* not to accept any more input from the currently dispatched client.
+* we do this be telling dispatch it is time to yield.
+
+* We call this when the server loses access to the glass
+* (user hot-keys away). This looks like a grab by the
+* server itself, but gets a little tricky if there is already
+* a grab in progress.
+******************/
+
+void
+DontListenToAnybody()
+{
+ if (!GrabInProgress)
+ {
+ XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput);
+ XFD_COPYSET(&AllSockets, &SavedAllSockets);
+ XFD_COPYSET(&AllClients, &SavedAllClients);
+ GrabInProgress = TRUE;
+ reallyGrabbed = FALSE;
+ }
+ else
+ {
+ XFD_COPYSET(&AllClients, &pendingActiveClients);
+ reallyGrabbed = TRUE;
+ }
+ FD_ZERO(&ClientsWithInput);
+ XFD_UNSET(&AllSockets, &AllClients);
+ FD_ZERO(&AllClients);
+ isItTimeToYield = TRUE;
+}
+
+void
+PayAttentionToClientsAgain()
+{
+ if (reallyGrabbed)
+ {
+ XFD_ORSET(&AllSockets, &AllSockets, &pendingActiveClients);
+ XFD_ORSET(&AllClients, &AllClients, &pendingActiveClients);
+ }
+ else
+ {
+ ListenToAllClients();
+ }
+ reallyGrabbed = FALSE;
+}
+
+#endif
diff --git a/os/io.c b/os/io.c
new file mode 100644
index 000000000..96bfd6885
--- /dev/null
+++ b/os/io.c
@@ -0,0 +1,1262 @@
+/***********************************************************
+
+Copyright 1987, 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.
+
+
+Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/* $Xorg: io.c,v 1.6 2001/02/09 02:05:23 xorgcvs Exp $ */
+/*****************************************************************
+ * i/o functions
+ *
+ * WriteToClient, ReadRequestFromClient
+ * InsertFakeRequest, ResetCurrentRequest
+ *
+ *****************************************************************/
+
+#ifdef WIN32
+#include <X11/Xwinsock.h>
+#endif
+#include <stdio.h>
+#include <X11/Xtrans.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+#include "Xmd.h"
+#include <errno.h>
+#ifndef WIN32
+#include <sys/uio.h>
+#endif
+#include "X.h"
+#define NEED_REPLIES
+#include "Xproto.h"
+#include "os.h"
+#include "Xpoll.h"
+#include "osdep.h"
+#include "opaque.h"
+#include "dixstruct.h"
+#include "misc.h"
+#ifdef LBX
+#include "lbxserve.h"
+#endif
+
+CallbackListPtr ReplyCallback;
+CallbackListPtr FlushCallback;
+
+/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
+ * systems are broken and return EWOULDBLOCK when they should return EAGAIN
+ */
+#if defined(EAGAIN) && defined(EWOULDBLOCK)
+#define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
+#else
+#ifdef EAGAIN
+#define ETEST(err) (err == EAGAIN)
+#else
+#define ETEST(err) (err == EWOULDBLOCK)
+#endif
+#endif
+
+extern fd_set ClientsWithInput, IgnoredClientsWithInput, AllClients;
+extern fd_set ClientsWriteBlocked;
+extern fd_set OutputPending;
+extern int ConnectionTranslation[];
+extern Bool NewOutputPending;
+extern Bool AnyClientsWriteBlocked;
+
+Bool CriticalOutputPending;
+int timesThisConnection = 0;
+ConnectionInputPtr FreeInputs = (ConnectionInputPtr)NULL;
+ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr)NULL;
+OsCommPtr AvailableInput = (OsCommPtr)NULL;
+
+#define get_req_len(req,cli) ((cli)->swapped ? \
+ lswaps((req)->length) : (req)->length)
+
+#ifdef BIGREQS
+#include "bigreqstr.h"
+
+#define get_big_req_len(req,cli) ((cli)->swapped ? \
+ lswapl(((xBigReq *)(req))->length) : \
+ ((xBigReq *)(req))->length)
+#endif
+
+#define MAX_TIMES_PER 10
+
+/*
+ * A lot of the code in this file manipulates a ConnectionInputPtr:
+ *
+ * -----------------------------------------------
+ * |------- bufcnt ------->| | |
+ * | |- gotnow ->| | |
+ * | |-------- needed ------>| |
+ * |-----------+--------- size --------+---------->|
+ * -----------------------------------------------
+ * ^ ^
+ * | |
+ * buffer bufptr
+ *
+ * buffer is a pointer to the start of the buffer.
+ * bufptr points to the start of the current request.
+ * bufcnt counts how many bytes are in the buffer.
+ * size is the size of the buffer in bytes.
+ *
+ * In several of the functions, gotnow and needed are local variables
+ * that do the following:
+ *
+ * gotnow is the number of bytes of the request that we're
+ * trying to read that are currently in the buffer.
+ * Typically, gotnow = (buffer + bufcnt) - bufptr
+ *
+ * needed = the length of the request that we're trying to
+ * read. Watch out: needed sometimes counts bytes and sometimes
+ * counts CARD32's.
+ */
+
+
+/*****************************************************************
+ * ReadRequestFromClient
+ * Returns one request in client->requestBuffer. The request
+ * length will be in client->req_len. Return status is:
+ *
+ * > 0 if successful, specifies length in bytes of the request
+ * = 0 if entire request is not yet available
+ * < 0 if client should be terminated
+ *
+ * The request returned must be contiguous so that it can be
+ * cast in the dispatcher to the correct request type. Because requests
+ * are variable length, ReadRequestFromClient() must look at the first 4
+ * or 8 bytes of a request to determine the length (the request length is
+ * in the 3rd and 4th bytes of the request unless it is a Big Request
+ * (see the Big Request Extension), in which case the 3rd and 4th bytes
+ * are zero and the following 4 bytes are the request length.
+ *
+ * Note: in order to make the server scheduler (WaitForSomething())
+ * "fair", the ClientsWithInput mask is used. This mask tells which
+ * clients have FULL requests left in their buffers. Clients with
+ * partial requests require a read. Basically, client buffers
+ * are drained before select() is called again. But, we can't keep
+ * reading from a client that is sending buckets of data (or has
+ * a partial request) because others clients need to be scheduled.
+ *****************************************************************/
+
+#define YieldControl() \
+ { isItTimeToYield = TRUE; \
+ timesThisConnection = 0; }
+#define YieldControlNoInput() \
+ { YieldControl(); \
+ FD_CLR(fd, &ClientsWithInput); }
+#define YieldControlDeath() \
+ { timesThisConnection = 0; }
+
+#ifdef hpux_not_tog
+#define LBX_NEED_OLD_SYMBOL_FOR_LOADABLES
+#endif
+
+#ifdef LBX
+#ifdef LBX_NEED_OLD_SYMBOL_FOR_LOADABLES
+#undef ReadRequestFromClient
+int
+ReadRequestFromClient(client)
+ ClientPtr client;
+{
+ return (*client->readRequest)(client);
+}
+#endif
+int
+StandardReadRequestFromClient(client)
+ ClientPtr client;
+#else
+int
+ReadRequestFromClient(client)
+ ClientPtr client;
+#endif
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ register ConnectionInputPtr oci = oc->input;
+ int fd = oc->fd;
+ register unsigned int gotnow, needed;
+ int result;
+ register xReq *request;
+ Bool need_header;
+#ifdef BIGREQS
+ Bool move_header;
+#endif
+
+ /* If an input buffer was empty, either free it if it is too big
+ * or link it into our list of free input buffers. This means that
+ * different clients can share the same input buffer (at different
+ * times). This was done to save memory.
+ */
+
+ if (AvailableInput)
+ {
+ if (AvailableInput != oc)
+ {
+ register ConnectionInputPtr aci = AvailableInput->input;
+ if (aci->size > BUFWATERMARK)
+ {
+ xfree(aci->buffer);
+ xfree(aci);
+ }
+ else
+ {
+ aci->next = FreeInputs;
+ FreeInputs = aci;
+ }
+ AvailableInput->input = (ConnectionInputPtr)NULL;
+ }
+ AvailableInput = (OsCommPtr)NULL;
+ }
+
+ /* make sure we have an input buffer */
+
+ if (!oci)
+ {
+ if (oci = FreeInputs)
+ {
+ FreeInputs = oci->next;
+ }
+ else if (!(oci = AllocateInputBuffer()))
+ {
+ YieldControlDeath();
+ return -1;
+ }
+ oc->input = oci;
+ }
+
+ /* advance to start of next request */
+
+ oci->bufptr += oci->lenLastReq;
+
+ need_header = FALSE;
+#ifdef BIGREQS
+ move_header = FALSE;
+#endif
+ gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
+ if (gotnow < sizeof(xReq))
+ {
+ /* We don't have an entire xReq yet. Can't tell how big
+ * the request will be until we get the whole xReq.
+ */
+ needed = sizeof(xReq);
+ need_header = TRUE;
+ }
+ else
+ {
+ /* We have a whole xReq. We can tell how big the whole
+ * request will be unless it is a Big Request.
+ */
+ request = (xReq *)oci->bufptr;
+ needed = get_req_len(request, client);
+#ifdef BIGREQS
+ if (!needed && client->big_requests)
+ {
+ /* It's a Big Request. */
+ move_header = TRUE;
+ if (gotnow < sizeof(xBigReq))
+ {
+ /* Still need more data to tell just how big. */
+ needed = sizeof(xBigReq) >> 2; /* needed is in CARD32s now */
+ need_header = TRUE;
+ }
+ else
+ needed = get_big_req_len(request, client);
+ }
+#endif
+ client->req_len = needed;
+ needed <<= 2; /* needed is in bytes now */
+ }
+ if (gotnow < needed)
+ {
+ /* Need to read more data, either so that we can get a
+ * complete xReq (if need_header is TRUE), a complete
+ * xBigReq (if move_header is TRUE), or the rest of the
+ * request (if need_header and move_header are both FALSE).
+ */
+
+ oci->lenLastReq = 0;
+ if (needed > MAXBUFSIZE)
+ {
+ /* request is too big for us to handle */
+ YieldControlDeath();
+ return -1;
+ }
+ if ((gotnow == 0) ||
+ ((oci->bufptr - oci->buffer + needed) > oci->size))
+ {
+ /* no data, or the request is too big to fit in the buffer */
+
+ if ((gotnow > 0) && (oci->bufptr != oci->buffer))
+ /* save the data we've already read */
+ memmove(oci->buffer, oci->bufptr, gotnow);
+ if (needed > oci->size)
+ {
+ /* make buffer bigger to accomodate request */
+ char *ibuf;
+
+ ibuf = (char *)xrealloc(oci->buffer, needed);
+ if (!ibuf)
+ {
+ YieldControlDeath();
+ return -1;
+ }
+ oci->size = needed;
+ oci->buffer = ibuf;
+ }
+ oci->bufptr = oci->buffer;
+ oci->bufcnt = gotnow;
+ }
+ /* XXX this is a workaround. This function is sometimes called
+ * after the trans_conn has been freed. In this case trans_conn
+ * will be null. Really ought to restructure things so that we
+ * never get here in those circumstances.
+ */
+ if (!oc->trans_conn)
+ {
+ /* treat as if an error occured on the read, which is what
+ * used to happen
+ */
+ YieldControlDeath();
+ return -1;
+ }
+#ifdef LBX
+ if (oc->proxy && oc->proxy->compHandle)
+ result = (*oc->proxy->streamOpts.streamCompRead)(fd,
+ (unsigned char *)oci->buffer + oci->bufcnt,
+ oci->size - oci->bufcnt);
+ else
+#endif
+ result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt,
+ oci->size - oci->bufcnt);
+ if (result <= 0)
+ {
+ if ((result < 0) && ETEST(errno))
+ {
+ YieldControlNoInput();
+ return 0;
+ }
+ YieldControlDeath();
+ return -1;
+ }
+ oci->bufcnt += result;
+ gotnow += result;
+ /* free up some space after huge requests */
+ if ((oci->size > BUFWATERMARK) &&
+ (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE))
+ {
+ char *ibuf;
+
+ ibuf = (char *)xrealloc(oci->buffer, BUFSIZE);
+ if (ibuf)
+ {
+ oci->size = BUFSIZE;
+ oci->buffer = ibuf;
+ oci->bufptr = ibuf + oci->bufcnt - gotnow;
+ }
+ }
+ if (need_header && gotnow >= needed)
+ {
+ /* We wanted an xReq, now we've gotten it. */
+ request = (xReq *)oci->bufptr;
+ needed = get_req_len(request, client);
+#ifdef BIGREQS
+ if (!needed && client->big_requests)
+ {
+ move_header = TRUE;
+ if (gotnow < sizeof(xBigReq))
+ needed = sizeof(xBigReq) >> 2;
+ else
+ needed = get_big_req_len(request, client);
+ }
+#endif
+ client->req_len = needed;
+ needed <<= 2;
+ }
+ if (gotnow < needed)
+ {
+ /* Still don't have enough; punt. */
+ YieldControlNoInput();
+ return 0;
+ }
+ }
+ if (needed == 0)
+ {
+#ifdef BIGREQS
+ if (client->big_requests)
+ needed = sizeof(xBigReq);
+ else
+#endif
+ needed = sizeof(xReq);
+ }
+ oci->lenLastReq = needed;
+
+ /*
+ * Check to see if client has at least one whole request in the
+ * buffer beyond the request we're returning to the caller.
+ * If there is only a partial request, treat like buffer
+ * is empty so that select() will be called again and other clients
+ * can get into the queue.
+ */
+
+ gotnow -= needed;
+ if (gotnow >= sizeof(xReq))
+ {
+ request = (xReq *)(oci->bufptr + needed);
+ if (gotnow >= (result = (get_req_len(request, client) << 2))
+#ifdef BIGREQS
+ && (result ||
+ (client->big_requests &&
+ (gotnow >= sizeof(xBigReq) &&
+ gotnow >= (get_big_req_len(request, client) << 2))))
+#endif
+ )
+ FD_SET(fd, &ClientsWithInput);
+ else
+ YieldControlNoInput();
+ }
+ else
+ {
+ if (!gotnow)
+ AvailableInput = oc;
+ YieldControlNoInput();
+ }
+ if (++timesThisConnection >= MAX_TIMES_PER)
+ YieldControl();
+#ifdef BIGREQS
+ if (move_header)
+ {
+ request = (xReq *)oci->bufptr;
+ oci->bufptr += (sizeof(xBigReq) - sizeof(xReq));
+ *(xReq *)oci->bufptr = *request;
+ oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq));
+ client->req_len -= (sizeof(xBigReq) - sizeof(xReq)) >> 2;
+ }
+#endif
+ client->requestBuffer = (pointer)oci->bufptr;
+ return needed;
+}
+
+/*****************************************************************
+ * InsertFakeRequest
+ * Splice a consed up (possibly partial) request in as the next request.
+ *
+ **********************/
+
+Bool
+InsertFakeRequest(client, data, count)
+ ClientPtr client;
+ char *data;
+ int count;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ register ConnectionInputPtr oci = oc->input;
+ int fd = oc->fd;
+ register int gotnow, moveup;
+
+ if (AvailableInput)
+ {
+ if (AvailableInput != oc)
+ {
+ register ConnectionInputPtr aci = AvailableInput->input;
+ if (aci->size > BUFWATERMARK)
+ {
+ xfree(aci->buffer);
+ xfree(aci);
+ }
+ else
+ {
+ aci->next = FreeInputs;
+ FreeInputs = aci;
+ }
+ AvailableInput->input = (ConnectionInputPtr)NULL;
+ }
+ AvailableInput = (OsCommPtr)NULL;
+ }
+ if (!oci)
+ {
+ if (oci = FreeInputs)
+ FreeInputs = oci->next;
+ else if (!(oci = AllocateInputBuffer()))
+ return FALSE;
+ oc->input = oci;
+ }
+ oci->bufptr += oci->lenLastReq;
+ oci->lenLastReq = 0;
+ gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
+ if ((gotnow + count) > oci->size)
+ {
+ char *ibuf;
+
+ ibuf = (char *)xrealloc(oci->buffer, gotnow + count);
+ if (!ibuf)
+ return(FALSE);
+ oci->size = gotnow + count;
+ oci->buffer = ibuf;
+ oci->bufptr = ibuf + oci->bufcnt - gotnow;
+ }
+ moveup = count - (oci->bufptr - oci->buffer);
+ if (moveup > 0)
+ {
+ if (gotnow > 0)
+ memmove(oci->bufptr + moveup, oci->bufptr, gotnow);
+ oci->bufptr += moveup;
+ oci->bufcnt += moveup;
+ }
+ memmove(oci->bufptr - count, data, count);
+ oci->bufptr -= count;
+ gotnow += count;
+ if ((gotnow >= sizeof(xReq)) &&
+ (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2)))
+ FD_SET(fd, &ClientsWithInput);
+ else
+ YieldControlNoInput();
+ return(TRUE);
+}
+
+/*****************************************************************
+ * ResetRequestFromClient
+ * Reset to reexecute the current request, and yield.
+ *
+ **********************/
+
+ResetCurrentRequest(client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ register ConnectionInputPtr oci = oc->input;
+ int fd = oc->fd;
+ register xReq *request;
+ int gotnow, needed;
+#ifdef LBX
+ Bool part;
+ LbxClientPtr lbxClient = LbxClient(client);
+
+ if (lbxClient) {
+ LbxSetForBlock(lbxClient);
+ if (!oci) {
+ AppendFakeRequest(client,
+ client->requestBuffer, client->req_len << 2);
+ return;
+ }
+ }
+#endif
+ if (AvailableInput == oc)
+ AvailableInput = (OsCommPtr)NULL;
+ oci->lenLastReq = 0;
+ gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
+ if (gotnow < sizeof(xReq))
+ {
+ YieldControlNoInput();
+ }
+ else
+ {
+ request = (xReq *)oci->bufptr;
+ needed = get_req_len(request, client);
+#ifdef BIGREQS
+ if (!needed && client->big_requests)
+ {
+ oci->bufptr -= sizeof(xBigReq) - sizeof(xReq);
+ *(xReq *)oci->bufptr = *request;
+ ((xBigReq *)oci->bufptr)->length = client->req_len;
+ if (client->swapped)
+ {
+ char n;
+ swapl(&((xBigReq *)oci->bufptr)->length, n);
+ }
+ }
+#endif
+ if (gotnow >= (needed << 2))
+ {
+ if (FD_ISSET(fd, &AllClients))
+ {
+ FD_SET(fd, &ClientsWithInput);
+ }
+ else
+ {
+ FD_SET(fd, &IgnoredClientsWithInput);
+ }
+ YieldControl();
+ }
+ else
+ YieldControlNoInput();
+ }
+}
+
+
+
+/*****************************************************************
+ * PeekNextRequest and SkipRequests were implemented to support DBE
+ * idioms, but can certainly be used outside of DBE. There are two
+ * related macros in os.h, ReqLen and CastxReq. See the porting
+ * layer document for more details.
+ *
+ **********************/
+
+
+/*****************************************************************
+ * PeekNextRequest
+ * lets you look ahead at the unexecuted requests in a
+ * client's request buffer.
+ *
+ * Note: this implementation of PeekNextRequest ignores the
+ * readmore parameter.
+ *
+ **********************/
+
+xReqPtr
+PeekNextRequest(req, client, readmore)
+ xReqPtr req; /* request we're starting from */
+ ClientPtr client; /* client whose requests we're skipping */
+ Bool readmore; /* attempt to read more if next request isn't there? */
+{
+ register ConnectionInputPtr oci = ((OsCommPtr)client->osPrivate)->input;
+ xReqPtr pnextreq;
+ int needed, gotnow, reqlen;
+
+ if (!oci) return NULL;
+
+ if (!req)
+ {
+ /* caller wants the request after the one currently being executed */
+ pnextreq = (xReqPtr)
+ (((CARD32 *)client->requestBuffer) + client->req_len);
+ }
+ else
+ {
+ /* caller wants the request after the one specified by req */
+ reqlen = get_req_len(req, client);
+#ifdef BIGREQS
+ if (!reqlen) reqlen = get_big_req_len(req, client);
+#endif
+ pnextreq = (xReqPtr)(((char *)req) + (reqlen << 2));
+ }
+
+ /* see how much of the next request we have available */
+
+ gotnow = oci->bufcnt - (((char *)pnextreq) - oci->buffer);
+
+ if (gotnow < sizeof(xReq))
+ return NULL;
+
+ needed = get_req_len(pnextreq, client) << 2;
+#ifdef BIGREQS
+ if (!needed)
+ {
+ /* it's a big request */
+ if (gotnow < sizeof(xBigReq))
+ return NULL;
+ needed = get_big_req_len(pnextreq, client) << 2;
+ }
+#endif
+
+ /* if we have less than we need, return NULL */
+
+ return (gotnow < needed) ? NULL : pnextreq;
+}
+
+/*****************************************************************
+ * SkipRequests
+ * lets you skip over some of the requests in a client's
+ * request buffer. Presumably the caller has used PeekNextRequest
+ * to examine the requests being skipped and has performed whatever
+ * actions they dictate.
+ *
+ **********************/
+
+CallbackListPtr SkippedRequestsCallback = NULL;
+
+void
+SkipRequests(req, client, numskipped)
+ xReqPtr req; /* last request being skipped */
+ ClientPtr client; /* client whose requests we're skipping */
+ int numskipped; /* how many requests we're skipping */
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ register ConnectionInputPtr oci = oc->input;
+ int reqlen;
+
+ /* see if anyone wants to snoop the skipped requests */
+
+ if (SkippedRequestsCallback)
+ {
+ SkippedRequestInfoRec skipinfo;
+ skipinfo.req = req;
+ skipinfo.client = client;
+ skipinfo.numskipped = numskipped;
+ CallCallbacks(&SkippedRequestsCallback, &skipinfo);
+ }
+
+ /* adjust the sequence number */
+ client->sequence += numskipped;
+
+ /* twiddle the oci to skip over the requests */
+
+ reqlen = get_req_len(req, client);
+#ifdef BIGREQS
+ if (!reqlen) reqlen = get_big_req_len(req, client);
+#endif
+ reqlen <<= 2;
+ oci->bufptr = (char *)req;
+ oci->lenLastReq = reqlen;
+
+ /* see if any requests left in the buffer */
+
+ if ( ((char *)req + reqlen) == (oci->buffer + oci->bufcnt) )
+ {
+ /* no requests; mark input buffer as available and client
+ * as having no input
+ */
+ int fd = oc->fd;
+ AvailableInput = oc;
+ YieldControlNoInput();
+ }
+}
+
+
+ /* lookup table for adding padding bytes to data that is read from
+ or written to the X socket. */
+static int padlength[4] = {0, 3, 2, 1};
+
+ /********************
+ * FlushAllOutput()
+ * Flush all clients with output. However, if some client still
+ * has input in the queue (more requests), then don't flush. This
+ * will prevent the output queue from being flushed every time around
+ * the round robin queue. Now, some say that it SHOULD be flushed
+ * every time around, but...
+ *
+ **********************/
+
+void
+FlushAllOutput()
+{
+ register int index, base, mask;
+ OsCommPtr oc;
+ register ClientPtr client;
+ Bool newoutput = NewOutputPending;
+#ifdef WIN32
+ fd_set newOutputPending;
+#endif
+
+ if (FlushCallback)
+ CallCallbacks(&FlushCallback, NULL);
+
+ if (!newoutput)
+ return;
+
+ /*
+ * It may be that some client still has critical output pending,
+ * but he is not yet ready to receive it anyway, so we will
+ * simply wait for the select to tell us when he's ready to receive.
+ */
+ CriticalOutputPending = FALSE;
+ NewOutputPending = FALSE;
+
+#ifndef WIN32
+ for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++)
+ {
+ mask = OutputPending.fds_bits[ base ];
+ OutputPending.fds_bits[ base ] = 0;
+ while (mask)
+ {
+ index = ffs(mask) - 1;
+ mask &= ~lowbit(mask);
+ if ((index = ConnectionTranslation[(base << 5) + index]) == 0)
+ continue;
+ client = clients[index];
+ if (client->clientGone)
+ continue;
+ oc = (OsCommPtr)client->osPrivate;
+ if (
+#ifdef LBX
+ !oc->proxy &&
+#endif
+ FD_ISSET(oc->fd, &ClientsWithInput))
+ {
+ FD_SET(oc->fd, &OutputPending); /* set the bit again */
+ NewOutputPending = TRUE;
+ }
+ else
+ (void)FlushClient(client, oc, (char *)NULL, 0);
+ }
+ }
+#else /* WIN32 */
+ FD_ZERO(&newOutputPending);
+ for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++)
+ {
+ index = XFD_FD(&OutputPending, base);
+ if ((index = ConnectionTranslation[index]) == 0)
+ continue;
+ client = clients[index];
+ if (client->clientGone)
+ continue;
+ oc = (OsCommPtr)client->osPrivate;
+ if (
+#ifdef LBX
+ !oc->proxy &&
+#endif
+ FD_ISSET(oc->fd, &ClientsWithInput))
+ {
+ FD_SET(oc->fd, &newOutputPending); /* set the bit again */
+ NewOutputPending = TRUE;
+ }
+ else
+ (void)FlushClient(client, oc, (char *)NULL, 0);
+ }
+ XFD_COPYSET(&newOutputPending, &OutputPending);
+#endif /* WIN32 */
+}
+
+void
+FlushIfCriticalOutputPending()
+{
+ if (CriticalOutputPending)
+ FlushAllOutput();
+}
+
+void
+SetCriticalOutputPending()
+{
+ CriticalOutputPending = TRUE;
+}
+
+/*****************
+ * WriteToClient
+ * Copies buf into ClientPtr.buf if it fits (with padding), else
+ * flushes ClientPtr.buf and buf to client. As of this writing,
+ * every use of WriteToClient is cast to void, and the result
+ * is ignored. Potentially, this could be used by requests
+ * that are sending several chunks of data and want to break
+ * out of a loop on error. Thus, we will leave the type of
+ * this routine as int.
+ *****************/
+
+int
+WriteToClient (who, count, buf)
+ ClientPtr who;
+ char *buf;
+ int count;
+{
+ OsCommPtr oc = (OsCommPtr)who->osPrivate;
+ register ConnectionOutputPtr oco = oc->output;
+ int padBytes;
+
+ if (!count)
+ return(0);
+
+ if (!oco)
+ {
+ if (oco = FreeOutputs)
+ {
+ FreeOutputs = oco->next;
+ }
+ else if (!(oco = AllocateOutputBuffer()))
+ {
+ if (oc->trans_conn) {
+ _XSERVTransDisconnect(oc->trans_conn);
+ _XSERVTransClose(oc->trans_conn);
+ oc->trans_conn = NULL;
+ }
+ MarkClientException(who);
+ return -1;
+ }
+ oc->output = oco;
+ }
+
+ padBytes = padlength[count & 3];
+
+ if(ReplyCallback)
+ {
+ ReplyInfoRec replyinfo;
+
+ replyinfo.client = who;
+ replyinfo.replyData = buf;
+ replyinfo.dataLenBytes = count + padBytes;
+ if (who->replyBytesRemaining)
+ { /* still sending data of an earlier reply */
+ who->replyBytesRemaining -= count + padBytes;
+ replyinfo.startOfReply = FALSE;
+ replyinfo.bytesRemaining = who->replyBytesRemaining;
+ CallCallbacks((&ReplyCallback), (pointer)&replyinfo);
+ }
+ else if (who->clientState == ClientStateRunning
+ && buf[0] == X_Reply)
+ { /* start of new reply */
+ CARD32 replylen;
+ unsigned long bytesleft;
+ char n;
+
+ replylen = ((xGenericReply *)buf)->length;
+ if (who->swapped)
+ swapl(&replylen, n);
+ bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes;
+ replyinfo.startOfReply = TRUE;
+ replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft;
+ CallCallbacks((&ReplyCallback), (pointer)&replyinfo);
+ }
+ }
+
+ if (oco->count + count + padBytes > oco->size)
+ {
+ FD_CLR(oc->fd, &OutputPending);
+ if(!XFD_ANYSET(&OutputPending)) {
+ CriticalOutputPending = FALSE;
+ NewOutputPending = FALSE;
+ }
+ return FlushClient(who, oc, buf, count);
+ }
+
+ NewOutputPending = TRUE;
+ FD_SET(oc->fd, &OutputPending);
+ memmove((char *)oco->buf + oco->count, buf, count);
+ oco->count += count + padBytes;
+ return(count);
+}
+
+ /********************
+ * FlushClient()
+ * If the client isn't keeping up with us, then we try to continue
+ * buffering the data and set the apropriate bit in ClientsWritable
+ * (which is used by WaitFor in the select). If the connection yields
+ * a permanent error, or we can't allocate any more space, we then
+ * close the connection.
+ *
+ **********************/
+
+#ifdef LBX
+#ifdef LBX_NEED_OLD_SYMBOL_FOR_LOADABLES
+#undef FlushClient
+int
+FlushClient(who, oc, extraBuf, extraCount)
+ ClientPtr who;
+ OsCommPtr oc;
+ char *extraBuf;
+ int extraCount;
+{
+ return (*oc->Flush)(who, oc, extraBuf, extraCount);
+}
+#endif
+int
+StandardFlushClient(who, oc, extraBuf, extraCount)
+#else
+int
+FlushClient(who, oc, extraBuf, extraCount)
+#endif
+ ClientPtr who;
+ OsCommPtr oc;
+ char *extraBuf;
+ int extraCount; /* do not modify... returned below */
+{
+ register ConnectionOutputPtr oco = oc->output;
+ int connection = oc->fd;
+ XtransConnInfo trans_conn = oc->trans_conn;
+ struct iovec iov[3];
+ static char padBuffer[3];
+ long written;
+ long padsize;
+ long notWritten;
+ long todo;
+
+ if (!oco)
+ return 0;
+ written = 0;
+ padsize = padlength[extraCount & 3];
+ notWritten = oco->count + extraCount + padsize;
+ todo = notWritten;
+ while (notWritten) {
+ long before = written; /* amount of whole thing written */
+ long remain = todo; /* amount to try this time, <= notWritten */
+ int i = 0;
+ long len;
+
+ /* You could be very general here and have "in" and "out" iovecs
+ * and write a loop without using a macro, but what the heck. This
+ * translates to:
+ *
+ * how much of this piece is new?
+ * if more new then we are trying this time, clamp
+ * if nothing new
+ * then bump down amount already written, for next piece
+ * else put new stuff in iovec, will need all of next piece
+ *
+ * Note that todo had better be at least 1 or else we'll end up
+ * writing 0 iovecs.
+ */
+#define InsertIOV(pointer, length) \
+ len = (length) - before; \
+ if (len > remain) \
+ len = remain; \
+ if (len <= 0) { \
+ before = (-len); \
+ } else { \
+ iov[i].iov_len = len; \
+ iov[i].iov_base = (pointer) + before; \
+ i++; \
+ remain -= len; \
+ before = 0; \
+ }
+
+ InsertIOV ((char *)oco->buf, oco->count)
+ InsertIOV (extraBuf, extraCount)
+ InsertIOV (padBuffer, padsize)
+
+ errno = 0;
+ if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0)
+ {
+ written += len;
+ notWritten -= len;
+ todo = notWritten;
+ }
+ else if (ETEST(errno)
+#ifdef SUNSYSV /* check for another brain-damaged OS bug */
+ || (errno == 0)
+#endif
+#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
+ || ((errno == EMSGSIZE) && (todo == 1))
+#endif
+ )
+ {
+ /* If we've arrived here, then the client is stuffed to the gills
+ and not ready to accept more. Make a note of it and buffer
+ the rest. */
+ FD_SET(connection, &ClientsWriteBlocked);
+ AnyClientsWriteBlocked = TRUE;
+
+ if (written < oco->count)
+ {
+ if (written > 0)
+ {
+ oco->count -= written;
+ memmove((char *)oco->buf,
+ (char *)oco->buf + written,
+ oco->count);
+ written = 0;
+ }
+ }
+ else
+ {
+ written -= oco->count;
+ oco->count = 0;
+ }
+
+ if (notWritten > oco->size)
+ {
+ unsigned char *obuf;
+
+ obuf = (unsigned char *)xrealloc(oco->buf,
+ notWritten + BUFSIZE);
+ if (!obuf)
+ {
+ _XSERVTransDisconnect(oc->trans_conn);
+ _XSERVTransClose(oc->trans_conn);
+ oc->trans_conn = NULL;
+ MarkClientException(who);
+ oco->count = 0;
+ return(-1);
+ }
+ oco->size = notWritten + BUFSIZE;
+ oco->buf = obuf;
+ }
+
+ /* If the amount written extended into the padBuffer, then the
+ difference "extraCount - written" may be less than 0 */
+ if ((len = extraCount - written) > 0)
+ memmove ((char *)oco->buf + oco->count,
+ extraBuf + written,
+ len);
+
+ oco->count = notWritten; /* this will include the pad */
+ /* return only the amount explicitly requested */
+ return extraCount;
+ }
+#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
+ else if (errno == EMSGSIZE)
+ {
+ todo >>= 1;
+ }
+#endif
+ else
+ {
+ if (oc->trans_conn)
+ {
+ _XSERVTransDisconnect(oc->trans_conn);
+ _XSERVTransClose(oc->trans_conn);
+ oc->trans_conn = NULL;
+ }
+ MarkClientException(who);
+ oco->count = 0;
+ return(-1);
+ }
+ }
+
+ /* everything was flushed out */
+ oco->count = 0;
+ /* check to see if this client was write blocked */
+ if (AnyClientsWriteBlocked)
+ {
+ FD_CLR(oc->fd, &ClientsWriteBlocked);
+ if (! XFD_ANYSET(&ClientsWriteBlocked))
+ AnyClientsWriteBlocked = FALSE;
+ }
+ if (oco->size > BUFWATERMARK)
+ {
+ xfree(oco->buf);
+ xfree(oco);
+ }
+ else
+ {
+ oco->next = FreeOutputs;
+ FreeOutputs = oco;
+ }
+ oc->output = (ConnectionOutputPtr)NULL;
+ return extraCount; /* return only the amount explicitly requested */
+}
+
+ConnectionInputPtr
+AllocateInputBuffer()
+{
+ register ConnectionInputPtr oci;
+
+ oci = (ConnectionInputPtr)xalloc(sizeof(ConnectionInput));
+ if (!oci)
+ return (ConnectionInputPtr)NULL;
+ oci->buffer = (char *)xalloc(BUFSIZE);
+ if (!oci->buffer)
+ {
+ xfree(oci);
+ return (ConnectionInputPtr)NULL;
+ }
+ oci->size = BUFSIZE;
+ oci->bufptr = oci->buffer;
+ oci->bufcnt = 0;
+ oci->lenLastReq = 0;
+ return oci;
+}
+
+ConnectionOutputPtr
+AllocateOutputBuffer()
+{
+ register ConnectionOutputPtr oco;
+
+ oco = (ConnectionOutputPtr)xalloc(sizeof(ConnectionOutput));
+ if (!oco)
+ return (ConnectionOutputPtr)NULL;
+ oco->buf = (unsigned char *) xalloc(BUFSIZE);
+ if (!oco->buf)
+ {
+ xfree(oco);
+ return (ConnectionOutputPtr)NULL;
+ }
+ oco->size = BUFSIZE;
+ oco->count = 0;
+#ifdef LBX
+ oco->nocompress = FALSE;
+#endif
+ return oco;
+}
+
+void
+FreeOsBuffers(oc)
+ OsCommPtr oc;
+{
+ register ConnectionInputPtr oci;
+ register ConnectionOutputPtr oco;
+
+ if (AvailableInput == oc)
+ AvailableInput = (OsCommPtr)NULL;
+ if (oci = oc->input)
+ {
+ if (FreeInputs)
+ {
+ xfree(oci->buffer);
+ xfree(oci);
+ }
+ else
+ {
+ FreeInputs = oci;
+ oci->next = (ConnectionInputPtr)NULL;
+ oci->bufptr = oci->buffer;
+ oci->bufcnt = 0;
+ oci->lenLastReq = 0;
+ }
+ }
+ if (oco = oc->output)
+ {
+ if (FreeOutputs)
+ {
+ xfree(oco->buf);
+ xfree(oco);
+ }
+ else
+ {
+ FreeOutputs = oco;
+ oco->next = (ConnectionOutputPtr)NULL;
+ oco->count = 0;
+ }
+ }
+#ifdef LBX
+ if (oci = oc->largereq) {
+ xfree(oci->buffer);
+ xfree(oci);
+ }
+#endif
+}
+
+void
+ResetOsBuffers()
+{
+ register ConnectionInputPtr oci;
+ register ConnectionOutputPtr oco;
+
+ while (oci = FreeInputs)
+ {
+ FreeInputs = oci->next;
+ xfree(oci->buffer);
+ xfree(oci);
+ }
+ while (oco = FreeOutputs)
+ {
+ FreeOutputs = oco->next;
+ xfree(oco->buf);
+ xfree(oco);
+ }
+}
diff --git a/os/k5auth.c b/os/k5auth.c
new file mode 100644
index 000000000..c6a2e3cc9
--- /dev/null
+++ b/os/k5auth.c
@@ -0,0 +1,796 @@
+/* $Xorg: k5auth.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */
+/*
+
+Copyright 1993, 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.
+
+*/
+
+/*
+ * Kerberos V5 authentication scheme
+ * Author: Tom Yu <tlyu@MIT.EDU>
+ *
+ * Mostly snarfed wholesale from the user_user demo in the
+ * krb5 distribution. (At least the checking part)
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#ifdef TCPCONN
+#include <netinet/in.h>
+#endif
+#ifdef DNETCONN
+#include <netdnet/dn.h>
+#endif
+#include <arpa/inet.h>
+#include <krb5/krb5.h>
+/* 9/93: krb5.h leaks some symbols */
+#undef BITS32
+#undef xfree
+#include <krb5/los-proto.h>
+#include "X.h"
+#include "os.h"
+#include "osdep.h"
+#include "Xproto.h"
+#include "Xfuncs.h"
+#include "dixstruct.h"
+#include <com_err.h>
+#include "Xauth.h"
+
+extern int (*k5_Vector[256])();
+extern int SendConnSetup();
+extern char *display; /* need this to generate rcache name */
+
+static XID krb5_id = ~0L;
+static krb5_principal srvname = NULL; /* service name */
+static char *ccname = NULL;
+static char *ktname = NULL; /* key table name */
+static char kerror[256];
+
+/*
+ * tgt_keyproc:
+ *
+ * extract session key from a credentials struct
+ */
+krb5_error_code tgt_keyproc(keyprocarg, principal, vno, key)
+ krb5_pointer keyprocarg;
+ krb5_principal principal;
+ krb5_kvno vno;
+ krb5_keyblock **key;
+{
+ krb5_creds *creds = (krb5_creds *)keyprocarg;
+
+ return krb5_copy_keyblock(&creds->keyblock, key);
+}
+
+/*
+ * k5_cmpenc:
+ *
+ * compare "encoded" principals
+ */
+Bool k5_cmpenc(pname, plen, buf)
+ unsigned char *pname;
+ short plen;
+ krb5_data *buf;
+{
+ return (plen == buf->length &&
+ memcmp(pname, buf->data, plen) == 0);
+}
+
+/*
+ * K5Check:
+ *
+ * This is stage 0 of the krb5 authentication protocol. It
+ * goes through the current credentials cache and extracts the
+ * primary principal and tgt to send to the client, or as
+ * appropriate, extracts from a keytab.
+ *
+ * The packet sent to the client has the following format:
+ *
+ * CARD8 reqType = 2
+ * CARD8 data = 0
+ * CARD16 length = total length of packet (in 32 bit units)
+ * CARD16 plen = length of encoded principal following
+ * STRING8 princ = encoded principal
+ * STRING8 ticket = server tgt
+ *
+ * For client-server authentication, the packet is as follows:
+ *
+ * CARD8 reqType = 3
+ * CARD8 data = 0
+ * CARD16 length = total length
+ * STRING8 princ = encoded principal of server
+ */
+XID K5Check(data_length, data, client, reason)
+ unsigned short data_length;
+ char *data;
+ ClientPtr client;
+ char **reason;
+{
+ krb5_error_code retval;
+ CARD16 tlen;
+ krb5_principal sprinc, cprinc;
+ krb5_ccache cc;
+ krb5_creds *creds;
+ char *outbuf, *cp;
+ krb5_data princ;
+ register char n;
+ xReq prefix;
+
+ if (krb5_id == ~0L)
+ return ~0L;
+ if (!ccname && !srvname)
+ return ~0L;
+ if (ccname)
+ {
+ if ((creds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL)
+ return ~0L;
+ if (retval = krb5_cc_resolve(ccname, &cc))
+ return ~0L;
+ bzero((char*)creds, sizeof (krb5_creds));
+ if (retval = krb5_cc_get_principal(cc, &cprinc))
+ {
+ krb5_free_creds(creds);
+ krb5_cc_close(cc);
+ return ~0L;
+ }
+ creds->client = cprinc;
+ if (retval =
+ krb5_build_principal_ext(&sprinc,
+ krb5_princ_realm(creds->client)->length,
+ krb5_princ_realm(creds->client)->data,
+ 6, "krbtgt",
+ krb5_princ_realm(creds->client)->length,
+ krb5_princ_realm(creds->client)->data,
+ 0))
+ {
+ krb5_free_creds(creds);
+ krb5_cc_close(cc);
+ return ~0L;
+ }
+ creds->server = sprinc;
+ retval = krb5_get_credentials(KRB5_GC_CACHED, cc, creds);
+ krb5_cc_close(cc);
+ if (retval)
+ {
+ krb5_free_creds(creds);
+ return ~0L;
+ }
+ if (retval = XauKrb5Encode(cprinc, &princ))
+ {
+ krb5_free_creds(creds);
+ return ~0L;
+ }
+ tlen = sz_xReq + 2 + princ.length + creds->ticket.length;
+ prefix.reqType = 2; /* opcode = authenticate user-to-user */
+ }
+ else if (srvname)
+ {
+ if (retval = XauKrb5Encode(srvname, &princ))
+ {
+ return ~0L;
+ }
+ tlen = sz_xReq + princ.length;
+ prefix.reqType = 3; /* opcode = authenticate client-server */
+ }
+ prefix.data = 0; /* stage = 0 */
+ prefix.length = (tlen + 3) >> 2; /* round up to nearest multiple
+ of 4 bytes */
+ if (client->swapped)
+ {
+ swaps(&prefix.length, n);
+ }
+ if ((cp = outbuf = (char *)malloc(tlen)) == NULL)
+ {
+ if (ccname)
+ {
+ krb5_free_creds(creds);
+ }
+ free(princ.data);
+ return ~0L;
+ }
+ memcpy(cp, &prefix, sz_xReq);
+ cp += sz_xReq;
+ if (ccname)
+ {
+ memcpy(cp, &princ.length, 2);
+ if (client->swapped)
+ {
+ swaps((CARD16 *)cp, n);
+ }
+ cp += 2;
+ }
+ memcpy(cp, princ.data, princ.length);
+ cp += princ.length;
+ free(princ.data); /* we don't need that anymore */
+ if (ccname)
+ memcpy(cp, creds->ticket.data, creds->ticket.length);
+ WriteToClient(client, tlen, outbuf);
+ free(outbuf);
+ client->requestVector = k5_Vector; /* hack in our dispatch vector */
+ client->clientState = ClientStateAuthenticating;
+ if (ccname)
+ {
+ ((OsCommPtr)client->osPrivate)->authstate.srvcreds = (pointer)creds; /* save tgt creds */
+ ((OsCommPtr)client->osPrivate)->authstate.ktname = NULL;
+ ((OsCommPtr)client->osPrivate)->authstate.srvname = NULL;
+ }
+ if (srvname)
+ {
+ ((OsCommPtr)client->osPrivate)->authstate.srvcreds = NULL;
+ ((OsCommPtr)client->osPrivate)->authstate.ktname = (pointer)ktname;
+ ((OsCommPtr)client->osPrivate)->authstate.srvname = (pointer)srvname;
+ }
+ ((OsCommPtr)client->osPrivate)->authstate.stageno = 1; /* next stage is 1 */
+ return krb5_id;
+}
+
+/*
+ * k5_stage1:
+ *
+ * This gets called out of the dispatcher after K5Check frobs with the
+ * client->requestVector. It accepts the ap_req from the client and verifies
+ * it. In addition, if the client has set AP_OPTS_MUTUAL_REQUIRED, it then
+ * sends an ap_rep to the client to achieve mutual authentication.
+ *
+ * client stage1 packet format is as follows:
+ *
+ * CARD8 reqType = 1
+ * CARD8 data = ignored
+ * CARD16 length = total length
+ * STRING8 data = the actual ap_req
+ *
+ * stage2 packet sent back to client for mutual authentication:
+ *
+ * CARD8 reqType = 2
+ * CARD8 data = 2
+ * CARD16 length = total length
+ * STRING8 data = the ap_rep
+ */
+int k5_stage1(client)
+ register ClientPtr client;
+{
+ long addrlen;
+ krb5_error_code retval, retval2;
+ register char n;
+ struct sockaddr cli_net_addr;
+ xReq prefix;
+ krb5_principal cprinc;
+ krb5_data buf;
+ krb5_creds *creds = (krb5_creds *)((OsCommPtr)client->osPrivate)->authstate.srvcreds;
+ krb5_keyblock *skey;
+ krb5_address cli_addr, **localaddrs = NULL;
+ krb5_tkt_authent *authdat;
+ krb5_ap_rep_enc_part rep;
+ krb5_int32 ctime, cusec;
+ krb5_rcache rcache = NULL;
+ char *cachename = NULL, *rc_type = NULL, *rc_base = "rcX", *kt = NULL;
+ REQUEST(xReq);
+
+ if (((OsCommPtr)client->osPrivate)->authstate.stageno != 1)
+ {
+ if (creds)
+ krb5_free_creds(creds);
+ return(SendConnSetup(client, "expected Krb5 stage1 packet"));
+ }
+ addrlen = sizeof (cli_net_addr);
+ if (getpeername(((OsCommPtr)client->osPrivate)->fd,
+ &cli_net_addr, &addrlen) == -1)
+ {
+ if (creds)
+ krb5_free_creds(creds);
+ return(SendConnSetup(client, "Krb5 stage1: getpeername failed"));
+ }
+ if (cli_net_addr.sa_family == AF_UNSPEC
+#if defined(UNIXCONN) || defined(LOCALCONN)
+ || cli_net_addr.sa_family == AF_UNIX
+#endif
+ ) /* assume local host */
+ {
+ krb5_os_localaddr(&localaddrs);
+ if (!localaddrs || !localaddrs[0])
+ {
+ if (creds)
+ krb5_free_creds(creds);
+ return(SendConnSetup(client, "Krb5 failed to get localaddrs"));
+ }
+ cli_addr.addrtype = localaddrs[0]->addrtype;
+ cli_addr.length = localaddrs[0]->length;
+ cli_addr.contents = localaddrs[0]->contents;
+ }
+ else
+ {
+ cli_addr.addrtype = cli_net_addr.sa_family; /* the values
+ are compatible */
+ switch (cli_net_addr.sa_family)
+ {
+#ifdef TCPCONN
+ case AF_INET:
+ cli_addr.length = sizeof (struct in_addr);
+ cli_addr.contents =
+ (krb5_octet *)&((struct sockaddr_in *)&cli_net_addr)->sin_addr;
+ break;
+#endif
+#ifdef DNETCONN
+ case AF_DECnet:
+ cli_addr.length = sizeof (struct dn_naddr);
+ cli_addr.contents =
+ (krb5_octet *)&((struct sockaddr_dn *)&cli_net_addr)->sdn_add;
+ break;
+#endif
+ default:
+ if (localaddrs)
+ krb5_free_addresses(localaddrs);
+ if (creds)
+ krb5_free_creds(creds);
+ sprintf(kerror, "Krb5 stage1: unknown address family %d from getpeername",
+ cli_net_addr.sa_family);
+ return(SendConnSetup(client, kerror));
+ }
+ }
+ if ((rcache = (krb5_rcache)malloc(sizeof(*rcache))) == NULL)
+ {
+ if (localaddrs)
+ krb5_free_addresses(localaddrs);
+ if (creds)
+ krb5_free_creds(creds);
+ return(SendConnSetup(client, "malloc bombed for krb5_rcache"));
+ }
+ if ((rc_type = krb5_rc_default_type()) == NULL)
+ rc_type = "dfl";
+ if (retval = krb5_rc_resolve_type(&rcache, rc_type))
+ {
+ if (localaddrs)
+ krb5_free_addresses(localaddrs);
+ if (creds)
+ krb5_free_creds(creds);
+ free(rcache);
+ strcpy(kerror, "krb5_rc_resolve_type failed: ");
+ strncat(kerror, error_message(retval), 231);
+ return(SendConnSetup(client, kerror));
+ }
+ if ((cachename = (char *)malloc(strlen(rc_base) + strlen(display) + 1))
+ == NULL)
+ {
+ if (localaddrs)
+ krb5_free_addresses(localaddrs);
+ if (creds)
+ krb5_free_creds(creds);
+ free(rcache);
+ return(SendConnSetup(client, "Krb5: malloc bombed for cachename"));
+ }
+ strcpy(cachename, rc_base);
+ strcat(cachename, display);
+ if (retval = krb5_rc_resolve(rcache, cachename))
+ {
+ if (localaddrs)
+ krb5_free_addresses(localaddrs);
+ if (creds)
+ krb5_free_creds(creds);
+ free(rcache);
+ free(cachename);
+ strcpy(kerror, "krb5_rc_resolve failed: ");
+ strncat(kerror, error_message(retval), 236);
+ return(SendConnSetup(client, kerror));
+ }
+ free(cachename);
+ if (krb5_rc_recover(rcache))
+ {
+ extern krb5_deltat krb5_clockskew;
+ if (retval = krb5_rc_initialize(rcache, krb5_clockskew))
+ {
+ if (localaddrs)
+ krb5_free_addresses(localaddrs);
+ if (creds)
+ krb5_free_creds(creds);
+ if (retval2 = krb5_rc_close(rcache))
+ {
+ strcpy(kerror, "krb5_rc_close failed: ");
+ strncat(kerror, error_message(retval2), 238);
+ return(SendConnSetup(client, kerror));
+ }
+ free(rcache);
+ strcpy(kerror, "krb5_rc_initialize failed: ");
+ strncat(kerror, error_message(retval), 233);
+ return(SendConnSetup(client, kerror));
+ }
+ }
+ buf.length = (stuff->length << 2) - sz_xReq;
+ buf.data = (char *)stuff + sz_xReq;
+ if (creds)
+ {
+ retval = krb5_rd_req(&buf,
+ NULL, /* don't bother with server name */
+ &cli_addr,
+ NULL, /* no fetchfrom */
+ tgt_keyproc,
+ creds, /* credentials as arg to
+ keyproc */
+ rcache,
+ &authdat);
+ krb5_free_creds(creds);
+ }
+ else if (kt = (char *)((OsCommPtr)client->osPrivate)->authstate.ktname)
+ {
+ retval = krb5_rd_req(&buf, srvname, &cli_addr, kt, NULL, NULL,
+ rcache, &authdat);
+ ((OsCommPtr)client->osPrivate)->authstate.ktname = NULL;
+ }
+ else
+ {
+ if (localaddrs)
+ krb5_free_addresses(localaddrs);
+ return(SendConnSetup(client, "Krb5: neither srvcreds nor ktname set"));
+ }
+ if (localaddrs)
+ krb5_free_addresses(localaddrs);
+ if (rcache)
+ {
+ if (retval2 = krb5_rc_close(rcache))
+ {
+ strcpy(kerror, "krb5_rc_close failed (2): ");
+ strncat(kerror, error_message(retval2), 230);
+ return(SendConnSetup(client, kerror));
+ }
+ free(rcache);
+ }
+ if (retval)
+ {
+ strcpy(kerror, "Krb5: Bad application request: ");
+ strncat(kerror, error_message(retval), 224);
+ return(SendConnSetup(client, kerror));
+ }
+ cprinc = authdat->ticket->enc_part2->client;
+ skey = authdat->ticket->enc_part2->session;
+ if (XauKrb5Encode(cprinc, &buf))
+ {
+ krb5_free_tkt_authent(authdat);
+ return(SendConnSetup(client, "XauKrb5Encode bombed"));
+ }
+ /*
+ * Now check to see if the principal we got is one that we want to let in
+ */
+ if (ForEachHostInFamily(FamilyKrb5Principal, k5_cmpenc, (pointer)&buf))
+ {
+ free(buf.data);
+ /*
+ * The following deals with sending an ap_rep to the client to
+ * achieve mutual authentication. The client sends back a stage 3
+ * packet if all is ok.
+ */
+ if (authdat->ap_options | AP_OPTS_MUTUAL_REQUIRED)
+ {
+ /*
+ * stage 2: send ap_rep to client
+ */
+ if (retval = krb5_us_timeofday(&ctime, &cusec))
+ {
+ krb5_free_tkt_authent(authdat);
+ strcpy(kerror, "error in krb5_us_timeofday: ");
+ strncat(kerror, error_message(retval), 234);
+ return(SendConnSetup(client, kerror));
+ }
+ rep.ctime = ctime;
+ rep.cusec = cusec;
+ rep.subkey = NULL;
+ rep.seq_number = 0;
+ if (retval = krb5_mk_rep(&rep, skey, &buf))
+ {
+ krb5_free_tkt_authent(authdat);
+ strcpy(kerror, "error in krb5_mk_rep: ");
+ strncat(kerror, error_message(retval), 238);
+ return(SendConnSetup(client, kerror));
+ }
+ prefix.reqType = 2; /* opcode = authenticate */
+ prefix.data = 2; /* stage = 2 */
+ prefix.length = (buf.length + sz_xReq + 3) >> 2;
+ if (client->swapped)
+ {
+ swaps(&prefix.length, n);
+ }
+ WriteToClient(client, sz_xReq, (char *)&prefix);
+ WriteToClient(client, buf.length, buf.data);
+ free(buf.data);
+ krb5_free_tkt_authent(authdat);
+ ((OsCommPtr)client->osPrivate)->authstate.stageno = 3; /* expect stage3 packet */
+ return(Success);
+ }
+ else
+ {
+ free(buf.data);
+ krb5_free_tkt_authent(authdat);
+ return(SendConnSetup(client, NULL)); /* success! */
+ }
+ }
+ else
+ {
+ char *kname;
+
+ krb5_free_tkt_authent(authdat);
+ free(buf.data);
+ retval = krb5_unparse_name(cprinc, &kname);
+ if (retval == 0)
+ {
+ sprintf(kerror, "Principal \"%s\" is not authorized to connect",
+ kname);
+ if (kname)
+ free(kname);
+ return(SendConnSetup(client, kerror));
+ }
+ else
+ return(SendConnSetup(client,"Principal is not authorized to connect to Server"));
+ }
+}
+
+/*
+ * k5_stage3:
+ *
+ * Get the short ack packet from the client. This packet can conceivably
+ * be expanded to allow for switching on end-to-end encryption.
+ *
+ * stage3 packet format:
+ *
+ * CARD8 reqType = 3
+ * CARD8 data = ignored (for now)
+ * CARD16 length = should be zero
+ */
+int k5_stage3(client)
+ register ClientPtr client;
+{
+ REQUEST(xReq);
+
+ if (((OsCommPtr)client->osPrivate)->authstate.stageno != 3)
+ {
+ return(SendConnSetup(client, "expected Krb5 stage3 packet"));
+ }
+ else
+ return(SendConnSetup(client, NULL)); /* success! */
+}
+
+k5_bad(client)
+ register ClientPtr client;
+{
+ if (((OsCommPtr)client->osPrivate)->authstate.srvcreds)
+ krb5_free_creds((krb5_creds *)((OsCommPtr)client->osPrivate)->authstate.srvcreds);
+ sprintf(kerror, "unrecognized Krb5 auth packet %d, expecting %d",
+ ((xReq *)client->requestBuffer)->reqType,
+ ((OsCommPtr)client->osPrivate)->authstate.stageno);
+ return(SendConnSetup(client, kerror));
+}
+
+/*
+ * K5Add:
+ *
+ * Takes the name of a credentials cache and resolves it. Also adds the
+ * primary principal of the ccache to the acl.
+ *
+ * Now will also take a service name.
+ */
+int K5Add(data_length, data, id)
+ unsigned short data_length;
+ char *data;
+ XID id;
+{
+ krb5_principal princ;
+ krb5_error_code retval;
+ krb5_keytab_entry tmp_entry;
+ krb5_keytab keytab;
+ krb5_kvno kvno = 0;
+ krb5_ccache cc;
+ char *nbuf, *cp;
+ krb5_data kbuf;
+ int i, ktlen;
+
+ krb5_init_ets(); /* can't think of a better place to put it */
+ krb5_id = ~0L;
+ if (data_length < 3)
+ return 0;
+ if ((nbuf = (char *)malloc(data_length - 2)) == NULL)
+ return 0;
+ memcpy(nbuf, data + 3, data_length - 3);
+ nbuf[data_length - 3] = '\0';
+ if (ccname)
+ {
+ free(ccname);
+ ccname = NULL;
+ }
+ if (srvname)
+ {
+ krb5_free_principal(srvname);
+ srvname = NULL;
+ }
+ if (ktname)
+ {
+ free(ktname);
+ ktname = NULL;
+ }
+ if (!strncmp(data, "UU:", 3))
+ {
+ if (retval = krb5_cc_resolve(nbuf, &cc))
+ {
+ ErrorF("K5Add: krb5_cc_resolve of \"%s\" failed: %s\n",
+ nbuf, error_message(retval));
+ free(nbuf);
+ return 0;
+ }
+ if (cc && !(retval = krb5_cc_get_principal(cc, &princ)))
+ {
+ if (XauKrb5Encode(princ, &kbuf))
+ {
+ free(nbuf);
+ krb5_free_principal(princ);
+ krb5_cc_close(cc);
+ return 0;
+ }
+ if (krb5_cc_close(cc))
+ return 0;
+ AddHost(NULL, FamilyKrb5Principal, kbuf.length, kbuf.data);
+ krb5_free_principal(princ);
+ free(kbuf.data);
+ ccname = nbuf;
+ krb5_id = id;
+ return 1;
+ }
+ else
+ {
+ ErrorF("K5Add: getting principal from cache \"%s\" failed: %s\n",
+ nbuf, error_message(retval));
+ }
+ }
+ else if (!strncmp(data, "CS:", 3))
+ {
+ if ((cp = strchr(nbuf, ',')) == NULL)
+ {
+ free(nbuf);
+ return 0;
+ }
+ *cp = '\0'; /* gross but it works :-) */
+ ktlen = strlen(cp + 1);
+ if ((ktname = (char *)malloc(ktlen + 1)) == NULL)
+ {
+ free(nbuf);
+ return 0;
+ }
+ strcpy(ktname, cp + 1);
+ retval = krb5_sname_to_principal(NULL, /* NULL for hostname uses
+ local host name*/
+ nbuf, KRB5_NT_SRV_HST,
+ &srvname);
+ free(nbuf);
+ if (retval)
+ {
+ free(ktname);
+ ktname = NULL;
+ return 0;
+ }
+ if (retval = krb5_kt_resolve(ktname, &keytab))
+ {
+ free(ktname);
+ ktname = NULL;
+ krb5_free_principal(srvname);
+ srvname = NULL;
+ return 0;
+ }
+ retval = krb5_kt_get_entry(keytab, srvname, kvno, &tmp_entry);
+ krb5_kt_free_entry(&tmp_entry);
+ if (retval)
+ {
+ free(ktname);
+ ktname = NULL;
+ krb5_free_principal(srvname);
+ srvname = NULL;
+ return 0;
+ }
+ if (XauKrb5Encode(srvname, &kbuf))
+ {
+ free(ktname);
+ ktname = NULL;
+ krb5_free_principal(srvname);
+ srvname = NULL;
+ return 0;
+ }
+ AddHost(NULL, FamilyKrb5Principal, kbuf.length, kbuf.data);
+ krb5_id = id;
+ return 1;
+ }
+ else
+ {
+ ErrorF("K5Add: credentials cache name \"%.*s\" in auth file: unknown type\n",
+ data_length, data);
+ }
+ return 0;
+}
+
+/*
+ * K5Reset:
+ *
+ * Reset krb5_id, also nuke the current principal from the acl.
+ */
+int K5Reset()
+{
+ krb5_principal princ;
+ krb5_error_code retval;
+ krb5_ccache cc;
+ krb5_data kbuf;
+ int i;
+
+ if (ccname)
+ {
+ if (retval = krb5_cc_resolve(ccname, &cc))
+ {
+ free(ccname);
+ ccname = NULL;
+ }
+ if (cc && !(retval = krb5_cc_get_principal(cc, &princ)))
+ {
+ if (XauKrb5Encode(princ, &kbuf))
+ return 1;
+ RemoveHost(NULL, FamilyKrb5Principal, kbuf.length, kbuf.data);
+ krb5_free_principal(princ);
+ free(kbuf.data);
+ if (krb5_cc_close(cc))
+ return 1;
+ free(ccname);
+ ccname = NULL;
+ }
+ }
+ if (srvname)
+ {
+ if (XauKrb5Encode(srvname, &kbuf))
+ return 1;
+ RemoveHost(NULL, FamilyKrb5Principal, kbuf.length, kbuf.data);
+ krb5_free_principal(srvname);
+ free(kbuf.data);
+ srvname = NULL;
+ }
+ if (ktname)
+ {
+ free(ktname);
+ ktname = NULL;
+ }
+ krb5_id = ~0L;
+ return 0;
+}
+
+XID K5ToID(data_length, data)
+ unsigned short data_length;
+ char *data;
+{
+ return krb5_id;
+}
+
+int K5FromID(id, data_lenp, datap)
+ XID id;
+ unsigned short *data_lenp;
+ char **datap;
+{
+ return 0;
+}
+
+int K5Remove(data_length, data)
+ unsigned short data_length;
+ char *data;
+{
+ return 0;
+}
diff --git a/os/lbxio.c b/os/lbxio.c
new file mode 100644
index 000000000..c72ac2c05
--- /dev/null
+++ b/os/lbxio.c
@@ -0,0 +1,585 @@
+/*
+
+Copyright 1996, 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.
+
+*/
+/***********************************************************
+Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts,
+and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or MIT not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/* $Xorg: lbxio.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */
+
+#include <stdio.h>
+#include <X11/Xtrans.h>
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+#include "Xmd.h"
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+#include "X.h"
+#include "Xproto.h"
+#include "os.h"
+#include "Xpoll.h"
+#include "osdep.h"
+#include "opaque.h"
+#include "dixstruct.h"
+#include "misc.h"
+#include "lbxserve.h"
+
+/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
+ * systems are broken and return EWOULDBLOCK when they should return EAGAIN
+ */
+#if defined(EAGAIN) && defined(EWOULDBLOCK)
+#define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
+#else
+#ifdef EAGAIN
+#define ETEST(err) (err == EAGAIN)
+#else
+#define ETEST(err) (err == EWOULDBLOCK)
+#endif
+#endif
+
+extern fd_set ClientsWithInput, IgnoredClientsWithInput;
+extern fd_set AllClients, AllSockets;
+extern fd_set ClientsWriteBlocked;
+extern fd_set OutputPending;
+extern int ConnectionTranslation[];
+extern Bool NewOutputPending;
+extern Bool AnyClientsWriteBlocked;
+extern Bool CriticalOutputPending;
+extern int timesThisConnection;
+extern ConnectionInputPtr FreeInputs;
+extern ConnectionOutputPtr FreeOutputs;
+extern OsCommPtr AvailableInput;
+
+#define get_req_len(req,cli) ((cli)->swapped ? \
+ lswaps((req)->length) : (req)->length)
+
+#define YieldControl() \
+ { isItTimeToYield = TRUE; \
+ timesThisConnection = 0; }
+#define YieldControlNoInput() \
+ { YieldControl(); \
+ FD_CLR(fd, &ClientsWithInput); }
+
+void
+SwitchClientInput (client, pending)
+ ClientPtr client;
+ Bool pending;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+
+ ConnectionTranslation[oc->fd] = client->index;
+ if (pending)
+ FD_SET(oc->fd, &ClientsWithInput);
+ else
+ YieldControl();
+}
+
+void
+LbxPrimeInput(client, proxy)
+ ClientPtr client;
+ LbxProxyPtr proxy;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ ConnectionInputPtr oci = oc->input;
+
+ if (oci && proxy->compHandle) {
+ char *extra = oci->bufptr + oci->lenLastReq;
+ int left = oci->bufcnt + oci->buffer - extra;
+
+ (*proxy->streamOpts.streamCompStuffInput)(oc->fd,
+ (unsigned char *)extra,
+ left);
+ oci->bufcnt -= left;
+ AvailableInput = oc;
+ }
+}
+
+void
+AvailableClientInput (client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+
+ if (FD_ISSET(oc->fd, &AllSockets))
+ FD_SET(oc->fd, &ClientsWithInput);
+}
+
+/*****************************************************************
+ * AppendFakeRequest
+ * Append a (possibly partial) request in as the last request.
+ *
+ **********************/
+
+Bool
+AppendFakeRequest (client, data, count)
+ ClientPtr client;
+ char *data;
+ int count;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ register ConnectionInputPtr oci = oc->input;
+ int fd = oc->fd;
+ register int gotnow;
+
+ if (!oci)
+ {
+ if (oci = FreeInputs)
+ FreeInputs = oci->next;
+ else if (!(oci = AllocateInputBuffer()))
+ return FALSE;
+ oc->input = oci;
+ } else if (AvailableInput == oc)
+ AvailableInput = (OsCommPtr)NULL;
+ /* do not free AvailableInput here, it could be proxy's */
+ oci->bufptr += oci->lenLastReq;
+ oci->lenLastReq = 0;
+ gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
+ if ((gotnow + count) > oci->size)
+ {
+ char *ibuf;
+
+ ibuf = (char *)xrealloc(oci->buffer, gotnow + count);
+ if (!ibuf)
+ return(FALSE);
+ oci->size = gotnow + count;
+ oci->buffer = ibuf;
+ oci->bufptr = ibuf + oci->bufcnt - gotnow;
+ }
+ if (oci->bufcnt + count > oci->size) {
+ memmove(oci->buffer, oci->bufptr, gotnow);
+ oci->bufcnt = gotnow;
+ oci->bufptr = oci->buffer;
+ }
+ memmove(oci->bufptr + gotnow, data, count);
+ oci->bufcnt += count;
+ gotnow += count;
+ if ((gotnow >= sizeof(xReq)) &&
+ (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2)))
+ FD_SET(fd, &ClientsWithInput);
+ else
+ YieldControlNoInput();
+ return(TRUE);
+}
+
+static int
+LbxWrite(trans_conn, proxy, buf, len)
+ XtransConnInfo trans_conn;
+ LbxProxyPtr proxy;
+ char *buf;
+ int len;
+{
+ struct iovec iov;
+ int n;
+ int notWritten;
+
+ notWritten = len;
+ iov.iov_base = buf;
+ iov.iov_len = len;
+ while (notWritten) {
+ errno = 0;
+ if (proxy->compHandle)
+ n = (*proxy->streamOpts.streamCompWriteV)(proxy->fd, &iov, 1);
+ else
+ n = _XSERVTransWritev(trans_conn, &iov, 1);
+ if (n >= 0) {
+ iov.iov_base = (char *)iov.iov_base + n;
+ notWritten -= n;
+ iov.iov_len = notWritten;
+ }
+ else if (ETEST(errno)
+#ifdef SUNSYSV /* check for another brain-damaged OS bug */
+ || (errno == 0)
+#endif
+#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
+ || ((errno == EMSGSIZE) && (iov.iov_len == 1))
+#endif
+ )
+ break;
+#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
+ else if (errno == EMSGSIZE)
+ iov.iov_len >>= 1;
+#endif
+ else
+ return -1;
+ }
+ return len - notWritten;
+}
+
+static Bool
+LbxAppendOutput(proxy, client, oco)
+ LbxProxyPtr proxy;
+ ClientPtr client;
+ ConnectionOutputPtr oco;
+{
+ ConnectionOutputPtr noco = proxy->olast;
+ LbxClientPtr lbxClient = LbxClient(client);
+
+ if (!lbxClient) {
+ xfree(oco->buf);
+ xfree(oco);
+ return TRUE;
+ }
+ if (noco)
+ LbxReencodeOutput(client,
+ (char *)noco->buf, &noco->count,
+ (char *)oco->buf, &oco->count);
+ else
+ LbxReencodeOutput(client,
+ (char *)NULL, (int *)NULL,
+ (char *)oco->buf, &oco->count);
+ if (!oco->count) {
+ if (oco->size > BUFWATERMARK)
+ {
+ xfree(oco->buf);
+ xfree(oco);
+ }
+ else
+ {
+ oco->next = FreeOutputs;
+ FreeOutputs = oco;
+ }
+ return TRUE;
+ }
+ if ((lbxClient->id != proxy->cur_send_id) && proxy->lbxClients[0]) {
+ xLbxSwitchEvent *ev;
+ int n;
+
+ if (!noco || (noco->size - noco->count) < sz_xLbxSwitchEvent) {
+ if (noco = FreeOutputs)
+ FreeOutputs = noco->next;
+ else
+ noco = AllocateOutputBuffer();
+ if (!noco) {
+ MarkClientException(client);
+ return FALSE;
+ }
+ noco->next = NULL;
+ if (proxy->olast)
+ proxy->olast->next = noco;
+ else
+ proxy->ofirst = noco;
+ proxy->olast = noco;
+ }
+ ev = (xLbxSwitchEvent *) (noco->buf + noco->count);
+ noco->count += sz_xLbxSwitchEvent;
+ proxy->cur_send_id = lbxClient->id;
+ ev->type = LbxEventCode;
+ ev->lbxType = LbxSwitchEvent;
+ ev->pad = 0;
+ ev->client = proxy->cur_send_id;
+ if (LbxProxyClient(proxy)->swapped) {
+ swapl(&ev->client, n);
+ }
+ }
+ oco->next = NULL;
+ if (proxy->olast)
+ proxy->olast->next = oco;
+ else
+ proxy->ofirst = oco;
+ proxy->olast = oco;
+ return TRUE;
+}
+
+static int
+LbxClientOutput(client, oc, extraBuf, extraCount, nocompress)
+ ClientPtr client;
+ OsCommPtr oc;
+ char *extraBuf;
+ int extraCount;
+ Bool nocompress;
+{
+ ConnectionOutputPtr oco;
+ int len;
+
+ if (oco = oc->output) {
+ oc->output = NULL;
+ if (!LbxAppendOutput(oc->proxy, client, oco))
+ return -1;
+ }
+
+ if (extraCount) {
+ NewOutputPending = TRUE;
+ FD_SET(oc->fd, &OutputPending);
+ len = (extraCount + 3) & ~3;
+ if ((oco = FreeOutputs) && (oco->size >= len))
+ FreeOutputs = oco->next;
+ else {
+ oco = (ConnectionOutputPtr)xalloc(sizeof(ConnectionOutput));
+ if (!oco) {
+ MarkClientException(client);
+ return -1;
+ }
+ oco->size = len;
+ if (oco->size < BUFSIZE)
+ oco->size = BUFSIZE;
+ oco->buf = (unsigned char *) xalloc(oco->size);
+ if (!oco->buf) {
+ xfree(oco);
+ MarkClientException(client);
+ return -1;
+ }
+ }
+ oco->count = len;
+ oco->nocompress = nocompress;
+ memmove((char *)oco->buf, extraBuf, extraCount);
+ if (!nocompress && oco->count < oco->size)
+ oc->output = oco;
+ else if (!LbxAppendOutput(oc->proxy, client, oco))
+ return -1;
+ }
+ return extraCount;
+}
+
+void
+LbxForceOutput(proxy)
+ LbxProxyPtr proxy;
+{
+ int i;
+ LbxClientPtr lbxClient;
+ OsCommPtr coc;
+ ConnectionOutputPtr oco;
+
+ for (i = proxy->maxIndex; i >= 0; i--) { /* proxy must be last */
+ lbxClient = proxy->lbxClients[i];
+ if (!lbxClient)
+ continue;
+ coc = (OsCommPtr)lbxClient->client->osPrivate;
+ if (oco = coc->output) {
+ coc->output = NULL;
+ LbxAppendOutput(proxy, lbxClient->client, oco);
+ }
+ }
+}
+
+int
+LbxFlushClient(who, oc, extraBuf, extraCount)
+ ClientPtr who;
+ OsCommPtr oc;
+ char *extraBuf;
+ int extraCount;
+{
+ LbxProxyPtr proxy;
+ ConnectionOutputPtr oco;
+ int n;
+ XtransConnInfo trans_conn;
+
+ if (extraBuf)
+ return LbxClientOutput(who, oc, extraBuf, extraCount, FALSE);
+ proxy = oc->proxy;
+ if (!proxy->lbxClients[0])
+ return 0;
+ LbxForceOutput(proxy);
+ if (!proxy->compHandle)
+ trans_conn = ((OsCommPtr)LbxProxyClient(proxy)->osPrivate)->trans_conn;
+ while (oco = proxy->ofirst) {
+ /* XXX bundle up into writev someday */
+ if (proxy->compHandle) {
+ if (oco->nocompress)
+ (*proxy->streamOpts.streamCompOff)(proxy->fd);
+ n = LbxWrite(NULL, proxy, (char *)oco->buf, oco->count);
+ if (oco->nocompress)
+ (*proxy->streamOpts.streamCompOn)(proxy->fd);
+ } else
+ n = LbxWrite(trans_conn, proxy, (char *)oco->buf, oco->count);
+ if (n < 0) {
+ ClientPtr pclient = LbxProxyClient(proxy);
+ if (proxy->compHandle)
+ trans_conn = ((OsCommPtr)pclient->osPrivate)->trans_conn;
+ _XSERVTransDisconnect(trans_conn);
+ _XSERVTransClose(trans_conn);
+ ((OsCommPtr)pclient->osPrivate)->trans_conn = NULL;
+ MarkClientException(pclient);
+ return 0;
+ } else if (n == oco->count) {
+ proxy->ofirst = oco->next;
+ if (!proxy->ofirst)
+ proxy->olast = NULL;
+ if (oco->size > BUFWATERMARK)
+ {
+ xfree(oco->buf);
+ xfree(oco);
+ }
+ else
+ {
+ oco->next = FreeOutputs;
+ oco->count = 0;
+ FreeOutputs = oco;
+ }
+ } else {
+ if (n) {
+ oco->count -= n;
+ memmove((char *)oco->buf, (char *)oco->buf + n, oco->count);
+ }
+ break;
+ }
+ }
+ if ((proxy->compHandle &&
+ (*proxy->streamOpts.streamCompFlush)(proxy->fd)) ||
+ proxy->ofirst) {
+ FD_SET(proxy->fd, &ClientsWriteBlocked);
+ AnyClientsWriteBlocked = TRUE;
+ }
+ return 0;
+}
+
+int
+UncompressedWriteToClient (who, count, buf)
+ ClientPtr who;
+ char *buf;
+ int count;
+{
+ return LbxClientOutput(who, (OsCommPtr)who->osPrivate, buf, count, TRUE);
+}
+
+LbxFreeOsBuffers(proxy)
+ LbxProxyPtr proxy;
+{
+ ConnectionOutputPtr oco;
+
+ while (oco = proxy->ofirst) {
+ proxy->ofirst = oco->next;
+ xfree(oco->buf);
+ xfree(oco);
+ }
+}
+
+Bool
+AllocateLargeReqBuffer(client, size)
+ ClientPtr client;
+ int size;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ register ConnectionInputPtr oci;
+
+ if (!(oci = oc->largereq)) {
+ if (oci = FreeInputs)
+ FreeInputs = oci->next;
+ else {
+ oci = (ConnectionInputPtr)xalloc(sizeof(ConnectionInput));
+ if (!oci)
+ return FALSE;
+ oci->buffer = NULL;
+ oci->size = 0;
+ }
+ }
+ if (oci->size < size) {
+ char *ibuf;
+
+ oci->size = size;
+ if (size < BUFSIZE)
+ oci->size = BUFSIZE;
+ if (!(ibuf = (char *)xrealloc(oci->buffer, oci->size)))
+ {
+ xfree(oci->buffer);
+ xfree(oci);
+ oc->largereq = NULL;
+ return FALSE;
+ }
+ oci->buffer = ibuf;
+ }
+ oci->bufptr = oci->buffer;
+ oci->bufcnt = 0;
+ oci->lenLastReq = size;
+ oc->largereq = oci;
+ return TRUE;
+}
+
+Bool
+AddToLargeReqBuffer(client, data, size)
+ ClientPtr client;
+ char *data;
+ int size;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ register ConnectionInputPtr oci = oc->largereq;
+
+ if (!oci || (oci->bufcnt + size > oci->lenLastReq))
+ return FALSE;
+ memcpy(oci->buffer + oci->bufcnt, data, size);
+ oci->bufcnt += size;
+ return TRUE;
+}
+
+static OsCommRec lbxAvailableInput;
+
+int
+PrepareLargeReqBuffer(client)
+ ClientPtr client;
+{
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ register ConnectionInputPtr oci = oc->largereq;
+
+ if (!oci)
+ return client->req_len << 2;
+ oc->largereq = NULL;
+ if (oci->bufcnt != oci->lenLastReq) {
+ xfree(oci->buffer);
+ xfree(oci);
+ return client->req_len << 2;
+ }
+ client->requestBuffer = oci->buffer;
+ client->req_len = oci->lenLastReq >> 2;
+ oci->bufcnt = 0;
+ oci->lenLastReq = 0;
+ if (AvailableInput)
+ {
+ register ConnectionInputPtr aci = AvailableInput->input;
+ if (aci->size > BUFWATERMARK)
+ {
+ xfree(aci->buffer);
+ xfree(aci);
+ }
+ else
+ {
+ aci->next = FreeInputs;
+ FreeInputs = aci;
+ }
+ AvailableInput->input = (ConnectionInputPtr)NULL;
+ }
+ lbxAvailableInput.input = oci;
+ AvailableInput = &lbxAvailableInput;
+ return client->req_len << 2;
+}
diff --git a/os/mitauth.c b/os/mitauth.c
new file mode 100644
index 000000000..274ab5829
--- /dev/null
+++ b/os/mitauth.c
@@ -0,0 +1,193 @@
+/* $Xorg: mitauth.c,v 1.4 2001/02/09 02:05:23 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.
+
+*/
+
+/*
+ * MIT-MAGIC-COOKIE-1 authorization scheme
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+#include "X.h"
+#include "os.h"
+#include "dixstruct.h"
+
+static struct auth {
+ struct auth *next;
+ unsigned short len;
+ char *data;
+ XID id;
+} *mit_auth;
+
+int
+MitAddCookie (data_length, data, id)
+unsigned short data_length;
+char *data;
+XID id;
+{
+ struct auth *new;
+
+ new = (struct auth *) xalloc (sizeof (struct auth));
+ if (!new)
+ return 0;
+ new->data = (char *) xalloc ((unsigned) data_length);
+ if (!new->data) {
+ xfree(new);
+ return 0;
+ }
+ new->next = mit_auth;
+ mit_auth = new;
+ memmove(new->data, data, (int) data_length);
+ new->len = data_length;
+ new->id = id;
+ return 1;
+}
+
+XID
+MitCheckCookie (data_length, data, client, reason)
+ unsigned short data_length;
+ char *data;
+ ClientPtr client;
+ char **reason;
+{
+ struct auth *auth;
+
+ for (auth = mit_auth; auth; auth=auth->next) {
+ if (data_length == auth->len &&
+ memcmp (data, auth->data, (int) data_length) == 0)
+ return auth->id;
+ }
+ *reason = "Invalid MIT-MAGIC-COOKIE-1 key";
+ return (XID) -1;
+}
+
+int
+MitResetCookie ()
+{
+ struct auth *auth, *next;
+
+ for (auth = mit_auth; auth; auth=next) {
+ next = auth->next;
+ xfree (auth->data);
+ xfree (auth);
+ }
+ mit_auth = 0;
+ return 0;
+}
+
+XID
+MitToID (data_length, data)
+unsigned short data_length;
+char *data;
+{
+ struct auth *auth;
+
+ for (auth = mit_auth; auth; auth=auth->next) {
+ if (data_length == auth->len &&
+ memcmp (data, auth->data, data_length) == 0)
+ return auth->id;
+ }
+ return (XID) -1;
+}
+
+int
+MitFromID (id, data_lenp, datap)
+XID id;
+unsigned short *data_lenp;
+char **datap;
+{
+ struct auth *auth;
+
+ for (auth = mit_auth; auth; auth=auth->next) {
+ if (id == auth->id) {
+ *data_lenp = auth->len;
+ *datap = auth->data;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+MitRemoveCookie (data_length, data)
+unsigned short data_length;
+char *data;
+{
+ struct auth *auth, *prev;
+
+ prev = 0;
+ for (auth = mit_auth; auth; prev = auth, auth=auth->next) {
+ if (data_length == auth->len &&
+ memcmp (data, auth->data, data_length) == 0)
+ {
+ if (prev)
+ prev->next = auth->next;
+ else
+ mit_auth = auth->next;
+ xfree (auth->data);
+ xfree (auth);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#ifdef XCSECURITY
+
+static char cookie[16]; /* 128 bits */
+
+XID
+MitGenerateCookie (data_length, data, id, data_length_return, data_return)
+ unsigned int data_length;
+ char *data;
+ XID id;
+ unsigned int *data_length_return;
+ char **data_return;
+{
+ int i = 0;
+ int status;
+
+ while (data_length--)
+ {
+ cookie[i++] += *data++;
+ if (i >= sizeof (cookie)) i = 0;
+ }
+ GenerateRandomData(sizeof (cookie), cookie);
+ status = MitAddCookie(sizeof (cookie), cookie, id);
+ if (!status)
+ {
+ id = -1;
+ }
+ else
+ {
+ *data_return = cookie;
+ *data_length_return = sizeof (cookie);
+ }
+ return id;
+}
+
+#endif /* XCSECURITY */
diff --git a/os/oscolor.c b/os/oscolor.c
new file mode 100644
index 000000000..f5fd61bc5
--- /dev/null
+++ b/os/oscolor.c
@@ -0,0 +1,294 @@
+/***********************************************************
+
+Copyright 1987, 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.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/* $Xorg: oscolor.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */
+
+#ifndef USE_RGB_TXT
+
+#ifdef NDBM
+#include <ndbm.h>
+#else
+#ifdef SVR4
+#include <rpcsvc/dbm.h>
+#else
+#include <dbm.h>
+#endif
+#endif
+#include "rgb.h"
+#include "os.h"
+#include "opaque.h"
+
+/* Note that we are assuming there is only one database for all the screens. */
+
+#ifdef NDBM
+DBM *rgb_dbm = (DBM *)NULL;
+#else
+int rgb_dbm = 0;
+#endif
+
+extern void CopyISOLatin1Lowered();
+
+int
+OsInitColors()
+{
+ if (!rgb_dbm)
+ {
+#ifdef NDBM
+ rgb_dbm = dbm_open(rgbPath, 0, 0);
+#else
+ if (dbminit(rgbPath) == 0)
+ rgb_dbm = 1;
+#endif
+ if (!rgb_dbm) {
+ ErrorF( "Couldn't open RGB_DB '%s'\n", rgbPath );
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/*ARGSUSED*/
+int
+OsLookupColor(screen, name, len, pred, pgreen, pblue)
+ int screen;
+ char *name;
+ unsigned len;
+ unsigned short *pred, *pgreen, *pblue;
+
+{
+ datum dbent;
+ RGB rgb;
+ char buf[64];
+ char *lowername;
+
+ if(!rgb_dbm)
+ return(0);
+
+ /* we use Xalloc here so that we can compile with cc without alloca
+ * when otherwise using gcc */
+ if (len < sizeof(buf))
+ lowername = buf;
+ else if (!(lowername = (char *)Xalloc(len + 1)))
+ return(0);
+ CopyISOLatin1Lowered ((unsigned char *) lowername, (unsigned char *) name,
+ (int)len);
+
+ dbent.dptr = lowername;
+ dbent.dsize = len;
+#ifdef NDBM
+ dbent = dbm_fetch(rgb_dbm, dbent);
+#else
+ dbent = fetch (dbent);
+#endif
+
+ if (len >= sizeof(buf))
+ Xfree(lowername);
+
+ if(dbent.dptr)
+ {
+ memmove((char *) &rgb, dbent.dptr, sizeof (RGB));
+ *pred = rgb.red;
+ *pgreen = rgb.green;
+ *pblue = rgb.blue;
+ return (1);
+ }
+ return(0);
+}
+
+#else /* USE_RGB_TXT */
+
+
+/*
+ * The dbm routines are a porting hassle. This implementation will do
+ * the same thing by reading the rgb.txt file directly, which is much
+ * more portable.
+ */
+
+#include <stdio.h>
+#include "os.h"
+#include "opaque.h"
+
+#define HASHSIZE 511
+
+typedef struct _dbEntry * dbEntryPtr;
+typedef struct _dbEntry {
+ dbEntryPtr link;
+ unsigned short red;
+ unsigned short green;
+ unsigned short blue;
+ char name[1]; /* some compilers complain if [0] */
+} dbEntry;
+
+
+extern void CopyISOLatin1Lowered();
+
+static dbEntryPtr hashTab[HASHSIZE];
+
+
+static dbEntryPtr
+lookup(name, len, create)
+ char *name;
+ int len;
+ Bool create;
+{
+ unsigned int h = 0, g;
+ dbEntryPtr entry, *prev;
+ char *str = name;
+
+ if (!(name = (char*)ALLOCATE_LOCAL(len +1))) return NULL;
+ CopyISOLatin1Lowered(name, str, len);
+ name[len] = '\0';
+
+ for(str = name; *str; str++) {
+ h = (h << 4) + *str;
+ if ((g = h) & 0xf0000000) h ^= (g >> 24);
+ h &= g;
+ }
+ h %= HASHSIZE;
+
+ if ( entry = hashTab[h] )
+ {
+ for( ; entry; prev = (dbEntryPtr*)entry, entry = entry->link )
+ if (! strcmp(name, entry->name) ) break;
+ }
+ else
+ prev = &(hashTab[h]);
+
+ if (!entry && create && (entry = (dbEntryPtr)Xalloc(sizeof(dbEntry) +len)))
+ {
+ *prev = entry;
+ entry->link = NULL;
+ strcpy( entry->name, name );
+ }
+
+ DEALLOCATE_LOCAL(name);
+
+ return entry;
+}
+
+
+Bool
+OsInitColors()
+{
+ FILE *rgb;
+ char *path;
+ char line[BUFSIZ];
+ char name[BUFSIZ];
+ int red, green, blue, lineno = 0;
+ dbEntryPtr entry;
+
+ static Bool was_here = FALSE;
+
+ if (!was_here)
+ {
+ path = (char*)ALLOCATE_LOCAL(strlen(rgbPath) +5);
+ strcpy(path, rgbPath);
+ strcat(path, ".txt");
+
+ if (!(rgb = fopen(path, "r")))
+ {
+ ErrorF( "Couldn't open RGB_DB '%s'\n", rgbPath );
+ DEALLOCATE_LOCAL(path);
+ return FALSE;
+ }
+
+ while(fgets(line, sizeof(line), rgb))
+ {
+ lineno++;
+ if (sscanf(line,"%d %d %d %[^\n]\n", &red, &green, &blue, name) == 4)
+ {
+ if (red >= 0 && red <= 0xff &&
+ green >= 0 && green <= 0xff &&
+ blue >= 0 && blue <= 0xff)
+ {
+ if (entry = lookup(name, strlen(name), TRUE))
+ {
+ entry->red = (red * 65535) / 255;
+ entry->green = (green * 65535) / 255;
+ entry->blue = (blue * 65535) / 255;
+ }
+ }
+ else
+ ErrorF("Value for \"%s\" out of range: %s:%d\n",
+ name, path, lineno);
+ }
+ else if (*line && *line != '#' && *line != '!')
+ ErrorF("Syntax Error: %s:%d\n", path, lineno);
+ }
+
+ fclose(rgb);
+ DEALLOCATE_LOCAL(path);
+
+ was_here = TRUE;
+ }
+
+ return TRUE;
+}
+
+
+
+Bool
+OsLookupColor(screen, name, len, pred, pgreen, pblue)
+ int screen;
+ char *name;
+ unsigned len;
+ unsigned short *pred, *pgreen, *pblue;
+
+{
+ dbEntryPtr entry;
+
+ if (entry = lookup(name, len, FALSE))
+ {
+ *pred = entry->red;
+ *pgreen = entry->green;
+ *pblue = entry->blue;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+#endif /* USE_RGB_TXT */
diff --git a/os/osdep.h b/os/osdep.h
new file mode 100644
index 000000000..c7c730740
--- /dev/null
+++ b/os/osdep.h
@@ -0,0 +1,186 @@
+/***********************************************************
+
+Copyright 1987, 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.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/* $Xorg: osdep.h,v 1.5 2001/02/09 02:05:23 xorgcvs Exp $ */
+
+#define BOTIMEOUT 200 /* in milliseconds */
+#define BUFSIZE 4096
+#define BUFWATERMARK 8192
+#define MAXBUFSIZE (1 << 22)
+
+#ifndef sgi /* SGI defines OPEN_MAX in a useless way */
+#ifndef X_NOT_POSIX
+#ifdef _POSIX_SOURCE
+#include <limits.h>
+#else
+#define _POSIX_SOURCE
+#include <limits.h>
+#undef _POSIX_SOURCE
+#endif
+#else /* X_NOT_POSIX */
+#ifdef WIN32
+#define _POSIX_
+#include <limits.h>
+#undef _POSIX_
+#endif
+#endif /* X_NOT_POSIX */
+#endif
+
+#ifndef OPEN_MAX
+#ifdef SVR4
+#define OPEN_MAX 256
+#else
+#include <sys/param.h>
+#ifndef OPEN_MAX
+#if defined(NOFILE) && !defined(NOFILES_MAX)
+#define OPEN_MAX NOFILE
+#else
+#define OPEN_MAX NOFILES_MAX
+#endif
+#endif
+#endif
+#endif
+
+#if OPEN_MAX <= 256
+#define MAXSOCKS (OPEN_MAX - 1)
+#else
+#define MAXSOCKS 256
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+typedef struct _connectionInput {
+ struct _connectionInput *next;
+ char *buffer; /* contains current client input */
+ char *bufptr; /* pointer to current start of data */
+ int bufcnt; /* count of bytes in buffer */
+ int lenLastReq;
+ int size;
+} ConnectionInput, *ConnectionInputPtr;
+
+typedef struct _connectionOutput {
+ struct _connectionOutput *next;
+ int size;
+ unsigned char *buf;
+ int count;
+#ifdef LBX
+ Bool nocompress;
+#endif
+} ConnectionOutput, *ConnectionOutputPtr;
+
+#ifdef K5AUTH
+typedef struct _k5_state {
+ int stageno; /* current stage of auth protocol */
+ pointer srvcreds; /* server credentials */
+ pointer srvname; /* server principal name */
+ pointer ktname; /* key table: principal-key pairs */
+ pointer skey; /* session key */
+} k5_state;
+#endif
+
+#ifdef LBX
+typedef struct _LbxProxy *OsProxyPtr;
+#endif
+
+typedef struct _osComm {
+ int fd;
+ ConnectionInputPtr input;
+ ConnectionOutputPtr output;
+ XID auth_id; /* authorization id */
+#ifdef K5AUTH
+ k5_state authstate; /* state of setup auth conversation */
+#endif
+ CARD32 conn_time; /* timestamp if not established, else 0 */
+ struct _XtransConnInfo *trans_conn; /* transport connection object */
+#ifdef LBX
+ OsProxyPtr proxy;
+ ConnectionInputPtr largereq;
+ void (*Close) ();
+ int (*Flush) ();
+#endif
+} OsCommRec, *OsCommPtr;
+
+#ifdef LBX
+#define FlushClient(who, oc, extraBuf, extraCount) \
+ (*(oc)->Flush)(who, oc, extraBuf, extraCount)
+extern int StandardFlushClient(
+#if NeedFunctionPrototypes
+ ClientPtr /*who*/,
+ OsCommPtr /*oc*/,
+ char* /*extraBuf*/,
+ int /*extraCount*/
+#endif
+);
+#else
+extern int FlushClient(
+#if NeedFunctionPrototypes
+ ClientPtr /*who*/,
+ OsCommPtr /*oc*/,
+ char* /*extraBuf*/,
+ int /*extraCount*/
+#endif
+);
+#endif
+
+extern void FreeOsBuffers(
+#if NeedFunctionPrototypes
+ OsCommPtr /*oc*/
+#endif
+);
+
+extern ConnectionInputPtr AllocateInputBuffer(
+#if NeedFunctionPrototypes
+ void
+#endif
+);
+
+extern ConnectionOutputPtr AllocateOutputBuffer(
+#if NeedFunctionPrototypes
+ void
+#endif
+);
diff --git a/os/osinit.c b/os/osinit.c
new file mode 100644
index 000000000..f240ea42c
--- /dev/null
+++ b/os/osinit.c
@@ -0,0 +1,200 @@
+/***********************************************************
+
+Copyright 1987, 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.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+/* $Xorg: osinit.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */
+
+#include <stdio.h>
+#include "X.h"
+#include "os.h"
+#include "osdep.h"
+#include "Xos.h"
+
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+
+#ifndef WIN32
+#ifndef SYSV
+#include <sys/resource.h>
+#endif
+#endif
+
+#ifndef ADMPATH
+#define ADMPATH "/usr/adm/X%smsgs"
+#endif
+
+extern char *display;
+#ifdef RLIMIT_DATA
+int limitDataSpace = -1;
+#endif
+#ifdef RLIMIT_STACK
+int limitStackSpace = -1;
+#endif
+#ifdef RLIMIT_NOFILE
+int limitNoFile = -1;
+#endif
+
+Bool OsDelayInitColors = FALSE;
+
+void
+OsInit()
+{
+ static Bool been_here = FALSE;
+ static char* admpath = ADMPATH;
+ static char* devnull = "/dev/null";
+ char fname[PATH_MAX];
+
+#ifdef macII
+ set42sig();
+#endif
+
+ if (!been_here) {
+ fclose(stdin);
+ fclose(stdout);
+ /*
+ * If a write of zero bytes to stderr returns non-zero, i.e. -1,
+ * then writing to stderr failed, and we'll write somewhere else
+ * instead. (Apparently this never happens in the Real World.)
+ */
+ if (write (2, fname, 0) == -1)
+ {
+ FILE *err;
+
+ if (strlen (display) + strlen (admpath) + 1 < sizeof fname)
+ sprintf (fname, admpath, display);
+ else
+ strcpy (fname, devnull);
+ /*
+ * uses stdio to avoid os dependencies here,
+ * a real os would use
+ * open (fname, O_WRONLY|O_APPEND|O_CREAT, 0666)
+ */
+ if (!(err = fopen (fname, "a+")))
+ err = fopen (devnull, "w");
+ if (err && (fileno(err) != 2)) {
+ dup2 (fileno (err), 2);
+ fclose (err);
+ }
+#if defined(SYSV) || defined(SVR4) || defined(WIN32)
+ {
+ static char buf[BUFSIZ];
+ setvbuf (stderr, buf, _IOLBF, BUFSIZ);
+ }
+#else
+ setlinebuf(stderr);
+#endif
+ }
+
+#ifndef X_NOT_POSIX
+ if (getpgrp () == 0)
+ setpgid (0, 0);
+#else
+#if !defined(SYSV) && !defined(WIN32)
+ if (getpgrp (0) == 0)
+ setpgrp (0, getpid ());
+#endif
+#endif
+
+#ifdef RLIMIT_DATA
+ if (limitDataSpace >= 0)
+ {
+ struct rlimit rlim;
+
+ if (!getrlimit(RLIMIT_DATA, &rlim))
+ {
+ if ((limitDataSpace > 0) && (limitDataSpace < rlim.rlim_max))
+ rlim.rlim_cur = limitDataSpace;
+ else
+ rlim.rlim_cur = rlim.rlim_max;
+ (void)setrlimit(RLIMIT_DATA, &rlim);
+ }
+ }
+#endif
+#ifdef RLIMIT_STACK
+ if (limitStackSpace >= 0)
+ {
+ struct rlimit rlim;
+
+ if (!getrlimit(RLIMIT_STACK, &rlim))
+ {
+ if ((limitStackSpace > 0) && (limitStackSpace < rlim.rlim_max))
+ rlim.rlim_cur = limitStackSpace;
+ else
+ rlim.rlim_cur = rlim.rlim_max;
+ (void)setrlimit(RLIMIT_STACK, &rlim);
+ }
+ }
+#endif
+#ifdef RLIMIT_NOFILE
+ if (limitNoFile >= 0)
+ {
+ struct rlimit rlim;
+
+ if (!getrlimit(RLIMIT_NOFILE, &rlim))
+ {
+ if ((limitNoFile > 0) && (limitNoFile < rlim.rlim_max))
+ rlim.rlim_cur = limitNoFile;
+ else
+ rlim.rlim_cur = rlim.rlim_max;
+ if (rlim.rlim_cur > MAXSOCKS)
+ rlim.rlim_cur = MAXSOCKS;
+ (void)setrlimit(RLIMIT_NOFILE, &rlim);
+ }
+ }
+#endif
+ been_here = TRUE;
+ }
+ TimerInit();
+#ifdef DDXOSINIT
+ OsVendorInit();
+#endif
+ OsInitAllocator();
+ if (!OsDelayInitColors) OsInitColors();
+}
diff --git a/os/rpcauth.c b/os/rpcauth.c
new file mode 100644
index 000000000..15111921f
--- /dev/null
+++ b/os/rpcauth.c
@@ -0,0 +1,202 @@
+/* $Xorg: rpcauth.c,v 1.4 2001/02/09 02:05:23 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.
+
+*/
+
+/*
+ * SUN-DES-1 authentication mechanism
+ * Author: Mayank Choudhary, Sun Microsystems
+ */
+
+
+#ifdef SECURE_RPC
+
+#include "X.h"
+#include "Xauth.h"
+#include "misc.h"
+#include "os.h"
+#include "dixstruct.h"
+
+#include <rpc/rpc.h>
+
+#ifdef ultrix
+#include <time.h>
+#include <rpc/auth_des.h>
+#endif
+
+static enum auth_stat why;
+
+static char *
+authdes_ezdecode(inmsg, len)
+char *inmsg;
+int len;
+{
+ struct rpc_msg msg;
+ char cred_area[MAX_AUTH_BYTES];
+ char verf_area[MAX_AUTH_BYTES];
+ char *temp_inmsg;
+ struct svc_req r;
+ bool_t res0, res1;
+ XDR xdr;
+ SVCXPRT xprt;
+
+ temp_inmsg = (char *) xalloc(len);
+ memmove(temp_inmsg, inmsg, len);
+
+ memset((char *)&msg, 0, sizeof(msg));
+ memset((char *)&r, 0, sizeof(r));
+ memset(cred_area, 0, sizeof(cred_area));
+ memset(verf_area, 0, sizeof(verf_area));
+
+ msg.rm_call.cb_cred.oa_base = cred_area;
+ msg.rm_call.cb_verf.oa_base = verf_area;
+ why = AUTH_FAILED;
+ xdrmem_create(&xdr, temp_inmsg, len, XDR_DECODE);
+
+ if ((r.rq_clntcred = (caddr_t) xalloc(MAX_AUTH_BYTES)) == NULL)
+ goto bad1;
+ r.rq_xprt = &xprt;
+
+ /* decode into msg */
+ res0 = xdr_opaque_auth(&xdr, &(msg.rm_call.cb_cred));
+ res1 = xdr_opaque_auth(&xdr, &(msg.rm_call.cb_verf));
+ if ( ! (res0 && res1) )
+ goto bad2;
+
+ /* do the authentication */
+
+ r.rq_cred = msg.rm_call.cb_cred; /* read by opaque stuff */
+ if (r.rq_cred.oa_flavor != AUTH_DES) {
+ why = AUTH_TOOWEAK;
+ goto bad2;
+ }
+#ifdef SVR4
+ if ((why = __authenticate(&r, &msg)) != AUTH_OK) {
+#else
+ if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
+#endif
+ goto bad2;
+ }
+ return (((struct authdes_cred *) r.rq_clntcred)->adc_fullname.name);
+
+bad2:
+ Xfree(r.rq_clntcred);
+bad1:
+ return ((char *)0); /* ((struct authdes_cred *) NULL); */
+}
+
+static XID rpc_id = (XID) ~0L;
+
+static Bool
+CheckNetName (addr, len, closure)
+ unsigned char *addr;
+ int len;
+ pointer closure;
+{
+ return (len == strlen ((char *) closure) &&
+ strncmp ((char *) addr, (char *) closure, len) == 0);
+}
+
+static char rpc_error[MAXNETNAMELEN+50];
+
+XID
+SecureRPCCheck (data_length, data, client, reason)
+ register unsigned short data_length;
+ char *data;
+ ClientPtr client;
+ char **reason;
+{
+ char *fullname;
+
+ if (rpc_id == (XID) ~0L) {
+ *reason = "Secure RPC authorization not initialized";
+ } else {
+ fullname = authdes_ezdecode(data, data_length);
+ if (fullname == (char *)0) {
+ sprintf(rpc_error, "Unable to authenticate secure RPC client (why=%d)", why);
+ *reason = rpc_error;
+ } else {
+ if (ForEachHostInFamily (FamilyNetname, CheckNetName,
+ (pointer) fullname))
+ return rpc_id;
+ else {
+ sprintf(rpc_error, "Principal \"%s\" is not authorized to connect",
+ fullname);
+ *reason = rpc_error;
+ }
+ }
+ }
+ return (XID) ~0L;
+}
+
+
+SecureRPCInit ()
+{
+ if (rpc_id == ~0L)
+ AddAuthorization (9, "SUN-DES-1", 0, (char *) 0);
+}
+
+int
+SecureRPCAdd (data_length, data, id)
+unsigned short data_length;
+char *data;
+XID id;
+{
+ if (data_length)
+ AddHost ((pointer) 0, FamilyNetname, data_length, data);
+ rpc_id = id;
+}
+
+int
+SecureRPCReset ()
+{
+ rpc_id = (XID) ~0L;
+}
+
+XID
+SecureRPCToID (data_length, data)
+ unsigned short data_length;
+ char *data;
+{
+ return rpc_id;
+}
+
+SecureRPCFromID (id, data_lenp, datap)
+ XID id;
+ unsigned short *data_lenp;
+ char **datap;
+{
+ return 0;
+}
+
+SecureRPCRemove (data_length, data)
+ unsigned short data_length;
+ char *data;
+{
+ return 0;
+}
+#endif /* SECURE_RPC */
diff --git a/os/secauth.c b/os/secauth.c
new file mode 100644
index 000000000..a73f4e718
--- /dev/null
+++ b/os/secauth.c
@@ -0,0 +1,201 @@
+/* $Xorg: secauth.c,v 1.5 2001/02/15 02:06:01 coskrey Exp $ */
+/*
+Copyright 1996, 1998, 2001 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.
+*/
+
+#include "X.h"
+#include "os.h"
+#include "osdep.h"
+#include "dixstruct.h"
+
+#ifdef XCSECURITY
+#define _SECURITY_SERVER
+#include "extensions/security.h"
+#endif
+
+static char InvalidPolicyReason[] = "invalid policy specification";
+static char PolicyViolationReason[] = "policy violation";
+
+static Bool
+AuthCheckSitePolicy(data_lengthP, dataP, client, reason)
+ unsigned short *data_lengthP;
+ char **dataP;
+ ClientPtr client;
+ char **reason;
+{
+ CARD8 *policy = *(CARD8 **)dataP;
+ int length;
+ Bool permit;
+ int nPolicies;
+ char **sitePolicies;
+ int nSitePolicies;
+ Bool found = FALSE;
+
+ if ((length = *data_lengthP) < 2) {
+ *reason = InvalidPolicyReason;
+ return FALSE;
+ }
+
+ permit = (*policy++ == 0);
+ nPolicies = (CARD8) *policy++;
+
+ length -= 2;
+
+ sitePolicies = SecurityGetSitePolicyStrings(&nSitePolicies);
+
+ while (nPolicies > 0) {
+ int strLen, sitePolicy;
+
+ if (length == 0) {
+ *reason = InvalidPolicyReason;
+ return FALSE;
+ }
+
+ strLen = (CARD8) *policy++;
+ if (--length < strLen) {
+ *reason = InvalidPolicyReason;
+ return FALSE;
+ }
+
+ if (!found)
+ {
+ for (sitePolicy = 0; sitePolicy < nSitePolicies; sitePolicy++)
+ {
+ char *testPolicy = sitePolicies[sitePolicy];
+ if ((strLen == strlen(testPolicy)) &&
+ (strncmp((char *)policy, testPolicy, strLen) == 0))
+ {
+ found = TRUE; /* need to continue parsing the policy... */
+ break;
+ }
+ }
+ }
+
+ policy += strLen;
+ length -= strLen;
+ nPolicies--;
+ }
+
+ if (found != permit)
+ {
+ *reason = PolicyViolationReason;
+ return FALSE;
+ }
+
+ *data_lengthP = length;
+ *dataP = (char *)policy;
+ return TRUE;
+}
+
+XID
+AuthSecurityCheck (data_length, data, client, reason)
+ unsigned short data_length;
+ char *data;
+ ClientPtr client;
+ char **reason;
+{
+#ifdef XCSECURITY
+ OsCommPtr oc = (OsCommPtr)client->osPrivate;
+ register ConnectionInputPtr oci = oc->input;
+ xConnSetupPrefix csp;
+ xReq freq;
+
+ if (client->clientState == ClientStateCheckedSecurity)
+ {
+ *reason = "repeated security check not permitted";
+ return (XID) -1;
+ }
+ else if (data_length > 0)
+ {
+ char policy_mask = *data++;
+
+ if (--data_length == 1) {
+ *reason = InvalidPolicyReason;
+ return (XID) -1;
+ }
+
+ if (policy_mask & 0x01) /* Extensions policy */
+ {
+ /* AuthCheckExtensionPolicy(&data_length, &data, client, reason) */
+ *reason = "security policy not implemented";
+ return (XID) -1;
+ }
+
+ if (policy_mask & 0x02) /* Site policy */
+ {
+ if (!AuthCheckSitePolicy(&data_length, &data, client, reason))
+ return (XID) -1;
+ }
+
+ if (data_length > 0) { /* did we consume the whole policy? */
+ *reason = InvalidPolicyReason;
+ return (XID) -1;
+ }
+
+ }
+ else if (!GetAccessControl())
+ {
+ /*
+ * The client - possibly the X FireWall Proxy - gave
+ * no auth data and host-based authorization is turned
+ * off. In this case, the client should be denied
+ * access to the X server.
+ */
+ *reason = "server host access control is disabled";
+ return (XID) -1;
+ }
+
+ client->clientState = ClientStateCheckingSecurity;
+
+ csp.success = 2 /* Authenticate */;
+ csp.lengthReason = 0;
+ csp.length = 0;
+ csp.majorVersion = X_PROTOCOL;
+ csp.minorVersion = X_PROTOCOL_REVISION;
+ if (client->swapped)
+ WriteSConnSetupPrefix(client, &csp);
+ else
+ (void)WriteToClient(client, sz_xConnSetupPrefix, (char *) &csp);
+
+ /*
+ * Next time the client sends the real auth data, we want
+ * ProcEstablishConnection to be called.
+ */
+
+ freq.reqType = 1;
+ freq.length = (sz_xReq + sz_xConnClientPrefix) >> 2;
+ client->swapped = FALSE;
+ if (!InsertFakeRequest(client, (char *)&freq, sz_xReq))
+ {
+ *reason = "internal error";
+ return (XID) -1;
+ }
+
+ return (XID) 0;
+#else
+ *reason = "method not supported";
+ return (XID) -1;
+#endif
+}
diff --git a/os/utils.c b/os/utils.c
new file mode 100644
index 000000000..2c3d0ba63
--- /dev/null
+++ b/os/utils.c
@@ -0,0 +1,1105 @@
+/* $Xorg: utils.c,v 1.5 2001/02/09 02:05:24 xorgcvs Exp $ */
+/*
+
+Copyright 1987, 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.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
+Copyright 1994 Quarterdeck Office Systems.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital and
+Quarterdeck not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
+OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+#ifdef WIN32
+#include <X11/Xwinsock.h>
+#endif
+#include "Xos.h"
+#include <stdio.h>
+#include "misc.h"
+#include "X.h"
+#include "input.h"
+#include "opaque.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 WIN32
+#ifndef SYSV
+#include <sys/resource.h>
+#endif
+#endif
+#include <time.h>
+#include <sys/stat.h>
+#include <ctype.h> /* for isspace */
+#if NeedVarargsPrototypes
+#include <stdarg.h>
+#endif
+#if defined(TCPCONN) || defined(STREAMSCONN)
+# ifndef WIN32
+# include <netdb.h>
+# endif
+#endif
+
+#define X_INCLUDE_NETDB_H
+#include <X11/Xos_r.h>
+
+extern char *display;
+
+extern CARD32 defaultScreenSaverTime; /* for parsing command line */
+extern CARD32 defaultScreenSaverInterval;
+extern int defaultScreenSaverBlanking;
+extern int defaultBackingStore;
+extern Bool disableBackingStore;
+extern Bool disableSaveUnders;
+extern Bool PartialNetwork;
+#ifndef NOLOGOHACK
+extern int logoScreenSaver;
+#endif
+#ifdef RLIMIT_DATA
+extern int limitDataSpace;
+#endif
+#ifdef RLIMIT_STACK
+extern int limitStackSpace;
+#endif
+#ifdef RLIMIT_NOFILE
+extern int limitNoFile;
+#endif
+extern int defaultColorVisualClass;
+extern Bool permitOldBugs;
+extern int monitorResolution;
+extern Bool defeatAccessControl;
+
+#ifdef DPMSExtension
+extern BOOL DPMSEnabledSwitch;
+extern BOOL DPMSDisabledSwitch;
+#endif
+
+Bool CoreDump;
+Bool noTestExtensions;
+
+Bool noPanoramiXExtension = TRUE;
+#ifdef PANORAMIX
+Bool PanoramiXVisibilityNotifySent = FALSE;
+Bool PanoramiXMapped = FALSE;
+Bool PanoramiXWindowExposureSent = FALSE;
+Bool PanoramiXOneExposeRequest = FALSE;
+#endif
+
+int auditTrailLevel = 1;
+
+void ddxUseMsg();
+#if NeedVarargsPrototypes
+void VErrorF(char*, va_list);
+#endif
+
+#ifdef AIXV3
+int SyncOn = 0;
+extern int SelectWaitTime;
+#endif
+
+#ifdef DEBUG
+#ifndef SPECIAL_MALLOC
+#define MEMBUG
+#endif
+#endif
+
+#ifdef MEMBUG
+#define MEM_FAIL_SCALE 100000
+long Memory_fail = 0;
+
+#endif
+
+#ifdef sgi
+int userdefinedfontpath = 0;
+#endif /* sgi */
+
+Bool Must_have_memory = FALSE;
+
+char *dev_tty_from_init = NULL; /* since we need to parse it anyway */
+
+OsSigHandlerPtr
+OsSignal(sig, handler)
+ int sig;
+ OsSigHandlerPtr handler;
+{
+#ifdef X_NOT_POSIX
+ return signal(sig, handler);
+#else
+ struct sigaction act, oact;
+
+ sigemptyset(&act.sa_mask);
+ if (handler != SIG_IGN)
+ sigaddset(&act.sa_mask, sig);
+ act.sa_flags = 0;
+ act.sa_handler = handler;
+ sigaction(sig, &act, &oact);
+ return oact.sa_handler;
+#endif
+}
+
+/* Force connections to close on SIGHUP from init */
+
+/*ARGSUSED*/
+SIGVAL
+AutoResetServer (sig)
+ int sig;
+{
+ dispatchException |= DE_RESET;
+ isItTimeToYield = TRUE;
+#ifdef GPROF
+ chdir ("/tmp");
+ exit (0);
+#endif
+#if defined(SYSV) && defined(X_NOT_POSIX)
+ OsSignal (SIGHUP, AutoResetServer);
+#endif
+}
+
+/* Force connections to close and then exit on SIGTERM, SIGINT */
+
+/*ARGSUSED*/
+SIGVAL
+GiveUp(sig)
+ int sig;
+{
+ dispatchException |= DE_TERMINATE;
+ isItTimeToYield = TRUE;
+#if defined(SYSV) && defined(X_NOT_POSIX)
+ if (sig)
+ OsSignal(sig, SIG_IGN);
+#endif
+}
+
+
+static void
+AbortServer()
+{
+ extern void AbortDDX();
+
+ AbortDDX();
+ fflush(stderr);
+ if (CoreDump)
+ abort();
+ exit (1);
+}
+
+void
+Error(str)
+ char *str;
+{
+ perror(str);
+}
+
+#ifndef DDXTIME
+CARD32
+GetTimeInMillis()
+{
+ struct timeval tp;
+
+ X_GETTIMEOFDAY(&tp);
+ return(tp.tv_sec * 1000) + (tp.tv_usec / 1000);
+}
+#endif
+
+AdjustWaitForDelay (waitTime, newdelay)
+ pointer waitTime;
+ unsigned long newdelay;
+{
+ static struct timeval delay_val;
+ struct timeval **wt = (struct timeval **) waitTime;
+ unsigned long olddelay;
+
+ if (*wt == NULL)
+ {
+ delay_val.tv_sec = newdelay / 1000;
+ delay_val.tv_usec = 1000 * (newdelay % 1000);
+ *wt = &delay_val;
+ }
+ else
+ {
+ olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000;
+ if (newdelay < olddelay)
+ {
+ (*wt)->tv_sec = newdelay / 1000;
+ (*wt)->tv_usec = 1000 * (newdelay % 1000);
+ }
+ }
+}
+
+void UseMsg()
+{
+#if !defined(AIXrt) && !defined(AIX386)
+ ErrorF("use: X [:<display>] [option]\n");
+ ErrorF("-a # mouse acceleration (pixels)\n");
+ ErrorF("-ac disable access control restrictions\n");
+#ifdef MEMBUG
+ ErrorF("-alloc int chance alloc should fail\n");
+#endif
+ ErrorF("-audit int set audit trail level\n");
+ ErrorF("-auth file select authorization file\n");
+ ErrorF("bc enable bug compatibility\n");
+ ErrorF("-bs disable any backing store support\n");
+ ErrorF("-c turns off key-click\n");
+ ErrorF("c # key-click volume (0-100)\n");
+ ErrorF("-cc int default color visual class\n");
+ ErrorF("-co file color database file\n");
+#ifdef COMMANDLINE_CHALLENGED_OPERATING_SYSTEMS
+ ErrorF("-config file read options from file\n");
+#endif
+ ErrorF("-core generate core dump on fatal error\n");
+ ErrorF("-dpi int screen resolution in dots per inch\n");
+#ifdef DPMSExtension
+ ErrorF("dpms enables VESA DPMS monitor control\n");
+ ErrorF("-dpms disables VESA DPMS monitor control\n");
+#endif
+ ErrorF("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n");
+ ErrorF("-f # bell base (0-100)\n");
+ ErrorF("-fc string cursor font\n");
+ ErrorF("-fn string default font name\n");
+ ErrorF("-fp string default font path\n");
+ ErrorF("-help prints message with these options\n");
+ ErrorF("-I ignore all remaining arguments\n");
+#ifdef RLIMIT_DATA
+ ErrorF("-ld int limit data space to N Kb\n");
+#endif
+#ifdef RLIMIT_NOFILE
+ ErrorF("-lf int limit number of open files to N\n");
+#endif
+#ifdef RLIMIT_STACK
+ ErrorF("-ls int limit stack space to N Kb\n");
+#endif
+#ifndef NOLOGOHACK
+ ErrorF("-logo enable logo in screen saver\n");
+ ErrorF("nologo disable logo in screen saver\n");
+#endif
+ ErrorF("-p # screen-saver pattern duration (minutes)\n");
+ ErrorF("-pn accept failure to listen on all ports\n");
+ ErrorF("-r turns off auto-repeat\n");
+ ErrorF("r turns on auto-repeat \n");
+ ErrorF("-s # screen-saver timeout (minutes)\n");
+#ifdef XCSECURITY
+ ErrorF("-sp file security policy file\n");
+#endif
+ ErrorF("-su disable any save under support\n");
+ ErrorF("-t # mouse threshold (pixels)\n");
+ ErrorF("-terminate terminate at server reset\n");
+ ErrorF("-to # connection time out\n");
+ ErrorF("-tst disable testing extensions\n");
+ ErrorF("ttyxx server started from init on /dev/ttyxx\n");
+ ErrorF("v video blanking for screen-saver\n");
+ ErrorF("-v screen-saver without video blanking\n");
+ ErrorF("-wm WhenMapped default backing-store\n");
+#ifdef PANORAMIX
+ ErrorF("+xinerama Enable XINERAMA extension\n");
+ ErrorF("-xinerama Disable XINERAMA extension\n");
+#endif
+ ErrorF("-x string loads named extension at init time \n");
+#ifdef XDMCP
+ XdmcpUseMsg();
+#endif
+#endif /* !AIXrt && ! AIX386 */
+#ifdef XKB
+ XkbUseMsg();
+#endif
+ ddxUseMsg();
+}
+
+/*
+ * This function parses the command line. Handles device-independent fields
+ * and allows ddx to handle additional fields. It is not allowed to modify
+ * argc or any of the strings pointed to by argv.
+ */
+void
+ProcessCommandLine ( argc, argv )
+int argc;
+char *argv[];
+
+{
+ int i, skip;
+
+ defaultKeyboardControl.autoRepeat = TRUE;
+
+ for ( i = 1; i < argc; i++ )
+ {
+ /* call ddx first, so it can peek/override if it wants */
+ if(skip = ddxProcessArgument(argc, argv, i))
+ {
+ i += (skip - 1);
+ }
+ else if(argv[i][0] == ':')
+ {
+ /* initialize display */
+ display = argv[i];
+ display++;
+ }
+ else if ( strcmp( argv[i], "-a") == 0)
+ {
+ if(++i < argc)
+ defaultPointerControl.num = atoi(argv[i]);
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-ac") == 0)
+ {
+ defeatAccessControl = TRUE;
+ }
+#ifdef MEMBUG
+ else if ( strcmp( argv[i], "-alloc") == 0)
+ {
+ if(++i < argc)
+ Memory_fail = atoi(argv[i]);
+ else
+ UseMsg();
+ }
+#endif
+ else if ( strcmp( argv[i], "-audit") == 0)
+ {
+ if(++i < argc)
+ auditTrailLevel = atoi(argv[i]);
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-auth") == 0)
+ {
+ if(++i < argc)
+ InitAuthorization (argv[i]);
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "bc") == 0)
+ permitOldBugs = TRUE;
+ else if ( strcmp( argv[i], "-bs") == 0)
+ disableBackingStore = TRUE;
+ else if ( strcmp( argv[i], "c") == 0)
+ {
+ if(++i < argc)
+ defaultKeyboardControl.click = atoi(argv[i]);
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-c") == 0)
+ {
+ defaultKeyboardControl.click = 0;
+ }
+ else if ( strcmp( argv[i], "-cc") == 0)
+ {
+ if(++i < argc)
+ defaultColorVisualClass = atoi(argv[i]);
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-co") == 0)
+ {
+ if(++i < argc)
+ rgbPath = argv[i];
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-core") == 0)
+ CoreDump = TRUE;
+ else if ( strcmp( argv[i], "-dpi") == 0)
+ {
+ if(++i < argc)
+ monitorResolution = atoi(argv[i]);
+ else
+ UseMsg();
+ }
+#ifdef DPMSExtension
+ else if ( strcmp( argv[i], "dpms") == 0)
+ DPMSEnabledSwitch = TRUE;
+ else if ( strcmp( argv[i], "-dpms") == 0)
+ DPMSDisabledSwitch = TRUE;
+#endif
+ else if ( strcmp( argv[i], "-deferglyphs") == 0)
+ {
+ if(++i >= argc || !ParseGlyphCachingMode(argv[i]))
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-f") == 0)
+ {
+ if(++i < argc)
+ defaultKeyboardControl.bell = atoi(argv[i]);
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-fc") == 0)
+ {
+ if(++i < argc)
+ defaultCursorFont = argv[i];
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-fn") == 0)
+ {
+ if(++i < argc)
+ defaultTextFont = argv[i];
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-fp") == 0)
+ {
+ if(++i < argc)
+ {
+#ifdef sgi
+ userdefinedfontpath = 1;
+#endif /* sgi */
+ defaultFontPath = argv[i];
+ }
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-help") == 0)
+ {
+ UseMsg();
+ exit(0);
+ }
+#ifdef XKB
+ else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) {
+ if (skip>0)
+ i+= skip-1;
+ else UseMsg();
+ }
+#endif
+#ifdef RLIMIT_DATA
+ else if ( strcmp( argv[i], "-ld") == 0)
+ {
+ if(++i < argc)
+ {
+ limitDataSpace = atoi(argv[i]);
+ if (limitDataSpace > 0)
+ limitDataSpace *= 1024;
+ }
+ else
+ UseMsg();
+ }
+#endif
+#ifdef RLIMIT_NOFILE
+ else if ( strcmp( argv[i], "-lf") == 0)
+ {
+ if(++i < argc)
+ limitNoFile = atoi(argv[i]);
+ else
+ UseMsg();
+ }
+#endif
+#ifdef RLIMIT_STACK
+ else if ( strcmp( argv[i], "-ls") == 0)
+ {
+ if(++i < argc)
+ {
+ limitStackSpace = atoi(argv[i]);
+ if (limitStackSpace > 0)
+ limitStackSpace *= 1024;
+ }
+ else
+ UseMsg();
+ }
+#endif
+#ifndef NOLOGOHACK
+ else if ( strcmp( argv[i], "-logo") == 0)
+ {
+ logoScreenSaver = 1;
+ }
+ else if ( strcmp( argv[i], "nologo") == 0)
+ {
+ logoScreenSaver = 0;
+ }
+#endif
+ else if ( strcmp( argv[i], "-p") == 0)
+ {
+ if(++i < argc)
+ defaultScreenSaverInterval = ((CARD32)atoi(argv[i])) *
+ MILLI_PER_MIN;
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-pn") == 0)
+ PartialNetwork = TRUE;
+ else if ( strcmp( argv[i], "r") == 0)
+ defaultKeyboardControl.autoRepeat = TRUE;
+ else if ( strcmp( argv[i], "-r") == 0)
+ defaultKeyboardControl.autoRepeat = FALSE;
+ else if ( strcmp( argv[i], "-s") == 0)
+ {
+ if(++i < argc)
+ defaultScreenSaverTime = ((CARD32)atoi(argv[i])) *
+ MILLI_PER_MIN;
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-su") == 0)
+ disableSaveUnders = TRUE;
+ else if ( strcmp( argv[i], "-t") == 0)
+ {
+ if(++i < argc)
+ defaultPointerControl.threshold = atoi(argv[i]);
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-terminate") == 0)
+ {
+ extern Bool terminateAtReset;
+
+ terminateAtReset = TRUE;
+ }
+ else if ( strcmp( argv[i], "-to") == 0)
+ {
+ if(++i < argc)
+ TimeOutValue = ((CARD32)atoi(argv[i])) * MILLI_PER_SECOND;
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-tst") == 0)
+ {
+ noTestExtensions = TRUE;
+ }
+ else if ( strcmp( argv[i], "v") == 0)
+ defaultScreenSaverBlanking = PreferBlanking;
+ else if ( strcmp( argv[i], "-v") == 0)
+ defaultScreenSaverBlanking = DontPreferBlanking;
+ else if ( strcmp( argv[i], "-wm") == 0)
+ defaultBackingStore = WhenMapped;
+#ifdef PANORAMIX
+ else if ( strcmp( argv[i], "+xinerama") == 0){
+ noPanoramiXExtension = FALSE;
+ }
+ else if ( strcmp( argv[i], "-xinerama") == 0){
+ noPanoramiXExtension = TRUE;
+ }
+#endif
+ else if ( strcmp( argv[i], "-x") == 0)
+ {
+ if(++i >= argc)
+ UseMsg();
+ /* For U**x, which doesn't support dynamic loading, there's nothing
+ * to do when we see a -x. Either the extension is linked in or
+ * it isn't */
+ }
+ else if ( strcmp( argv[i], "-I") == 0)
+ {
+ /* ignore all remaining arguments */
+ break;
+ }
+ else if (strncmp (argv[i], "tty", 3) == 0)
+ {
+ /* just in case any body is interested */
+ dev_tty_from_init = argv[i];
+ }
+#ifdef XDMCP
+ else if ((skip = XdmcpOptions(argc, argv, i)) != i)
+ {
+ i = skip - 1;
+ }
+#endif
+#ifdef XPRINT
+ else if ((skip = XprintOptions(argc, argv, i)) != i)
+ {
+ i = skip - 1;
+ }
+#endif
+#ifdef XCSECURITY
+ else if ((skip = XSecurityOptions(argc, argv, i)) != i)
+ {
+ i = skip - 1;
+ }
+#endif
+#ifdef AIXV3
+ else if ( strcmp( argv[i], "-timeout") == 0)
+ {
+ if(++i < argc)
+ SelectWaitTime = atoi(argv[i]);
+ else
+ UseMsg();
+ }
+ else if ( strcmp( argv[i], "-sync") == 0)
+ {
+ SyncOn++;
+ }
+#endif
+ else
+ {
+ UseMsg();
+ exit (1);
+ }
+ }
+}
+
+#ifdef COMMANDLINE_CHALLENGED_OPERATING_SYSTEMS
+static void
+InsertFileIntoCommandLine(resargc, resargv, prefix_argc, prefix_argv,
+ filename, suffix_argc, suffix_argv)
+ int *resargc;
+ char ***resargv;
+ int prefix_argc;
+ char **prefix_argv;
+ char *filename;
+ int suffix_argc;
+ char **suffix_argv;
+{
+ struct stat st;
+ FILE *f;
+ char *p;
+ char *q;
+ int insert_argc;
+ char *buf;
+ int len;
+ int i;
+
+ f = fopen(filename, "r");
+ if (!f)
+ FatalError("Can't open option file %s\n", filename);
+
+ fstat(fileno(f), &st);
+
+ buf = (char *) xalloc((unsigned) st.st_size + 1);
+ if (!buf)
+ FatalError("Out of Memory\n");
+
+ len = fread(buf, 1, (unsigned) st.st_size, f);
+
+ fclose(f);
+
+ if (len < 0)
+ FatalError("Error reading option file %s\n", filename);
+
+ buf[len] = '\0';
+
+ p = buf;
+ q = buf;
+ insert_argc = 0;
+
+ while (*p)
+ {
+ while (isspace(*p))
+ p++;
+ if (!*p)
+ break;
+ if (*p == '#')
+ {
+ while (*p && *p != '\n')
+ p++;
+ } else
+ {
+ while (*p && !isspace(*p))
+ *q++ = *p++;
+ /* Since p and q might still be pointing at the same place, we */
+ /* need to step p over the whitespace now before we add the null. */
+ if (*p)
+ p++;
+ *q++ = '\0';
+ insert_argc++;
+ }
+ }
+
+ buf = (char *) xrealloc(buf, q - buf);
+ if (!buf)
+ FatalError("Out of memory reallocing option buf\n");
+
+ *resargc = prefix_argc + insert_argc + suffix_argc;
+ *resargv = (char **) xalloc((*resargc + 1) * sizeof(char *));
+ if (!*resargv)
+ FatalError("Out of Memory\n");
+
+ memcpy(*resargv, prefix_argv, prefix_argc * sizeof(char *));
+
+ p = buf;
+ for (i = 0; i < insert_argc; i++)
+ {
+ (*resargv)[prefix_argc + i] = p;
+ p += strlen(p) + 1;
+ }
+
+ memcpy(*resargv + prefix_argc + insert_argc,
+ suffix_argv, suffix_argc * sizeof(char *));
+
+ (*resargv)[*resargc] = NULL;
+} /* end InsertFileIntoCommandLine */
+
+
+void
+ExpandCommandLine(pargc, pargv)
+ int *pargc;
+ char ***pargv;
+{
+ int i;
+ for (i = 1; i < *pargc; i++)
+ {
+ if ( (0 == strcmp((*pargv)[i], "-config")) && (i < (*pargc - 1)) )
+ {
+ InsertFileIntoCommandLine(pargc, pargv,
+ i, *pargv,
+ (*pargv)[i+1], /* filename */
+ *pargc - i - 2, *pargv + i + 2);
+ i--;
+ }
+ }
+} /* end ExpandCommandLine */
+#endif
+
+/* Implement a simple-minded font authorization scheme. The authorization
+ name is "hp-hostname-1", the contents are simply the host name. */
+int
+set_font_authorizations(authorizations, authlen, client)
+char **authorizations;
+int *authlen;
+pointer client;
+{
+#define AUTHORIZATION_NAME "hp-hostname-1"
+#if defined(TCPCONN) || defined(STREAMSCONN)
+ static char result[1024];
+ static char *p = NULL;
+
+ if (p == NULL)
+ {
+ char hname[1024], *hnameptr;
+ struct hostent *host;
+ int len;
+ _Xgethostbynameparams hparams;
+
+ gethostname(hname, 1024);
+ host = _XGethostbyname(hname, hparams);
+ if (host == NULL)
+ hnameptr = hname;
+ else
+ hnameptr = host->h_name;
+
+ p = result;
+ *p++ = sizeof(AUTHORIZATION_NAME) >> 8;
+ *p++ = sizeof(AUTHORIZATION_NAME) & 0xff;
+ *p++ = (len = strlen(hnameptr) + 1) >> 8;
+ *p++ = (len & 0xff);
+
+ memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME));
+ p += sizeof(AUTHORIZATION_NAME);
+ memmove(p, hnameptr, len);
+ p += len;
+ }
+ *authlen = p - result;
+ *authorizations = result;
+ return 1;
+#else /* TCPCONN */
+ return 0;
+#endif /* TCPCONN */
+}
+
+/* XALLOC -- X's internal memory allocator. Why does it return unsigned
+ * long * instead of the more common char *? Well, if you read K&R you'll
+ * see they say that alloc must return a pointer "suitable for conversion"
+ * to whatever type you really want. In a full-blown generic allocator
+ * there's no way to solve the alignment problems without potentially
+ * wasting lots of space. But we have a more limited problem. We know
+ * we're only ever returning pointers to structures which will have to
+ * be long word aligned. So we are making a stronger guarantee. It might
+ * have made sense to make Xalloc return char * to conform with people's
+ * expectations of malloc, but this makes lint happier.
+ */
+
+unsigned long *
+Xalloc (amount)
+ unsigned long amount;
+{
+ char *malloc();
+ register pointer ptr;
+
+ if ((long)amount <= 0)
+ return (unsigned long *)NULL;
+ /* aligned extra on long word boundary */
+ amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
+#ifdef MEMBUG
+ if (!Must_have_memory && Memory_fail &&
+ ((random() % MEM_FAIL_SCALE) < Memory_fail))
+ return (unsigned long *)NULL;
+#endif
+ if (ptr = (pointer)malloc(amount))
+ return (unsigned long *)ptr;
+ if (Must_have_memory)
+ FatalError("Out of memory");
+ return (unsigned long *)NULL;
+}
+
+/*****************
+ * XNFalloc
+ * "no failure" realloc, alternate interface to Xalloc w/o Must_have_memory
+ *****************/
+
+unsigned long *
+XNFalloc (amount)
+ unsigned long amount;
+{
+ char *malloc();
+ register pointer ptr;
+
+ if ((long)amount <= 0)
+ {
+ return (unsigned long *)NULL;
+ }
+ /* aligned extra on long word boundary */
+ amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
+ ptr = (pointer)malloc(amount);
+ if (!ptr)
+ {
+ FatalError("Out of memory");
+ }
+ return ((unsigned long *)ptr);
+}
+
+/*****************
+ * Xcalloc
+ *****************/
+
+unsigned long *
+Xcalloc (amount)
+ unsigned long amount;
+{
+ unsigned long *ret;
+
+ ret = Xalloc (amount);
+ if (ret)
+ bzero ((char *) ret, (int) amount);
+ return ret;
+}
+
+/*****************
+ * Xrealloc
+ *****************/
+
+unsigned long *
+Xrealloc (ptr, amount)
+ register pointer ptr;
+ unsigned long amount;
+{
+ char *malloc();
+ char *realloc();
+
+#ifdef MEMBUG
+ if (!Must_have_memory && Memory_fail &&
+ ((random() % MEM_FAIL_SCALE) < Memory_fail))
+ return (unsigned long *)NULL;
+#endif
+ if ((long)amount <= 0)
+ {
+ if (ptr && !amount)
+ free(ptr);
+ return (unsigned long *)NULL;
+ }
+ amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
+ if (ptr)
+ ptr = (pointer)realloc((char *)ptr, amount);
+ else
+ ptr = (pointer)malloc(amount);
+ if (ptr)
+ return (unsigned long *)ptr;
+ if (Must_have_memory)
+ FatalError("Out of memory");
+ return (unsigned long *)NULL;
+}
+
+/*****************
+ * XNFrealloc
+ * "no failure" realloc, alternate interface to Xrealloc w/o Must_have_memory
+ *****************/
+
+unsigned long *
+XNFrealloc (ptr, amount)
+ register pointer ptr;
+ unsigned long amount;
+{
+ if (( ptr = (pointer)Xrealloc( ptr, amount ) ) == NULL)
+ {
+ FatalError( "Out of memory" );
+ }
+ return ((unsigned long *)ptr);
+}
+
+/*****************
+ * Xfree
+ * calls free
+ *****************/
+
+void
+Xfree(ptr)
+ register pointer ptr;
+{
+ if (ptr)
+ free((char *)ptr);
+}
+
+OsInitAllocator ()
+{
+#ifdef MEMBUG
+ static int been_here;
+
+ /* Check the memory system after each generation */
+ if (been_here)
+ CheckMemory ();
+ else
+ been_here = 1;
+#endif
+}
+
+void
+AuditPrefix(f)
+ char *f;
+{
+#ifdef X_NOT_STDC_ENV
+ long tm;
+#else
+ time_t tm;
+#endif
+ char *autime, *s;
+ if (*f != ' ')
+ {
+ time(&tm);
+ autime = ctime(&tm);
+ if (s = strchr(autime, '\n'))
+ *s = '\0';
+ if (s = strrchr(argvGlobal[0], '/'))
+ s++;
+ else
+ s = argvGlobal[0];
+ ErrorF("AUDIT: %s: %d %s: ", autime, getpid(), s);
+ }
+}
+
+/*VARARGS1*/
+void
+AuditF(
+#if NeedVarargsPrototypes
+ char * f, ...)
+#else
+ f, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9) /* limit of ten args */
+ char *f;
+ char *s0, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9;
+#endif
+{
+#if NeedVarargsPrototypes
+ va_list args;
+#endif
+
+ AuditPrefix(f);
+
+#if NeedVarargsPrototypes
+ va_start(args, f);
+ VErrorF(f, args);
+ va_end(args);
+#else
+ ErrorF(f, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9);
+#endif
+}
+
+/*VARARGS1*/
+void
+FatalError(
+#if NeedVarargsPrototypes
+ char *f, ...)
+#else
+f, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9) /* limit of ten args */
+ char *f;
+ char *s0, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9;
+#endif
+{
+#if NeedVarargsPrototypes
+ va_list args;
+#endif
+ ErrorF("\nFatal server error:\n");
+#if NeedVarargsPrototypes
+ va_start(args, f);
+ VErrorF(f, args);
+ va_end(args);
+#else
+ ErrorF(f, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9);
+#endif
+ ErrorF("\n");
+ AbortServer();
+ /*NOTREACHED*/
+}
+
+#if NeedVarargsPrototypes
+void
+VErrorF(f, args)
+ char *f;
+ va_list args;
+{
+#ifdef AIXV3
+ if (SyncOn)
+ sync();
+#else
+ vfprintf(stderr, f, args);
+#endif /* AIXV3 */
+}
+#endif
+
+/*VARARGS1*/
+void
+ErrorF(
+#if NeedVarargsPrototypes
+ char * f, ...)
+#else
+ f, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9) /* limit of ten args */
+ char *f;
+ char *s0, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9;
+#endif
+{
+#if NeedVarargsPrototypes
+ va_list args;
+ va_start(args, f);
+ VErrorF(f, args);
+ va_end(args);
+#else
+#ifdef AIXV3
+ if (SyncOn)
+ sync();
+#else /* not AIXV3 */
+ fprintf( stderr, f, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9);
+#endif /* AIXV3 */
+#endif
+}
diff --git a/os/xdmauth.c b/os/xdmauth.c
new file mode 100644
index 000000000..d6abd6a14
--- /dev/null
+++ b/os/xdmauth.c
@@ -0,0 +1,518 @@
+/* $Xorg: xdmauth.c,v 1.4 2001/02/09 02:05:24 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-AUTHENTICATION-1 (XDMCP authentication) and
+ * XDM-AUTHORIZATION-1 (client authorization) protocols
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+#include <stdio.h>
+#include "X.h"
+#include "Xtrans.h"
+#include "os.h"
+#include "osdep.h"
+#include "dixstruct.h"
+
+#ifdef HASXDMAUTH
+
+static Bool authFromXDMCP;
+
+#ifdef XDMCP
+#include "Xmd.h"
+#undef REQUEST
+#include "Xdmcp.h"
+
+/* XDM-AUTHENTICATION-1 */
+
+static XdmAuthKeyRec privateKey;
+static char XdmAuthenticationName[] = "XDM-AUTHENTICATION-1";
+#define XdmAuthenticationNameLen (sizeof XdmAuthenticationName - 1)
+static XdmAuthKeyRec rho;
+
+static Bool XdmAuthenticationValidator (privateData, incomingData, packet_type)
+ ARRAY8Ptr privateData, incomingData;
+ xdmOpCode packet_type;
+{
+ XdmAuthKeyPtr incoming;
+
+ XdmcpUnwrap (incomingData->data, &privateKey,
+ incomingData->data,incomingData->length);
+ switch (packet_type)
+ {
+ case ACCEPT:
+ if (incomingData->length != 8)
+ return FALSE;
+ incoming = (XdmAuthKeyPtr) incomingData->data;
+ XdmcpDecrementKey (incoming);
+ return XdmcpCompareKeys (incoming, &rho);
+ }
+ return FALSE;
+}
+
+static Bool
+XdmAuthenticationGenerator (privateData, outgoingData, packet_type)
+ ARRAY8Ptr privateData, outgoingData;
+ xdmOpCode packet_type;
+{
+ outgoingData->length = 0;
+ outgoingData->data = 0;
+ switch (packet_type)
+ {
+ case REQUEST:
+ if (XdmcpAllocARRAY8 (outgoingData, 8))
+ XdmcpWrap (&rho, &privateKey, outgoingData->data, 8);
+ }
+ return TRUE;
+}
+
+static Bool
+XdmAuthenticationAddAuth (name_len, name, data_len, data)
+ int name_len, data_len;
+ char *name, *data;
+{
+ Bool ret;
+ XdmcpUnwrap (data, &privateKey, data, data_len);
+ authFromXDMCP = TRUE;
+ ret = AddAuthorization (name_len, name, data_len, data);
+ authFromXDMCP = FALSE;
+ return ret;
+}
+
+
+#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 int
+HexToBinary (in, out, len)
+ char *out, *in;
+ int len;
+{
+ int top, bottom;
+
+ while (len > 0)
+ {
+ top = atox(in[0]);
+ if (top == -1)
+ return 0;
+ bottom = atox(in[1]);
+ if (bottom == -1)
+ return 0;
+ *out++ = (top << 4) | bottom;
+ in += 2;
+ len -= 2;
+ }
+ if (len)
+ return 0;
+ *out++ = '\0';
+ return 1;
+}
+
+void
+XdmAuthenticationInit (cookie, cookie_len)
+ char *cookie;
+ int cookie_len;
+{
+ bzero (privateKey.data, 8);
+ if (!strncmp (cookie, "0x", 2) || !strncmp (cookie, "0X", 2))
+ {
+ if (cookie_len > 2 + 2 * 8)
+ cookie_len = 2 + 2 * 8;
+ HexToBinary (cookie + 2, (char *)privateKey.data, cookie_len - 2);
+ }
+ else
+ {
+ if (cookie_len > 7)
+ cookie_len = 7;
+ memmove (privateKey.data + 1, cookie, cookie_len);
+ }
+ XdmcpGenerateKey (&rho);
+ XdmcpRegisterAuthentication (XdmAuthenticationName, XdmAuthenticationNameLen,
+ &rho,
+ sizeof (rho),
+ XdmAuthenticationValidator,
+ XdmAuthenticationGenerator,
+ XdmAuthenticationAddAuth);
+}
+
+#endif /* XDMCP */
+
+/* XDM-AUTHORIZATION-1 */
+typedef struct _XdmAuthorization {
+ struct _XdmAuthorization *next;
+ XdmAuthKeyRec rho;
+ XdmAuthKeyRec key;
+ XID id;
+} XdmAuthorizationRec, *XdmAuthorizationPtr;
+
+static XdmAuthorizationPtr xdmAuth;
+
+typedef struct _XdmClientAuth {
+ struct _XdmClientAuth *next;
+ XdmAuthKeyRec rho;
+ char client[6];
+ long time;
+} XdmClientAuthRec, *XdmClientAuthPtr;
+
+static XdmClientAuthPtr xdmClients;
+static long clockOffset;
+static Bool gotClock;
+
+#define TwentyMinutes (20 * 60)
+#define TwentyFiveMinutes (25 * 60)
+
+static Bool
+XdmClientAuthCompare (a, b)
+ XdmClientAuthPtr a, b;
+{
+ int i;
+
+ if (!XdmcpCompareKeys (&a->rho, &b->rho))
+ return FALSE;
+ for (i = 0; i < 6; i++)
+ if (a->client[i] != b->client[i])
+ return FALSE;
+ return a->time == b->time;
+}
+
+static void
+XdmClientAuthDecode (plain, auth)
+ unsigned char *plain;
+ XdmClientAuthPtr auth;
+{
+ int i, j;
+
+ j = 0;
+ for (i = 0; i < 8; i++)
+ {
+ auth->rho.data[i] = plain[j];
+ ++j;
+ }
+ for (i = 0; i < 6; i++)
+ {
+ auth->client[i] = plain[j];
+ ++j;
+ }
+ auth->time = 0;
+ for (i = 0; i < 4; i++)
+ {
+ auth->time |= plain[j] << ((3 - i) << 3);
+ j++;
+ }
+}
+
+static void
+XdmClientAuthTimeout (now)
+ long now;
+{
+ XdmClientAuthPtr client, next, prev;
+
+ prev = 0;
+ for (client = xdmClients; client; client=next)
+ {
+ next = client->next;
+ if (abs (now - client->time) > TwentyFiveMinutes)
+ {
+ if (prev)
+ prev->next = next;
+ else
+ xdmClients = next;
+ xfree (client);
+ }
+ else
+ prev = client;
+ }
+}
+
+static XdmClientAuthPtr
+XdmAuthorizationValidate (plain, length, rho, xclient, reason)
+ unsigned char *plain;
+ int length;
+ XdmAuthKeyPtr rho;
+ ClientPtr xclient;
+ char **reason;
+{
+ XdmClientAuthPtr client, existing;
+ long now;
+ int i;
+
+ if (length != (192 / 8)) {
+ if (reason)
+ *reason = "Bad XDM authorization key length";
+ return NULL;
+ }
+ client = (XdmClientAuthPtr) xalloc (sizeof (XdmClientAuthRec));
+ if (!client)
+ return NULL;
+ XdmClientAuthDecode (plain, client);
+ if (!XdmcpCompareKeys (&client->rho, rho))
+ {
+ xfree (client);
+ if (reason)
+ *reason = "Invalid XDM-AUTHORIZATION-1 key (failed key comparison)";
+ return NULL;
+ }
+ for (i = 18; i < 24; i++)
+ if (plain[i] != 0) {
+ xfree (client);
+ if (reason)
+ *reason = "Invalid XDM-AUTHORIZATION-1 key (failed NULL check)";
+ return NULL;
+ }
+ if (xclient) {
+ int family, addr_len;
+ Xtransaddr *addr;
+
+ if (_XSERVTransGetPeerAddr(((OsCommPtr)xclient->osPrivate)->trans_conn,
+ &family, &addr_len, &addr) == 0
+ && _XSERVTransConvertAddress(&family, &addr_len, &addr) == 0) {
+#if defined(TCPCONN) || defined(STREAMSCONN)
+ if (family == FamilyInternet &&
+ memcmp((char *)addr, client->client, 4) != 0) {
+ xfree (client);
+ xfree (addr);
+ if (reason)
+ *reason = "Invalid XDM-AUTHORIZATION-1 key (failed address comparison)";
+ return NULL;
+
+ }
+#endif
+ xfree (addr);
+ }
+ }
+ now = time(0);
+ if (!gotClock)
+ {
+ clockOffset = client->time - now;
+ gotClock = TRUE;
+ }
+ now += clockOffset;
+ XdmClientAuthTimeout (now);
+ if (abs (client->time - now) > TwentyMinutes)
+ {
+ xfree (client);
+ if (reason)
+ *reason = "Excessive XDM-AUTHORIZATION-1 time offset";
+ return NULL;
+ }
+ for (existing = xdmClients; existing; existing=existing->next)
+ {
+ if (XdmClientAuthCompare (existing, client))
+ {
+ xfree (client);
+ if (reason)
+ *reason = "XDM authorization key matches an existing client!";
+ return NULL;
+ }
+ }
+ return client;
+}
+
+int
+XdmAddCookie (data_length, data, id)
+unsigned short data_length;
+char *data;
+XID id;
+{
+ XdmAuthorizationPtr new;
+ unsigned char *rho_bits, *key_bits;
+
+ switch (data_length)
+ {
+ case 16: /* auth from files is 16 bytes long */
+ if (authFromXDMCP)
+ {
+ /* R5 xdm sent bogus authorization data in the accept packet,
+ * but we can recover */
+ rho_bits = rho.data;
+ key_bits = (unsigned char *) data;
+ key_bits[0] = '\0';
+ }
+ else
+ {
+ rho_bits = (unsigned char *) data;
+ key_bits = (unsigned char *) (data + 8);
+ }
+ break;
+ case 8: /* auth from XDMCP is 8 bytes long */
+ rho_bits = rho.data;
+ key_bits = (unsigned char *) data;
+ break;
+ default:
+ return 0;
+ }
+ /* the first octet of the key must be zero */
+ if (key_bits[0] != '\0')
+ return 0;
+ new = (XdmAuthorizationPtr) xalloc (sizeof (XdmAuthorizationRec));
+ if (!new)
+ return 0;
+ new->next = xdmAuth;
+ xdmAuth = new;
+ memmove (new->key.data, key_bits, (int) 8);
+ memmove (new->rho.data, rho_bits, (int) 8);
+ new->id = id;
+ return 1;
+}
+
+XID
+XdmCheckCookie (cookie_length, cookie, xclient, reason)
+ unsigned short cookie_length;
+ char *cookie;
+ ClientPtr xclient;
+ char **reason;
+{
+ XdmAuthorizationPtr auth;
+ XdmClientAuthPtr client;
+ unsigned char *plain;
+
+ /* Auth packets must be a multiple of 8 bytes long */
+ if (cookie_length & 7)
+ return (XID) -1;
+ plain = (unsigned char *) xalloc (cookie_length);
+ if (!plain)
+ return (XID) -1;
+ for (auth = xdmAuth; auth; auth=auth->next) {
+ XdmcpUnwrap (cookie, &auth->key, plain, cookie_length);
+ if (client = XdmAuthorizationValidate (plain, cookie_length, &auth->rho, xclient, reason))
+ {
+ client->next = xdmClients;
+ xdmClients = client;
+ xfree (plain);
+ return auth->id;
+ }
+ }
+ xfree (plain);
+ return (XID) -1;
+}
+
+int
+XdmResetCookie ()
+{
+ XdmAuthorizationPtr auth, next_auth;
+ XdmClientAuthPtr client, next_client;
+
+ for (auth = xdmAuth; auth; auth=next_auth)
+ {
+ next_auth = auth->next;
+ xfree (auth);
+ }
+ xdmAuth = 0;
+ for (client = xdmClients; client; client=next_client)
+ {
+ next_client = client->next;
+ xfree (client);
+ }
+ xdmClients = (XdmClientAuthPtr) 0;
+ return 1;
+}
+
+XID
+XdmToID (cookie_length, cookie)
+unsigned short cookie_length;
+char *cookie;
+{
+ XdmAuthorizationPtr auth;
+ XdmClientAuthPtr client;
+ unsigned char *plain;
+
+ plain = (unsigned char *) xalloc (cookie_length);
+ if (!plain)
+ return (XID) -1;
+ for (auth = xdmAuth; auth; auth=auth->next) {
+ XdmcpUnwrap (cookie, &auth->key, plain, cookie_length);
+ if (client = XdmAuthorizationValidate (plain, cookie_length, &auth->rho, NULL, NULL))
+ {
+ xfree (client);
+ xfree (cookie);
+ return auth->id;
+ }
+ }
+ xfree (cookie);
+ return (XID) -1;
+}
+
+int
+XdmFromID (id, data_lenp, datap)
+XID id;
+unsigned short *data_lenp;
+char **datap;
+{
+ XdmAuthorizationPtr auth;
+
+ for (auth = xdmAuth; auth; auth=auth->next) {
+ if (id == auth->id) {
+ *data_lenp = 16;
+ *datap = (char *) &auth->rho;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+XdmRemoveCookie (data_length, data)
+unsigned short data_length;
+char *data;
+{
+ XdmAuthorizationPtr auth, prev;
+ XdmAuthKeyPtr key_bits, rho_bits;
+
+ prev = 0;
+ switch (data_length)
+ {
+ case 16:
+ rho_bits = (XdmAuthKeyPtr) data;
+ key_bits = (XdmAuthKeyPtr) (data + 8);
+ break;
+ case 8:
+ rho_bits = &rho;
+ key_bits = (XdmAuthKeyPtr) data;
+ break;
+ default:
+ return 0;
+ }
+ for (auth = xdmAuth; auth; auth=auth->next) {
+ if (XdmcpCompareKeys (rho_bits, &auth->rho) &&
+ XdmcpCompareKeys (key_bits, &auth->key))
+ {
+ if (prev)
+ prev->next = auth->next;
+ else
+ xdmAuth = auth->next;
+ xfree (auth);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#endif
diff --git a/os/xdmcp.c b/os/xdmcp.c
new file mode 100644
index 000000000..6d683b66d
--- /dev/null
+++ b/os/xdmcp.c
@@ -0,0 +1,1341 @@
+/* $Xorg: xdmcp.c,v 1.4 2001/01/31 13:37:19 pookie Exp $ */
+/*
+ * Copyright 1989 Network Computing Devices, Inc., Mountain View, California.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of N.C.D. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. N.C.D. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ */
+
+#ifdef WIN32
+/* avoid conflicting definitions */
+#define BOOL wBOOL
+#define ATOM wATOM
+#define FreeResource wFreeResource
+#include <winsock.h>
+#undef BOOL
+#undef ATOM
+#undef FreeResource
+#undef CreateWindowA
+#undef RT_FONT
+#undef RT_CURSOR
+#endif
+#include "Xos.h"
+#ifndef WIN32
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#endif
+#include <stdio.h>
+#include "X.h"
+#include "Xmd.h"
+#include "misc.h"
+#include "Xpoll.h"
+#include "osdep.h"
+#include "input.h"
+#include "dixstruct.h"
+#include "opaque.h"
+
+#ifdef STREAMSCONN
+#include <tiuser.h>
+#include <netconfig.h>
+#include <netdir.h>
+#endif
+
+#ifdef XDMCP
+#undef REQUEST
+#include "Xdmcp.h"
+
+#define X_INCLUDE_NETDB_H
+#include <X11/Xos_r.h>
+
+extern char *display;
+extern fd_set EnabledDevices;
+extern fd_set AllClients;
+extern char *defaultDisplayClass;
+
+static int xdmcpSocket, sessionSocket;
+static xdmcp_states state;
+static struct sockaddr_in req_sockaddr;
+static int req_socklen;
+static CARD32 SessionID;
+static CARD32 timeOutTime;
+static int timeOutRtx;
+static CARD32 defaultKeepaliveDormancy = XDM_DEF_DORMANCY;
+static CARD32 keepaliveDormancy = XDM_DEF_DORMANCY;
+static CARD16 DisplayNumber;
+static xdmcp_states XDM_INIT_STATE = XDM_OFF;
+#ifdef HASXDMAUTH
+static char *xdmAuthCookie;
+#endif
+
+static XdmcpBuffer buffer;
+
+static struct sockaddr_in ManagerAddress;
+
+static void get_xdmcp_sock(
+#if NeedFunctionPrototypes
+ void
+#endif
+);
+
+static void send_query_msg(
+#if NeedFunctionPrototypes
+ void
+#endif
+);
+
+static void recv_willing_msg(
+#if NeedFunctionPrototypes
+ struct sockaddr_in */*from*/,
+ int /*fromlen*/,
+ unsigned /*length*/
+#endif
+);
+
+static void send_request_msg(
+#if NeedFunctionPrototypes
+ void
+#endif
+);
+
+static void recv_accept_msg(
+#if NeedFunctionPrototypes
+ unsigned /*length*/
+#endif
+);
+
+static void recv_decline_msg(
+#if NeedFunctionPrototypes
+ unsigned /*length*/
+#endif
+);
+
+static void send_manage_msg(
+#if NeedFunctionPrototypes
+ void
+#endif
+);
+
+static void recv_refuse_msg(
+#if NeedFunctionPrototypes
+ unsigned /*length*/
+#endif
+);
+
+static void recv_failed_msg(
+#if NeedFunctionPrototypes
+ unsigned /*length*/
+#endif
+);
+
+static void send_keepalive_msg(
+#if NeedFunctionPrototypes
+ void
+#endif
+);
+
+static void recv_alive_msg(
+#if NeedFunctionPrototypes
+ unsigned /*length*/
+#endif
+);
+
+static XdmcpFatal(
+#if NeedFunctionPrototypes
+ char */*type*/,
+ ARRAY8Ptr /*status*/
+#endif
+);
+
+static XdmcpWarning(
+#if NeedFunctionPrototypes
+ char */*str*/
+#endif
+);
+
+static get_manager_by_name(
+#if NeedFunctionPrototypes
+ int /*argc*/,
+ char **/*argv*/,
+ int /*i*/
+#endif
+);
+
+static void receive_packet(
+#if NeedFunctionPrototypes
+ void
+#endif
+);
+
+static send_packet(
+#if NeedFunctionPrototypes
+ void
+#endif
+);
+
+extern int XdmcpDeadSession(
+#if NeedFunctionPrototypes
+ char */*reason*/
+#endif
+);
+
+static void timeout(
+#if NeedFunctionPrototypes
+ void
+#endif
+);
+
+static restart(
+#if NeedFunctionPrototypes
+ void
+#endif
+);
+
+static void XdmcpBlockHandler(
+#if NeedFunctionPrototypes
+ pointer /*data*/,
+ struct timeval **/*wt*/,
+ pointer /*LastSelectMask*/
+#endif
+);
+
+static void XdmcpWakeupHandler(
+#if NeedFunctionPrototypes
+ pointer /*data*/,
+ int /*i*/,
+ pointer /*LastSelectMask*/
+#endif
+);
+
+void XdmcpRegisterManufacturerDisplayID(
+#if NeedFunctionPrototypes
+ char * /*name*/,
+ int /*length*/
+#endif
+);
+
+static short xdm_udp_port = XDM_UDP_PORT;
+static Bool OneSession = FALSE;
+
+XdmcpUseMsg ()
+{
+ ErrorF("-query host-name contact named host for XDMCP\n");
+ ErrorF("-broadcast broadcast for XDMCP\n");
+ ErrorF("-indirect host-name contact named host for indirect XDMCP\n");
+ ErrorF("-port port-num UDP port number to send messages to\n");
+ ErrorF("-once Terminate server after one session\n");
+ ErrorF("-class display-class specify display class to send in manage\n");
+#ifdef HASXDMAUTH
+ ErrorF("-cookie xdm-auth-bits specify the magic cookie for XDMCP\n");
+#endif
+ ErrorF("-displayID display-id manufacturer display ID for request\n");
+}
+
+int
+XdmcpOptions(argc, argv, i)
+ int argc, i;
+ char **argv;
+{
+ if (strcmp(argv[i], "-query") == 0) {
+ get_manager_by_name(argc, argv, ++i);
+ XDM_INIT_STATE = XDM_QUERY;
+ AccessUsingXdmcp ();
+ return (i + 1);
+ }
+ if (strcmp(argv[i], "-broadcast") == 0) {
+ XDM_INIT_STATE = XDM_BROADCAST;
+ AccessUsingXdmcp ();
+ return (i + 1);
+ }
+ if (strcmp(argv[i], "-indirect") == 0) {
+ get_manager_by_name(argc, argv, ++i);
+ XDM_INIT_STATE = XDM_INDIRECT;
+ AccessUsingXdmcp ();
+ return (i + 1);
+ }
+ if (strcmp(argv[i], "-port") == 0) {
+ ++i;
+ xdm_udp_port = atoi(argv[i]);
+ return (i + 1);
+ }
+ if (strcmp(argv[i], "-once") == 0) {
+ OneSession = TRUE;
+ return (i + 1);
+ }
+ if (strcmp(argv[i], "-class") == 0) {
+ ++i;
+ defaultDisplayClass = argv[i];
+ return (i + 1);
+ }
+#ifdef HASXDMAUTH
+ if (strcmp(argv[i], "-cookie") == 0) {
+ ++i;
+ xdmAuthCookie = argv[i];
+ return (i + 1);
+ }
+#endif
+ if (strcmp(argv[i], "-displayID") == 0) {
+ ++i;
+ XdmcpRegisterManufacturerDisplayID (argv[i], strlen (argv[i]));
+ return (i + 1);
+ }
+ return (i);
+}
+
+/*
+ * This section is a collection of routines for
+ * registering server-specific data with the XDMCP
+ * state machine.
+ */
+
+
+/*
+ * Save all broadcast addresses away so BroadcastQuery
+ * packets get sent everywhere
+ */
+
+#define MAX_BROADCAST 10
+
+static struct sockaddr_in BroadcastAddresses[MAX_BROADCAST];
+static int NumBroadcastAddresses;
+
+void
+XdmcpRegisterBroadcastAddress (addr)
+ struct sockaddr_in *addr;
+{
+ struct sockaddr_in *bcast;
+ if (NumBroadcastAddresses >= MAX_BROADCAST)
+ return;
+ bcast = &BroadcastAddresses[NumBroadcastAddresses++];
+ bzero (bcast, sizeof (struct sockaddr_in));
+#ifdef BSD44SOCKETS
+ bcast->sin_len = addr->sin_len;
+#endif
+ bcast->sin_family = addr->sin_family;
+ bcast->sin_port = htons (xdm_udp_port);
+ bcast->sin_addr = addr->sin_addr;
+}
+
+/*
+ * Each authentication type is registered here; Validator
+ * will be called to check all access attempts using
+ * the specified authentication type
+ */
+
+static ARRAYofARRAY8 AuthenticationNames, AuthenticationDatas;
+typedef struct _AuthenticationFuncs {
+ Bool (*Validator)();
+ Bool (*Generator)();
+ Bool (*AddAuth)();
+} AuthenticationFuncsRec, *AuthenticationFuncsPtr;
+
+static AuthenticationFuncsPtr AuthenticationFuncsList;
+
+void
+XdmcpRegisterAuthentication (name, namelen, data, datalen, Validator, Generator, AddAuth)
+ char *name;
+ int namelen;
+ char *data;
+ int datalen;
+ Bool (*Validator)();
+ Bool (*Generator)();
+ Bool (*AddAuth)();
+{
+ int i;
+ ARRAY8 AuthenticationName, AuthenticationData;
+ static AuthenticationFuncsPtr newFuncs;
+
+ if (!XdmcpAllocARRAY8 (&AuthenticationName, namelen))
+ return;
+ if (!XdmcpAllocARRAY8 (&AuthenticationData, datalen))
+ {
+ XdmcpDisposeARRAY8 (&AuthenticationName);
+ return;
+ }
+ for (i = 0; i < namelen; i++)
+ AuthenticationName.data[i] = name[i];
+ for (i = 0; i < datalen; i++)
+ AuthenticationData.data[i] = data[i];
+ if (!(XdmcpReallocARRAYofARRAY8 (&AuthenticationNames,
+ AuthenticationNames.length + 1) &&
+ XdmcpReallocARRAYofARRAY8 (&AuthenticationDatas,
+ AuthenticationDatas.length + 1) &&
+ (newFuncs = (AuthenticationFuncsPtr) xalloc (
+ (AuthenticationNames.length + 1) * sizeof (AuthenticationFuncsRec)))))
+ {
+ XdmcpDisposeARRAY8 (&AuthenticationName);
+ XdmcpDisposeARRAY8 (&AuthenticationData);
+ return;
+ }
+ for (i = 0; i < AuthenticationNames.length - 1; i++)
+ newFuncs[i] = AuthenticationFuncsList[i];
+ newFuncs[AuthenticationNames.length-1].Validator = Validator;
+ newFuncs[AuthenticationNames.length-1].Generator = Generator;
+ newFuncs[AuthenticationNames.length-1].AddAuth = AddAuth;
+ xfree (AuthenticationFuncsList);
+ AuthenticationFuncsList = newFuncs;
+ AuthenticationNames.data[AuthenticationNames.length-1] = AuthenticationName;
+ AuthenticationDatas.data[AuthenticationDatas.length-1] = AuthenticationData;
+}
+
+/*
+ * Select the authentication type to be used; this is
+ * set by the manager of the host to be connected to.
+ */
+
+ARRAY8 noAuthenticationName = {(CARD16) 0, (CARD8Ptr) 0};
+ARRAY8 noAuthenticationData = {(CARD16) 0, (CARD8Ptr) 0};
+ARRAY8Ptr AuthenticationName = &noAuthenticationName;
+ARRAY8Ptr AuthenticationData = &noAuthenticationData;
+AuthenticationFuncsPtr AuthenticationFuncs;
+
+void
+XdmcpSetAuthentication (name)
+ ARRAY8Ptr name;
+{
+ int i;
+
+ for (i = 0; i < AuthenticationNames.length; i++)
+ if (XdmcpARRAY8Equal (&AuthenticationNames.data[i], name))
+ {
+ AuthenticationName = &AuthenticationNames.data[i];
+ AuthenticationData = &AuthenticationDatas.data[i];
+ AuthenticationFuncs = &AuthenticationFuncsList[i];
+ break;
+ }
+}
+
+/*
+ * Register the host address for the display
+ */
+
+static ARRAY16 ConnectionTypes;
+static ARRAYofARRAY8 ConnectionAddresses;
+static long xdmcpGeneration;
+
+void
+XdmcpRegisterConnection (type, address, addrlen)
+ int type;
+ char *address;
+ int addrlen;
+{
+ int i;
+ CARD8 *newAddress;
+
+ if (xdmcpGeneration != serverGeneration)
+ {
+ XdmcpDisposeARRAY16 (&ConnectionTypes);
+ XdmcpDisposeARRAYofARRAY8 (&ConnectionAddresses);
+ xdmcpGeneration = serverGeneration;
+ }
+ newAddress = (CARD8 *) xalloc (addrlen * sizeof (CARD8));
+ if (!newAddress)
+ return;
+ if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1))
+ {
+ xfree (newAddress);
+ return;
+ }
+ if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses,
+ ConnectionAddresses.length + 1))
+ {
+ xfree (newAddress);
+ return;
+ }
+ ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type;
+ for (i = 0; i < addrlen; i++)
+ newAddress[i] = address[i];
+ ConnectionAddresses.data[ConnectionAddresses.length-1].data = newAddress;
+ ConnectionAddresses.data[ConnectionAddresses.length-1].length = addrlen;
+}
+
+/*
+ * Register an Authorization Name. XDMCP advertises this list
+ * to the manager.
+ */
+
+static ARRAYofARRAY8 AuthorizationNames;
+
+void
+XdmcpRegisterAuthorizations ()
+{
+ XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames);
+ RegisterAuthorizations ();
+}
+
+void
+XdmcpRegisterAuthorization (name, namelen)
+ char *name;
+ int namelen;
+{
+ ARRAY8 authName;
+ int i;
+
+ authName.data = (CARD8 *) xalloc (namelen * sizeof (CARD8));
+ if (!authName.data)
+ return;
+ if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1))
+ {
+ xfree (authName.data);
+ return;
+ }
+ for (i = 0; i < namelen; i++)
+ authName.data[i] = (CARD8) name[i];
+ authName.length = namelen;
+ AuthorizationNames.data[AuthorizationNames.length-1] = authName;
+}
+
+/*
+ * Register the DisplayClass string
+ */
+
+ARRAY8 DisplayClass;
+
+void
+XdmcpRegisterDisplayClass (name, length)
+ char *name;
+ int length;
+{
+ int i;
+
+ XdmcpDisposeARRAY8 (&DisplayClass);
+ if (!XdmcpAllocARRAY8 (&DisplayClass, length))
+ return;
+ for (i = 0; i < length; i++)
+ DisplayClass.data[i] = (CARD8) name[i];
+}
+
+/*
+ * Register the Manufacturer display ID
+ */
+
+ARRAY8 ManufacturerDisplayID;
+
+void
+XdmcpRegisterManufacturerDisplayID (name, length)
+ char *name;
+ int length;
+{
+ int i;
+
+ XdmcpDisposeARRAY8 (&ManufacturerDisplayID);
+ if (!XdmcpAllocARRAY8 (&ManufacturerDisplayID, length))
+ return;
+ for (i = 0; i < length; i++)
+ ManufacturerDisplayID.data[i] = (CARD8) name[i];
+}
+
+/*
+ * initialize XDMCP; create the socket, compute the display
+ * number, set up the state machine
+ */
+
+void
+XdmcpInit()
+{
+ state = XDM_INIT_STATE;
+#ifdef HASXDMAUTH
+ if (xdmAuthCookie)
+ XdmAuthenticationInit (xdmAuthCookie, strlen (xdmAuthCookie));
+#endif
+ if (state != XDM_OFF)
+ {
+ XdmcpRegisterAuthorizations();
+ XdmcpRegisterDisplayClass (defaultDisplayClass, strlen (defaultDisplayClass));
+ AccessUsingXdmcp();
+ RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
+ (pointer) 0);
+ timeOutRtx = 0;
+ DisplayNumber = (CARD16) atoi(display);
+ get_xdmcp_sock();
+ send_packet();
+ }
+}
+
+void
+XdmcpReset ()
+{
+ state = XDM_INIT_STATE;
+ if (state != XDM_OFF)
+ {
+ RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler,
+ (pointer) 0);
+ timeOutRtx = 0;
+ send_packet();
+ }
+}
+
+/*
+ * Called whenever a new connection is created; notices the
+ * first connection and saves it to terminate the session
+ * when it is closed
+ */
+
+void
+XdmcpOpenDisplay(sock)
+ int sock;
+{
+ if (state != XDM_AWAIT_MANAGE_RESPONSE)
+ return;
+ state = XDM_RUN_SESSION;
+ sessionSocket = sock;
+}
+
+void
+XdmcpCloseDisplay(sock)
+ int sock;
+{
+ if ((state != XDM_RUN_SESSION && state != XDM_AWAIT_ALIVE_RESPONSE)
+ || sessionSocket != sock)
+ return;
+ state = XDM_INIT_STATE;
+ if (OneSession)
+ dispatchException |= DE_TERMINATE;
+ else
+ dispatchException |= DE_RESET;
+ isItTimeToYield = TRUE;
+}
+
+/*
+ * called before going to sleep, this routine
+ * may modify the timeout value about to be sent
+ * to select; in this way XDMCP can do appropriate things
+ * dynamically while starting up
+ */
+
+/*ARGSUSED*/
+static void
+XdmcpBlockHandler(data, wt, pReadmask)
+ pointer data; /* unused */
+ struct timeval **wt;
+ pointer pReadmask;
+{
+ fd_set *LastSelectMask = (fd_set*)pReadmask;
+ CARD32 millisToGo, wtMillis;
+ static struct timeval waittime;
+
+ if (state == XDM_OFF)
+ return;
+ FD_SET(xdmcpSocket, LastSelectMask);
+ if (timeOutTime == 0)
+ return;
+ millisToGo = GetTimeInMillis();
+ if (millisToGo < timeOutTime)
+ millisToGo = timeOutTime - millisToGo;
+ else
+ millisToGo = 0;
+ if (*wt == NULL)
+ {
+ waittime.tv_sec = (millisToGo) / 1000;
+ waittime.tv_usec = 1000 * (millisToGo % 1000);
+ *wt = &waittime;
+ }
+ else
+ {
+ wtMillis = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000;
+ if (millisToGo < wtMillis)
+ {
+ (*wt)->tv_sec = (millisToGo) / 1000;
+ (*wt)->tv_usec = 1000 * (millisToGo % 1000);
+ }
+ }
+}
+
+/*
+ * called after select returns; this routine will
+ * recognise when XDMCP packets await and
+ * process them appropriately
+ */
+
+/*ARGSUSED*/
+static void
+XdmcpWakeupHandler(data, i, pReadmask)
+ pointer data; /* unused */
+ int i;
+ pointer pReadmask;
+{
+ fd_set* LastSelectMask = (fd_set*)pReadmask;
+ fd_set devicesReadable;
+
+ if (state == XDM_OFF)
+ return;
+ if (i > 0)
+ {
+ if (FD_ISSET(xdmcpSocket, LastSelectMask))
+ {
+ receive_packet();
+ FD_CLR(xdmcpSocket, LastSelectMask);
+ }
+ XFD_ANDSET(&devicesReadable, LastSelectMask, &EnabledDevices);
+ if (XFD_ANYSET(&devicesReadable))
+ {
+ if (state == XDM_AWAIT_USER_INPUT)
+ restart();
+ else if (state == XDM_RUN_SESSION)
+ keepaliveDormancy = defaultKeepaliveDormancy;
+ }
+ if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION)
+ timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
+ }
+ else if (timeOutTime && GetTimeInMillis() >= timeOutTime)
+ {
+ if (state == XDM_RUN_SESSION)
+ {
+ state = XDM_KEEPALIVE;
+ send_packet();
+ }
+ else
+ timeout();
+ }
+}
+
+/*
+ * This routine should be called from the routine that drives the
+ * user's host menu when the user selects a host
+ */
+
+XdmcpSelectHost(host_sockaddr, host_len, AuthenticationName)
+ struct sockaddr_in *host_sockaddr;
+ int host_len;
+ ARRAY8Ptr AuthenticationName;
+{
+ state = XDM_START_CONNECTION;
+ memmove(&req_sockaddr, host_sockaddr, host_len);
+ req_socklen = host_len;
+ XdmcpSetAuthentication (AuthenticationName);
+ send_packet();
+}
+
+/*
+ * !!! this routine should be replaced by a routine that adds
+ * the host to the user's host menu. the current version just
+ * selects the first host to respond with willing message.
+ */
+
+/*ARGSUSED*/
+XdmcpAddHost(from, fromlen, AuthenticationName, hostname, status)
+ struct sockaddr_in *from;
+ ARRAY8Ptr AuthenticationName, hostname, status;
+{
+ XdmcpSelectHost(from, fromlen, AuthenticationName);
+}
+
+/*
+ * A message is queued on the socket; read it and
+ * do the appropriate thing
+ */
+
+ARRAY8 UnwillingMessage = { (CARD8) 14, (CARD8 *) "Host unwilling" };
+
+static void
+receive_packet()
+{
+ struct sockaddr_in from;
+ int fromlen = sizeof(struct sockaddr_in);
+ XdmcpHeader header;
+
+ /* read message off socket */
+ if (!XdmcpFill (xdmcpSocket, &buffer, (struct sockaddr *) &from, &fromlen))
+ return;
+
+ /* reset retransmission backoff */
+ timeOutRtx = 0;
+
+ if (!XdmcpReadHeader (&buffer, &header))
+ return;
+
+ if (header.version != XDM_PROTOCOL_VERSION)
+ return;
+
+ switch (header.opcode) {
+ case WILLING:
+ recv_willing_msg(&from, fromlen, header.length);
+ break;
+ case UNWILLING:
+ XdmcpFatal("Manager unwilling", &UnwillingMessage);
+ break;
+ case ACCEPT:
+ recv_accept_msg(header.length);
+ break;
+ case DECLINE:
+ recv_decline_msg(header.length);
+ break;
+ case REFUSE:
+ recv_refuse_msg(header.length);
+ break;
+ case FAILED:
+ recv_failed_msg(header.length);
+ break;
+ case ALIVE:
+ recv_alive_msg(header.length);
+ break;
+ }
+}
+
+/*
+ * send the appropriate message given the current state
+ */
+
+static
+send_packet()
+{
+ int rtx;
+ switch (state) {
+ case XDM_QUERY:
+ case XDM_BROADCAST:
+ case XDM_INDIRECT:
+ send_query_msg();
+ break;
+ case XDM_START_CONNECTION:
+ send_request_msg();
+ break;
+ case XDM_MANAGE:
+ send_manage_msg();
+ break;
+ case XDM_KEEPALIVE:
+ send_keepalive_msg();
+ break;
+ }
+ rtx = (XDM_MIN_RTX << timeOutRtx);
+ if (rtx > XDM_MAX_RTX)
+ rtx = XDM_MAX_RTX;
+ timeOutTime = GetTimeInMillis() + rtx * 1000;
+}
+
+/*
+ * The session is declared dead for some reason; too many
+ * timeouts, or Keepalive failure.
+ */
+
+XdmcpDeadSession (reason)
+ char *reason;
+{
+ ErrorF ("XDM: %s, declaring session dead\n", reason);
+ state = XDM_INIT_STATE;
+ isItTimeToYield = TRUE;
+ dispatchException |= DE_RESET;
+ timeOutTime = 0;
+ timeOutRtx = 0;
+ send_packet();
+}
+
+/*
+ * Timeout waiting for an XDMCP response.
+ */
+
+static void
+timeout()
+{
+ timeOutRtx++;
+ if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT )
+ {
+ XdmcpDeadSession ("too many keepalive retransmissions");
+ return;
+ }
+ else if (timeOutRtx >= XDM_RTX_LIMIT)
+ {
+ ErrorF("XDM: too many retransmissions\n");
+ state = XDM_AWAIT_USER_INPUT;
+ timeOutTime = 0;
+ timeOutRtx = 0;
+ return;
+ }
+
+ switch (state) {
+ case XDM_COLLECT_QUERY:
+ state = XDM_QUERY;
+ break;
+ case XDM_COLLECT_BROADCAST_QUERY:
+ state = XDM_BROADCAST;
+ break;
+ case XDM_COLLECT_INDIRECT_QUERY:
+ state = XDM_INDIRECT;
+ break;
+ case XDM_AWAIT_REQUEST_RESPONSE:
+ state = XDM_START_CONNECTION;
+ break;
+ case XDM_AWAIT_MANAGE_RESPONSE:
+ state = XDM_MANAGE;
+ break;
+ case XDM_AWAIT_ALIVE_RESPONSE:
+ state = XDM_KEEPALIVE;
+ break;
+ }
+ send_packet();
+}
+
+static
+restart()
+{
+ state = XDM_INIT_STATE;
+ timeOutRtx = 0;
+ send_packet();
+}
+
+XdmcpCheckAuthentication (Name, Data, packet_type)
+ ARRAY8Ptr Name, Data;
+ int packet_type;
+{
+ return (XdmcpARRAY8Equal (Name, AuthenticationName) &&
+ (AuthenticationName->length == 0 ||
+ (*AuthenticationFuncs->Validator) (AuthenticationData, Data, packet_type)));
+}
+
+XdmcpAddAuthorization (name, data)
+ ARRAY8Ptr name, data;
+{
+ Bool (*AddAuth)(), AddAuthorization();
+
+ if (AuthenticationFuncs && AuthenticationFuncs->AddAuth)
+ AddAuth = AuthenticationFuncs->AddAuth;
+ else
+ AddAuth = AddAuthorization;
+ return (*AddAuth) ((unsigned short)name->length,
+ (char *)name->data,
+ (unsigned short)data->length,
+ (char *)data->data);
+}
+
+/*
+ * from here to the end of this file are routines private
+ * to the state machine.
+ */
+
+static void
+get_xdmcp_sock()
+{
+ int soopts = 1;
+
+#ifdef STREAMSCONN
+ struct netconfig *nconf;
+
+ if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) {
+ XdmcpWarning("t_open() of /dev/udp failed");
+ return;
+ }
+
+ if( t_bind(xdmcpSocket,NULL,NULL) < 0 ) {
+ XdmcpWarning("UDP socket creation failed");
+ t_error("t_bind(xdmcpSocket) failed" );
+ t_close(xdmcpSocket);
+ return;
+ }
+
+ /*
+ * This part of the code looks contrived. It will actually fit in nicely
+ * when the CLTS part of Xtrans is implemented.
+ */
+
+ if( (nconf=getnetconfigent("udp")) == NULL ) {
+ XdmcpWarning("UDP socket creation failed: getnetconfigent()");
+ t_unbind(xdmcpSocket);
+ t_close(xdmcpSocket);
+ return;
+ }
+
+ if( netdir_options(nconf, ND_SET_BROADCAST, xdmcpSocket, NULL) ) {
+ XdmcpWarning("UDP set broadcast option failed: netdir_options()");
+ freenetconfigent(nconf);
+ t_unbind(xdmcpSocket);
+ t_close(xdmcpSocket);
+ return;
+ }
+
+ freenetconfigent(nconf);
+#else
+ if ((xdmcpSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ XdmcpWarning("UDP socket creation failed");
+#ifdef SO_BROADCAST
+ else if (setsockopt(xdmcpSocket, SOL_SOCKET, SO_BROADCAST, (char *)&soopts,
+ sizeof(soopts)) < 0)
+ XdmcpWarning("UDP set broadcast socket-option failed");
+#endif /* SO_BROADCAST */
+#endif /* STREAMSCONN */
+}
+
+static void
+send_query_msg()
+{
+ XdmcpHeader header;
+ Bool broadcast = FALSE;
+ int i;
+
+ header.version = XDM_PROTOCOL_VERSION;
+ switch(state){
+ case XDM_QUERY:
+ header.opcode = (CARD16) QUERY;
+ state = XDM_COLLECT_QUERY;
+ break;
+ case XDM_BROADCAST:
+ header.opcode = (CARD16) BROADCAST_QUERY;
+ state = XDM_COLLECT_BROADCAST_QUERY;
+ broadcast = TRUE;
+ break;
+ case XDM_INDIRECT:
+ header.opcode = (CARD16) INDIRECT_QUERY;
+ state = XDM_COLLECT_INDIRECT_QUERY;
+ break;
+ }
+ header.length = 1;
+ for (i = 0; i < AuthenticationNames.length; i++)
+ header.length += 2 + AuthenticationNames.data[i].length;
+
+ XdmcpWriteHeader (&buffer, &header);
+ XdmcpWriteARRAYofARRAY8 (&buffer, &AuthenticationNames);
+ if (broadcast)
+ {
+ int i;
+
+ for (i = 0; i < NumBroadcastAddresses; i++)
+ XdmcpFlush (xdmcpSocket, &buffer, &BroadcastAddresses[i],
+ sizeof (struct sockaddr_in));
+ }
+ else
+ {
+ XdmcpFlush (xdmcpSocket, &buffer, &ManagerAddress,
+ sizeof (ManagerAddress));
+ }
+}
+
+static void
+recv_willing_msg(from, fromlen, length)
+ struct sockaddr_in *from;
+ int fromlen;
+ unsigned length;
+{
+ ARRAY8 authenticationName;
+ ARRAY8 hostname;
+ ARRAY8 status;
+
+ authenticationName.data = 0;
+ hostname.data = 0;
+ status.data = 0;
+ if (XdmcpReadARRAY8 (&buffer, &authenticationName) &&
+ XdmcpReadARRAY8 (&buffer, &hostname) &&
+ XdmcpReadARRAY8 (&buffer, &status))
+ {
+ if (length == 6 + authenticationName.length +
+ hostname.length + status.length)
+ {
+ switch (state)
+ {
+ case XDM_COLLECT_QUERY:
+ XdmcpSelectHost(from, fromlen, &authenticationName);
+ break;
+ case XDM_COLLECT_BROADCAST_QUERY:
+ case XDM_COLLECT_INDIRECT_QUERY:
+ XdmcpAddHost(from, fromlen, &authenticationName, &hostname, &status);
+ break;
+ }
+ }
+ }
+ XdmcpDisposeARRAY8 (&authenticationName);
+ XdmcpDisposeARRAY8 (&hostname);
+ XdmcpDisposeARRAY8 (&status);
+}
+
+static void
+send_request_msg()
+{
+ XdmcpHeader header;
+ int length;
+ int i;
+ ARRAY8 authenticationData;
+
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) REQUEST;
+
+ length = 2; /* display number */
+ length += 1 + 2 * ConnectionTypes.length; /* connection types */
+ length += 1; /* connection addresses */
+ for (i = 0; i < ConnectionAddresses.length; i++)
+ length += 2 + ConnectionAddresses.data[i].length;
+ authenticationData.length = 0;
+ authenticationData.data = 0;
+ if (AuthenticationFuncs)
+ {
+ (*AuthenticationFuncs->Generator) (AuthenticationData,
+ &authenticationData,
+ REQUEST);
+ }
+ length += 2 + AuthenticationName->length; /* authentication name */
+ length += 2 + authenticationData.length; /* authentication data */
+ length += 1; /* authorization names */
+ for (i = 0; i < AuthorizationNames.length; i++)
+ length += 2 + AuthorizationNames.data[i].length;
+ length += 2 + ManufacturerDisplayID.length; /* display ID */
+ header.length = length;
+
+ if (!XdmcpWriteHeader (&buffer, &header))
+ {
+ XdmcpDisposeARRAY8 (&authenticationData);
+ return;
+ }
+ XdmcpWriteCARD16 (&buffer, DisplayNumber);
+ XdmcpWriteARRAY16 (&buffer, &ConnectionTypes);
+ XdmcpWriteARRAYofARRAY8 (&buffer, &ConnectionAddresses);
+
+ XdmcpWriteARRAY8 (&buffer, AuthenticationName);
+ XdmcpWriteARRAY8 (&buffer, &authenticationData);
+ XdmcpDisposeARRAY8 (&authenticationData);
+ XdmcpWriteARRAYofARRAY8 (&buffer, &AuthorizationNames);
+ XdmcpWriteARRAY8 (&buffer, &ManufacturerDisplayID);
+ if (XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen))
+ state = XDM_AWAIT_REQUEST_RESPONSE;
+}
+
+static void
+recv_accept_msg(length)
+ unsigned length;
+{
+ CARD32 AcceptSessionID;
+ ARRAY8 AcceptAuthenticationName, AcceptAuthenticationData;
+ ARRAY8 AcceptAuthorizationName, AcceptAuthorizationData;
+
+ if (state != XDM_AWAIT_REQUEST_RESPONSE)
+ return;
+ AcceptAuthenticationName.data = 0;
+ AcceptAuthenticationData.data = 0;
+ AcceptAuthorizationName.data = 0;
+ AcceptAuthorizationData.data = 0;
+ if (XdmcpReadCARD32 (&buffer, &AcceptSessionID) &&
+ XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationName) &&
+ XdmcpReadARRAY8 (&buffer, &AcceptAuthenticationData) &&
+ XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationName) &&
+ XdmcpReadARRAY8 (&buffer, &AcceptAuthorizationData))
+ {
+ if (length == 12 + AcceptAuthenticationName.length +
+ AcceptAuthenticationData.length +
+ AcceptAuthorizationName.length +
+ AcceptAuthorizationData.length)
+ {
+ if (!XdmcpCheckAuthentication (&AcceptAuthenticationName,
+ &AcceptAuthenticationData, ACCEPT))
+ {
+ XdmcpFatal ("Authentication Failure", &AcceptAuthenticationName);
+ }
+ /* permit access control manipulations from this host */
+ AugmentSelf (&req_sockaddr, req_socklen);
+ /* if the authorization specified in the packet fails
+ * to be acceptable, enable the local addresses
+ */
+ if (!XdmcpAddAuthorization (&AcceptAuthorizationName,
+ &AcceptAuthorizationData))
+ {
+ AddLocalHosts ();
+ }
+ SessionID = AcceptSessionID;
+ state = XDM_MANAGE;
+ send_packet();
+ }
+ }
+ XdmcpDisposeARRAY8 (&AcceptAuthenticationName);
+ XdmcpDisposeARRAY8 (&AcceptAuthenticationData);
+ XdmcpDisposeARRAY8 (&AcceptAuthorizationName);
+ XdmcpDisposeARRAY8 (&AcceptAuthorizationData);
+}
+
+static void
+recv_decline_msg(length)
+ unsigned length;
+{
+ ARRAY8 status, DeclineAuthenticationName, DeclineAuthenticationData;
+
+ status.data = 0;
+ DeclineAuthenticationName.data = 0;
+ DeclineAuthenticationData.data = 0;
+ if (XdmcpReadARRAY8 (&buffer, &status) &&
+ XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationName) &&
+ XdmcpReadARRAY8 (&buffer, &DeclineAuthenticationData))
+ {
+ if (length == 6 + status.length +
+ DeclineAuthenticationName.length +
+ DeclineAuthenticationData.length &&
+ XdmcpCheckAuthentication (&DeclineAuthenticationName,
+ &DeclineAuthenticationData, DECLINE))
+ {
+ XdmcpFatal ("Session declined", &status);
+ }
+ }
+ XdmcpDisposeARRAY8 (&status);
+ XdmcpDisposeARRAY8 (&DeclineAuthenticationName);
+ XdmcpDisposeARRAY8 (&DeclineAuthenticationData);
+}
+
+static void
+send_manage_msg()
+{
+ XdmcpHeader header;
+
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) MANAGE;
+ header.length = 8 + DisplayClass.length;
+
+ if (!XdmcpWriteHeader (&buffer, &header))
+ return;
+ XdmcpWriteCARD32 (&buffer, SessionID);
+ XdmcpWriteCARD16 (&buffer, DisplayNumber);
+ XdmcpWriteARRAY8 (&buffer, &DisplayClass);
+ state = XDM_AWAIT_MANAGE_RESPONSE;
+ XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen);
+}
+
+static void
+recv_refuse_msg(length)
+ unsigned length;
+{
+ CARD32 RefusedSessionID;
+
+ if (state != XDM_AWAIT_MANAGE_RESPONSE)
+ return;
+ if (length != 4)
+ return;
+ if (XdmcpReadCARD32 (&buffer, &RefusedSessionID))
+ {
+ if (RefusedSessionID == SessionID)
+ {
+ state = XDM_START_CONNECTION;
+ send_packet();
+ }
+ }
+}
+
+static void
+recv_failed_msg(length)
+ unsigned length;
+{
+ CARD32 FailedSessionID;
+ ARRAY8 status;
+
+ if (state != XDM_AWAIT_MANAGE_RESPONSE)
+ return;
+ status.data = 0;
+ if (XdmcpReadCARD32 (&buffer, &FailedSessionID) &&
+ XdmcpReadARRAY8 (&buffer, &status))
+ {
+ if (length == 6 + status.length &&
+ SessionID == FailedSessionID)
+ {
+ XdmcpFatal ("Session failed", &status);
+ }
+ }
+ XdmcpDisposeARRAY8 (&status);
+}
+
+static void
+send_keepalive_msg()
+{
+ XdmcpHeader header;
+
+ header.version = XDM_PROTOCOL_VERSION;
+ header.opcode = (CARD16) KEEPALIVE;
+ header.length = 6;
+
+ XdmcpWriteHeader (&buffer, &header);
+ XdmcpWriteCARD16 (&buffer, DisplayNumber);
+ XdmcpWriteCARD32 (&buffer, SessionID);
+
+ state = XDM_AWAIT_ALIVE_RESPONSE;
+ XdmcpFlush (xdmcpSocket, &buffer, &req_sockaddr, req_socklen);
+}
+
+static void
+recv_alive_msg (length)
+ unsigned length;
+{
+ CARD8 SessionRunning;
+ CARD32 AliveSessionID;
+ int dormancy;
+
+ if (state != XDM_AWAIT_ALIVE_RESPONSE)
+ return;
+ if (length != 5)
+ return;
+ if (XdmcpReadCARD8 (&buffer, &SessionRunning) &&
+ XdmcpReadCARD32 (&buffer, &AliveSessionID))
+ {
+ if (SessionRunning && AliveSessionID == SessionID)
+ {
+ /* backoff dormancy period */
+ state = XDM_RUN_SESSION;
+ if ((GetTimeInMillis() - lastDeviceEventTime.milliseconds) >
+ keepaliveDormancy * 1000)
+ {
+ keepaliveDormancy <<= 1;
+ if (keepaliveDormancy > XDM_MAX_DORMANCY)
+ keepaliveDormancy = XDM_MAX_DORMANCY;
+ }
+ timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000;
+ }
+ else
+ {
+ XdmcpDeadSession ("Alive respose indicates session dead");
+ }
+ }
+}
+
+static
+XdmcpFatal (type, status)
+ char *type;
+ ARRAY8Ptr status;
+{
+ extern void AbortDDX();
+
+ ErrorF ("XDMCP fatal error: %s %*.*s\n", type,
+ status->length, status->length, status->data);
+ AbortDDX ();
+ exit (1);
+}
+
+static
+XdmcpWarning(str)
+ char *str;
+{
+ ErrorF("XDMCP warning: %s\n", str);
+}
+
+static
+get_manager_by_name(argc, argv, i)
+ int argc, i;
+ char **argv;
+{
+ struct hostent *hep;
+ _Xgethostbynameparams hparams;
+
+ if (i == argc)
+ {
+ ErrorF("Xserver: missing host name in command line\n");
+ exit(1);
+ }
+ if (!(hep = _XGethostbyname(argv[i], hparams)))
+ {
+ ErrorF("Xserver: unknown host: %s\n", argv[i]);
+ exit(1);
+ }
+ if (hep->h_length == sizeof (struct in_addr))
+ {
+ memmove(&ManagerAddress.sin_addr, hep->h_addr, hep->h_length);
+#ifdef BSD44SOCKETS
+ ManagerAddress.sin_len = sizeof(ManagerAddress);
+#endif
+ ManagerAddress.sin_family = AF_INET;
+ ManagerAddress.sin_port = htons (xdm_udp_port);
+ }
+ else
+ {
+ ErrorF ("Xserver: host on strange network %s\n", argv[i]);
+ exit (1);
+ }
+}
+#else
+static int xdmcp_non_empty; /* avoid complaint by ranlib */
+#endif /* XDMCP */