diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:54 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:54 +0000 |
commit | ded6147bfb5d75ff1e67c858040a628b61bc17d1 (patch) | |
tree | 82355105e93cdac89ef7d987424351c77545faf0 /os | |
parent | cb6ef07bf01e72d1a6e6e83ceb7f76d6534da941 (diff) |
R6.6 is the Xorg base-lineXORG-MAIN
Diffstat (limited to 'os')
-rw-r--r-- | os/WaitFor.c | 613 | ||||
-rw-r--r-- | os/access.c | 1232 | ||||
-rw-r--r-- | os/auth.c | 411 | ||||
-rw-r--r-- | os/connection.c | 1281 | ||||
-rw-r--r-- | os/io.c | 1262 | ||||
-rw-r--r-- | os/k5auth.c | 796 | ||||
-rw-r--r-- | os/lbxio.c | 585 | ||||
-rw-r--r-- | os/mitauth.c | 193 | ||||
-rw-r--r-- | os/oscolor.c | 294 | ||||
-rw-r--r-- | os/osdep.h | 186 | ||||
-rw-r--r-- | os/osinit.c | 200 | ||||
-rw-r--r-- | os/rpcauth.c | 202 | ||||
-rw-r--r-- | os/secauth.c | 201 | ||||
-rw-r--r-- | os/utils.c | 1105 | ||||
-rw-r--r-- | os/xdmauth.c | 518 | ||||
-rw-r--r-- | os/xdmcp.c | 1341 |
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, + ¬used, &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, ¬ime); + 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, ¬ime); + 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 = ρ + 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 */ |