diff options
Diffstat (limited to 'nx-X11/programs/Xserver/os')
23 files changed, 15403 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/os/Imakefile b/nx-X11/programs/Xserver/os/Imakefile new file mode 100644 index 000000000..7932e32cd --- /dev/null +++ b/nx-X11/programs/Xserver/os/Imakefile @@ -0,0 +1,262 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* nx-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +#include <Server.tmpl> + +NULL = + +/* + * If you have any extra files to be put into the library, define them here. + */ + +ZONEID_DEFINES = -UHAVE_GETZONEID + +#if NXLibraries + +NX_INCLUDES = -I../../../../nxcomp + +NX_DEFINES = -DNX_TRANS_SOCKET \ + -DNX_TRANS_AUTH \ + -DNX_TRANS_FOPEN \ + -DNX_TRANS_SLEEP \ + -DNX_TRANS_EXIT \ + -DNX_TRANS_WAKEUP=1000 \ + -DNXAGENT_SERVER \ + $(NULL) + +# -DNX_TRANS_WARN \ +# -DNX_TRANS_INFO \ +# -DNX_TRANS_TEST \ +# -DNX_TRANS_DEBUG \ + +#endif + +/* + * do not modify the following two definitions + */ + +#ifndef OtherSources +#define OtherSources +#endif + +#ifndef OtherObjects +#define OtherObjects +#endif + +#if HasXdmAuth +XDMAUTHDEFS = -DHASXDMAUTH +XDMAUTHOBJS = xdmauth.o +XDMAUTHSRCS = xdmauth.c +#else +XDMAUTHDEFS = +XDMAUTHOBJS = +XDMAUTHSCRS = +#endif + +#if HasSecureRPC +RPCDEFS = -DSECURE_RPC +RPCOBJS = rpcauth.o +RPCSRCS = rpcauth.c +#else +RPCDEFS = +RPCOBJS = +RPCSRCS = +#endif + +#if HasBSD44Sockets + SOCK_DEFINES = -DBSD44SOCKETS +#endif + +#if HasGetIfAddrs + IFADDRS_DEFINES = -DHAS_GETIFADDRS +#endif + +#if !defined(DDXOsColor) +COLOR_SRCS=oscolor.c +COLOR_OBJS=oscolor.o +#endif + +#if !HasSnprintf +SNPRINTF_SRCS = snprintf.c +SNPRINTF_OBJS = snprintf.o +#endif + +#if !HasStrlcat +STRLCAT_SRCS = strlcat.c strlcpy.c +STRLCAT_OBJS = strlcat.o strlcpy.o +#endif + +#if !HasReallocarray +REALLOCARRAY_SRCS = reallocarray.c +REALLOCARRAY_OBJS = reallocarray.o +#endif + +#if HasGetpeerucred +GETPEER_DEFINES = -DHAS_GETPEERUCRED +#else +# if HasGetpeereid +GETPEER_DEFINES = -DHAS_GETPEEREID +# endif +#endif + +#if !HasTimingsafeMemcmp +TMEMCMP_SRCS = timingsafe_memcmp.c +TMEMCMP_OBJS = timingsafe_memcmp.o +#endif + +BOOTSTRAPCFLAGS = + SRCS = WaitFor.c \ + access.c \ + client.c \ + connection.c \ + io.c \ + $(COLOR_SRCS) \ + osinit.c \ + utils.c \ + log.c \ + auth.c \ + mitauth.c \ + secauth.c \ + $(XDMAUTHSRCS) \ + $(RPCSRCS) \ + xdmcp.c \ + OtherSources \ + xstrans.c \ + $(SNPRINTF_SRCS) \ + $(STRLCAT_SRCS) \ + $(REALLOCARRAY_SRCS) \ + xprintf.c \ + $(TMEMCMP_SRCS) \ + $(NULL) + + OBJS = WaitFor.o \ + access.o \ + client.o \ + connection.o \ + io.o \ + $(COLOR_OBJS) \ + osinit.o \ + utils.o \ + log.o \ + auth.o \ + mitauth.o \ + secauth.o \ + $(XDMAUTHOBJS) \ + $(RPCOBJS) \ + xdmcp.o \ + OtherObjects \ + xstrans.o \ + $(SNPRINTF_OBJS) \ + $(STRLCAT_OBJS) \ + $(REALLOCARRAY_OBJS) \ + xprintf.o \ + $(TMEMCMP_OBJS) \ + $(NULL) + +#if UseMemLeak + MEM_DEFINES = -DMEMBUG +#endif + ADM_DEFINES = -DADMPATH=\"$(ADMDIR)/X\%smsgs\" + XDMCP_DEFINES = ServerXdmcpDefines + ERROR_DEFINES = ServerErrorDefines +#if HasPam && HasPamMisc + PAM_DEFINES = -DUSE_PAM +#endif + XTRANS_DEFINES = -DXTRANS_SEND_FDS=0 + + DEFINES = $(CONNECTION_FLAGS) \ + $(MEM_DEFINES) \ + $(XDMAUTHDEFS) \ + $(RPCDEFS) \ + $(SIGNAL_DEFINES) \ + $(OS_DEFINES) \ + $(GETPEER_DEFINES) \ + $(RANDOM_DEFINES) \ + $(BUGMSG) \ + $(XTRANS_FAILDEFINES) \ + $(XTRANS_DEFINES) \ + $(NX_DEFINES) \ + $(NULL) + + INCLUDES = -I. \ + -I../include \ + -I$(XINCLUDESRC) \ + -I$(EXTINCSRC) \ + -I$(SERVERSRC)/Xext \ + -I$(SERVERSRC)/render \ + -I$(TOP)/lib/Xau \ + $(NX_INCLUDES) \ + `pkg-config --cflags-only-I pixman-1` \ + $(NULL) + + DEPEND_DEFINES = $(XDMCP_DEFINES) \ + $(EXT_DEFINES) \ + $(TRANS_INCLUDES) \ + $(CONNECTION_FLAGS) \ + $(GETPEER_DEFINES) \ + DependDefines \ + $(NULL) + + LINTLIBS = ../dix/llib-ldix.ln + +#ifdef NEED_ALLOCA_FROM_LIBPW + PWLIB = /lib/libPW.a +#endif /* NEED_ALLOCA_FROM_LIBPW */ + +NormalLibraryObjectRule() +NormalLibraryTarget(os,$(OBJS)) +LintLibraryTarget(os,$(SRCS)) +NormalLintTarget($(SRCS)) + +#ifdef NEED_ALLOCA_FROM_LIBPW +XCOMM +XCOMM And this one is to get the version of alloca that lives in /lib/libPW.a +XCOMM without getting all of the rest of the stuff in there. +XCOMM +alloca.o: $(PWLIB) + rm -f alloca.o + ar x $(PWLIB) alloca.o +#endif /* NEED_ALLOCA_FROM_LIBPW */ + +SpecialCObjectRule(access,$(ICONFIGFILES),$(XDMCP_DEFINES) $(SOCK_DEFINES) $(IFADDRS_DEFINES) $(ZONEID_DEFINES)) +SpecialCObjectRule(auth,$(ICONFIGFILES),$(XDMCP_DEFINES)) +SpecialCObjectRule(xdmauth,$(ICONFIGFILES),$(XDMCP_DEFINES)) +SpecialCObjectRule(xdmcp,$(ICONFIGFILES),$(SOCK_DEFINES) $(XDMCP_DEFINES)) +SpecialCObjectRule(connection,$(ICONFIGFILES),$(SOCK_DEFINES) $(XDMCP_DEFINES)) +SpecialCObjectRule(osinit,$(ICONFIGFILES),$(ADM_DEFINES)) +SpecialCObjectRule(WaitFor,$(ICONFIGFILES),$(EXT_DEFINES)) +SpecialCObjectRule(io,$(ICONFIGFILES),$(EXT_DEFINES)) +SpecialCObjectRule(utils,$(ICONFIGFILES),$(XDMCP_DEFINES) $(EXT_DEFINES) $(ERROR_DEFINES) $(PAM_DEFINES)) +#if defined(SparcArchitecture) && HasGcc && !HasGcc2 +oscolor.o: oscolor.c $(ICONFIGFILES) + $(RM) $@ + cc -c $(CDEBUGFLAGS) $(ALLDEFINES) $*.c +#endif + +#if !HasSnprintf +LinkSourceFile(snprintf.c,$(LIBSRC)/misc) +#endif + +DependTarget() diff --git a/nx-X11/programs/Xserver/os/WaitFor.c b/nx-X11/programs/Xserver/os/WaitFor.c new file mode 100644 index 000000000..76e5da5f2 --- /dev/null +++ b/nx-X11/programs/Xserver/os/WaitFor.c @@ -0,0 +1,829 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* nx-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/*********************************************************** + +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. + +******************************************************************/ + +/***************************************************************** + * OS Dependent input routines: + * + * WaitForSomething + * TimerForce, TimerSet, TimerCheck, TimerFree + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <nx-X11/Xwinsock.h> +#endif +#include <nx-X11/Xos.h> /* for strings, fcntl, time */ +#include <errno.h> +#include <stdio.h> +#include <nx-X11/X.h> +#include "misc.h" + +#include "osdep.h" +#include <nx-X11/Xpoll.h> +#include "dixstruct.h" +#include "opaque.h" +#ifdef DPMSExtension +#include "dpmsproc.h" +#endif + +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_WAKEUP) + +static unsigned long startTimeInMillis; + +#endif + +#ifdef WIN32 +/* Error codes from windows sockets differ from fileio error codes */ +#undef EINTR +#define EINTR WSAEINTR +#undef EINVAL +#define EINVAL WSAEINVAL +#undef EBADF +#define EBADF WSAENOTSOCK +/* Windows select does not set errno. Use GetErrno as wrapper for + WSAGetLastError */ +#define GetErrno WSAGetLastError +#else +/* This is just a fallback to errno to hide the differences between unix and + Windows in the code */ +#define GetErrno() errno +#endif + +/* modifications by raphael */ +int +mffs(fd_mask mask) +{ + int i; + + if (!mask) return 0; + i = 1; + while (!(mask & 1)) + { + i++; + mask >>= 1; + } + return i; +} + +#ifdef DPMSExtension +#define DPMS_SERVER +#include <nx-X11/extensions/dpms.h> +#endif + +#ifdef XTESTEXT1 +/* + * defined in xtestext1dd.c + */ +extern int playback_on; +#endif /* XTESTEXT1 */ + +struct _OsTimerRec { + OsTimerPtr next; + CARD32 expires; + OsTimerCallback callback; + void * arg; +}; + +static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev); +static OsTimerPtr timers = NULL; + +/***************** + * 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. + *****************/ + +int +WaitForSomething(int *pClientsReady) +{ + int i; + struct timeval waittime, *wt; + INT32 timeout = 0; + fd_set clientsReadable; + fd_set clientsWritable; + int curclient; + int selecterr; + int nready; + CARD32 now = 0; + Bool someReady = FALSE; + Bool someNotifyWriteReady = FALSE; + +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG) + fprintf(stderr, "WaitForSomething: Got called.\n"); +#endif + + FD_ZERO(&clientsReadable); + +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_WAKEUP) + + startTimeInMillis = GetTimeInMillis(); + +#endif + + /* 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)) + { + someReady = TRUE; + waittime.tv_sec = 0; + waittime.tv_usec = 0; + wt = &waittime; + } + if (someReady) + { + XFD_COPYSET(&AllSockets, &LastSelectMask); + XFD_UNSET(&LastSelectMask, &ClientsWithInput); + } + else + { + wt = NULL; + if (timers) + { + now = GetTimeInMillis(); + timeout = timers->expires - now; + if (timeout < 0) + timeout = 0; + waittime.tv_sec = timeout / MILLI_PER_SECOND; + waittime.tv_usec = (timeout % MILLI_PER_SECOND) * + (1000000 / MILLI_PER_SECOND); + wt = &waittime; + } + XFD_COPYSET(&AllSockets, &LastSelectMask); + } + SmartScheduleStopTimer (); + + BlockHandler((void *)&wt, (void *)&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 */ + +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_WAKEUP) + + /* + * If caller has marked the first element of pClientsReady[], + * bail out of select after a short timeout. We need this to + * let the NX agent remove the splash screen when the timeout + * is expired. A better option would be to use the existing + * screen-saver timeout but it can be modified by clients, so + * we would need a special handling. This hack is trivial and + * keeps WaitForSomething() backward compatible with the exis- + * ting servers. + */ + + if (pClientsReady[0] == -1) + { + unsigned long timeoutInMillis; + +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_WAKEUP) && defined(NX_TRANS_DEBUG) + fprintf(stderr, "WaitForSomething: pClientsReady[0] is [%d], pClientsReady[1] is [%d].\n", + pClientsReady[0], pClientsReady[1]); +#endif + + timeoutInMillis = GetTimeInMillis(); + + if (timeoutInMillis - startTimeInMillis >= NX_TRANS_WAKEUP) + { +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_WAKEUP) && defined(NX_TRANS_DEBUG) + fprintf(stderr, "WaitForSomething: Returning 0 because of wakeup timeout.\n"); +#endif + return 0; + } + + timeoutInMillis = NX_TRANS_WAKEUP - (timeoutInMillis - startTimeInMillis); + +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_WAKEUP) && defined(NX_TRANS_DEBUG) + fprintf(stderr, "WaitForSomething: Milliseconds to next wakeup are %ld.\n", + timeoutInMillis); +#endif + if (wt == NULL || (wt -> tv_sec * MILLI_PER_SECOND + + wt -> tv_usec / MILLI_PER_SECOND) > timeoutInMillis) + { + if ((waittime.tv_sec * MILLI_PER_SECOND + + waittime.tv_usec / MILLI_PER_SECOND) > timeoutInMillis) + { + waittime.tv_sec = timeoutInMillis / MILLI_PER_SECOND; + waittime.tv_usec = (timeoutInMillis * MILLI_PER_SECOND) % + (MILLI_PER_SECOND * 1000); + wt = &waittime; + } + +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_WAKEUP) && defined(NX_TRANS_DEBUG) + fprintf(stderr, "WaitForSomething: Next wakeup timeout set to %ld milliseconds.\n", + (waittime.tv_sec * MILLI_PER_SECOND) + + (waittime.tv_usec / MILLI_PER_SECOND)); +#endif + } +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_WAKEUP) && defined(NX_TRANS_DEBUG) + else + { + fprintf(stderr, "WaitForSomething: Using existing timeout of %ld milliseconds.\n", + (waittime.tv_sec * MILLI_PER_SECOND) + + (waittime.tv_usec / MILLI_PER_SECOND)); + } +#endif + } +#endif + + /* keep this check close to select() call to minimize race */ +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG) + if (dispatchException) + { + i = -1; + + fprintf(stderr, "WaitForSomething: Value of dispatchException is true. Set i = -1.\n"); + } +#else + if (dispatchException) + i = -1; +#endif + else if (AnyWritesPending) + { +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG) + if (wt == NULL) + { + fprintf(stderr, "WaitForSomething: Executing select with LastSelectMask and " + "clientsWritable and null timeout.\n"); + } + else + { + fprintf(stderr, "WaitForSomething: Executing select with LastSelectMask, " + "clientsWritable, %ld secs and %ld usecs.\n", + wt -> tv_sec, wt -> tv_usec); + } +#endif + XFD_COPYSET(&ClientsWriteBlocked, &LastSelectWriteMask); + XFD_ORSET(&LastSelectWriteMask, &NotifyWriteFds, &LastSelectWriteMask); + i = Select(MaxClients, &LastSelectMask, &LastSelectWriteMask, NULL, wt); + } + else + { +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG) + if (wt == NULL) + { + fprintf(stderr, "WaitForSomething: Executing select with LastSelectMask and null timeout.\n"); + } + else + { + fprintf(stderr, "WaitForSomething: Executing select with LastSelectMask, %ld secs and %ld usecs.\n", + wt -> tv_sec, wt -> tv_usec); + } +#endif + i = Select (MaxClients, &LastSelectMask, NULL, NULL, wt); + } +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG) + fprintf(stderr, "WaitForSomething: Bailed out with i = [%d] and errno = [%d].\n", i, errno); + + if (i < 0) + { + fprintf(stderr, "WaitForSomething: Error is [%s].\n", strerror(errno)); + } +#endif + selecterr = GetErrno(); + WakeupHandler(i, (void *)&LastSelectMask); +#ifdef XTESTEXT1 + if (playback_on) { + i = XTestProcessInputAction (i, &waittime); + } +#endif /* XTESTEXT1 */ + SmartScheduleStartTimer (); + + if (i <= 0) /* An error or timeout occurred */ + { +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG) + if (dispatchException) + { + fprintf(stderr, "WaitForSomething: Returning 0 because of (dispatchException).\n"); + return 0; + } +#else + if (dispatchException) + return 0; +#endif + if (i < 0) + { + if (selecterr == EBADF) /* Some client disconnected */ + { + CheckConnections (); +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG) + if (! XFD_ANYSET (&AllClients)) + { + fprintf(stderr, "WaitForSomething: Returning 0 because of (! XFD_ANYSET (&AllClients)).\n"); + return 0; + } +#else + if (! XFD_ANYSET (&AllClients)) + return 0; +#endif + } + else if (selecterr == EINVAL) + { + FatalError("WaitForSomething(): select: errno=%d\n", + selecterr); + } + else if (selecterr != EINTR) + { + ErrorF("WaitForSomething(): select: errno=%d\n", + selecterr); + } + } + else if (someReady) + { + /* + * If no-one else is home, bail quickly + */ + XFD_COPYSET(&ClientsWithInput, &LastSelectMask); + XFD_COPYSET(&ClientsWithInput, &clientsReadable); + break; + } +#if defined(NX_TRANS_SOCKET) + if (*checkForInput[0] != *checkForInput[1]) + { +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG) + fprintf(stderr, "WaitForSomething: Returning 0 because of (*checkForInput[0] != *checkForInput[1]).\n"); +#endif + return 0; + } +#else + if (*checkForInput[0] != *checkForInput[1]) + return 0; +#endif + + if (timers) + { + int expired = 0; + now = GetTimeInMillis(); + if ((int) (timers->expires - now) <= 0) + expired = 1; + + while (timers && (int) (timers->expires - now) <= 0) + DoTimer(timers, now, &timers); + + if (expired) + return 0; + } + } + else + { + fd_set tmp_set; + + if (*checkForInput[0] == *checkForInput[1]) { + if (timers) + { + int expired = 0; + now = GetTimeInMillis(); + if ((int) (timers->expires - now) <= 0) + expired = 1; + + while (timers && (int) (timers->expires - now) <= 0) + DoTimer(timers, now, &timers); + + if (expired) + return 0; + } + } + if (someReady) + XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask); + if (AnyWritesPending) { + XFD_ANDSET(&clientsWritable, &LastSelectWriteMask, &ClientsWriteBlocked); + if (XFD_ANYSET(&clientsWritable)) { + NewOutputPending = TRUE; + XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending); + XFD_UNSET(&ClientsWriteBlocked, &clientsWritable); + if (!XFD_ANYSET(&ClientsWriteBlocked) && NumNotifyWriteFd == 0) + AnyWritesPending = FALSE; + } + if (NumNotifyWriteFd != 0) { + XFD_ANDSET(&tmp_set, &LastSelectWriteMask, &NotifyWriteFds); + if (XFD_ANYSET(&tmp_set)) + someNotifyWriteReady = TRUE; + } + } + + XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients); + + XFD_ANDSET(&tmp_set, &LastSelectMask, &NotifyReadFds); + if (XFD_ANYSET(&tmp_set) || someNotifyWriteReady) + HandleNotifyFds(); + + if (XFD_ANYSET (&clientsReadable)) + break; +#ifdef WIN32 + /* Windows keyboard and mouse events are added to the input queue + in Block- and WakupHandlers. There is no device to check if + data is ready. So check here if new input is available */ +#if defined(NX_TRANS_SOCKET) + if (*checkForInput[0] != *checkForInput[1]) + { +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG) + fprintf(stderr, "WaitForSomething: Returning 0 because of (*checkForInput[0] != *checkForInput[1]).\n"); +#endif + return 0; + } +#else + if (*checkForInput[0] != *checkForInput[1]) + return 0; +#endif +#endif + } + } + + nready = 0; + if (XFD_ANYSET (&clientsReadable)) + { +#ifndef WIN32 + for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++) + { + while (clientsReadable.fds_bits[i]) + { + int client_index; + + curclient = ffs (clientsReadable.fds_bits[i]) - 1; + client_index = /* raphael: modified */ + ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))]; +#else + 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 = GetConnectionTranslation(curclient); +#endif + pClientsReady[nready++] = client_index; +#ifndef WIN32 + clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient); + } +#else + FD_CLR(curclient, &clientsReadable); +#endif + } + } +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_DEBUG) + fprintf(stderr, "WaitForSomething: Returning nready.\n"); +#endif + return nready; +} + +#if 0 +/* + * This is not always a macro. + */ +ANYSET(FdMask *src) +{ + int i; + + for (i=0; i<mskcnt; i++) + if (src[ i ]) + return (TRUE); + return (FALSE); +} +#endif + + +static void +DoTimer(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(OsTimerPtr timer, int flags, CARD32 millis, + OsTimerCallback func, void * arg) +{ + register OsTimerPtr *prev; + CARD32 now = GetTimeInMillis(); + + if (!timer) + { + timer = (OsTimerPtr)malloc(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 ((int) (millis - now) <= 0) + { + timer->next = NULL; + millis = (*timer->callback)(timer, now, timer->arg); + if (!millis) + return timer; + } + for (prev = &timers; + *prev && (int) ((*prev)->expires - millis) <= 0; + prev = &(*prev)->next) + ; + timer->next = *prev; + *prev = timer; + return timer; +} + +Bool +TimerForce(OsTimerPtr timer) +{ + OsTimerPtr *prev; + + for (prev = &timers; *prev; prev = &(*prev)->next) + { + if (*prev == timer) + { + DoTimer(timer, GetTimeInMillis(), prev); + return TRUE; + } + } + return FALSE; +} + + +void +TimerCancel(OsTimerPtr timer) +{ + OsTimerPtr *prev; + + if (!timer) + return; + for (prev = &timers; *prev; prev = &(*prev)->next) + { + if (*prev == timer) + { + *prev = timer->next; + break; + } + } +} + +void +TimerFree(OsTimerPtr timer) +{ + if (!timer) + return; + TimerCancel(timer); + free(timer); +} + +void +TimerCheck(void) +{ + CARD32 now = GetTimeInMillis(); + + while (timers && (int) (timers->expires - now) <= 0) + DoTimer(timers, now, &timers); +} + +void +TimerInit(void) +{ + OsTimerPtr timer; + + while ((timer = timers)) + { + timers = timer->next; + free(timer); + } +} + +static CARD32 +ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,void * arg) +{ + INT32 timeout = now - lastDeviceEventTime.milliseconds; + + if (timeout < ScreenSaverTime) { + return ScreenSaverTime - timeout; + } + + ResetOsBuffers(); /* not ideal, but better than nothing */ + SaveScreens(SCREEN_SAVER_ON, ScreenSaverActive); + +#ifdef DPMSExtension + if (ScreenSaverInterval > 0 && DPMSPowerLevel == DPMSModeOn) +#else + if (ScreenSaverInterval > 0) +#endif /* DPMSExtension */ + return ScreenSaverInterval; + + return 0; +} + +static OsTimerPtr ScreenSaverTimer = NULL; + +void +FreeScreenSaverTimer(void) +{ + if (ScreenSaverTimer) { + TimerFree(ScreenSaverTimer); + ScreenSaverTimer = NULL; + } +} + +void +SetScreenSaverTimer(void) +{ + if (ScreenSaverTime > 0) { + ScreenSaverTimer = TimerSet(ScreenSaverTimer, 0, ScreenSaverTime, + ScreenSaverTimeoutExpire, NULL); + } else if (ScreenSaverTimer) { + FreeScreenSaverTimer(); + } +} + +#ifdef DPMSExtension + +static OsTimerPtr DPMSStandbyTimer = NULL; +static OsTimerPtr DPMSSuspendTimer = NULL; +static OsTimerPtr DPMSOffTimer = NULL; + +static CARD32 +DPMSStandbyTimerExpire(OsTimerPtr timer,CARD32 now,void * arg) +{ + INT32 timeout = now - lastDeviceEventTime.milliseconds; + + if (timeout < DPMSStandbyTime) { + return DPMSStandbyTime - timeout; + } + if (DPMSPowerLevel < DPMSModeStandby) { + if (DPMSEnabled) + DPMSSet(DPMSModeStandby); + } + return DPMSStandbyTime; +} + +static CARD32 +DPMSSuspendTimerExpire(OsTimerPtr timer,CARD32 now,void * arg) +{ + INT32 timeout = now - lastDeviceEventTime.milliseconds; + + if (timeout < DPMSSuspendTime) { + return DPMSSuspendTime - timeout; + } + if (DPMSPowerLevel < DPMSModeSuspend) { + if (DPMSEnabled) + DPMSSet(DPMSModeSuspend); + } + return DPMSSuspendTime; +} + +static CARD32 +DPMSOffTimerExpire(OsTimerPtr timer,CARD32 now,void * arg) +{ + INT32 timeout = now - lastDeviceEventTime.milliseconds; + + if (timeout < DPMSOffTime) { + return DPMSOffTime - timeout; + } + if (DPMSPowerLevel < DPMSModeOff) { + if (DPMSEnabled) + DPMSSet(DPMSModeOff); + } + return DPMSOffTime; +} + +void +FreeDPMSTimers(void) +{ + if (DPMSStandbyTimer) { + TimerFree(DPMSStandbyTimer); + DPMSStandbyTimer = NULL; + } + if (DPMSSuspendTimer) { + TimerFree(DPMSSuspendTimer); + DPMSSuspendTimer = NULL; + } + if (DPMSOffTimer) { + TimerFree(DPMSOffTimer); + DPMSOffTimer = NULL; + } +} + +void +SetDPMSTimers(void) +{ + if (!DPMSEnabled) + return; + + DPMSStandbyTimer = TimerSet(DPMSStandbyTimer, 0, DPMSStandbyTime, + DPMSStandbyTimerExpire, NULL); + DPMSSuspendTimer = TimerSet(DPMSSuspendTimer, 0, DPMSSuspendTime, + DPMSSuspendTimerExpire, NULL); + DPMSOffTimer = TimerSet(DPMSOffTimer, 0, DPMSOffTime, + DPMSOffTimerExpire, NULL); +} +#endif diff --git a/nx-X11/programs/Xserver/os/access.c b/nx-X11/programs/Xserver/os/access.c new file mode 100644 index 000000000..d8d035ade --- /dev/null +++ b/nx-X11/programs/Xserver/os/access.c @@ -0,0 +1,2285 @@ +/*********************************************************** + +Copyright 1987, 1998 The Open Group +Copyright 2004 Sun Microsystems, Inc. + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +X Window System is a trademark of 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 HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <nx-X11/Xwinsock.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <nx-X11/Xtrans/Xtrans.h> +#include <nx-X11/Xauth.h> +#include <nx-X11/X.h> +#include <nx-X11/Xproto.h> +#include "misc.h" +#include "site.h" +#include <errno.h> +#include <sys/types.h> +#ifndef WIN32 +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <ctype.h> + +#if defined(TCPCONN) || defined(ISC) || defined(__SCO__) +#include <netinet/in.h> +#endif /* TCPCONN || ISC || __SCO__ */ + +#ifdef HAS_GETPEERUCRED +# include <ucred.h> +# ifdef sun +# include <zone.h> +# endif +#endif + +#if defined(SVR4) || (defined(SYSV) && defined(i386)) || defined(__GNU__) +# include <sys/utsname.h> +#endif +#if defined(SYSV) && defined(i386) +# include <sys/stream.h> +# ifdef ISC +# include <sys/stropts.h> +# include <sys/sioctl.h> +# endif /* ISC */ +#endif +#ifdef __GNU__ +#undef SIOCGIFCONF +#include <netdb.h> +#else /*!__GNU__*/ +# include <net/if.h> +#endif /*__GNU__ */ + +#ifdef SVR4 +#include <sys/sockio.h> +#include <sys/stropts.h> +#endif + +#include <netdb.h> + +#ifdef CSRG_BASED +#include <sys/param.h> +#if (BSD >= 199103) +#define VARIABLE_IFREQ +#endif +#endif + +#ifdef BSD44SOCKETS +#ifndef VARIABLE_IFREQ +#define VARIABLE_IFREQ +#endif +#endif + +#ifdef HAS_GETIFADDRS +#include <ifaddrs.h> +#endif + +/* Solaris provides an extended interface SIOCGLIFCONF. Other systems + * may have this as well, but the code has only been tested on Solaris + * so far, so we only enable it there. Other platforms may be added as + * needed. + * + * Test for Solaris commented out -- TSI @ UQV 2003.06.13 + */ +#ifdef SIOCGLIFCONF +/* #if defined(sun) */ +#define USE_SIOCGLIFCONF +/* #endif */ +#endif + +#endif /* WIN32 */ + +#ifndef PATH_MAX +#include <sys/param.h> +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif +#endif + +#ifdef __SCO__ +/* The system defined value is wrong. MAXPATHLEN is set in sco5.cf. */ +#undef PATH_MAX +#endif + +#define X_INCLUDE_NETDB_H +#include <nx-X11/Xos_r.h> + +#include "dixstruct.h" +#include "osdep.h" + +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <nx-X11/extensions/security.h> +#endif + +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#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(struct sockaddr * /*saddr*/, + int * /*len*/, + void ** /*addr*/); + +static int CheckAddr(int /*family*/, + void * /*pAddr*/, + unsigned /*length*/); + +static Bool NewHost(int /*family*/, + void * /*addr*/, + int /*len*/, + int /* addingLocalHosts */); + +/* XFree86 bug #156: To keep track of which hosts were explicitly requested in + /etc/X<display>.hosts, we've added a requested field to the HOST struct, + and a LocalHostRequested variable. These default to FALSE, but are set + to TRUE in ResetHosts when reading in /etc/X<display>.hosts. They are + checked in DisableLocalHost(), which is called to disable the default + local host entries when stronger authentication is turned on. */ + +typedef struct _host { + short family; + short len; + unsigned char *addr; + struct _host *next; + int requested; +} HOST; + +#define MakeHost(h,l) (h)=(HOST *) malloc(sizeof *(h)+(l));\ + if (h) { \ + (h)->addr=(unsigned char *) ((h) + 1);\ + (h)->requested = FALSE; \ + } +#define FreeHost(h) free(h) +static HOST *selfhosts = NULL; +static HOST *validhosts = NULL; +static int AccessEnabled = DEFAULT_ACCESS_CONTROL; +static int LocalHostEnabled = FALSE; +static int LocalHostRequested = FALSE; +static int UsingXdmcp = FALSE; + +/* FamilyServerInterpreted implementation */ +static Bool siAddrMatch(int family, void * addr, int len, HOST *host, + ClientPtr client); +static int siCheckAddr(const char *addrString, int length); +static void siTypesInitialize(void); + +/* + * called when authorization is not enabled to add the + * local host to the access list + */ + +void +EnableLocalHost (void) +{ + if (!UsingXdmcp) + { + LocalHostEnabled = TRUE; + AddLocalHosts (); + } +} + +/* + * called when authorization is enabled to keep us secure + */ +void +DisableLocalHost (void) +{ + HOST *self; + + if (!LocalHostRequested) /* Fix for XFree86 bug #156 */ + LocalHostEnabled = FALSE; + for (self = selfhosts; self; self = self->next) { + if (!self->requested) /* Fix for XFree86 bug #156 */ + (void) RemoveHost ((ClientPtr)NULL, self->family, self->len, (void *)self->addr); + } +} + +/* + * called at init time when XDMCP will be used; xdmcp always + * adds local hosts manually when needed + */ + +void +AccessUsingXdmcp (void) +{ + UsingXdmcp = TRUE; + LocalHostEnabled = FALSE; +} + + +#if ((defined(SVR4) && !defined(SCO325) && !defined(sun) && !defined(NCR)) || defined(ISC)) && defined(SIOCGIFCONF) && !defined(USE_SIOCGLIFCONF) + +/* Deal with different SIOCGIFCONF ioctl semantics on these OSs */ + +static int +ifioctl (int fd, int cmd, char *arg) +{ + struct strioctl ioc; + int ret; + + bzero((char *) &ioc, sizeof(ioc)); + ioc.ic_cmd = cmd; + ioc.ic_timout = 0; + if (cmd == SIOCGIFCONF) + { + ioc.ic_len = ((struct ifconf *) arg)->ifc_len; + ioc.ic_dp = ((struct ifconf *) arg)->ifc_buf; +#ifdef ISC + /* SIOCGIFCONF is somewhat brain damaged on ISC. The argument + * buffer must contain the ifconf structure as header. Ifc_req + * is also not a pointer but a one element array of ifreq + * structures. On return this array is extended by enough + * ifreq fields to hold all interfaces. The return buffer length + * is placed in the buffer header. + */ + ((struct ifconf *) ioc.ic_dp)->ifc_len = + ioc.ic_len - sizeof(struct ifconf); +#endif + } + else + { + ioc.ic_len = sizeof(struct ifreq); + ioc.ic_dp = arg; + } + ret = ioctl(fd, I_STR, (char *) &ioc); + if (ret >= 0 && cmd == SIOCGIFCONF) +#ifdef SVR4 + ((struct ifconf *) arg)->ifc_len = ioc.ic_len; +#endif +#ifdef ISC + { + ((struct ifconf *) arg)->ifc_len = + ((struct ifconf *)ioc.ic_dp)->ifc_len; + ((struct ifconf *) arg)->ifc_buf = + (caddr_t)((struct ifconf *)ioc.ic_dp)->ifc_req; + } +#endif + return(ret); +} +#else /* Case sun, SCO325 NCR and others */ +#define ifioctl ioctl +#endif /* ((SVR4 && !sun !SCO325 !NCR) || ISC) && SIOCGIFCONF */ + +/* + * 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 (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 (1)"); + + /* 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 (2)"); + } + + 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 (3)"); + } + + len = sizeof(struct sockaddr_in); + family = ConvertAddr (IA_SIN(&ifaddr), &len, (void **)&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; + + /* + * Ignore '0.0.0.0' entries as they are + * returned by some OSes for unconfigured NICs but they are + * not useful on the other end of the wire. + */ + if (len == 4 && + addr[0] == 0 && addr[1] == 0 && + addr[2] == 0 && addr[3] == 0) + 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) +void +DefineSelf (int fd) +{ +#if !defined(TCPCONN) && !defined(UNIXCONN) + return; +#else + register int n; + int len; + caddr_t addr; + int family; + register HOST *host; + +#ifndef WIN32 + struct utsname name; +#else + struct { + char nodename[512]; + } name; +#endif + + register struct hostent *hp; + + union { + struct sockaddr sa; + struct sockaddr_in in; +#if defined(IPv6) && defined(AF_INET6) + struct sockaddr_in6 in6; +#endif + } saddr; + + struct sockaddr_in *inetaddr; + struct sockaddr_in6 *inet6addr; + struct sockaddr_in broad_addr; +#ifdef XTHREADS_NEEDS_BYNAMEPARAMS + _Xgethostbynameparams hparams; +#endif + + /* 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. + */ +#ifndef WIN32 + uname(&name); +#else + gethostname(name.nodename, sizeof(name.nodename)); +#endif + + hp = _XGethostbyname(name.nodename, hparams); + if (hp != NULL) + { + saddr.sa.sa_family = hp->h_addrtype; + switch (hp->h_addrtype) { + case AF_INET: + inetaddr = (struct sockaddr_in *) (&(saddr.sa)); + acopy ( hp->h_addr, &(inetaddr->sin_addr), hp->h_length); + len = sizeof(saddr.sa); + break; +#if defined(IPv6) && defined(AF_INET6) + case AF_INET6: + inet6addr = (struct sockaddr_in6 *) (&(saddr.sa)); + acopy ( hp->h_addr, &(inet6addr->sin6_addr), hp->h_length); + len = sizeof(saddr.in6); + break; +#endif + default: + goto DefineLocalHost; + } + family = ConvertAddr ( &(saddr.sa), &len, (void **)&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), nor the bogus address (0.0.0.0), + * register it. + */ + if (family == FamilyInternet && + !(len == 4 && + ((addr[0] == 127 && addr[1] == 0 && + addr[2] == 0 && addr[3] == 1) || + (addr[0] == 0 && addr[1] == 0 && + addr[2] == 0 && addr[3] == 0))) + ) + { + 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); + } +#if defined(IPv6) && defined(AF_INET6) + else if (family == FamilyInternet6 && + !(IN6_IS_ADDR_LOOPBACK((struct in6_addr *)addr))) + { + XdmcpRegisterConnection (family, (char *)addr, len); + } +#endif + +#endif /* XDMCP */ + } + } + } + /* + * now add a host of family FamilyLocalHost... + */ +DefineLocalHost: + 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 + +#ifdef USE_SIOCGLIFCONF +#define ifr_type struct lifreq +#else +#define ifr_type struct ifreq +#endif + +#ifdef VARIABLE_IFREQ +#define ifr_size(p) (sizeof (struct ifreq) + \ + (p->ifr_addr.sa_len > sizeof (p->ifr_addr) ? \ + p->ifr_addr.sa_len - sizeof (p->ifr_addr) : 0)) +#define ifraddr_size(a) (a.sa_len) +#else +#define ifr_size(p) (sizeof (ifr_type)) +#define ifraddr_size(a) (sizeof (a)) +#endif + +#if defined(DEF_SELF_DEBUG) || (defined(IPv6) && defined(AF_INET6)) +#include <arpa/inet.h> +#endif + +#if defined(IPv6) && defined(AF_INET6) +static void +in6_fillscopeid(struct sockaddr_in6 *sin6) +{ +#if defined(__KAME__) + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + sin6->sin6_scope_id = + ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); + sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; + } +#endif +} +#endif + +void +DefineSelf (int fd) +{ +#ifndef HAS_GETIFADDRS + char buf[2048], *cp, *cplim; + void * bufptr = buf; +#ifdef USE_SIOCGLIFCONF + struct lifconf ifc; + register struct lifreq *ifr; +#ifdef SIOCGLIFNUM + struct lifnum ifn; +#endif +#else + struct ifconf ifc; + register struct ifreq *ifr; +#endif +#else + struct ifaddrs * ifap, *ifr; +#endif + int len; + unsigned char * addr; + int family; + register HOST *host; + +#ifndef HAS_GETIFADDRS + + len = sizeof(buf); + +#ifdef USE_SIOCGLIFCONF + +#ifdef SIOCGLIFNUM + ifn.lifn_family = AF_UNSPEC; + ifn.lifn_flags = 0; + if (ioctl (fd, SIOCGLIFNUM, (char *) &ifn) < 0) + Error ("Getting interface count"); + if (len < (ifn.lifn_count * sizeof(struct lifreq))) { + len = ifn.lifn_count * sizeof(struct lifreq); + bufptr = malloc(len); + } +#endif + + ifc.lifc_family = AF_UNSPEC; + ifc.lifc_flags = 0; + ifc.lifc_len = len; + ifc.lifc_buf = bufptr; + +#define IFC_IOCTL_REQ SIOCGLIFCONF +#define IFC_IFC_REQ ifc.lifc_req +#define IFC_IFC_LEN ifc.lifc_len +#define IFR_IFR_ADDR ifr->lifr_addr +#define IFR_IFR_NAME ifr->lifr_name + +#else /* Use SIOCGIFCONF */ + ifc.ifc_len = len; + ifc.ifc_buf = bufptr; + +#define IFC_IOCTL_REQ SIOCGIFCONF +#ifdef ISC +#define IFC_IFC_REQ (struct ifreq *) ifc.ifc_buf +#else +#define IFC_IFC_REQ ifc.ifc_req +#endif /* ISC */ +#define IFC_IFC_LEN ifc.ifc_len +#define IFR_IFR_ADDR ifr->ifr_addr +#define IFR_IFR_NAME ifr->ifr_name +#endif + + if (ifioctl (fd, IFC_IOCTL_REQ, (void *) &ifc) < 0) + Error ("Getting interface configuration (4)"); + + cplim = (char *) IFC_IFC_REQ + IFC_IFC_LEN; + + for (cp = (char *) IFC_IFC_REQ; cp < cplim; cp += ifr_size (ifr)) + { + ifr = (ifr_type *) cp; + len = ifraddr_size (IFR_IFR_ADDR); + family = ConvertAddr ((struct sockaddr *) &IFR_IFR_ADDR, + &len, (void **)&addr); + if (family == -1 || family == FamilyLocal) + continue; +#if defined(IPv6) && defined(AF_INET6) + if (family == FamilyInternet6) + in6_fillscopeid((struct sockaddr_in6 *)&IFR_IFR_ADDR); +#endif +#ifdef DEF_SELF_DEBUG + if (family == FamilyInternet) + ErrorF("Xserver: DefineSelf(): ifname = %s, addr = %d.%d.%d.%d\n", + IFR_IFR_NAME, addr[0], addr[1], addr[2], addr[3]); +#if defined(IPv6) && defined(AF_INET6) + else if (family == FamilyInternet6) { + char cp[INET6_ADDRSTRLEN] = ""; + inet_ntop(AF_INET6, addr, cp, sizeof(cp)); + ErrorF("Xserver: DefineSelf(): ifname = %s, addr = %s\n", + IFR_IFR_NAME, cp); + } +#endif +#endif /* DEF_SELF_DEBUG */ + 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 + { +#ifdef USE_SIOCGLIFCONF + struct sockaddr_storage broad_addr; +#else + struct sockaddr broad_addr; +#endif + + /* + * If this isn't an Internet Address, don't register it. + */ + if (family != FamilyInternet +#if defined(IPv6) && defined(AF_INET6) + && family != FamilyInternet6 +#endif + ) + continue; + + /* + * ignore 'localhost' entries as they're not useful + * on the other end of the wire + */ + if (family == FamilyInternet && + addr[0] == 127 && addr[1] == 0 && + addr[2] == 0 && addr[3] == 1) + continue; +#if defined(IPv6) && defined(AF_INET6) + else if (family == FamilyInternet6 && + IN6_IS_ADDR_LOOPBACK((struct in6_addr *)addr)) + continue; +#endif + + /* + * Ignore '0.0.0.0' entries as they are + * returned by some OSes for unconfigured NICs but they are + * not useful on the other end of the wire. + */ + if (len == 4 && + addr[0] == 0 && addr[1] == 0 && + addr[2] == 0 && addr[3] == 0) + continue; + + XdmcpRegisterConnection (family, (char *)addr, len); + +#if defined(IPv6) && defined(AF_INET6) + /* IPv6 doesn't support broadcasting, so we drop out here */ + if (family == FamilyInternet6) + continue; +#endif + + broad_addr = IFR_IFR_ADDR; + + ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr = + htonl (INADDR_BROADCAST); +#if defined(USE_SIOCGLIFCONF) && defined(SIOCGLIFBRDADDR) + { + struct lifreq broad_req; + + broad_req = *ifr; + if (ioctl (fd, SIOCGLIFFLAGS, (char *) &broad_req) != -1 && + (broad_req.lifr_flags & IFF_BROADCAST) && + (broad_req.lifr_flags & IFF_UP) + ) + { + broad_req = *ifr; + if (ioctl (fd, SIOCGLIFBRDADDR, &broad_req) != -1) + broad_addr = broad_req.lifr_broadaddr; + else + continue; + } + else + continue; + } + +#elif defined(SIOCGIFBRDADDR) + { + struct ifreq broad_req; + + broad_req = *ifr; + if (ifioctl (fd, SIOCGIFFLAGS, (void *) &broad_req) != -1 && + (broad_req.ifr_flags & IFF_BROADCAST) && + (broad_req.ifr_flags & IFF_UP) + ) + { + broad_req = *ifr; + if (ifioctl (fd, SIOCGIFBRDADDR, (void *) &broad_req) != -1) + broad_addr = broad_req.ifr_addr; + else + continue; + } + else + continue; + } +#endif /* SIOCGIFBRDADDR */ +#ifdef DEF_SELF_DEBUG + ErrorF("Xserver: DefineSelf(): ifname = %s, baddr = %s\n", + IFR_IFR_NAME, + inet_ntoa(((struct sockaddr_in *) &broad_addr)->sin_addr)); +#endif /* DEF_SELF_DEBUG */ + XdmcpRegisterBroadcastAddress ((struct sockaddr_in *) &broad_addr); + } +#endif /* XDMCP */ + } + if (bufptr != buf) + free(bufptr); +#else /* HAS_GETIFADDRS */ + if (getifaddrs(&ifap) < 0) { + ErrorF("Warning: getifaddrs returns %s\n", strerror(errno)); + return; + } + for (ifr = ifap; ifr != NULL; ifr = ifr->ifa_next) { + if (!ifr->ifa_addr) + continue; + len = sizeof(*(ifr->ifa_addr)); + family = ConvertAddr(ifr->ifa_addr, &len, (void **)&addr); + if (family == -1 || family == FamilyLocal) + continue; +#if defined(IPv6) && defined(AF_INET6) + if (family == FamilyInternet6) + in6_fillscopeid((struct sockaddr_in6 *)ifr->ifa_addr); +#endif + +#ifdef DEF_SELF_DEBUG + if (family == FamilyInternet) + ErrorF("Xserver: DefineSelf(): ifname = %s, addr = %d.%d.%d.%d\n", + ifr->ifa_name, addr[0], addr[1], addr[2], addr[3]); +#if defined(IPv6) && defined(AF_INET6) + else if (family == FamilyInternet6) { + char cp[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET6, addr, cp, sizeof(cp)); + ErrorF("Xserver: DefineSelf(): ifname = %s addr = %s\n", + ifr->ifa_name, cp); + } +#endif +#endif /* DEF_SELF_DEBUG */ + for (host = selfhosts; + host != NULL && !addrEqual(family, addr, len, host); + host = host->next) + ; + if (host != NULL) + continue; + MakeHost(host, len); + if (host != NULL) { + 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 +#if defined(IPv6) && defined(AF_INET6) + && family != FamilyInternet6 +#endif + ) + continue; + + /* + * ignore 'localhost' entries as they're not useful + * on the other end of the wire + */ + if (ifr->ifa_flags & IFF_LOOPBACK) + continue; + + if (family == FamilyInternet && + addr[0] == 127 && addr[1] == 0 && + addr[2] == 0 && addr[3] == 1) + continue; + + /* + * Ignore '0.0.0.0' entries as they are + * returned by some OSes for unconfigured NICs but they are + * not useful on the other end of the wire. + */ + if (len == 4 && + addr[0] == 0 && addr[1] == 0 && + addr[2] == 0 && addr[3] == 0) + continue; +#if defined(IPv6) && defined(AF_INET6) + else if (family == FamilyInternet6 && + IN6_IS_ADDR_LOOPBACK((struct in6_addr *)addr)) + continue; +#endif + XdmcpRegisterConnection(family, (char *)addr, len); +#if defined(IPv6) && defined(AF_INET6) + if (family == FamilyInternet6) + /* IPv6 doesn't support broadcasting, so we drop out here */ + continue; +#endif + if ((ifr->ifa_flags & IFF_BROADCAST) && + (ifr->ifa_flags & IFF_UP)) + broad_addr = *ifr->ifa_broadaddr; + else + continue; +#ifdef DEF_SELF_DEBUG + ErrorF("Xserver: DefineSelf(): ifname = %s, baddr = %s\n", + ifr->ifa_name, + inet_ntoa(((struct sockaddr_in *) &broad_addr)->sin_addr)); +#endif /* DEF_SELF_DEBUG */ + XdmcpRegisterBroadcastAddress((struct sockaddr_in *) + &broad_addr); + } +#endif /* XDMCP */ + + } /* for */ + freeifaddrs(ifap); +#endif /* HAS_GETIFADDRS */ + + /* + * 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 /* !SIOCGIFCONF */ +#endif /* WINTCP */ + +#ifdef XDMCP +void +AugmentSelf(void * from, int len) +{ + int family; + void * addr; + register HOST *host; + + family = ConvertAddr(from, &len, (void **)&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 (void) +{ + HOST *self; + + for (self = selfhosts; self; self = self->next) + /* Fix for XFree86 bug #156: pass addingLocal = TRUE to + * NewHost to tell that we are adding the default local + * host entries and not to flag the entries as being + * explicitely requested */ + (void) NewHost (self->family, self->addr, self->len, TRUE); +} + +/* Reset access control list to initial hosts */ +void +ResetHosts (char *display) +{ + register HOST *host; + char lhostname[120], ohostname[120]; + char *hostname = ohostname; + char fname[PATH_MAX + 1]; + int fnamelen; + FILE *fd; + char *ptr; + int i, hostlen; +#if (defined(TCPCONN) && (!defined(IPv6) || !defined(AF_INET6))) + union { + struct sockaddr sa; +#if defined(TCPCONN) + struct sockaddr_in in; +#endif /* TCPCONN */ + } saddr; +#endif + int family = 0; + void *addr = NULL; + int len; + + siTypesInitialize(); + AccessEnabled = defeatAccessControl ? FALSE : DEFAULT_ACCESS_CONTROL; + LocalHostEnabled = FALSE; + while ((host = validhosts) != 0) + { + validhosts = host->next; + FreeHost (host); + } + +#define ETC_HOST_PREFIX "/etc/X" +#define ETC_HOST_SUFFIX ".hosts" + fnamelen = strlen(ETC_HOST_PREFIX) + strlen(ETC_HOST_SUFFIX) + + strlen(display) + 1; + if (fnamelen > sizeof(fname)) + FatalError("Display name `%s' is too long\n", display); + sprintf(fname, ETC_HOST_PREFIX "%s" ETC_HOST_SUFFIX, display); + + if ((fd = fopen (fname, "r")) != 0) + { + while (fgets (ohostname, sizeof (ohostname), fd)) + { + family = FamilyWild; + if (*ohostname == '#') + continue; + if ((ptr = strchr(ohostname, '\n')) != 0) + *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, FALSE); + LocalHostRequested = TRUE; /* Fix for XFree86 bug #156 */ + } +#if defined(TCPCONN) + else if (!strncmp("inet:", lhostname, 5)) + { + family = FamilyInternet; + hostname = ohostname + 5; + } +#if defined(IPv6) && defined(AF_INET6) + else if (!strncmp("inet6:", lhostname, 6)) + { + family = FamilyInternet6; + hostname = ohostname + 6; + } +#endif +#endif +#ifdef SECURE_RPC + else if (!strncmp("nis:", lhostname, 4)) + { + family = FamilyNetname; + hostname = ohostname + 4; + } +#endif + else if (!strncmp("si:", lhostname, 3)) + { + family = FamilyServerInterpreted; + hostname = ohostname + 3; + hostlen -= 3; + } + + + if (family == FamilyServerInterpreted) + { + len = siCheckAddr(hostname, hostlen); + if (len >= 0) { + NewHost(family, hostname, len, FALSE); + } + } + else +#ifdef SECURE_RPC + if ((family == FamilyNetname) || (strchr(hostname, '@'))) + { + SecureRPCInit (); + (void) NewHost (FamilyNetname, hostname, strlen (hostname), FALSE); + } + else +#endif /* SECURE_RPC */ +#if defined(TCPCONN) + { +#if defined(IPv6) && defined(AF_INET6) + if ( (family == FamilyInternet) || (family == FamilyInternet6) || + (family == FamilyWild) ) + { + struct addrinfo *addresses; + struct addrinfo *a; + int f; + + if (getaddrinfo(hostname, NULL, NULL, &addresses) == 0) { + for (a = addresses ; a != NULL ; a = a->ai_next) { + len = a->ai_addrlen; + f = ConvertAddr(a->ai_addr,&len,(void **)&addr); + if (addr && ((family == f) || + ((family == FamilyWild) && (f != -1)))) { + NewHost(f, addr, len, FALSE); + } + } + freeaddrinfo(addresses); + } + } +#else +#ifdef XTHREADS_NEEDS_BYNAMEPARAMS + _Xgethostbynameparams hparams; +#endif + register struct hostent *hp; + + /* host name */ + if ((family == FamilyInternet && + ((hp = _XGethostbyname(hostname, hparams)) != 0)) || + ((hp = _XGethostbyname(hostname, hparams)) != 0)) + { + saddr.sa.sa_family = hp->h_addrtype; + len = sizeof(saddr.sa); + if ((family = ConvertAddr (&saddr.sa, &len, (void **)&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, (void *)*list, len, FALSE); +#else + (void) NewHost (family, (void *)hp->h_addr, len, FALSE); +#endif + } + } +#endif /* IPv6 */ + } +#endif /* TCPCONN */ + family = FamilyWild; + } + fclose (fd); + } +} + +/* Is client on the local host */ +Bool +ComputeLocalClient(ClientPtr client) +{ + int alen, family, notused; + Xtransaddr *from = NULL; + void *addr; + register HOST *host; + OsCommPtr oc = (OsCommPtr) client->osPrivate; + + if (!oc->trans_conn) + return FALSE; + +#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 + if (!_XSERVTransGetPeerAddr (oc->trans_conn, ¬used, &alen, &from)) + { + family = ConvertAddr ((struct sockaddr *) from, + &alen, (void **)&addr); + if (family == -1) + { + free(from); + return FALSE; + } + if (family == FamilyLocal) + { + free(from); + return TRUE; + } + for (host = selfhosts; host; host = host->next) + { + if (addrEqual (family, addr, alen, host)) { + free(from); + return TRUE; + } + } + free(from); + } + return FALSE; +} + +/* + * Return the uid and gid of a connected local client + * + * Used by XShm to test access rights to shared memory segments + */ +int +LocalClientCred(ClientPtr client, int *pUid, int *pGid) +{ + LocalClientCredRec *lcc; + int ret = GetLocalClientCreds(client, &lcc); + + if (ret == 0) { +#ifdef HAVE_GETZONEID /* only local if in the same zone */ + if ((lcc->fieldsSet & LCC_ZID_SET) && (lcc->zoneid != getzoneid())) { + FreeLocalClientCreds(lcc); + return -1; + } +#endif + if ((lcc->fieldsSet & LCC_UID_SET) && (pUid != NULL)) + *pUid = lcc->euid; + if ((lcc->fieldsSet & LCC_GID_SET) && (pGid != NULL)) + *pGid = lcc->egid; + FreeLocalClientCreds(lcc); + } + return ret; +} + +/* + * Return the uid and all gids of a connected local client + * Allocates a LocalClientCredRec - caller must call FreeLocalClientCreds + * + * Used by localuser & localgroup ServerInterpreted access control forms below + * Used by AuthAudit to log where local connections came from + */ +int +GetLocalClientCreds(ClientPtr client, LocalClientCredRec **lccp) +{ +#if defined(HAS_GETPEEREID) || defined(HAS_GETPEERUCRED) || defined(SO_PEERCRED) + int fd; + XtransConnInfo ci; + LocalClientCredRec *lcc; +#ifdef HAS_GETPEEREID + uid_t uid; + gid_t gid; +#elif defined(HAS_GETPEERUCRED) + ucred_t *peercred = NULL; + const gid_t *gids; +#elif defined(SO_PEERCRED) + struct ucred peercred; + socklen_t so_len = sizeof(peercred); +#endif + + if (client == NULL) + return -1; + ci = ((OsCommPtr)client->osPrivate)->trans_conn; +#if !(defined(sun) && defined(HAS_GETPEERUCRED)) + /* Most implementations can only determine peer credentials for Unix + * domain sockets - Solaris getpeerucred can work with a bit more, so + * we just let it tell us if the connection type is supported or not + */ + if (!_XSERVTransIsLocal(ci)) { + return -1; + } +#endif + + *lccp = calloc(1, sizeof(LocalClientCredRec)); + if (*lccp == NULL) + return -1; + lcc = *lccp; + + fd = _XSERVTransGetConnectionNumber(ci); +#ifdef HAS_GETPEEREID + if (getpeereid(fd, &uid, &gid) == -1) { + FreeLocalClientCreds(lcc); + return -1; + } + lcc->euid = uid; + lcc->egid = gid; + lcc->fieldsSet = LCC_UID_SET | LCC_GID_SET; + return 0; +#elif defined(HAS_GETPEERUCRED) + if (getpeerucred(fd, &peercred) < 0) { + FreeLocalClientCreds(lcc); + return -1; + lcc->euid = ucred_geteuid(peercred); + if (lcc->euid != -1) + lcc->fieldsSet |= LCC_UID_SET; + lcc->egid = ucred_getegid(peercred); + if (lcc->egid != -1) + lcc->fieldsSet |= LCC_GID_SET; + lcc->pid = ucred_getpid(peercred); + if (lcc->pid != -1) + lcc->fieldsSet |= LCC_PID_SET; +#ifdef HAVE_GETZONEID + lcc->zoneid = ucred_getzoneid(peercred); + if (lcc->zoneid != -1) + lcc->fieldsSet |= LCC_ZID_SET; +#endif + lcc->nSuppGids = ucred_getgroups(peercred, &gids); + if (lcc->nSuppGids > 0) { + lcc->pSuppGids = calloc((lcc->nSuppGids), sizeof(int)); + if (lcc->pSuppGids == NULL) { + lcc->nSuppGids = 0; + } else { + int i; + for (i = 0 ; i < lcc->nSuppGids; i++) { + (lcc->pSuppGids)[i] = (int) gids[i]; + } + } + } else { + lcc->nSuppGids = 0; + } + ucred_free(peercred); + return 0; +#elif defined(SO_PEERCRED) + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) == -1) { + FreeLocalClientCreds(lcc); + return -1; + } + lcc->euid = peercred.uid; + lcc->egid = peercred.gid; + lcc->pid = peercred.pid; + lcc->fieldsSet = LCC_UID_SET | LCC_GID_SET | LCC_PID_SET; + return 0; +#endif +#else + /* No system call available to get the credentials of the peer */ +#define NO_LOCAL_CLIENT_CRED + return -1; +#endif +} + +void +FreeLocalClientCreds(LocalClientCredRec *lcc) +{ + if (lcc != NULL) { + if (lcc->nSuppGids > 0) { + free(lcc->pSuppGids); + } + free(lcc); + } +} + +static Bool +AuthorizedClient(ClientPtr client) +{ + if (!client || defeatAccessControl) + return TRUE; + return client->local ? Success : BadAccess; +} + +/* Add a host to the access control list. This is the external interface + * called from the dispatcher */ + +int +AddHost (ClientPtr client, + int family, + unsigned length, /* of bytes in pAddr */ + void *pAddr) +{ + int len; + + if (!AuthorizedClient(client)) + return(BadAccess); + switch (family) { + case FamilyLocalHost: + len = length; + LocalHostEnabled = TRUE; + break; +#ifdef SECURE_RPC + case FamilyNetname: + len = length; + SecureRPCInit (); + break; +#endif + case FamilyInternet: +#if defined(IPv6) && defined(AF_INET6) + case FamilyInternet6: +#endif + case FamilyChaos: + case FamilyServerInterpreted: + 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, FALSE)) + return Success; + return BadAlloc; +} + +Bool +ForEachHostInFamily (int family, + Bool (*func)( + unsigned char * /* addr */, + short /* len */, + void * /* closure */), + void * 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 (int family, + void *addr, + int len, + int addingLocalHosts) +{ + register HOST *host; + + for (host = validhosts; host; host = host->next) + { + if (addrEqual (family, addr, len, host)) + return TRUE; + } + if (!addingLocalHosts) { /* Fix for XFree86 bug #156 */ + for (host = selfhosts; host; host = host->next) { + if (addrEqual (family, addr, len, host)) { + host->requested = TRUE; + break; + } + } + } + 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 ( + ClientPtr client, + int family, + unsigned length, /* of bytes in pAddr */ + void *pAddr) +{ + int len; + register HOST *host, **prev; + + if (!AuthorizedClient(client)) + return(BadAccess); + switch (family) { + case FamilyLocalHost: + len = length; + LocalHostEnabled = FALSE; + break; +#ifdef SECURE_RPC + case FamilyNetname: + len = length; + break; +#endif + case FamilyInternet: +#if defined(IPv6) && defined(AF_INET6) + case FamilyInternet6: +#endif + case FamilyChaos: + case FamilyServerInterpreted: + 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 ( + void * *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); + /* Could check for INT_MAX, but in reality having more than 1mb of + hostnames in the access list is ridiculous */ + if (n >= 1024*1024) + break; + } + if (n) + { + *data = ptr = (void *) malloc (n); + if (!ptr) + { + return(BadAlloc); + } + for (host = validhosts; host; host = host->next) + { + len = host->len; + if ((ptr + sizeof(xHostEntry) + len) > ((unsigned char *) *data + n)) + break; + ((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 ( + int family, + void * pAddr, + unsigned length) +{ + int len; + + switch (family) + { +#if defined(TCPCONN) + case FamilyInternet: + if (length == sizeof (struct in_addr)) + len = length; + else + len = -1; + break; +#if defined(IPv6) && defined(AF_INET6) + case FamilyInternet6: + if (length == sizeof (struct in6_addr)) + len = length; + else + len = -1; + break; +#endif +#endif + case FamilyServerInterpreted: + len = siCheckAddr(pAddr, length); + break; + 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. */ + +int +InvalidHost ( + register struct sockaddr *saddr, + int len, + ClientPtr client) +{ + int family; + void *addr = NULL; + register HOST *selfhost, *host; + + if (!AccessEnabled) /* just let them in */ + return(0); + family = ConvertAddr (saddr, &len, (void **)&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; + } + } + } else + return 0; + } + for (host = validhosts; host; host = host->next) + { + if ((host->family == FamilyServerInterpreted)) { + if (siAddrMatch (family, addr, len, host, client)) { + return (0); + } + } else { + if (addr && addrEqual (family, addr, len, host)) + return (0); + } + + } + return (1); +} + +static int +ConvertAddr ( + register struct sockaddr *saddr, + int *len, + void **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) + case AF_INET: +#ifdef WIN32 + if (16777343 == *(long*)&((struct sockaddr_in *) saddr)->sin_addr) + return FamilyLocal; +#endif + *len = sizeof (struct in_addr); + *addr = (void *) &(((struct sockaddr_in *) saddr)->sin_addr); + return FamilyInternet; +#if defined(IPv6) && defined(AF_INET6) + case AF_INET6: + { + struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) saddr; + if (IN6_IS_ADDR_V4MAPPED(&(saddr6->sin6_addr))) { + *len = sizeof (struct in_addr); + *addr = (void *) &(saddr6->sin6_addr.s6_addr[12]); + return FamilyInternet; + } else { + *len = sizeof (struct in6_addr); + *addr = (void *) &(saddr6->sin6_addr); + return FamilyInternet6; + } + } +#endif +#endif +#ifdef CHAOSCONN + case AF_CHAOS: + { + not implemented + } + return FamilyChaos; +#endif + default: + return -1; + } +} + +int +ChangeAccessControl( + ClientPtr client, + int fEnabled) +{ + if (!AuthorizedClient(client)) + return BadAccess; + AccessEnabled = fEnabled; + return Success; +} + +/* returns FALSE if xhost + in effect, else TRUE */ +int +GetAccessControl(void) +{ + return AccessEnabled; +} + +/***************************************************************************** + * FamilyServerInterpreted host entry implementation + * + * Supports an extensible system of host types which the server can interpret + * See the IPv6 extensions to the X11 protocol spec for the definition. + * + * Currently supported schemes: + * + * hostname - hostname as defined in IETF RFC 2396 + * ipv6 - IPv6 literal address as defined in IETF RFC's 3513 and <TBD> + * + * See xc/doc/specs/SIAddresses for formal definitions of each type. + */ + +/* These definitions and the siTypeAdd function could be exported in the + * future to enable loading additional host types, but that was not done for + * the initial implementation. + */ +typedef Bool (*siAddrMatchFunc)(int family, void * addr, int len, + const char *siAddr, int siAddrlen, ClientPtr client, void *siTypePriv); +typedef int (*siCheckAddrFunc)(const char *addrString, int length, + void *siTypePriv); + +struct siType { + struct siType * next; + const char * typeName; + siAddrMatchFunc addrMatch; + siCheckAddrFunc checkAddr; + void * typePriv; /* Private data for type routines */ +}; + +static struct siType *siTypeList; + +static int +siTypeAdd(const char *typeName, siAddrMatchFunc addrMatch, + siCheckAddrFunc checkAddr, void *typePriv) +{ + struct siType *s, *p; + + if ((typeName == NULL) || (addrMatch == NULL) || (checkAddr == NULL)) + return BadValue; + + for (s = siTypeList, p = NULL; s != NULL ; p = s, s = s->next) { + if (strcmp(typeName, s->typeName) == 0) { + s->addrMatch = addrMatch; + s->checkAddr = checkAddr; + s->typePriv = typePriv; + return Success; + } + } + + s = (struct siType *) malloc(sizeof(struct siType)); + if (s == NULL) + return BadAlloc; + + if (p == NULL) + siTypeList = s; + else + p->next = s; + + s->next = NULL; + s->typeName = typeName; + s->addrMatch = addrMatch; + s->checkAddr = checkAddr; + s->typePriv = typePriv; + return Success; +} + +/* Checks to see if a host matches a server-interpreted host entry */ +static Bool +siAddrMatch(int family, void * addr, int len, HOST *host, ClientPtr client) +{ + Bool matches = FALSE; + struct siType *s; + const char *valueString; + int addrlen; + + valueString = (const char *) memchr(host->addr, '\0', host->len); + if (valueString != NULL) { + for (s = siTypeList; s != NULL ; s = s->next) { + if (strcmp((char *) host->addr, s->typeName) == 0) { + addrlen = host->len - (strlen((char *)host->addr) + 1); + matches = s->addrMatch(family, addr, len, + valueString + 1, addrlen, client, s->typePriv); + break; + } + } +#ifdef FAMILY_SI_DEBUG + ErrorF( + "Xserver: siAddrMatch(): type = %s, value = %*.*s -- %s\n", + host->addr, addrlen, addrlen, valueString + 1, + (matches) ? "accepted" : "rejected"); +#endif + } + return matches; +} + +static int +siCheckAddr(const char *addrString, int length) +{ + const char *valueString; + int addrlen, typelen; + int len = -1; + struct siType *s; + + /* Make sure there is a \0 byte inside the specified length + to separate the address type from the address value. */ + valueString = (const char *) memchr(addrString, '\0', length); + if (valueString != NULL) { + /* Make sure the first string is a recognized address type, + * and the second string is a valid address of that type. + */ + typelen = strlen(addrString) + 1; + addrlen = length - typelen; + + for (s = siTypeList; s != NULL ; s = s->next) { + if (strcmp(addrString, s->typeName) == 0) { + len = s->checkAddr(valueString + 1, addrlen, s->typePriv); + if (len >= 0) { + len += typelen; + } + break; + } + } +#ifdef FAMILY_SI_DEBUG + { + const char *resultMsg; + + if (s == NULL) { + resultMsg = "type not registered"; + } else { + if (len == -1) + resultMsg = "rejected"; + else + resultMsg = "accepted"; + } + + ErrorF("Xserver: siCheckAddr(): type = %s, value = %*.*s, len = %d -- %s\n", + addrString, addrlen, addrlen, valueString + 1, len, resultMsg); + } +#endif + } + return len; +} + + +/*** + * Hostname server-interpreted host type + * + * Stored as hostname string, explicitly defined to be resolved ONLY + * at access check time, to allow for hosts with dynamic addresses + * but static hostnames, such as found in some DHCP & mobile setups. + * + * Hostname must conform to IETF RFC 2396 sec. 3.2.2, which defines it as: + * hostname = *( domainlabel "." ) toplabel [ "." ] + * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum + * toplabel = alpha | alpha *( alphanum | "-" ) alphanum + */ + +#ifdef NI_MAXHOST +# define SI_HOSTNAME_MAXLEN NI_MAXHOST +#else +# ifdef MAXHOSTNAMELEN +# define SI_HOSTNAME_MAXLEN MAXHOSTNAMELEN +# else +# define SI_HOSTNAME_MAXLEN 256 +# endif +#endif + +static Bool +siHostnameAddrMatch(int family, void * addr, int len, + const char *siAddr, int siAddrLen, ClientPtr client, void *typePriv) +{ + Bool res = FALSE; + +/* Currently only supports checking against IPv4 & IPv6 connections, but + * support for other address families, such as DECnet, could be added if + * desired. + */ +#if defined(IPv6) && defined(AF_INET6) + if ((family == FamilyInternet) || (family == FamilyInternet6)) { + char hostname[SI_HOSTNAME_MAXLEN]; + struct addrinfo *addresses; + struct addrinfo *a; + int f, hostaddrlen; + void * hostaddr = NULL; + + if (siAddrLen >= sizeof(hostname)) + return FALSE; + + strncpy(hostname, siAddr, siAddrLen); + hostname[siAddrLen] = '\0'; + + if (getaddrinfo(hostname, NULL, NULL, &addresses) == 0) { + for (a = addresses ; a != NULL ; a = a->ai_next) { + hostaddrlen = a->ai_addrlen; + f = ConvertAddr(a->ai_addr,&hostaddrlen,&hostaddr); + if ((f == family) && (len == hostaddrlen) && hostaddr && + (acmp (addr, hostaddr, len) == 0) ) { + res = TRUE; + break; + } + } + freeaddrinfo(addresses); + } + } +#else /* IPv6 not supported, use gethostbyname instead for IPv4 */ + if (family == FamilyInternet) { + register struct hostent *hp; +#ifdef XTHREADS_NEEDS_BYNAMEPARAMS + _Xgethostbynameparams hparams; +#endif + char hostname[SI_HOSTNAME_MAXLEN]; + int f, hostaddrlen; + void * hostaddr; + const char **addrlist; + + if (siAddrLen >= sizeof(hostname)) + return FALSE; + + strncpy(hostname, siAddr, siAddrLen); + hostname[siAddrLen] = '\0'; + + if ((hp = _XGethostbyname(hostname, hparams)) != NULL) { +#ifdef h_addr /* new 4.3bsd version of gethostent */ + /* iterate over the addresses */ + for (addrlist = hp->h_addr_list; *addrlist; addrlist++) +#else + addrlist = &hp->h_addr; +#endif + { + struct sockaddr_in sin; + + sin.sin_family = hp->h_addrtype; + acopy ( *addrlist, &(sin.sin_addr), hp->h_length); + hostaddrlen = sizeof(sin); + f = ConvertAddr ((struct sockaddr *)&sin, + &hostaddrlen, &hostaddr); + if ((f == family) && (len == hostaddrlen) && + (acmp (addr, hostaddr, len) == 0) ) { + res = TRUE; + break; + } + } + } + } +#endif + return res; +} + + +static int +siHostnameCheckAddr(const char *valueString, int length, void *typePriv) +{ + /* Check conformance of hostname to RFC 2396 sec. 3.2.2 definition. + * We do not use ctype functions here to avoid locale-specific + * character sets. Hostnames must be pure ASCII. + */ + int len = length; + int i; + Bool dotAllowed = FALSE; + Bool dashAllowed = FALSE; + + if ((length <= 0) || (length >= SI_HOSTNAME_MAXLEN)) { + len = -1; + } else { + for (i = 0; i < length; i++) { + char c = valueString[i]; + + if (c == 0x2E) { /* '.' */ + if (dotAllowed == FALSE) { + len = -1; + break; + } else { + dotAllowed = FALSE; + dashAllowed = FALSE; + } + } else if (c == 0x2D) { /* '-' */ + if (dashAllowed == FALSE) { + len = -1; + break; + } else { + dotAllowed = FALSE; + } + } else if (((c >= 0x30) && (c <= 0x3A)) /* 0-9 */ || + ((c >= 0x61) && (c <= 0x7A)) /* a-z */ || + ((c >= 0x41) && (c <= 0x5A)) /* A-Z */) { + dotAllowed = TRUE; + dashAllowed = TRUE; + } else { /* Invalid character */ + len = -1; + break; + } + } + } + return len; +} + +#if defined(IPv6) && defined(AF_INET6) +/*** + * "ipv6" server interpreted type + * + * Currently supports only IPv6 literal address as specified in IETF RFC 3513 + * + * Once draft-ietf-ipv6-scoping-arch-00.txt becomes an RFC, support will be + * added for the scoped address format it specifies. + */ + +/* Maximum length of an IPv6 address string - increase when adding support + * for scoped address qualifiers. Includes room for trailing NUL byte. + */ +#define SI_IPv6_MAXLEN INET6_ADDRSTRLEN + +static Bool +siIPv6AddrMatch(int family, void * addr, int len, + const char *siAddr, int siAddrlen, ClientPtr client, void *typePriv) +{ + struct in6_addr addr6; + char addrbuf[SI_IPv6_MAXLEN]; + + if ((family != FamilyInternet6) || (len != sizeof(addr6))) + return FALSE; + + memcpy(addrbuf, siAddr, siAddrlen); + addrbuf[siAddrlen] = '\0'; + + if (inet_pton(AF_INET6, addrbuf, &addr6) != 1) { + perror("inet_pton"); + return FALSE; + } + + if (memcmp(addr, &addr6, len) == 0) { + return TRUE; + } else { + return FALSE; + } +} + +static int +siIPv6CheckAddr(const char *addrString, int length, void *typePriv) +{ + int len; + + /* Minimum length is 3 (smallest legal address is "::1") */ + if (length < 3) { + /* Address is too short! */ + len = -1; + } else if (length >= SI_IPv6_MAXLEN) { + /* Address is too long! */ + len = -1; + } else { + /* Assume inet_pton is sufficient validation */ + struct in6_addr addr6; + char addrbuf[SI_IPv6_MAXLEN]; + + memcpy(addrbuf, addrString, length); + addrbuf[length] = '\0'; + + if (inet_pton(AF_INET6, addrbuf, &addr6) != 1) { + perror("inet_pton"); + len = -1; + } else { + len = length; + } + } + return len; +} +#endif /* IPv6 */ + +#if !defined(NO_LOCAL_CLIENT_CRED) +/*** + * "localuser" & "localgroup" server interpreted types + * + * Allows local connections from a given local user or group + */ + +#include <pwd.h> +#include <grp.h> + +#define LOCAL_USER 1 +#define LOCAL_GROUP 2 + +typedef struct { + int credType; +} siLocalCredPrivRec, *siLocalCredPrivPtr; + +static siLocalCredPrivRec siLocalUserPriv = { LOCAL_USER }; +static siLocalCredPrivRec siLocalGroupPriv = { LOCAL_GROUP }; + +static Bool +siLocalCredGetId(const char *addr, int len, siLocalCredPrivPtr lcPriv, int *id) +{ + Bool parsedOK = FALSE; + char *addrbuf = malloc(len + 1); + + if (addrbuf == NULL) { + return FALSE; + } + + memcpy(addrbuf, addr, len); + addrbuf[len] = '\0'; + + if (addr[0] == '#') { /* numeric id */ + char *cp; + errno = 0; + *id = strtol(addrbuf + 1, &cp, 0); + if ((errno == 0) && (cp != (addrbuf+1))) { + parsedOK = TRUE; + } + } else { /* non-numeric name */ + if (lcPriv->credType == LOCAL_USER) { + struct passwd *pw = getpwnam(addrbuf); + + if (pw != NULL) { + *id = (int) pw->pw_uid; + parsedOK = TRUE; + } + } else { /* group */ + struct group *gr = getgrnam(addrbuf); + + if (gr != NULL) { + *id = (int) gr->gr_gid; + parsedOK = TRUE; + } + } + } + + free(addrbuf); + return parsedOK; +} + +static Bool +siLocalCredAddrMatch(int family, void * addr, int len, + const char *siAddr, int siAddrlen, ClientPtr client, void *typePriv) +{ + int siAddrId; + LocalClientCredRec *lcc; + siLocalCredPrivPtr lcPriv = (siLocalCredPrivPtr) typePriv; + + if (GetLocalClientCreds(client, &lcc) == -1) { + return FALSE; + } + +#ifdef HAVE_GETZONEID /* Ensure process is in the same zone */ + if ((lcc->fieldsSet & LCC_ZID_SET) && (lcc->zoneid != getzoneid())) { + FreeLocalClientCreds(lcc); + return FALSE; + } +#endif + + if (siLocalCredGetId(siAddr, siAddrlen, lcPriv, &siAddrId) == FALSE) { + FreeLocalClientCreds(lcc); + return FALSE; + } + + if (lcPriv->credType == LOCAL_USER) { + if ((lcc->fieldsSet & LCC_UID_SET) && (lcc->euid == siAddrId)) { + FreeLocalClientCreds(lcc); + return TRUE; + } + } else { + if ((lcc->fieldsSet & LCC_GID_SET) && (lcc->egid == siAddrId)) { + FreeLocalClientCreds(lcc); + return TRUE; + } + if (lcc->pSuppGids != NULL) { + int i; + + for (i = 0 ; i < lcc->nSuppGids; i++) { + if (lcc->pSuppGids[i] == siAddrId) { + FreeLocalClientCreds(lcc); + return TRUE; + } + } + } + } + FreeLocalClientCreds(lcc); + return FALSE; +} + +static int +siLocalCredCheckAddr(const char *addrString, int length, void *typePriv) +{ + int len = length; + int id; + + if (siLocalCredGetId(addrString, length, + (siLocalCredPrivPtr)typePriv, &id) == FALSE) { + len = -1; + } + return len; +} +#endif /* localuser */ + +static void +siTypesInitialize(void) +{ + siTypeAdd("hostname", siHostnameAddrMatch, siHostnameCheckAddr, NULL); +#if defined(IPv6) && defined(AF_INET6) + siTypeAdd("ipv6", siIPv6AddrMatch, siIPv6CheckAddr, NULL); +#endif +#if !defined(NO_LOCAL_CLIENT_CRED) + siTypeAdd("localuser", siLocalCredAddrMatch, siLocalCredCheckAddr, + &siLocalUserPriv); + siTypeAdd("localgroup", siLocalCredAddrMatch, siLocalCredCheckAddr, + &siLocalGroupPriv); +#endif +} diff --git a/nx-X11/programs/Xserver/os/auth.c b/nx-X11/programs/Xserver/os/auth.c new file mode 100644 index 000000000..84bc5c3c6 --- /dev/null +++ b/nx-X11/programs/Xserver/os/auth.c @@ -0,0 +1,602 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* nx-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +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 HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +# include <nx-X11/X.h> +# include <nx-X11/Xauth.h> +# include "misc.h" +# include "osdep.h" +# include "dixstruct.h" +# include <sys/types.h> +# include <sys/stat.h> +#ifdef XCSECURITY +#define _SECURITY_SERVER +# include <nx-X11/extensions/security.h> +#endif +#ifdef WIN32 +#include <nx-X11/Xw32defs.h> +#endif + +struct protocol { + unsigned short name_length; + char *name; + AuthAddCFunc Add; /* new authorization data */ + AuthCheckFunc Check; /* verify client authorization data */ + AuthRstCFunc Reset; /* delete all authorization data entries */ + AuthToIDFunc ToID; /* convert cookie to ID */ + AuthFromIDFunc FromID; /* convert ID to cookie */ + AuthRemCFunc Remove; /* remove a specific cookie */ +#ifdef XCSECURITY + AuthGenCFunc Generate; +#endif +}; + +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 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 (char *file_name) +{ +#ifdef __sun + char * envBuffer; +#endif + authorization_file = file_name; +#ifdef NX_TRANS_AUTH +#ifdef NX_TRANS_TEST + fprintf(stderr, "InitAuthorization: Going to propagate auth file '%s' to the environment.\n", + authorization_file); +#endif +#ifdef __sun + envBuffer = malloc(15+strlen(authorization_file)); + sprintf(envBuffer,"NX_XAUTHORITY=%s",authorization_file); + putenv(envBuffer); +#else + setenv("NX_XAUTHORITY", authorization_file, 1); +#endif +#endif + +} + +static int +LoadAuthorization (void) +{ + FILE *f; + Xauth *auth; + int i; + int count = 0; + + ShouldLoadAuth = FALSE; + if (!authorization_file) + return 0; + +#ifdef NX_TRANS_AUTH + + /* + * We think that the way LoadAuthorization() is working is wrong. + * It doesn't reset the list of stored authorizations before reading + * the new cookies. Our take is that if a new auth file is to be + * read, the only cookies that are to be accepted are those that are + * in the new file, not those in the file -plus- those that have + * been in the file in the past. Furthermore, if the list can't be + * read or it is empty, it should assume that it ignores which co- + * okies are valid and thus it should disable any access. Your mile- + * age can vary. A less draconian approach could be to leave the old + * cookies if the file can't be read and remove them only if the + * file is empty. + * + * Adding the cookies without removing the old values for the same + * protocol has an important implication. If an user shares the co- + * okie with somebody and later wants to revoke the access to the + * display, changing the cookie will not work. This is especially + * important with NX. For security reasons, after reconnecting the + * session to a different display, it is advisable to generate a + * new set of cookies, but doing that it is useless with the current + * code, as the old cookies are going to be still accepted. On the + * same topic, consider that once an user has got access to the X + * server, he/she can freely enable host authentication from any + * host, so the safe behaviour should be to reset the host based + * authenthication at least at reconnection, and keep as valid only + * the cookies that are actually in the file. This behaviour would + * surely break many applications, among them a SSH connection run + * inside a NX session, as ssh -X reads the cookie for the display + * only at session startup and does not read the cookies again + * when the auth file is changed. + * + * Another bug (or feature, depending on how you want to consider + * it) is that if the authority file contains entries for different + * displays (as it is the norm when the authority file is the default + * .Xauthority in the user's home), the server will match -any- of + * the cookies, even cookies that are not for its own display. This + * means that you have be careful when passing an authority file to + * nxagent or Xnest and maybe keep separate files for letting nxagent + * find the cookie to be used to connect to the remote display and + * for letting it find what cookies to accept. If the file is the + * same, clients will be able to connect to nxagent with both the + * cookies. + */ + +#ifdef NX_TRANS_AUTH_RESET + + #ifdef NX_TRANS_TEST + fprintf(stderr, "LoadAuthorization: Resetting authorization info.\n"); + #endif + + for (i = 0; i < NUM_AUTHORIZATION; i++) { + if (protocols[i].Reset) { + (*protocols[i].Reset) (); + } + } + +#endif + +#endif /* #ifdef NX_TRANS_AUTH */ + + f = Fopen (authorization_file, "r"); + if (!f) + return -1; + + while ((auth = XauReadAuth (f)) != 0) { + 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) + { +#ifdef NX_TRANS_AUTH + + #ifdef NX_TRANS_TEST + fprintf(stderr, "LoadAuthorization: Adding new record from file [%s].\n", + authorization_file); + #endif + +#endif + ++count; + (*protocols[i].Add) (auth->data_length, auth->data, + FakeClientID(0)); + } + } + XauDisposeAuth (auth); + } + +#ifdef NX_TRANS_AUTH + + if (count == 0) + { + fprintf(stderr, "Warning: No authorization record could be read from file '%s'.\n", + authorization_file); + + fprintf(stderr, "Warning: Please, create a valid authorization cookie using the command\n" + "Warning: 'xauth -f %s add <display> MIT-MAGIC-COOKIE-1 <cookie>'.\n", + authorization_file); + } + +#endif + +#ifdef NX_TRANS_AUTH + if (Fclose (f) != 0) + { + /* + * If the Fclose() fails, for example because of a signal, + * it's advisable to return the number of protocols read, + * if any, or otherwise the server would believe that no + * cookie is valid and eventually fall back to host based + * authentication. Note anyway that the new code in Check- + * Authorization() doesn't care the return value and gives + * a chance to the function to check the file at the next + * connection. + */ + + if (count > 0) + { + return count; + } + else + { + return -1; + } + } +#else + Fclose (f); +#endif + return count; +} + +#ifdef XDMCP +/* + * XdmcpInit calls this function to discover all authorization + * schemes supported by the display + */ +void +RegisterAuthorizations (void) +{ + int i; + + for (i = 0; i < NUM_AUTHORIZATION; i++) + XdmcpRegisterAuthorization (protocols[i].name, + (int)protocols[i].name_length); +} +#endif + +XID +CheckAuthorization ( + 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; + + #ifndef NX_TRANS_AUTH + static Bool loaded = FALSE; + #endif + + 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) + { + int loadauth = LoadAuthorization(); + + /* + * If the authorization file has at least one entry for this server, + * disable local host access. (loadauth > 0) + * + * If there are zero entries (either initially or when the + * authorization file is later reloaded), or if a valid + * authorization file was never loaded, enable local host access. + * (loadauth == 0 || !loaded) + * + * If the authorization file was loaded initially (with valid + * entries for this server), and reloading it later fails, don't + * change anything. (loadauth == -1 && loaded) + */ + +#ifdef NX_TRANS_AUTH + + /* + * The implementation of CheckAuthorization() was changed. The way + * the auth file was handled previously was questionable and could + * open the way to a vast array of security problems. There might be + * ways for an attacker to prevent the server from reading the file + * and it was enough for the server to fail reading the file once + * (because of a not blocked signal, for example) to leave the dis- + * play open to all the users running a session on the same terminal + * server. + * + * In NX we want to have only two cases: either we have to check an + * authorization file or we don't. In the first case we need to do our + * best to read the file at any new client access and never fall back + * to host based authentication. Falling back to local host access has + * no way back, as it will always take precedence over the auth cookie + * (unless the user explicitly disables, one by one, all the rules + * allowing local access, if and only if he/she becomes aware of the + * problem). In the second case we assume that user doesn't care secu- + * rity and so allow unrestricted access from the local machine. + */ + + #ifdef NX_TRANS_TEST + fprintf(stderr, "CheckAuthorization: Going to set authorization with loadauth [%d].\n", + loadauth); + #endif + + if (authorization_file) + { + #ifdef NX_TRANS_TEST + fprintf(stderr, "CheckAuthorization: Disabling local host access.\n"); + #endif + + DisableLocalHost(); + } + else + { + /* + * Enable host-based authentication only if + * the authorization file was not specified + * either on the command line or in the env- + * ironment. + */ + + #ifdef NX_TRANS_TEST + fprintf(stderr, "CheckAuthorization: Enabling local host access.\n"); + #endif + + EnableLocalHost(); + } + + /* + * Avoid the 'unused variable' warning. + */ + + loadauth = loadauth; + +#else /* #ifdef NX_TRANS_AUTH */ + + if (loadauth > 0) + { + DisableLocalHost(); /* got at least one */ + loaded = TRUE; + } + else if (loadauth == 0 || !loaded) + EnableLocalHost (); + +#endif /* #ifdef NX_TRANS_AUTH */ + } + 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); + } + *reason = "Protocol not supported by server\n"; + } + } else *reason = "No protocol specified\n"; + return (XID) ~0L; +} + +void +ResetAuthorization (void) +{ + int i; + + for (i = 0; i < NUM_AUTHORIZATION; i++) + if (protocols[i].Reset) + (*protocols[i].Reset)(); + ShouldLoadAuth = TRUE; +} + +XID +AuthorizationToID ( + 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 ( + 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 ( + 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 (unsigned name_length, char *name, unsigned 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( + unsigned name_length, + char *name, + unsigned data_length, + char *data, + unsigned *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(void) +{ + next = next * 1103515245 + 12345; + return (unsigned int)(next/65536) % 32768; +} + +static void +xdm_srand(unsigned int seed) +{ + next = seed; +} + +void +GenerateRandomData (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/nx-X11/programs/Xserver/os/client.c b/nx-X11/programs/Xserver/os/client.c new file mode 100644 index 000000000..ef5e3935d --- /dev/null +++ b/nx-X11/programs/Xserver/os/client.c @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). All + * rights reserved. + * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * @file + * + * This file contains functionality for identifying clients by various + * means. The primary purpose of identification is to simply aid in + * finding out which clients are using X server and how they are using + * it. For example, it's often necessary to monitor what requests + * clients are executing (to spot bad behaviour) and how they are + * allocating resources in X server (to spot excessive resource + * usage). + * + * This framework automatically allocates information, that can be + * used for client identification, when a client connects to the + * server. The information is freed when the client disconnects. The + * allocated information is just a collection of various IDs, such as + * PID and process name for local clients, that are likely to be + * useful in analyzing X server usage. + * + * Users of the framework can query ID information about clients at + * any time. To avoid repeated polling of IDs the users can also + * subscribe for notifications about the availability of ID + * information. IDs have been allocated before ClientStateCallback is + * called with ClientStateInitial state. Similarly the IDs will be + * released after ClientStateCallback is called with ClientStateGone + * state. + * + * Author: Rami Ylimäki <rami.ylimaki@vincit.fi> + */ + +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "client.h" +#include "os.h" +#include "dixstruct.h" + +#ifdef __sun +#include <errno.h> +#include <procfs.h> +#endif + +#ifdef __OpenBSD__ +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/types.h> + +#include <kvm.h> +#include <limits.h> +#endif + +/** + * Try to determine a PID for a client from its connection + * information. This should be called only once when new client has + * connected, use GetClientPid to determine the PID at other times. + * + * @param[in] client Connection linked to some process. + * + * @return PID of the client. Error (-1) if PID can't be determined + * for the client. + * + * @see GetClientPid + */ +pid_t +DetermineClientPid(struct _Client * client) +{ + LocalClientCredRec *lcc = NULL; + pid_t pid = -1; + + if (client == NullClient) + return pid; + + if (client == serverClient) + return getpid(); + + if (GetLocalClientCreds(client, &lcc) != -1) { + if (lcc->fieldsSet & LCC_PID_SET) + pid = lcc->pid; + FreeLocalClientCreds(lcc); + } + + return pid; +} + +/** + * Try to determine a command line string for a client based on its + * PID. Note that mapping PID to a command hasn't been implemented for + * some operating systems. This should be called only once when a new + * client has connected, use GetClientCmdName/Args to determine the + * string at other times. + * + * @param[in] pid Process ID of a client. + + * @param[out] cmdname Client process name without arguments. You must + * release this by calling free. On error NULL is + * returned. Pass NULL if you aren't interested in + * this value. + * @param[out] cmdargs Arguments to client process. Useful for + * identifying a client that is executed from a + * launcher program. You must release this by + * calling free. On error NULL is returned. Pass + * NULL if you aren't interested in this value. + * + * @see GetClientCmdName/Args + */ +void +DetermineClientCmd(pid_t pid, const char **cmdname, const char **cmdargs) +{ + char path[PATH_MAX + 1]; + int totsize = 0; + int fd = 0; + + if (cmdname) + *cmdname = NULL; + if (cmdargs) + *cmdargs = NULL; + + if (pid == -1) + return; + +#ifdef __sun /* Solaris */ + /* Solaris does not support /proc/pid/cmdline, but makes information + * similar to what ps shows available in a binary structure in the + * /proc/pid/psinfo file. */ + if (snprintf(path, sizeof(path), "/proc/%d/psinfo", pid) < 0) + return; + fd = open(path, O_RDONLY); + if (fd < 0) { + ErrorF("Failed to open %s: %s\n", path, strerror(errno)); + return; + } + else { + psinfo_t psinfo = { 0 }; + char *sp; + + totsize = read(fd, &psinfo, sizeof(psinfo_t)); + close(fd); + if (totsize <= 0) + return; + + /* pr_psargs is the first PRARGSZ (80) characters of the command + * line string - assume up to the first space is the command name, + * since it's not delimited. While there is also pr_fname, that's + * more limited, giving only the first 16 chars of the basename of + * the file that was exec'ed, thus cutting off many long gnome + * command names, or returning "isapython2.6" for all python scripts. + */ + psinfo.pr_psargs[PRARGSZ - 1] = '\0'; + sp = strchr(psinfo.pr_psargs, ' '); + if (sp) + *sp++ = '\0'; + + if (cmdname) + *cmdname = strdup(psinfo.pr_psargs); + + if (cmdargs && sp) + *cmdargs = strdup(sp); + } +#elif defined(__OpenBSD__) + /* on OpenBSD use kvm_getargv() */ + { + kvm_t *kd; + char errbuf[_POSIX2_LINE_MAX]; + char **argv; + struct kinfo_proc *kp; + size_t len = 0; + int i, n; + + kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, errbuf); + if (kd == NULL) + return; + kp = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(struct kinfo_proc), + &n); + if (n != 1) + return; + argv = kvm_getargv(kd, kp, 0); + *cmdname = strdup(argv[0]); + i = 1; + while (argv[i] != NULL) { + len += strlen(argv[i]) + 1; + i++; + } + *cmdargs = calloc(1, len); + i = 1; + while (argv[i] != NULL) { + strlcat(*cmdargs, argv[i], len); + strlcat(*cmdargs, " ", len); + i++; + } + kvm_close(kd); + } +#else /* Linux using /proc/pid/cmdline */ + + /* Check if /proc/pid/cmdline exists. It's not supported on all + * operating systems. */ + if (snprintf(path, sizeof(path), "/proc/%d/cmdline", pid) < 0) + return; + fd = open(path, O_RDONLY); + if (fd < 0) + return; + + /* Read the contents of /proc/pid/cmdline. It should contain the + * process name and arguments. */ + totsize = read(fd, path, sizeof(path)); + close(fd); + if (totsize <= 0) + return; + path[totsize - 1] = '\0'; + + /* Contruct the process name without arguments. */ + if (cmdname) { + *cmdname = strdup(path); + } + + /* Construct the arguments for client process. */ + if (cmdargs) { + int cmdsize = strlen(path) + 1; + int argsize = totsize - cmdsize; + char *args = NULL; + + if (argsize > 0) + args = malloc(argsize); + if (args) { + int i = 0; + + for (i = 0; i < (argsize - 1); ++i) { + const char c = path[cmdsize + i]; + + args[i] = (c == '\0') ? ' ' : c; + } + args[argsize - 1] = '\0'; + *cmdargs = args; + } + } +#endif +} + +/** + * Called when a new client connects. Allocates client ID information. + * + * @param[in] client Recently connected client. + */ +void +ReserveClientIds(struct _Client *client) +{ +#ifdef CLIENTIDS + if (client == NullClient) + return; + + assert(!client->clientIds); + client->clientIds = calloc(1, sizeof(ClientIdRec)); + if (!client->clientIds) + return; + + client->clientIds->pid = DetermineClientPid(client); + if (client->clientIds->pid != -1) + DetermineClientCmd(client->clientIds->pid, &client->clientIds->cmdname, + &client->clientIds->cmdargs); + + DebugF("client(%lx): Reserved pid(%d).\n", + (unsigned long) client->clientAsMask, client->clientIds->pid); + DebugF("client(%lx): Reserved cmdname(%s) and cmdargs(%s).\n", + (unsigned long) client->clientAsMask, + client->clientIds->cmdname ? client->clientIds->cmdname : "NULL", + client->clientIds->cmdargs ? client->clientIds->cmdargs : "NULL"); +#endif /* CLIENTIDS */ +} + +/** + * Called when an existing client disconnects. Frees client ID + * information. + * + * @param[in] client Recently disconnected client. + */ +void +ReleaseClientIds(struct _Client *client) +{ +#ifdef CLIENTIDS + if (client == NullClient) + return; + + if (!client->clientIds) + return; + + DebugF("client(%lx): Released pid(%d).\n", + (unsigned long) client->clientAsMask, client->clientIds->pid); + DebugF("client(%lx): Released cmdline(%s) and cmdargs(%s).\n", + (unsigned long) client->clientAsMask, + client->clientIds->cmdname ? client->clientIds->cmdname : "NULL", + client->clientIds->cmdargs ? client->clientIds->cmdargs : "NULL"); + + free((void *) client->clientIds->cmdname); /* const char * */ + free((void *) client->clientIds->cmdargs); /* const char * */ + free(client->clientIds); + client->clientIds = NULL; +#endif /* CLIENTIDS */ +} + +/** + * Get cached PID of a client. + * + * param[in] client Client whose PID has been already cached. + * + * @return Cached client PID. Error (-1) if called: + * - before ClientStateInitial client state notification + * - after ClientStateGone client state notification + * - for remote clients + * + * @see DetermineClientPid + */ +pid_t +GetClientPid(struct _Client *client) +{ + if (client == NullClient) + return -1; + + if (!client->clientIds) + return -1; + + return client->clientIds->pid; +} + +/** + * Get cached command name string of a client. + * + * param[in] client Client whose command line string has been already + * cached. + * + * @return Cached client command name. Error (NULL) if called: + * - before ClientStateInitial client state notification + * - after ClientStateGone client state notification + * - for remote clients + * - on OS that doesn't support mapping of PID to command line + * + * @see DetermineClientCmd + */ +const char * +GetClientCmdName(struct _Client *client) +{ + if (client == NullClient) + return NULL; + + if (!client->clientIds) + return NULL; + + return client->clientIds->cmdname; +} + +/** + * Get cached command arguments string of a client. + * + * param[in] client Client whose command line string has been already + * cached. + * + * @return Cached client command arguments. Error (NULL) if called: + * - before ClientStateInitial client state notification + * - after ClientStateGone client state notification + * - for remote clients + * - on OS that doesn't support mapping of PID to command line + * + * @see DetermineClientCmd + */ +const char * +GetClientCmdArgs(struct _Client *client) +{ + if (client == NullClient) + return NULL; + + if (!client->clientIds) + return NULL; + + return client->clientIds->cmdargs; +} diff --git a/nx-X11/programs/Xserver/os/connection.c b/nx-X11/programs/Xserver/os/connection.c new file mode 100644 index 000000000..c5ebeea1e --- /dev/null +++ b/nx-X11/programs/Xserver/os/connection.c @@ -0,0 +1,1377 @@ +/*********************************************************** + +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, + * 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 HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <nx-X11/Xwinsock.h> +#endif +#include <nx-X11/X.h> +#include <nx-X11/Xproto.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <nx-X11/Xtrans/Xtrans.h> +#include <nx-X11/Xtrans/Xtransint.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#ifndef WIN32 +#include <sys/socket.h> + +#if defined(TCPCONN) +# include <netinet/in.h> +# include <arpa/inet.h> + +/* FIXME: correct indentation levels after ancient platform support clean-up */ + +# ifdef apollo +# ifndef NO_TCP_H +# include <netinet/tcp.h> +# endif +# else +# ifdef CSRG_BASED +# include <sys/param.h> +# endif +# include <netinet/tcp.h> +# endif +# include <arpa/inet.h> +#endif + +#include <sys/uio.h> +#endif /* WIN32 */ +#include "misc.h" +#include "osdep.h" +#include <nx-X11/Xpoll.h> +#include "opaque.h" +#include "dixstruct.h" +#include "list.h" +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <nx-X11/extensions/security.h> +#endif + +#ifdef X_NOT_POSIX +#define Pid_t int +#else +#define Pid_t pid_t +#endif + +int lastfdesc; /* maximum file descriptor */ + +fd_set NotifyReadFds; /* mask for other file descriptors */ +fd_set NotifyWriteFds; /* mask for other write file descriptors */ +fd_set AllSockets; /* select on this */ +fd_set AllClients; /* available clients */ +fd_set LastSelectMask; /* mask returned from last select call */ +fd_set LastSelectWriteMask; /* 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 */ +int MaxClients = 0; +int NumNotifyWriteFd; /* Number of NotifyFd members with write set */ +Bool NewOutputPending; /* not yet attempted to write some new output */ +Bool AnyWritesPending; /* true if some client blocked on write or NotifyFd with write */ +Bool NoListenAll; /* Don't establish any listening sockets */ +Bool RunFromSmartParent; /* send SIGUSR1 to parent process */ +static char dynamic_display[7]; /* display name */ +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; + +static void +QueueNewConnections(int curconn, int ready, void *data); + +#if !defined(WIN32) +int *ConnectionTranslation = NULL; +#else +/* + * 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. + * Do storage is a hash table of size 256. Collisions are handled in a linked + * list. + */ + +#undef MAXSOCKS +#define MAXSOCKS 500 +#undef MAXSELECT +#define MAXSELECT 500 +#define MAXFD 500 + +struct _ct_node { + struct _ct_node *next; + int key; + int value; +}; + +struct _ct_node *ct_head[256]; + +void InitConnectionTranslation(void) +{ + bzero(ct_head, sizeof(ct_head)); +} + +int GetConnectionTranslation(int conn) +{ + struct _ct_node *node = ct_head[conn & 0xff]; + while (node != NULL) + { + if (node->key == conn) + return node->value; + node = node->next; + } + return 0; +} + +void SetConnectionTranslation(int conn, int client) +{ + struct _ct_node **node = ct_head + (conn & 0xff); + if (client == 0) /* remove entry */ + { + while (*node != NULL) + { + if ((*node)->key == conn) + { + struct _ct_node *temp = *node; + *node = (*node)->next; + free(temp); + return; + } + node = &((*node)->next); + } + return; + } else + { + while (*node != NULL) + { + if ((*node)->key == conn) + { + (*node)->value = client; + return; + } + node = &((*node)->next); + } + *node = (struct _ct_node*)malloc(sizeof(struct _ct_node)); + (*node)->next = NULL; + (*node)->key = conn; + (*node)->value = client; + return; + } +} + +void ClearConnectionTranslation(void) +{ + unsigned i; + for (i = 0; i < 256; i++) + { + struct _ct_node *node = ct_head[i]; + while (node != NULL) + { + struct _ct_node *temp = node; + node = node->next; + free(temp); + } + } +} +#endif + +XtransConnInfo *ListenTransConns = NULL; +int *ListenTransFds = NULL; +int ListenTransCount; + +static void ErrorConnMax(XtransConnInfo /* trans_conn */); + +static +void CloseDownFileDescriptor( + OsCommPtr /*oc*/ +); + + +static XtransConnInfo +lookup_trans_conn (int fd) +{ + if (ListenTransFds) + { + int i; + for (i = 0; i < ListenTransCount; i++) + if (ListenTransFds[i] == fd) + return ListenTransConns[i]; + } + + return (NULL); +} + +/* Set MaxClients and lastfdesc, and allocate ConnectionTranslation */ + +void +InitConnectionLimits(void) +{ + lastfdesc = -1; + +#ifndef __CYGWIN__ + +#if !defined(XNO_SYSCONF) && defined(_SC_OPEN_MAX) + lastfdesc = sysconf(_SC_OPEN_MAX) - 1; +#endif + +#ifdef HAS_GETDTABLESIZE + if (lastfdesc < 0) + lastfdesc = getdtablesize() - 1; +#endif + +#ifdef _NFILE + if (lastfdesc < 0) + lastfdesc = _NFILE - 1; +#endif + +#endif /* __CYGWIN__ */ + + /* This is the fallback */ + if (lastfdesc < 0) + lastfdesc = MAXSOCKS; + + if (lastfdesc > MAXSELECT) + lastfdesc = MAXSELECT; + + if (lastfdesc > MAXCLIENTS) + { + lastfdesc = MAXCLIENTS; + if (debug_conns) + ErrorF( "REACHED MAXIMUM CLIENTS LIMIT %d\n", MAXCLIENTS); + } + MaxClients = lastfdesc; + +#ifdef DEBUG + ErrorF("InitConnectionLimits: MaxClients = %d\n", MaxClients); +#endif + +#if !defined(WIN32) + ConnectionTranslation = (int *)xnfalloc(sizeof(int)*(lastfdesc + 1)); +#else + InitConnectionTranslation(); +#endif +} + +/* + * 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. + */ +static void +InitParentProcess(void) +{ +#if !defined(WIN32) + OsSigHandlerPtr handler; + handler = OsSignal (SIGUSR1, SIG_IGN); + if ( handler == SIG_IGN) + RunFromSmartParent = TRUE; + OsSignal(SIGUSR1, handler); + ParentProcess = getppid (); +#ifdef __UNIXOS2__ + /* + * fg030505: under OS/2, xinit is not the parent process but + * the "grant parent" process of the server because execvpe() + * presents us an additional process number; + * GetPPID(pid) is part of libemxfix + */ + ParentProcess = GetPPID (ParentProcess); +#endif /* __UNIXOS2__ */ +#endif +} + +void +NotifyParentProcess(void) +{ +#if !defined(WIN32) + if (displayfd >= 0) { +#ifdef NXAGENT_SERVER + if (displayfd == STDERR_FILENO) + { + const char *msg = "Auto-detected display number is: DISPLAY=:"; + if (write(displayfd, msg, strlen(msg)) != strlen(msg)) + FatalError("Cannot write display number to fd %d\n", displayfd); + } +#endif + if (write(displayfd, display, strlen(display)) != strlen(display)) + FatalError("Cannot write display number to fd %d\n", displayfd); + if (write(displayfd, "\n", 1) != 1) + FatalError("Cannot write display number to fd %d\n", displayfd); + close(displayfd); + displayfd = -1; + } + if (RunFromSmartParent) { + if (ParentProcess > 1) { + kill (ParentProcess, SIGUSR1); + } + } +#endif +} + +static Bool +TryCreateSocket(int num, int *partial) +{ + char port[20]; + + snprintf(port, sizeof(port), "%d", num); + + return (_XSERVTransMakeAllCOTSServerListeners(port, partial, + &ListenTransCount, + &ListenTransConns) >= 0); +} + +/***************** + * CreateWellKnownSockets + * At initialization, create the sockets to listen on for new clients. + *****************/ + +void +CreateWellKnownSockets(void) +{ + int i; + int partial; + + FD_ZERO(&AllSockets); + FD_ZERO(&AllClients); + FD_ZERO(&LastSelectMask); + FD_ZERO(&ClientsWithInput); + +#if !defined(WIN32) + for (i=0; i<MaxClients; i++) ConnectionTranslation[i] = 0; +#else + ClearConnectionTranslation(); +#endif + + /* display is initialized to "0" by main(). It is then set to the display + * number if specified on the command line. */ + if (NoListenAll) { + ListenTransCount = 0; + } +#ifndef NXAGENT_SERVER + else if ((displayfd < 0) || explicit_display) { +#else + else if (displayfd < 0) { +#endif /* ! NXAGENT_SERVER */ + if (TryCreateSocket(atoi(display), &partial) && + ListenTransCount >= 1) + if (!PartialNetwork && partial) + FatalError ("Failed to establish all listening sockets"); + } + else { /* -displayfd and no explicit display number */ + Bool found = 0; + int i_offset = 0; +#ifdef NXAGENT_SERVER + if (explicit_display) + i_offset = atoi(display); +#endif /* NXAGENT_SERVER */ + for (i = i_offset; i < 65536 - X_TCP_PORT; i++) { + if (TryCreateSocket(i, &partial) && !partial) { + found = 1; + break; + } + else + CloseWellKnownConnections(); + } + if (!found) + FatalError("Failed to find a socket to listen on"); + snprintf(dynamic_display, sizeof(dynamic_display), "%d", i); + display = dynamic_display; + LogSetDisplay(); + } + + ListenTransFds = malloc(ListenTransCount * sizeof (int)); + + for (i = 0; i < ListenTransCount; i++) { + int fd = _XSERVTransGetConnectionNumber(ListenTransConns[i]); + + ListenTransFds[i] = fd; + SetNotifyFd(fd, QueueNewConnections, X_NOTIFY_READ, NULL); + + if (!_XSERVTransIsLocal(ListenTransConns[i])) + DefineSelf (fd); + } + + if (ListenTransCount == 0 && !NoListenAll) + FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running"); +#if !defined(WIN32) + OsSignal (SIGPIPE, SIG_IGN); + OsSignal (SIGHUP, AutoResetServer); +#endif + OsSignal (SIGINT, GiveUp); + OsSignal (SIGTERM, GiveUp); + ResetHosts(display); + + InitParentProcess(); + +#ifdef XDMCP + XdmcpInit (); +#endif +} + +#ifdef NX_TRANS_SOCKET + +/* + * The following block is now defined also + * under Cygwin to support this environment. + */ + +#ifndef __DARWIN__ + +/* + * This is defined in Xtranssock.c and must + * be called explicitly as it doesn't share + * a pointer in the transport function table. + */ + +extern void _XSERVTransSocketRejectConnection(XtransConnInfo); + +void +RejectWellKnownSockets () +{ + int i; + + for (i = 0; i < ListenTransCount; i++) + { + _XSERVTransSocketRejectConnection(ListenTransConns[i]); + } +} + +#endif /* #ifndef __DARWIN__ */ + +#else /* #ifdef NX_TRANS_SOCKET */ + +void +RejectWellKnownSockets () +{ +} + +#endif /* #ifdef NX_TRANS_SOCKET */ + +void +ResetWellKnownSockets (void) +{ + 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. + */ + + RemoveNotifyFd(ListenTransFds[i]); + 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]); + + ListenTransFds[i] = newfd; + } + } + } + + for (i = 0; i < ListenTransCount; i++) + SetNotifyFd(ListenTransFds[i], QueueNewConnections, X_NOTIFY_READ, NULL); + + ResetAuthorization (); + ResetHosts(display); + /* + * restart XDMCP + */ +#ifdef XDMCP + XdmcpReset (); +#endif +} + +void +CloseWellKnownConnections(void) +{ + int i; + + for (i = 0; i < ListenTransCount; i++) { + if (ListenTransConns[i] != NULL) { + _XSERVTransClose(ListenTransConns[i]); + ListenTransConns[i] = NULL; + if (ListenTransFds != NULL) + RemoveNotifyFd(ListenTransFds[i]); + } + } + ListenTransCount = 0; +} + +static void +AuthAudit (ClientPtr client, Bool letin, + struct sockaddr *saddr, int len, + unsigned int proto_n, char *auth_proto, int auth_id) +{ + char addr[128]; + char *out = addr; + + char client_uid_string[64]; + LocalClientCredRec *lcc; + + 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) + case AF_INET: + sprintf(out, "IP %s", + inet_ntoa(((struct sockaddr_in *) saddr)->sin_addr)); + break; +#if defined(IPv6) && defined(AF_INET6) + case AF_INET6: { + char ipaddr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &((struct sockaddr_in6 *) saddr)->sin6_addr, + ipaddr, sizeof(ipaddr)); + sprintf(out, "IP %s", ipaddr); + } + break; +#endif +#endif + default: + strcpy(out, "unknown address"); + } + + if (GetLocalClientCreds(client, &lcc) != -1) { + int slen; /* length written to client_uid_string */ + + strcpy(client_uid_string, " ( "); + slen = 3; + + if (lcc->fieldsSet & LCC_UID_SET) { + snprintf(client_uid_string + slen, + sizeof(client_uid_string) - slen, + "uid=%ld ", (long) lcc->euid); + slen = strlen(client_uid_string); + } + + if (lcc->fieldsSet & LCC_GID_SET) { + snprintf(client_uid_string + slen, + sizeof(client_uid_string) - slen, + "gid=%ld ", (long) lcc->egid); + slen = strlen(client_uid_string); + } + + if (lcc->fieldsSet & LCC_PID_SET) { + snprintf(client_uid_string + slen, + sizeof(client_uid_string) - slen, + "pid=%ld ", (long) lcc->pid); + slen = strlen(client_uid_string); + } + + if (lcc->fieldsSet & LCC_ZID_SET) { + snprintf(client_uid_string + slen, + sizeof(client_uid_string) - slen, + "zoneid=%ld ", (long) lcc->zoneid); + slen = strlen(client_uid_string); + } + + snprintf(client_uid_string + slen, sizeof(client_uid_string) - slen, ")"); + FreeLocalClientCreds(lcc); + } + else { + client_uid_string[0] = '\0'; + } + + if (proto_n) + AuditF("client %d %s from %s%s\n Auth name: %.*s ID: %d\n", + client->index, letin ? "connected" : "rejected", addr, + client_uid_string, (int)proto_n, auth_proto, auth_id); + else + AuditF("client %d %s from %s%s\n", + client->index, letin ? "connected" : "rejected", addr, + client_uid_string); +} + +XID +AuthorizationIDOfClient(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(ClientPtr client, + unsigned int proto_n, char *auth_proto, + unsigned int string_n, char *auth_string) +{ + OsCommPtr priv; + Xtransaddr *from = NULL; + int family; + int fromlen; + XID auth_id; + char *reason = NULL; + XtransConnInfo trans_conn; + + priv = (OsCommPtr)client->osPrivate; + trans_conn = priv->trans_conn; + + auth_id = CheckAuthorization (proto_n, auth_proto, + string_n, auth_string, client, &reason); + + 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 ( + InvalidHost ((struct sockaddr *) from, fromlen, client)) + 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 */ + /* 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 +AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time) +{ + OsCommPtr oc; + ClientPtr client; + + if ( +#ifndef WIN32 + fd >= lastfdesc +#else + XFD_SETCOUNT(&AllClients) >= MaxClients +#endif + ) + return NullClient; + oc = (OsCommPtr)malloc(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; + if (!(client = NextAvailableClient((void *)oc))) + { + free (oc); + return NullClient; + } + client->local = ComputeLocalClient(client); + { +#if !defined(WIN32) + ConnectionTranslation[fd] = client->index; +#else + SetConnectionTranslation(fd, client->index); +#endif + if (GrabInProgress) + { + FD_SET(fd, &SavedAllClients); + FD_SET(fd, &SavedAllSockets); + } + else + { + FD_SET(fd, &AllClients); + FD_SET(fd, &AllSockets); + } + } + +#ifdef DEBUG + ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n", + client->index, fd); +#endif + + return client; +} + +/***************** + * EstablishNewConnections + * If anyone is waiting on listened sockets, accept them. + * Returns a mask with indices of new clients. Updates AllClients + * and AllSockets. + *****************/ + +static Bool +EstablishNewConnections(ClientPtr clientUnused, void * closure) +{ + int curconn = (int) (intptr_t) closure; + int newconn; /* fd of new client */ + CARD32 connect_time; + int i; + ClientPtr client; + OsCommPtr oc; + XtransConnInfo trans_conn, new_trans_conn; + int status; + + 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); + } + } + if ((trans_conn = lookup_trans_conn(curconn)) == NULL) + return TRUE; + + if ((new_trans_conn = _XSERVTransAccept(trans_conn, &status)) == NULL) + return TRUE; + + newconn = _XSERVTransGetConnectionNumber(new_trans_conn); + + if (newconn < lastfdesc) { + int clientid; + +#if !defined(WIN32) + clientid = ConnectionTranslation[newconn]; +#else + clientid = GetConnectionTranslation(newconn); +#endif + if (clientid && (client = clients[clientid])) + CloseDownClient(client); + } + + _XSERVTransSetOption(new_trans_conn, TRANS_NONBLOCKING, 1); + + if (trans_conn->flags & TRANS_NOXAUTH) + new_trans_conn->flags = new_trans_conn->flags | TRANS_NOXAUTH; + + if (!AllocNewConnection(new_trans_conn, newconn, connect_time)) { + ErrorConnMax(new_trans_conn); + } + + return TRUE; +} + +static void +QueueNewConnections(int fd, int ready, void *data) +{ + QueueWorkProc(EstablishNewConnections, NULL, (void *) (intptr_t) fd); +} + +#define NOROOM "Maximum number of clients reached" + +/************ + * ErrorConnMax + * Fail a connection due to lack of client or file descriptor space + ************/ + +static void +ConnMaxNotify(int fd, int events, void *data) +{ + XtransConnInfo trans_conn = data; + char order = 0; + + /* try to read the byte-order of the connection */ + (void)_XSERVTransRead(trans_conn, &order, 1); + if (order == 'l' || order == 'B' || order == 'r' || order == 'R') + { + + xConnSetupPrefix csp; + char pad[3] = { 0, 0, 0 }; + int whichbyte = 1; + struct iovec iov[3]; + + 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) && (order == 'B' || order == 'R')) || + (!(*(char *) &whichbyte) && (order == 'l' || order == 'r'))) + { + swaps(&csp.majorVersion); + swaps(&csp.minorVersion); + swaps(&csp.length); + } + 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); + } + RemoveNotifyFd(trans_conn->fd); + _XSERVTransClose(trans_conn); +} + +static void +ErrorConnMax(XtransConnInfo trans_conn) +{ + if (!SetNotifyFd(trans_conn->fd, ConnMaxNotify, X_NOTIFY_READ, trans_conn)) + _XSERVTransClose(trans_conn); +} + +/************ + * CloseDownFileDescriptor: + * Remove this file descriptor and it's I/O buffers, etc. + ************/ + +static void +CloseDownFileDescriptor(OsCommPtr oc) +{ + int connection = oc->fd; + + if (oc->trans_conn) { + _XSERVTransDisconnect(oc->trans_conn); + _XSERVTransClose(oc->trans_conn); + } + FreeOsBuffers(oc); + free(oc); +#ifndef WIN32 + ConnectionTranslation[connection] = 0; +#else + SetConnectionTranslation(connection, 0); +#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) && NumNotifyWriteFd == 0) + AnyWritesPending = FALSE; + FD_CLR(connection, &OutputPending); +} + +/***************** + * CheckConnections + * 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(void) +{ +#ifndef WIN32 + fd_mask mask; +#endif + fd_set tmask; + 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 * (sizeof(fd_mask)*8)); + FD_ZERO(&tmask); + FD_SET(curclient, &tmask); + r = Select (curclient + 1, &tmask, NULL, NULL, ¬ime); + if (r < 0) + CloseDownClient(clients[ConnectionTranslation[curclient]]); + mask &= ~((fd_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[GetConnectionTranslation(curclient)]); + } +#endif +} + + +/***************** + * CloseDownConnection + * Delete client from AllClients and free resources + *****************/ + +void +CloseDownConnection(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + + if (FlushCallback) + CallCallbacks(&FlushCallback, client); + + if (oc->output && oc->output->count) + FlushClient(client, oc, (char *)NULL, 0); +#ifdef XDMCP + XdmcpCloseDisplay(oc->fd); +#endif + CloseDownFileDescriptor(oc); + client->osPrivate = (void *)NULL; + if (auditTrailLevel > 1) + AuditF("client %d disconnected\n", client->index); +} + +struct notify_fd { + struct xorg_list list; + int fd; + int mask; + NotifyFdProcPtr notify; + void *data; +}; + +static struct xorg_list notify_fds; + +void +InitNotifyFds(void) +{ + struct notify_fd *s, *next; + static int been_here; + + if (been_here) + xorg_list_for_each_entry_safe(s, next, ¬ify_fds, list) + RemoveNotifyFd(s->fd); + + xorg_list_init(¬ify_fds); + NumNotifyWriteFd = 0; + been_here = 1; +} + +/***************** + * SetNotifyFd + * Registers a callback to be invoked when the specified + * file descriptor becomes readable. + *****************/ + +Bool +SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data) +{ + struct notify_fd *n; + int changes; + + xorg_list_for_each_entry(n, ¬ify_fds, list) + if (n->fd == fd) + break; + + if (&n->list == ¬ify_fds) { + if (mask == 0) + return TRUE; + + n = calloc(1, sizeof (struct notify_fd)); + if (!n) + return FALSE; + n->fd = fd; + xorg_list_add(&n->list, ¬ify_fds); + } + + changes = n->mask ^ mask; + + if (changes & X_NOTIFY_READ) { + if (mask & X_NOTIFY_READ) { + FD_SET(fd, &NotifyReadFds); + FD_SET(fd, &AllSockets); + if (GrabInProgress) + FD_SET(fd, &SavedAllSockets); + } else { + FD_CLR(fd, &AllSockets); + if (GrabInProgress) + FD_CLR(fd, &SavedAllSockets); + FD_CLR(fd, &NotifyReadFds); + } + } + + if (changes & X_NOTIFY_WRITE) { + if (mask & X_NOTIFY_WRITE) { + FD_SET(fd, &NotifyWriteFds); + if (!NumNotifyWriteFd++) + AnyWritesPending = TRUE; + } else { + FD_CLR(fd, &NotifyWriteFds); + if (!--NumNotifyWriteFd) + if (!XFD_ANYSET(&ClientsWriteBlocked)) + AnyWritesPending = FALSE; + } + } + + if (mask == 0) { + xorg_list_del(&n->list); + free(n); + } else { + n->mask = mask; + n->data = data; + n->notify = notify; + } + + return TRUE; +} + +/***************** + * HandlNotifyFds + * A WorkProc to be called when any of the registered + * file descriptors are readable. + *****************/ + +void +HandleNotifyFds(void) +{ + struct notify_fd *n, *next; + + xorg_list_for_each_entry_safe(n, next, ¬ify_fds, list) { + int ready = 0; + if ((n->mask & X_NOTIFY_READ) && FD_ISSET(n->fd, &LastSelectMask)) + ready |= X_NOTIFY_READ; + if ((n->mask & X_NOTIFY_WRITE) & FD_ISSET(n->fd, &LastSelectWriteMask)) + ready |= X_NOTIFY_WRITE; + if (ready != 0) + n->notify(n->fd, ready, n->data); + } +} + +/***************** + * 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() + *****************/ + +void +OnlyListenToOneClient(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() + ****************/ + +void +ListenToAllClients(void) +{ + 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. + ****************/ + +void +IgnoreClient (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; + + isItTimeToYield = TRUE; + 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. + ****************/ + +void +AttendClient (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; + 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 */ + +void +MakeClientGrabImpervious(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 */ + +void +MakeClientGrabPervious(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); + } +} + diff --git a/nx-X11/programs/Xserver/os/io.c b/nx-X11/programs/Xserver/os/io.c new file mode 100644 index 000000000..07399438e --- /dev/null +++ b/nx-X11/programs/Xserver/os/io.c @@ -0,0 +1,1293 @@ +/*********************************************************** + +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. + + +******************************************************************/ +/***************************************************************** + * i/o functions + * + * WriteToClient, ReadRequestFromClient + * InsertFakeRequest, ResetCurrentRequest + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#if 0 +#define DEBUG_COMMUNICATION +#endif +#ifdef WIN32 +#include <nx-X11/Xwinsock.h> +#endif +#include <stdio.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <nx-X11/Xtrans/Xtrans.h> +#include <nx-X11/Xmd.h> +#include <errno.h> +#if !defined(WIN32) +#include <sys/uio.h> +#endif +#include <nx-X11/X.h> +#include <nx-X11/Xproto.h> +#include "os.h" +#include "osdep.h" +#include <nx-X11/Xpoll.h> +#include "opaque.h" +#include "dixstruct.h" +#include "misc.h" + +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 + */ +#ifndef WIN32 +#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 +#else /* WIN32 The socket errorcodes differ from the normal errors*/ +#define ETEST(err) (err == EAGAIN || err == WSAEWOULDBLOCK) +#endif + +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 <nx-X11/extensions/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; } + +int +ReadRequestFromClient(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + ConnectionInputPtr oci = oc->input; + int fd = oc->fd; + 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) + { + free(aci->buffer); + free(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 (oci->ignoreBytes > 0) { + if (oci->ignoreBytes > oci->size) + needed = oci->size; + else + needed = oci->ignoreBytes; + } + else 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 */ + /* + * Mark the rest of it as needing to be ignored, and then return + * the full size. Dispatch() will turn it into a BadLength error. + */ + oci->ignoreBytes = needed - gotnow; + oci->lenLastReq = gotnow; + return needed; + } + 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 *)realloc(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; + } + result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt, + oci->size - oci->bufcnt); + if (result <= 0) + { + if ((result < 0) && ETEST(errno)) + { +#if defined(SVR4) && defined(i386) && !defined(sun) + if (0) +#endif + { + 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 *)realloc(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); + } + + /* If there are bytes to ignore, ignore them now. */ + + if (oci->ignoreBytes > 0) { + assert(needed == oci->ignoreBytes || needed == oci->size); + oci->ignoreBytes -= gotnow; + needed = gotnow = 0; + /* + * The _XSERVTransRead call above may return more or fewer bytes than we + * want to ignore. Ignore the smaller of the two sizes. + */ + if (gotnow < needed) { + oci->ignoreBytes -= gotnow; + oci->bufptr += gotnow; + gotnow = 0; + } else { + oci->ignoreBytes -= needed; + oci->bufptr += needed; + gotnow -= needed; + } + needed = 0; + } + + 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 + { + FD_CLR(fd, &ClientsWithInput); + } + } + else + { + if (!gotnow) + AvailableInput = oc; + FD_CLR(fd, &ClientsWithInput); + } +#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 = (void *)oci->bufptr; +#ifdef DEBUG_COMMUNICATION + { + xReq *req = client->requestBuffer; + ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n", + client->index,req->reqType,req->data,req->length); + } +#endif + return needed; +} + +/***************************************************************** + * InsertFakeRequest + * Splice a consed up (possibly partial) request in as the next request. + * + **********************/ + +Bool +InsertFakeRequest(ClientPtr client, char *data, int count) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + ConnectionInputPtr oci = oc->input; + int fd = oc->fd; + int gotnow, moveup; + + if (AvailableInput) + { + if (AvailableInput != oc) + { + ConnectionInputPtr aci = AvailableInput->input; + if (aci->size > BUFWATERMARK) + { + free(aci->buffer); + free(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 *)realloc(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. + * + **********************/ + +void +ResetCurrentRequest(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + register ConnectionInputPtr oci = oc->input; + int fd = oc->fd; + register xReq *request; + int gotnow, needed; + 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) + { + swapl(&((xBigReq *)oci->bufptr)->length); + } + } +#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( + 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( + 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(void) +{ + register int index, base; + register fd_mask mask; /* raphael */ + OsCommPtr oc; + register ClientPtr client; + Bool newoutput = NewOutputPending; +#if defined(WIN32) + fd_set newOutputPending; +#endif + + 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 * (sizeof(fd_mask)*8)) + index]) == 0) + continue; + client = clients[index]; + if (client->clientGone) + continue; + oc = (OsCommPtr)client->osPrivate; + if ( + 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 = GetConnectionTranslation(index)) == 0) + continue; + client = clients[index]; + if (client->clientGone) + continue; + oc = (OsCommPtr)client->osPrivate; + if ( + 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(void) +{ + if (CriticalOutputPending) + FlushAllOutput(); +} + +void +SetCriticalOutputPending(void) +{ + 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 (ClientPtr who, int count, const void *__buf) +{ + OsCommPtr oc; + ConnectionOutputPtr oco; + int padBytes; + const char *buf = __buf; +#ifdef DEBUG_COMMUNICATION + Bool multicount = FALSE; +#endif + if (!count || !who || who == serverClient || who->clientGone) + return(0); + oc = who->osPrivate; + oco = oc->output; +#ifdef DEBUG_COMMUNICATION + { + char info[128]; + xError *err; + xGenericReply *rep; + xEvent *ev; + + if (!who->replyBytesRemaining) { + switch(buf[0]) { + case X_Reply: + rep = (xGenericReply*)buf; + if (rep->sequenceNumber == who->sequence) { + snprintf(info,127,"Xreply: type: 0x%x data: 0x%x " + "len: %i seq#: 0x%x", rep->type, rep->data1, + rep->length, rep->sequenceNumber); + multicount = TRUE; + } + break; + case X_Error: + err = (xError*)buf; + snprintf(info,127,"Xerror: Code: 0x%x resID: 0x%x maj: 0x%x " + "min: %x", err->errorCode,err->resourceID, + err->minorCode,err->majorCode); + break; + default: + if ((buf[0] & 0x7f) == KeymapNotify) + snprintf(info,127,"KeymapNotifyEvent: %i",buf[0]); + else { + ev = (xEvent*)buf; + snprintf(info,127,"XEvent: type: 0x%x detail: 0x%x " + "seq#: 0x%x", ev->u.u.type, ev->u.u.detail, + ev->u.u.sequenceNumber); + } + } + ErrorF("REPLY: ClientIDX: %i %s\n",who->index, info); + } else + multicount = TRUE; + } +#endif + + 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), (void *)&replyinfo); + } + else if (who->clientState == ClientStateRunning + && buf[0] == X_Reply) + { /* start of new reply */ + CARD32 replylen; + unsigned long bytesleft; + + replylen = ((xGenericReply *)buf)->length; + if (who->swapped) + swapl(&replylen); + bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes; + replyinfo.startOfReply = TRUE; + replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft; + CallCallbacks((&ReplyCallback), (void *)&replyinfo); + } + } +#ifdef DEBUG_COMMUNICATION + else if (multicount) { + if (who->replyBytesRemaining) { + who->replyBytesRemaining -= (count + padBytes); + } else { + CARD32 replylen; + replylen = ((xGenericReply *)buf)->length; + who->replyBytesRemaining = + (replylen * 4) + SIZEOF(xReply) - count - padBytes; + } + } +#endif + if (oco->count == 0 || 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; + if (padBytes) { + memset(oco->buf + oco->count, '\0', padBytes); + oco->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. + * + **********************/ + +int +FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount) +{ + ConnectionOutputPtr oco = oc->output; + int connection = oc->fd; + XtransConnInfo trans_conn = oc->trans_conn; + struct iovec iov[3]; + static char padBuffer[3]; + const char *extraBuf = __extraBuf; + long written; + long padsize; + long notWritten; + long todo; + + if (!oco) + return 0; + written = 0; + padsize = padlength[extraCount & 3]; + notWritten = oco->count + extraCount + padsize; + + if (!notWritten) + return 0; + + if (FlushCallback) + CallCallbacks(&FlushCallback, who); + + 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 ((char *)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); + AnyWritesPending = 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 = NULL; + + if (notWritten + BUFSIZE <= INT_MAX) { + obuf = realloc(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 (AnyWritesPending) + { + FD_CLR(oc->fd, &ClientsWriteBlocked); + if (!XFD_ANYSET(&ClientsWriteBlocked) && NumNotifyWriteFd == 0) + AnyWritesPending = FALSE; + + } + if (oco->size > BUFWATERMARK) + { + free(oco->buf); + free(oco); + } + else + { + oco->next = FreeOutputs; + FreeOutputs = oco; + } + oc->output = (ConnectionOutputPtr)NULL; + return extraCount; /* return only the amount explicitly requested */ +} + +ConnectionInputPtr +AllocateInputBuffer(void) +{ + ConnectionInputPtr oci; + + oci = (ConnectionInputPtr)malloc(sizeof(ConnectionInput)); + if (!oci) + return (ConnectionInputPtr)NULL; + oci->buffer = (char *)malloc(BUFSIZE); + if (!oci->buffer) + { + free(oci); + return (ConnectionInputPtr)NULL; + } + oci->size = BUFSIZE; + oci->bufptr = oci->buffer; + oci->bufcnt = 0; + oci->lenLastReq = 0; + oci->ignoreBytes = 0; + return oci; +} + +ConnectionOutputPtr +AllocateOutputBuffer(void) +{ + ConnectionOutputPtr oco; + + oco = (ConnectionOutputPtr)malloc(sizeof(ConnectionOutput)); + if (!oco) + return (ConnectionOutputPtr)NULL; + oco->buf = (unsigned char *) malloc(BUFSIZE); + if (!oco->buf) + { + free(oco); + return (ConnectionOutputPtr)NULL; + } + oco->size = BUFSIZE; + oco->count = 0; + return oco; +} + +void +FreeOsBuffers(OsCommPtr oc) +{ + ConnectionInputPtr oci; + ConnectionOutputPtr oco; + + if (AvailableInput == oc) + AvailableInput = (OsCommPtr)NULL; + if ((oci = oc->input)) + { + if (FreeInputs) + { + free(oci->buffer); + free(oci); + } + else + { + FreeInputs = oci; + oci->next = (ConnectionInputPtr)NULL; + oci->bufptr = oci->buffer; + oci->bufcnt = 0; + oci->lenLastReq = 0; + oci->ignoreBytes = 0; + } + } + if ((oco = oc->output)) + { + if (FreeOutputs) + { + free(oco->buf); + free(oco); + } + else + { + FreeOutputs = oco; + oco->next = (ConnectionOutputPtr)NULL; + oco->count = 0; + } + } +} + +void +ResetOsBuffers(void) +{ + ConnectionInputPtr oci; + ConnectionOutputPtr oco; + + while ((oci = FreeInputs)) + { + FreeInputs = oci->next; + free(oci->buffer); + free(oci); + } + while ((oco = FreeOutputs)) + { + FreeOutputs = oco->next; + free(oco->buf); + free(oco); + } +} diff --git a/nx-X11/programs/Xserver/os/log.c b/nx-X11/programs/Xserver/os/log.c new file mode 100644 index 000000000..0ead6e9f0 --- /dev/null +++ b/nx-X11/programs/Xserver/os/log.c @@ -0,0 +1,779 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* nx-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +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. + +*/ + +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 copyright holder(s) + * and author(s) 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 copyright holder(s) and author(s). + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <nx-X11/Xos.h> +#include <stdio.h> +#include <time.h> +#include <sys/stat.h> +#include <stdarg.h> +#include <stdlib.h> /* for malloc() */ +#include <errno.h> + +#include "input.h" +#include "site.h" +#include "opaque.h" + +#ifdef WIN32 +#include <process.h> +#define getpid(x) _getpid(x) +#endif + +#ifdef NX_TRANS_SOCKET + +#include <nx/NX.h> + +#endif + +#ifdef DDXOSVERRORF +void (*OsVendorVErrorFProc)(const char *, va_list args) = NULL; +#ifdef NX_TRANS_EXIT +int OsVendorVErrorFFatal = 0; +#endif +#endif + +static FILE *logFile = NULL; +static Bool logFlush = FALSE; +static Bool logSync = FALSE; +static int logVerbosity = DEFAULT_LOG_VERBOSITY; +static int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY; + +/* Buffer to information logged before the log file is opened. */ +static char *saveBuffer = NULL; +static int bufferSize = 0, bufferUnused = 0, bufferPos = 0; +static Bool needBuffer = TRUE; + +/* Prefix strings for log messages. */ +#ifndef X_UNKNOWN_STRING +#define X_UNKNOWN_STRING "(\?\?)" +#endif +#ifndef X_PROBE_STRING +#define X_PROBE_STRING "(--)" +#endif +#ifndef X_CONFIG_STRING +#define X_CONFIG_STRING "(**)" +#endif +#ifndef X_DEFAULT_STRING +#define X_DEFAULT_STRING "(==)" +#endif +#ifndef X_CMDLINE_STRING +#define X_CMDLINE_STRING "(++)" +#endif +#ifndef X_NOTICE_STRING +#define X_NOTICE_STRING "(!!)" +#endif +#ifndef X_ERROR_STRING +#define X_ERROR_STRING "(EE)" +#endif +#ifndef X_WARNING_STRING +#define X_WARNING_STRING "(WW)" +#endif +#ifndef X_INFO_STRING +#define X_INFO_STRING "(II)" +#endif +#ifndef X_NOT_IMPLEMENTED_STRING +#define X_NOT_IMPLEMENTED_STRING "(NI)" +#endif + +/* + * LogFilePrep is called to setup files for logging, including getting + * an old file out of the way, but it doesn't actually open the file, + * since it may be used for renaming a file we're already logging to. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +static char * +LogFilePrep(const char *fname, const char *backup, const char *idstring) +{ + char *logFileName = NULL; + + if (asprintf(&logFileName, fname, idstring) == -1) + FatalError("Cannot allocate space for the log file name\n"); + + if (backup && *backup) { + struct stat buf; + + if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) { + char *suffix; + char *oldLog; + + if ((asprintf(&suffix, backup, idstring) == -1) || + (asprintf(&oldLog, "%s%s", logFileName, suffix) == -1)) { + FatalError("Cannot allocate space for the log file name\n"); + } + free(suffix); + + if (rename(logFileName, oldLog) == -1) { + FatalError("Cannot move old log file \"%s\" to \"%s\"\n", + logFileName, oldLog); + } + free(oldLog); + } + } + else { + if (remove(logFileName) != 0) { + FatalError("Cannot remove old log file \"%s\": %s\n", + logFileName, strerror(errno)); + } + } + + return logFileName; +} +#pragma GCC diagnostic pop + +/* + * LogInit is called to start logging to a file. It is also called (with + * NULL arguments) when logging to a file is not wanted. It must always be + * called, otherwise log messages will continue to accumulate in a buffer. + * + * %s, if present in the fname or backup strings, is expanded to the display + * string (or to a string containing the pid if the display is not yet set). + */ + +static char *saved_log_fname; +static char *saved_log_backup; +static char *saved_log_tempname; + +const char * +LogInit(const char *fname, const char *backup) +{ + char *logFileName = NULL; + + if (fname && *fname) { + if (displayfd != -1) { + /* Display isn't set yet, so we can't use it in filenames yet. */ + char pidstring[32]; + snprintf(pidstring, sizeof(pidstring), "pid-%ld", + (unsigned long) getpid()); + logFileName = LogFilePrep(fname, backup, pidstring); + saved_log_tempname = logFileName; + + /* Save the patterns for use when the display is named. */ + saved_log_fname = strdup(fname); + if (backup == NULL) + saved_log_backup = NULL; + else + saved_log_backup = strdup(backup); + } else + logFileName = LogFilePrep(fname, backup, display); + if ((logFile = fopen(logFileName, "w")) == NULL) + FatalError("Cannot open log file \"%s\"\n", logFileName); + setvbuf(logFile, NULL, _IONBF, 0); + + /* Flush saved log information. */ + if (saveBuffer && bufferSize > 0) { + fwrite(saveBuffer, bufferPos, 1, logFile); + fflush(logFile); +#ifndef WIN32 + fsync(fileno(logFile)); +#endif + } + } + + /* + * Unconditionally free the buffer, and flag that the buffer is no longer + * needed. + */ + if (saveBuffer && bufferSize > 0) { + free(saveBuffer); /* Must be free(), not free() */ + saveBuffer = NULL; + bufferSize = 0; + } + needBuffer = FALSE; + + return logFileName; +} + +void +LogSetDisplay(void) +{ + if (saved_log_fname) { + char *logFileName; + + logFileName = LogFilePrep(saved_log_fname, saved_log_backup, display); + + if (rename(saved_log_tempname, logFileName) == 0) { + LogMessageVerb(X_PROBED, 0, + "Log file renamed from \"%s\" to \"%s\"\n", + saved_log_tempname, logFileName); + + if (strlen(saved_log_tempname) >= strlen(logFileName)) + strncpy(saved_log_tempname, logFileName, + strlen(saved_log_tempname)); + } + else { + ErrorF("Failed to rename log file \"%s\" to \"%s\": %s\n", + saved_log_tempname, logFileName, strerror(errno)); + } + + /* free newly allocated string - can't free old one since existing + pointers to it may exist in DDX callers. */ + free(logFileName); + free(saved_log_fname); + free(saved_log_backup); + } +} + +void +LogClose() +{ + if (logFile) { + fclose(logFile); + logFile = NULL; + } +} + +Bool +LogSetParameter(LogParameter param, int value) +{ + switch (param) { + case XLOG_FLUSH: + logFlush = value ? TRUE : FALSE; + return TRUE; + case XLOG_SYNC: + logSync = value ? TRUE : FALSE; + return TRUE; + case XLOG_VERBOSITY: + logVerbosity = value; + return TRUE; + case XLOG_FILE_VERBOSITY: + logFileVerbosity = value; + return TRUE; + default: + return FALSE; + } +} + +/* This function does the actual log message writes. */ + +void +LogVWrite(int verb, const char *f, va_list args) +{ + static char tmpBuffer[1024]; + int len = 0; + + /* + * Since a va_list can only be processed once, write the string to a + * buffer, and then write the buffer out to the appropriate output + * stream(s). + */ + if (verb < 0 || logFileVerbosity >= verb || logVerbosity >= verb) { + vsnprintf(tmpBuffer, sizeof(tmpBuffer), f, args); +#ifdef NX_TRANS_EXIT + /* + * Beautify the message. Make the + * first letter uppercase. + */ + + *tmpBuffer = toupper(*tmpBuffer); + + /* + * Remove the trailing newline. + */ + + if (strlen(tmpBuffer) > 0 && + *(tmpBuffer + strlen(tmpBuffer) - 1) == '\n') { + *(tmpBuffer + strlen(tmpBuffer) - 1) = '\0'; + } + + /* + * Remove the trailing full-stop. + */ + + if (strlen(tmpBuffer) > 0 && + *(tmpBuffer + strlen(tmpBuffer) - 1) == '.') { + *(tmpBuffer + strlen(tmpBuffer) - 1) = '\0'; + } +#endif /* #ifdef NX_TRANS_EXIT */ + len = strlen(tmpBuffer); + } + if ((verb < 0 || logVerbosity >= verb) && len > 0) + fwrite(tmpBuffer, len, 1, stderr); + if ((verb < 0 || logFileVerbosity >= verb) && len > 0) { + if (logFile) { + fwrite(tmpBuffer, len, 1, logFile); + if (logFlush) { + fflush(logFile); +#ifndef WIN32 + if (logSync) + fsync(fileno(logFile)); +#endif + } + } else if (needBuffer) { + /* + * Note, this code is used before OsInit() has been called, so + * malloc() and friends can't be used. + */ + if (len > bufferUnused) { + bufferSize += 1024; + bufferUnused += 1024; + if (saveBuffer) + saveBuffer = realloc(saveBuffer, bufferSize); + else + saveBuffer = malloc(bufferSize); + if (!saveBuffer) + FatalError("realloc() failed while saving log messages\n"); + } + bufferUnused -= len; + memcpy(saveBuffer + bufferPos, tmpBuffer, len); + bufferPos += len; + } + } +} + +void +LogWrite(int verb, const char *f, ...) +{ + va_list args; + + va_start(args, f); + LogVWrite(verb, f, args); + va_end(args); +} + +void +LogVMessageVerb(MessageType type, int verb, const char *format, va_list args) +{ + const char *s = X_UNKNOWN_STRING; + char *tmpBuf = NULL; + + /* Ignore verbosity for X_ERROR */ + if (logVerbosity >= verb || logFileVerbosity >= verb || type == X_ERROR) { + switch (type) { + case X_PROBED: + s = X_PROBE_STRING; + break; + case X_CONFIG: + s = X_CONFIG_STRING; + break; + case X_DEFAULT: + s = X_DEFAULT_STRING; + break; + case X_CMDLINE: + s = X_CMDLINE_STRING; + break; + case X_NOTICE: + s = X_NOTICE_STRING; + break; + case X_ERROR: + s = X_ERROR_STRING; + if (verb > 0) + verb = 0; + break; + case X_WARNING: + s = X_WARNING_STRING; + break; + case X_INFO: + s = X_INFO_STRING; + break; + case X_NOT_IMPLEMENTED: + s = X_NOT_IMPLEMENTED_STRING; + break; + case X_UNKNOWN: + s = X_UNKNOWN_STRING; + break; + case X_NONE: + s = NULL; + break; + } + + /* + * Prefix the format string with the message type. We do it this way + * so that LogVWrite() is only called once per message. + */ + if (s) { + tmpBuf = malloc(strlen(format) + strlen(s) + 1 + 1); + /* Silently return if malloc fails here. */ + if (!tmpBuf) + return; + sprintf(tmpBuf, "%s ", s); + strcat(tmpBuf, format); + LogVWrite(verb, tmpBuf, args); + free(tmpBuf); + } else + LogVWrite(verb, format, args); + } +} + +/* Log message with verbosity level specified. */ +void +LogMessageVerb(MessageType type, int verb, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + LogVMessageVerb(type, verb, format, ap); + va_end(ap); +} + +/* Log a message with the standard verbosity level of 1. */ +void +LogMessage(MessageType type, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + LogVMessageVerb(type, 1, format, ap); + va_end(ap); +} + +#ifdef __GNUC__ +void AbortServer(void) __attribute__((noreturn)); +#endif + +void +AbortServer(void) +{ +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_TEST) + fprintf(stderr, "AbortServer: Going to abort the current server.\n"); +#endif + OsCleanup(TRUE); + AbortDDX(); + fflush(stderr); + if (CoreDump) + abort(); +#ifdef NX_TRANS_EXIT +#ifdef NX_TRANS_TEST + fprintf(stderr, "AbortServer: Going to clean up NX resources and exit.\n"); +#endif + NXTransExit(1); +#else /* #ifdef NX_TRANS_EXIT */ + exit (1); +#endif +} + +#ifndef AUDIT_PREFIX +#define AUDIT_PREFIX "AUDIT: %s: %ld %s: " +#endif +#ifndef AUDIT_TIMEOUT +#define AUDIT_TIMEOUT ((CARD32)(120 * 1000)) /* 2 mn */ +#endif + +static int nrepeat = 0; +static int oldlen = -1; +static OsTimerPtr auditTimer = NULL; + +void +FreeAuditTimer(void) +{ + if (auditTimer != NULL) { + /* Force output of pending messages */ + TimerForce(auditTimer); + TimerFree(auditTimer); + auditTimer = NULL; + } +} + +static char * +AuditPrefix(void) +{ + time_t tm; + char *autime, *s; + char *tmpBuf; + int len; + + time(&tm); + autime = ctime(&tm); + if ((s = strchr(autime, '\n'))) + *s = '\0'; + if ((s = strrchr(argvGlobal[0], '/'))) + s++; + else + s = argvGlobal[0]; + len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + strlen(s) + 1; + tmpBuf = malloc(len); + if (!tmpBuf) + return NULL; + snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long)getpid(), s); + return tmpBuf; +} + +void +AuditF(const char * f, ...) +{ + va_list args; + + va_start(args, f); + + VAuditF(f, args); + va_end(args); +} + +static CARD32 +AuditFlush(OsTimerPtr timer, CARD32 now, void * arg) +{ + char *prefix; + + if (nrepeat > 0) { + prefix = AuditPrefix(); + ErrorF("%slast message repeated %d times\n", + prefix != NULL ? prefix : "", nrepeat); + nrepeat = 0; + if (prefix != NULL) + free(prefix); + return AUDIT_TIMEOUT; + } else { + /* if the timer expires without anything to print, flush the message */ + oldlen = -1; + return 0; + } +} + +void +VAuditF(const char *f, va_list args) +{ + char *prefix; + char buf[1024]; + int len; + static char oldbuf[1024]; + + prefix = AuditPrefix(); + len = vsnprintf(buf, sizeof(buf), f, args); + + if (len == oldlen && strcmp(buf, oldbuf) == 0) { + /* Message already seen */ + nrepeat++; + } else { + /* new message */ + if (auditTimer != NULL) + TimerForce(auditTimer); + ErrorF("%s%s", prefix != NULL ? prefix : "", buf); + strlcpy(oldbuf, buf, sizeof(oldbuf)); + oldlen = len; + nrepeat = 0; + auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL); + } + if (prefix != NULL) + free(prefix); +} + +void +FatalError(const char *f, ...) +{ + va_list args; + static Bool beenhere = FALSE; + +#ifdef NX_TRANS_EXIT + if (beenhere) { + fprintf(stderr, "Error: Aborting session with fatal error function reentered.\n"); + } + else { + /* + * Tell to the log function that this + * is a fatal error. + */ + + OsVendorVErrorFFatal = 1; + + fprintf(stderr, "Error: Aborting session with '"); + + va_start(args, f); + VErrorF(f, args); + va_end(args); + + fprintf(stderr, "'.\n"); + } +#else /* #ifdef NX_TRANS_EXIT */ + if (beenhere) + ErrorF("\nFatalError re-entered, aborting\n"); + else + ErrorF("\nFatal server error:\n"); + + va_start(args, f); + VErrorF(f, args); + va_end(args); + ErrorF("\n"); +#endif /* #ifdef NX_TRANS_EXIT */ +#ifdef DDXOSFATALERROR + if (!beenhere) + OsVendorFatalError(); +#endif +#ifdef ABORTONFATALERROR + abort(); +#endif + if (!beenhere) { + beenhere = TRUE; + AbortServer(); + } else + abort(); + /*NOTREACHED*/ +} + +void +VErrorF(const char *f, va_list args) +{ +#ifdef DDXOSVERRORF + if (OsVendorVErrorFProc) + OsVendorVErrorFProc(f, args); + else + LogVWrite(-1, f, args); +#else + LogVWrite(-1, f, args); +#endif +} + +void +ErrorF(const char * f, ...) +{ + va_list args; + + va_start(args, f); + VErrorF(f, args); + va_end(args); +} + +/* A perror() workalike. */ + +#ifndef NEED_STRERROR +#ifdef SYSV +#if !defined(ISC) || defined(ISC202) || defined(ISC22) +#define NEED_STRERROR +#endif +#endif +#endif + +#if defined(NEED_STRERROR) && !defined(strerror) +extern char *sys_errlist[]; +extern int sys_nerr; +#define strerror(n) \ + ((n) >= 0 && (n) < sys_nerr) ? sys_errlist[(n)] : "unknown error" +#endif + +void +Error(char *str) +{ + char *err = NULL; + int saveErrno = errno; + + if (str) { + err = malloc(strlen(strerror(saveErrno)) + strlen(str) + 2 + 1); + if (!err) + return; + sprintf(err, "%s: ", str); + strcat(err, strerror(saveErrno)); + LogWrite(-1, "%s", err); + } else + LogWrite(-1, "%s", strerror(saveErrno)); +} + +void +LogPrintMarkers() +{ + /* Show what the message marker symbols mean. */ + ErrorF("Markers: "); + LogMessageVerb(X_PROBED, -1, "probed, "); + LogMessageVerb(X_CONFIG, -1, "from config file, "); + LogMessageVerb(X_DEFAULT, -1, "default setting,\n\t"); + LogMessageVerb(X_CMDLINE, -1, "from command line, "); + LogMessageVerb(X_NOTICE, -1, "notice, "); + LogMessageVerb(X_INFO, -1, "informational,\n\t"); + LogMessageVerb(X_WARNING, -1, "warning, "); + LogMessageVerb(X_ERROR, -1, "error, "); + LogMessageVerb(X_NOT_IMPLEMENTED, -1, "not implemented, "); + LogMessageVerb(X_UNKNOWN, -1, "unknown.\n"); +} + diff --git a/nx-X11/programs/Xserver/os/mitauth.c b/nx-X11/programs/Xserver/os/mitauth.c new file mode 100644 index 000000000..578f8ba42 --- /dev/null +++ b/nx-X11/programs/Xserver/os/mitauth.c @@ -0,0 +1,197 @@ +/* + +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 + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <nx-X11/X.h> +#include "os.h" +#include "osdep.h" +#include "dixstruct.h" + +static struct auth { + struct auth *next; + unsigned short len; + char *data; + XID id; +} *mit_auth; + +int +MitAddCookie ( + unsigned short data_length, + char *data, + XID id) +{ + struct auth *new; + + new = (struct auth *) malloc (sizeof (struct auth)); + if (!new) + return 0; + new->data = (char *) malloc ((unsigned) data_length); + if (!new->data) { + free(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 ( + 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 && + timingsafe_memcmp (data, auth->data, (int) data_length) == 0) + return auth->id; + } + *reason = "Invalid MIT-MAGIC-COOKIE-1 key"; + return (XID) -1; +} + +int +MitResetCookie (void) +{ + struct auth *auth, *next; + + for (auth = mit_auth; auth; auth=next) { + next = auth->next; + free (auth->data); + free (auth); + } + mit_auth = 0; + return 0; +} + +XID +MitToID ( + 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 ( + 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 ( + 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; + free (auth->data); + free (auth); + return 1; + } + } + return 0; +} + +#ifdef XCSECURITY + +static char cookie[16]; /* 128 bits */ + +XID +MitGenerateCookie ( + unsigned data_length, + char *data, + XID id, + unsigned *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/nx-X11/programs/Xserver/os/oscolor.c b/nx-X11/programs/Xserver/os/oscolor.c new file mode 100644 index 000000000..70940653f --- /dev/null +++ b/nx-X11/programs/Xserver/os/oscolor.c @@ -0,0 +1,1661 @@ +/*********************************************************** + +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 HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "os.h" + +typedef struct _builtinColor { + unsigned char red; + unsigned char green; + unsigned char blue; + unsigned short name; +} BuiltinColor; + +static const char BuiltinColorNames[] = { + "alice blue\0" + "AliceBlue\0" + "antique white\0" + "AntiqueWhite\0" + "AntiqueWhite1\0" + "AntiqueWhite2\0" + "AntiqueWhite3\0" + "AntiqueWhite4\0" + "aqua\0" + "aquamarine\0" + "aquamarine1\0" + "aquamarine2\0" + "aquamarine3\0" + "aquamarine4\0" + "azure\0" + "azure1\0" + "azure2\0" + "azure3\0" + "azure4\0" + "beige\0" + "bisque\0" + "bisque1\0" + "bisque2\0" + "bisque3\0" + "bisque4\0" + "black\0" + "blanched almond\0" + "BlanchedAlmond\0" + "blue\0" + "blue violet\0" + "blue1\0" + "blue2\0" + "blue3\0" + "blue4\0" + "BlueViolet\0" + "brown\0" + "brown1\0" + "brown2\0" + "brown3\0" + "brown4\0" + "burlywood\0" + "burlywood1\0" + "burlywood2\0" + "burlywood3\0" + "burlywood4\0" + "cadet blue\0" + "CadetBlue\0" + "CadetBlue1\0" + "CadetBlue2\0" + "CadetBlue3\0" + "CadetBlue4\0" + "chartreuse\0" + "chartreuse1\0" + "chartreuse2\0" + "chartreuse3\0" + "chartreuse4\0" + "chocolate\0" + "chocolate1\0" + "chocolate2\0" + "chocolate3\0" + "chocolate4\0" + "coral\0" + "coral1\0" + "coral2\0" + "coral3\0" + "coral4\0" + "cornflower blue\0" + "CornflowerBlue\0" + "cornsilk\0" + "cornsilk1\0" + "cornsilk2\0" + "cornsilk3\0" + "cornsilk4\0" + "crimson\0" + "cyan\0" + "cyan1\0" + "cyan2\0" + "cyan3\0" + "cyan4\0" + "dark blue\0" + "dark cyan\0" + "dark goldenrod\0" + "dark gray\0" + "dark green\0" + "dark grey\0" + "dark khaki\0" + "dark magenta\0" + "dark olive green\0" + "dark orange\0" + "dark orchid\0" + "dark red\0" + "dark salmon\0" + "dark sea green\0" + "dark slate blue\0" + "dark slate gray\0" + "dark slate grey\0" + "dark turquoise\0" + "dark violet\0" + "DarkBlue\0" + "DarkCyan\0" + "DarkGoldenrod\0" + "DarkGoldenrod1\0" + "DarkGoldenrod2\0" + "DarkGoldenrod3\0" + "DarkGoldenrod4\0" + "DarkGray\0" + "DarkGreen\0" + "DarkGrey\0" + "DarkKhaki\0" + "DarkMagenta\0" + "DarkOliveGreen\0" + "DarkOliveGreen1\0" + "DarkOliveGreen2\0" + "DarkOliveGreen3\0" + "DarkOliveGreen4\0" + "DarkOrange\0" + "DarkOrange1\0" + "DarkOrange2\0" + "DarkOrange3\0" + "DarkOrange4\0" + "DarkOrchid\0" + "DarkOrchid1\0" + "DarkOrchid2\0" + "DarkOrchid3\0" + "DarkOrchid4\0" + "DarkRed\0" + "DarkSalmon\0" + "DarkSeaGreen\0" + "DarkSeaGreen1\0" + "DarkSeaGreen2\0" + "DarkSeaGreen3\0" + "DarkSeaGreen4\0" + "DarkSlateBlue\0" + "DarkSlateGray\0" + "DarkSlateGray1\0" + "DarkSlateGray2\0" + "DarkSlateGray3\0" + "DarkSlateGray4\0" + "DarkSlateGrey\0" + "DarkTurquoise\0" + "DarkViolet\0" + "deep pink\0" + "deep sky blue\0" + "DeepPink\0" + "DeepPink1\0" + "DeepPink2\0" + "DeepPink3\0" + "DeepPink4\0" + "DeepSkyBlue\0" + "DeepSkyBlue1\0" + "DeepSkyBlue2\0" + "DeepSkyBlue3\0" + "DeepSkyBlue4\0" + "dim gray\0" + "dim grey\0" + "DimGray\0" + "DimGrey\0" + "dodger blue\0" + "DodgerBlue\0" + "DodgerBlue1\0" + "DodgerBlue2\0" + "DodgerBlue3\0" + "DodgerBlue4\0" + "firebrick\0" + "firebrick1\0" + "firebrick2\0" + "firebrick3\0" + "firebrick4\0" + "floral white\0" + "FloralWhite\0" + "forest green\0" + "ForestGreen\0" + "fuchsia\0" + "gainsboro\0" + "ghost white\0" + "GhostWhite\0" + "gold\0" + "gold1\0" + "gold2\0" + "gold3\0" + "gold4\0" + "goldenrod\0" + "goldenrod1\0" + "goldenrod2\0" + "goldenrod3\0" + "goldenrod4\0" + "gray\0" + "gray0\0" + "gray1\0" + "gray10\0" + "gray100\0" + "gray11\0" + "gray12\0" + "gray13\0" + "gray14\0" + "gray15\0" + "gray16\0" + "gray17\0" + "gray18\0" + "gray19\0" + "gray2\0" + "gray20\0" + "gray21\0" + "gray22\0" + "gray23\0" + "gray24\0" + "gray25\0" + "gray26\0" + "gray27\0" + "gray28\0" + "gray29\0" + "gray3\0" + "gray30\0" + "gray31\0" + "gray32\0" + "gray33\0" + "gray34\0" + "gray35\0" + "gray36\0" + "gray37\0" + "gray38\0" + "gray39\0" + "gray4\0" + "gray40\0" + "gray41\0" + "gray42\0" + "gray43\0" + "gray44\0" + "gray45\0" + "gray46\0" + "gray47\0" + "gray48\0" + "gray49\0" + "gray5\0" + "gray50\0" + "gray51\0" + "gray52\0" + "gray53\0" + "gray54\0" + "gray55\0" + "gray56\0" + "gray57\0" + "gray58\0" + "gray59\0" + "gray6\0" + "gray60\0" + "gray61\0" + "gray62\0" + "gray63\0" + "gray64\0" + "gray65\0" + "gray66\0" + "gray67\0" + "gray68\0" + "gray69\0" + "gray7\0" + "gray70\0" + "gray71\0" + "gray72\0" + "gray73\0" + "gray74\0" + "gray75\0" + "gray76\0" + "gray77\0" + "gray78\0" + "gray79\0" + "gray8\0" + "gray80\0" + "gray81\0" + "gray82\0" + "gray83\0" + "gray84\0" + "gray85\0" + "gray86\0" + "gray87\0" + "gray88\0" + "gray89\0" + "gray9\0" + "gray90\0" + "gray91\0" + "gray92\0" + "gray93\0" + "gray94\0" + "gray95\0" + "gray96\0" + "gray97\0" + "gray98\0" + "gray99\0" + "green\0" + "green yellow\0" + "green1\0" + "green2\0" + "green3\0" + "green4\0" + "GreenYellow\0" + "grey\0" + "grey0\0" + "grey1\0" + "grey10\0" + "grey100\0" + "grey11\0" + "grey12\0" + "grey13\0" + "grey14\0" + "grey15\0" + "grey16\0" + "grey17\0" + "grey18\0" + "grey19\0" + "grey2\0" + "grey20\0" + "grey21\0" + "grey22\0" + "grey23\0" + "grey24\0" + "grey25\0" + "grey26\0" + "grey27\0" + "grey28\0" + "grey29\0" + "grey3\0" + "grey30\0" + "grey31\0" + "grey32\0" + "grey33\0" + "grey34\0" + "grey35\0" + "grey36\0" + "grey37\0" + "grey38\0" + "grey39\0" + "grey4\0" + "grey40\0" + "grey41\0" + "grey42\0" + "grey43\0" + "grey44\0" + "grey45\0" + "grey46\0" + "grey47\0" + "grey48\0" + "grey49\0" + "grey5\0" + "grey50\0" + "grey51\0" + "grey52\0" + "grey53\0" + "grey54\0" + "grey55\0" + "grey56\0" + "grey57\0" + "grey58\0" + "grey59\0" + "grey6\0" + "grey60\0" + "grey61\0" + "grey62\0" + "grey63\0" + "grey64\0" + "grey65\0" + "grey66\0" + "grey67\0" + "grey68\0" + "grey69\0" + "grey7\0" + "grey70\0" + "grey71\0" + "grey72\0" + "grey73\0" + "grey74\0" + "grey75\0" + "grey76\0" + "grey77\0" + "grey78\0" + "grey79\0" + "grey8\0" + "grey80\0" + "grey81\0" + "grey82\0" + "grey83\0" + "grey84\0" + "grey85\0" + "grey86\0" + "grey87\0" + "grey88\0" + "grey89\0" + "grey9\0" + "grey90\0" + "grey91\0" + "grey92\0" + "grey93\0" + "grey94\0" + "grey95\0" + "grey96\0" + "grey97\0" + "grey98\0" + "grey99\0" + "honeydew\0" + "honeydew1\0" + "honeydew2\0" + "honeydew3\0" + "honeydew4\0" + "hot pink\0" + "HotPink\0" + "HotPink1\0" + "HotPink2\0" + "HotPink3\0" + "HotPink4\0" + "indian red\0" + "IndianRed\0" + "IndianRed1\0" + "IndianRed2\0" + "IndianRed3\0" + "IndianRed4\0" + "indigo\0" + "ivory\0" + "ivory1\0" + "ivory2\0" + "ivory3\0" + "ivory4\0" + "khaki\0" + "khaki1\0" + "khaki2\0" + "khaki3\0" + "khaki4\0" + "lavender\0" + "lavender blush\0" + "LavenderBlush\0" + "LavenderBlush1\0" + "LavenderBlush2\0" + "LavenderBlush3\0" + "LavenderBlush4\0" + "lawn green\0" + "LawnGreen\0" + "lemon chiffon\0" + "LemonChiffon\0" + "LemonChiffon1\0" + "LemonChiffon2\0" + "LemonChiffon3\0" + "LemonChiffon4\0" + "light blue\0" + "light coral\0" + "light cyan\0" + "light goldenrod\0" + "light goldenrod yellow\0" + "light gray\0" + "light green\0" + "light grey\0" + "light pink\0" + "light salmon\0" + "light sea green\0" + "light sky blue\0" + "light slate blue\0" + "light slate gray\0" + "light slate grey\0" + "light steel blue\0" + "light yellow\0" + "LightBlue\0" + "LightBlue1\0" + "LightBlue2\0" + "LightBlue3\0" + "LightBlue4\0" + "LightCoral\0" + "LightCyan\0" + "LightCyan1\0" + "LightCyan2\0" + "LightCyan3\0" + "LightCyan4\0" + "LightGoldenrod\0" + "LightGoldenrod1\0" + "LightGoldenrod2\0" + "LightGoldenrod3\0" + "LightGoldenrod4\0" + "LightGoldenrodYellow\0" + "LightGray\0" + "LightGreen\0" + "LightGrey\0" + "LightPink\0" + "LightPink1\0" + "LightPink2\0" + "LightPink3\0" + "LightPink4\0" + "LightSalmon\0" + "LightSalmon1\0" + "LightSalmon2\0" + "LightSalmon3\0" + "LightSalmon4\0" + "LightSeaGreen\0" + "LightSkyBlue\0" + "LightSkyBlue1\0" + "LightSkyBlue2\0" + "LightSkyBlue3\0" + "LightSkyBlue4\0" + "LightSlateBlue\0" + "LightSlateGray\0" + "LightSlateGrey\0" + "LightSteelBlue\0" + "LightSteelBlue1\0" + "LightSteelBlue2\0" + "LightSteelBlue3\0" + "LightSteelBlue4\0" + "LightYellow\0" + "LightYellow1\0" + "LightYellow2\0" + "LightYellow3\0" + "LightYellow4\0" + "lime\0" + "lime green\0" + "LimeGreen\0" + "linen\0" + "magenta\0" + "magenta1\0" + "magenta2\0" + "magenta3\0" + "magenta4\0" + "maroon\0" + "maroon1\0" + "maroon2\0" + "maroon3\0" + "maroon4\0" + "medium aquamarine\0" + "medium blue\0" + "medium orchid\0" + "medium purple\0" + "medium sea green\0" + "medium slate blue\0" + "medium spring green\0" + "medium turquoise\0" + "medium violet red\0" + "MediumAquamarine\0" + "MediumBlue\0" + "MediumOrchid\0" + "MediumOrchid1\0" + "MediumOrchid2\0" + "MediumOrchid3\0" + "MediumOrchid4\0" + "MediumPurple\0" + "MediumPurple1\0" + "MediumPurple2\0" + "MediumPurple3\0" + "MediumPurple4\0" + "MediumSeaGreen\0" + "MediumSlateBlue\0" + "MediumSpringGreen\0" + "MediumTurquoise\0" + "MediumVioletRed\0" + "midnight blue\0" + "MidnightBlue\0" + "mint cream\0" + "MintCream\0" + "misty rose\0" + "MistyRose\0" + "MistyRose1\0" + "MistyRose2\0" + "MistyRose3\0" + "MistyRose4\0" + "moccasin\0" + "navajo white\0" + "NavajoWhite\0" + "NavajoWhite1\0" + "NavajoWhite2\0" + "NavajoWhite3\0" + "NavajoWhite4\0" + "navy\0" + "navy blue\0" + "NavyBlue\0" + "old lace\0" + "OldLace\0" + "olive\0" + "olive drab\0" + "OliveDrab\0" + "OliveDrab1\0" + "OliveDrab2\0" + "OliveDrab3\0" + "OliveDrab4\0" + "orange\0" + "orange red\0" + "orange1\0" + "orange2\0" + "orange3\0" + "orange4\0" + "OrangeRed\0" + "OrangeRed1\0" + "OrangeRed2\0" + "OrangeRed3\0" + "OrangeRed4\0" + "orchid\0" + "orchid1\0" + "orchid2\0" + "orchid3\0" + "orchid4\0" + "pale goldenrod\0" + "pale green\0" + "pale turquoise\0" + "pale violet red\0" + "PaleGoldenrod\0" + "PaleGreen\0" + "PaleGreen1\0" + "PaleGreen2\0" + "PaleGreen3\0" + "PaleGreen4\0" + "PaleTurquoise\0" + "PaleTurquoise1\0" + "PaleTurquoise2\0" + "PaleTurquoise3\0" + "PaleTurquoise4\0" + "PaleVioletRed\0" + "PaleVioletRed1\0" + "PaleVioletRed2\0" + "PaleVioletRed3\0" + "PaleVioletRed4\0" + "papaya whip\0" + "PapayaWhip\0" + "peach puff\0" + "PeachPuff\0" + "PeachPuff1\0" + "PeachPuff2\0" + "PeachPuff3\0" + "PeachPuff4\0" + "peru\0" + "pink\0" + "pink1\0" + "pink2\0" + "pink3\0" + "pink4\0" + "plum\0" + "plum1\0" + "plum2\0" + "plum3\0" + "plum4\0" + "powder blue\0" + "PowderBlue\0" + "purple\0" + "purple1\0" + "purple2\0" + "purple3\0" + "purple4\0" + "rebecca purple\0" + "RebeccaPurple\0" + "red\0" + "red1\0" + "red2\0" + "red3\0" + "red4\0" + "rosy brown\0" + "RosyBrown\0" + "RosyBrown1\0" + "RosyBrown2\0" + "RosyBrown3\0" + "RosyBrown4\0" + "royal blue\0" + "RoyalBlue\0" + "RoyalBlue1\0" + "RoyalBlue2\0" + "RoyalBlue3\0" + "RoyalBlue4\0" + "saddle brown\0" + "SaddleBrown\0" + "salmon\0" + "salmon1\0" + "salmon2\0" + "salmon3\0" + "salmon4\0" + "sandy brown\0" + "SandyBrown\0" + "sea green\0" + "SeaGreen\0" + "SeaGreen1\0" + "SeaGreen2\0" + "SeaGreen3\0" + "SeaGreen4\0" + "seashell\0" + "seashell1\0" + "seashell2\0" + "seashell3\0" + "seashell4\0" + "sienna\0" + "sienna1\0" + "sienna2\0" + "sienna3\0" + "sienna4\0" + "silver\0" + "sky blue\0" + "SkyBlue\0" + "SkyBlue1\0" + "SkyBlue2\0" + "SkyBlue3\0" + "SkyBlue4\0" + "slate blue\0" + "slate gray\0" + "slate grey\0" + "SlateBlue\0" + "SlateBlue1\0" + "SlateBlue2\0" + "SlateBlue3\0" + "SlateBlue4\0" + "SlateGray\0" + "SlateGray1\0" + "SlateGray2\0" + "SlateGray3\0" + "SlateGray4\0" + "SlateGrey\0" + "snow\0" + "snow1\0" + "snow2\0" + "snow3\0" + "snow4\0" + "spring green\0" + "SpringGreen\0" + "SpringGreen1\0" + "SpringGreen2\0" + "SpringGreen3\0" + "SpringGreen4\0" + "steel blue\0" + "SteelBlue\0" + "SteelBlue1\0" + "SteelBlue2\0" + "SteelBlue3\0" + "SteelBlue4\0" + "tan\0" + "tan1\0" + "tan2\0" + "tan3\0" + "tan4\0" + "teal\0" + "thistle\0" + "thistle1\0" + "thistle2\0" + "thistle3\0" + "thistle4\0" + "tomato\0" + "tomato1\0" + "tomato2\0" + "tomato3\0" + "tomato4\0" + "turquoise\0" + "turquoise1\0" + "turquoise2\0" + "turquoise3\0" + "turquoise4\0" + "violet\0" + "violet red\0" + "VioletRed\0" + "VioletRed1\0" + "VioletRed2\0" + "VioletRed3\0" + "VioletRed4\0" + "web gray\0" + "web green\0" + "web grey\0" + "web maroon\0" + "web purple\0" + "WebGray\0" + "WebGreen\0" + "WebGrey\0" + "WebMaroon\0" + "WebPurple\0" + "wheat\0" + "wheat1\0" + "wheat2\0" + "wheat3\0" + "wheat4\0" + "white\0" + "white smoke\0" + "WhiteSmoke\0" + "x11 gray\0" + "x11 green\0" + "x11 grey\0" + "x11 maroon\0" + "x11 purple\0" + "X11Gray\0" + "X11Green\0" + "X11Grey\0" + "X11Maroon\0" + "X11Purple\0" + "yellow\0" + "yellow green\0" + "yellow1\0" + "yellow2\0" + "yellow3\0" + "yellow4\0" + "YellowGreen\0" +}; + +static const BuiltinColor BuiltinColors[] = { + {240, 248, 255, 0}, /* alice blue */ + {240, 248, 255, 11}, /* AliceBlue */ + {250, 235, 215, 21}, /* antique white */ + {250, 235, 215, 35}, /* AntiqueWhite */ + {255, 239, 219, 48}, /* AntiqueWhite1 */ + {238, 223, 204, 62}, /* AntiqueWhite2 */ + {205, 192, 176, 76}, /* AntiqueWhite3 */ + {139, 131, 120, 90}, /* AntiqueWhite4 */ + {0, 255, 255, 104}, /* aqua */ + {127, 255, 212, 109}, /* aquamarine */ + {127, 255, 212, 120}, /* aquamarine1 */ + {118, 238, 198, 132}, /* aquamarine2 */ + {102, 205, 170, 144}, /* aquamarine3 */ + {69, 139, 116, 156}, /* aquamarine4 */ + {240, 255, 255, 168}, /* azure */ + {240, 255, 255, 174}, /* azure1 */ + {224, 238, 238, 181}, /* azure2 */ + {193, 205, 205, 188}, /* azure3 */ + {131, 139, 139, 195}, /* azure4 */ + {245, 245, 220, 202}, /* beige */ + {255, 228, 196, 208}, /* bisque */ + {255, 228, 196, 215}, /* bisque1 */ + {238, 213, 183, 223}, /* bisque2 */ + {205, 183, 158, 231}, /* bisque3 */ + {139, 125, 107, 239}, /* bisque4 */ + {0, 0, 0, 247}, /* black */ + {255, 235, 205, 253}, /* blanched almond */ + {255, 235, 205, 269}, /* BlanchedAlmond */ + {0, 0, 255, 284}, /* blue */ + {138, 43, 226, 289}, /* blue violet */ + {0, 0, 255, 301}, /* blue1 */ + {0, 0, 238, 307}, /* blue2 */ + {0, 0, 205, 313}, /* blue3 */ + {0, 0, 139, 319}, /* blue4 */ + {138, 43, 226, 325}, /* BlueViolet */ + {165, 42, 42, 336}, /* brown */ + {255, 64, 64, 342}, /* brown1 */ + {238, 59, 59, 349}, /* brown2 */ + {205, 51, 51, 356}, /* brown3 */ + {139, 35, 35, 363}, /* brown4 */ + {222, 184, 135, 370}, /* burlywood */ + {255, 211, 155, 380}, /* burlywood1 */ + {238, 197, 145, 391}, /* burlywood2 */ + {205, 170, 125, 402}, /* burlywood3 */ + {139, 115, 85, 413}, /* burlywood4 */ + {95, 158, 160, 424}, /* cadet blue */ + {95, 158, 160, 435}, /* CadetBlue */ + {152, 245, 255, 445}, /* CadetBlue1 */ + {142, 229, 238, 456}, /* CadetBlue2 */ + {122, 197, 205, 467}, /* CadetBlue3 */ + {83, 134, 139, 478}, /* CadetBlue4 */ + {127, 255, 0, 489}, /* chartreuse */ + {127, 255, 0, 500}, /* chartreuse1 */ + {118, 238, 0, 512}, /* chartreuse2 */ + {102, 205, 0, 524}, /* chartreuse3 */ + {69, 139, 0, 536}, /* chartreuse4 */ + {210, 105, 30, 548}, /* chocolate */ + {255, 127, 36, 558}, /* chocolate1 */ + {238, 118, 33, 569}, /* chocolate2 */ + {205, 102, 29, 580}, /* chocolate3 */ + {139, 69, 19, 591}, /* chocolate4 */ + {255, 127, 80, 602}, /* coral */ + {255, 114, 86, 608}, /* coral1 */ + {238, 106, 80, 615}, /* coral2 */ + {205, 91, 69, 622}, /* coral3 */ + {139, 62, 47, 629}, /* coral4 */ + {100, 149, 237, 636}, /* cornflower blue */ + {100, 149, 237, 652}, /* CornflowerBlue */ + {255, 248, 220, 667}, /* cornsilk */ + {255, 248, 220, 676}, /* cornsilk1 */ + {238, 232, 205, 686}, /* cornsilk2 */ + {205, 200, 177, 696}, /* cornsilk3 */ + {139, 136, 120, 706}, /* cornsilk4 */ + {220, 20, 60, 716}, /* crimson */ + {0, 255, 255, 724}, /* cyan */ + {0, 255, 255, 729}, /* cyan1 */ + {0, 238, 238, 735}, /* cyan2 */ + {0, 205, 205, 741}, /* cyan3 */ + {0, 139, 139, 747}, /* cyan4 */ + {0, 0, 139, 753}, /* dark blue */ + {0, 139, 139, 763}, /* dark cyan */ + {184, 134, 11, 773}, /* dark goldenrod */ + {169, 169, 169, 788}, /* dark gray */ + {0, 100, 0, 798}, /* dark green */ + {169, 169, 169, 809}, /* dark grey */ + {189, 183, 107, 819}, /* dark khaki */ + {139, 0, 139, 830}, /* dark magenta */ + {85, 107, 47, 843}, /* dark olive green */ + {255, 140, 0, 860}, /* dark orange */ + {153, 50, 204, 872}, /* dark orchid */ + {139, 0, 0, 884}, /* dark red */ + {233, 150, 122, 893}, /* dark salmon */ + {143, 188, 143, 905}, /* dark sea green */ + {72, 61, 139, 920}, /* dark slate blue */ + {47, 79, 79, 936}, /* dark slate gray */ + {47, 79, 79, 952}, /* dark slate grey */ + {0, 206, 209, 968}, /* dark turquoise */ + {148, 0, 211, 983}, /* dark violet */ + {0, 0, 139, 995}, /* DarkBlue */ + {0, 139, 139, 1004}, /* DarkCyan */ + {184, 134, 11, 1013}, /* DarkGoldenrod */ + {255, 185, 15, 1027}, /* DarkGoldenrod1 */ + {238, 173, 14, 1042}, /* DarkGoldenrod2 */ + {205, 149, 12, 1057}, /* DarkGoldenrod3 */ + {139, 101, 8, 1072}, /* DarkGoldenrod4 */ + {169, 169, 169, 1087}, /* DarkGray */ + {0, 100, 0, 1096}, /* DarkGreen */ + {169, 169, 169, 1106}, /* DarkGrey */ + {189, 183, 107, 1115}, /* DarkKhaki */ + {139, 0, 139, 1125}, /* DarkMagenta */ + {85, 107, 47, 1137}, /* DarkOliveGreen */ + {202, 255, 112, 1152}, /* DarkOliveGreen1 */ + {188, 238, 104, 1168}, /* DarkOliveGreen2 */ + {162, 205, 90, 1184}, /* DarkOliveGreen3 */ + {110, 139, 61, 1200}, /* DarkOliveGreen4 */ + {255, 140, 0, 1216}, /* DarkOrange */ + {255, 127, 0, 1227}, /* DarkOrange1 */ + {238, 118, 0, 1239}, /* DarkOrange2 */ + {205, 102, 0, 1251}, /* DarkOrange3 */ + {139, 69, 0, 1263}, /* DarkOrange4 */ + {153, 50, 204, 1275}, /* DarkOrchid */ + {191, 62, 255, 1286}, /* DarkOrchid1 */ + {178, 58, 238, 1298}, /* DarkOrchid2 */ + {154, 50, 205, 1310}, /* DarkOrchid3 */ + {104, 34, 139, 1322}, /* DarkOrchid4 */ + {139, 0, 0, 1334}, /* DarkRed */ + {233, 150, 122, 1342}, /* DarkSalmon */ + {143, 188, 143, 1353}, /* DarkSeaGreen */ + {193, 255, 193, 1366}, /* DarkSeaGreen1 */ + {180, 238, 180, 1380}, /* DarkSeaGreen2 */ + {155, 205, 155, 1394}, /* DarkSeaGreen3 */ + {105, 139, 105, 1408}, /* DarkSeaGreen4 */ + {72, 61, 139, 1422}, /* DarkSlateBlue */ + {47, 79, 79, 1436}, /* DarkSlateGray */ + {151, 255, 255, 1450}, /* DarkSlateGray1 */ + {141, 238, 238, 1465}, /* DarkSlateGray2 */ + {121, 205, 205, 1480}, /* DarkSlateGray3 */ + {82, 139, 139, 1495}, /* DarkSlateGray4 */ + {47, 79, 79, 1510}, /* DarkSlateGrey */ + {0, 206, 209, 1524}, /* DarkTurquoise */ + {148, 0, 211, 1538}, /* DarkViolet */ + {255, 20, 147, 1549}, /* deep pink */ + {0, 191, 255, 1559}, /* deep sky blue */ + {255, 20, 147, 1573}, /* DeepPink */ + {255, 20, 147, 1582}, /* DeepPink1 */ + {238, 18, 137, 1592}, /* DeepPink2 */ + {205, 16, 118, 1602}, /* DeepPink3 */ + {139, 10, 80, 1612}, /* DeepPink4 */ + {0, 191, 255, 1622}, /* DeepSkyBlue */ + {0, 191, 255, 1634}, /* DeepSkyBlue1 */ + {0, 178, 238, 1647}, /* DeepSkyBlue2 */ + {0, 154, 205, 1660}, /* DeepSkyBlue3 */ + {0, 104, 139, 1673}, /* DeepSkyBlue4 */ + {105, 105, 105, 1686}, /* dim gray */ + {105, 105, 105, 1695}, /* dim grey */ + {105, 105, 105, 1704}, /* DimGray */ + {105, 105, 105, 1712}, /* DimGrey */ + {30, 144, 255, 1720}, /* dodger blue */ + {30, 144, 255, 1732}, /* DodgerBlue */ + {30, 144, 255, 1743}, /* DodgerBlue1 */ + {28, 134, 238, 1755}, /* DodgerBlue2 */ + {24, 116, 205, 1767}, /* DodgerBlue3 */ + {16, 78, 139, 1779}, /* DodgerBlue4 */ + {178, 34, 34, 1791}, /* firebrick */ + {255, 48, 48, 1801}, /* firebrick1 */ + {238, 44, 44, 1812}, /* firebrick2 */ + {205, 38, 38, 1823}, /* firebrick3 */ + {139, 26, 26, 1834}, /* firebrick4 */ + {255, 250, 240, 1845}, /* floral white */ + {255, 250, 240, 1858}, /* FloralWhite */ + {34, 139, 34, 1870}, /* forest green */ + {34, 139, 34, 1883}, /* ForestGreen */ + {255, 0, 255, 1895}, /* fuchsia */ + {220, 220, 220, 1903}, /* gainsboro */ + {248, 248, 255, 1913}, /* ghost white */ + {248, 248, 255, 1925}, /* GhostWhite */ + {255, 215, 0, 1936}, /* gold */ + {255, 215, 0, 1941}, /* gold1 */ + {238, 201, 0, 1947}, /* gold2 */ + {205, 173, 0, 1953}, /* gold3 */ + {139, 117, 0, 1959}, /* gold4 */ + {218, 165, 32, 1965}, /* goldenrod */ + {255, 193, 37, 1975}, /* goldenrod1 */ + {238, 180, 34, 1986}, /* goldenrod2 */ + {205, 155, 29, 1997}, /* goldenrod3 */ + {139, 105, 20, 2008}, /* goldenrod4 */ + {190, 190, 190, 2019}, /* gray */ + {0, 0, 0, 2024}, /* gray0 */ + {3, 3, 3, 2030}, /* gray1 */ + {26, 26, 26, 2036}, /* gray10 */ + {255, 255, 255, 2043}, /* gray100 */ + {28, 28, 28, 2051}, /* gray11 */ + {31, 31, 31, 2058}, /* gray12 */ + {33, 33, 33, 2065}, /* gray13 */ + {36, 36, 36, 2072}, /* gray14 */ + {38, 38, 38, 2079}, /* gray15 */ + {41, 41, 41, 2086}, /* gray16 */ + {43, 43, 43, 2093}, /* gray17 */ + {46, 46, 46, 2100}, /* gray18 */ + {48, 48, 48, 2107}, /* gray19 */ + {5, 5, 5, 2114}, /* gray2 */ + {51, 51, 51, 2120}, /* gray20 */ + {54, 54, 54, 2127}, /* gray21 */ + {56, 56, 56, 2134}, /* gray22 */ + {59, 59, 59, 2141}, /* gray23 */ + {61, 61, 61, 2148}, /* gray24 */ + {64, 64, 64, 2155}, /* gray25 */ + {66, 66, 66, 2162}, /* gray26 */ + {69, 69, 69, 2169}, /* gray27 */ + {71, 71, 71, 2176}, /* gray28 */ + {74, 74, 74, 2183}, /* gray29 */ + {8, 8, 8, 2190}, /* gray3 */ + {77, 77, 77, 2196}, /* gray30 */ + {79, 79, 79, 2203}, /* gray31 */ + {82, 82, 82, 2210}, /* gray32 */ + {84, 84, 84, 2217}, /* gray33 */ + {87, 87, 87, 2224}, /* gray34 */ + {89, 89, 89, 2231}, /* gray35 */ + {92, 92, 92, 2238}, /* gray36 */ + {94, 94, 94, 2245}, /* gray37 */ + {97, 97, 97, 2252}, /* gray38 */ + {99, 99, 99, 2259}, /* gray39 */ + {10, 10, 10, 2266}, /* gray4 */ + {102, 102, 102, 2272}, /* gray40 */ + {105, 105, 105, 2279}, /* gray41 */ + {107, 107, 107, 2286}, /* gray42 */ + {110, 110, 110, 2293}, /* gray43 */ + {112, 112, 112, 2300}, /* gray44 */ + {115, 115, 115, 2307}, /* gray45 */ + {117, 117, 117, 2314}, /* gray46 */ + {120, 120, 120, 2321}, /* gray47 */ + {122, 122, 122, 2328}, /* gray48 */ + {125, 125, 125, 2335}, /* gray49 */ + {13, 13, 13, 2342}, /* gray5 */ + {127, 127, 127, 2348}, /* gray50 */ + {130, 130, 130, 2355}, /* gray51 */ + {133, 133, 133, 2362}, /* gray52 */ + {135, 135, 135, 2369}, /* gray53 */ + {138, 138, 138, 2376}, /* gray54 */ + {140, 140, 140, 2383}, /* gray55 */ + {143, 143, 143, 2390}, /* gray56 */ + {145, 145, 145, 2397}, /* gray57 */ + {148, 148, 148, 2404}, /* gray58 */ + {150, 150, 150, 2411}, /* gray59 */ + {15, 15, 15, 2418}, /* gray6 */ + {153, 153, 153, 2424}, /* gray60 */ + {156, 156, 156, 2431}, /* gray61 */ + {158, 158, 158, 2438}, /* gray62 */ + {161, 161, 161, 2445}, /* gray63 */ + {163, 163, 163, 2452}, /* gray64 */ + {166, 166, 166, 2459}, /* gray65 */ + {168, 168, 168, 2466}, /* gray66 */ + {171, 171, 171, 2473}, /* gray67 */ + {173, 173, 173, 2480}, /* gray68 */ + {176, 176, 176, 2487}, /* gray69 */ + {18, 18, 18, 2494}, /* gray7 */ + {179, 179, 179, 2500}, /* gray70 */ + {181, 181, 181, 2507}, /* gray71 */ + {184, 184, 184, 2514}, /* gray72 */ + {186, 186, 186, 2521}, /* gray73 */ + {189, 189, 189, 2528}, /* gray74 */ + {191, 191, 191, 2535}, /* gray75 */ + {194, 194, 194, 2542}, /* gray76 */ + {196, 196, 196, 2549}, /* gray77 */ + {199, 199, 199, 2556}, /* gray78 */ + {201, 201, 201, 2563}, /* gray79 */ + {20, 20, 20, 2570}, /* gray8 */ + {204, 204, 204, 2576}, /* gray80 */ + {207, 207, 207, 2583}, /* gray81 */ + {209, 209, 209, 2590}, /* gray82 */ + {212, 212, 212, 2597}, /* gray83 */ + {214, 214, 214, 2604}, /* gray84 */ + {217, 217, 217, 2611}, /* gray85 */ + {219, 219, 219, 2618}, /* gray86 */ + {222, 222, 222, 2625}, /* gray87 */ + {224, 224, 224, 2632}, /* gray88 */ + {227, 227, 227, 2639}, /* gray89 */ + {23, 23, 23, 2646}, /* gray9 */ + {229, 229, 229, 2652}, /* gray90 */ + {232, 232, 232, 2659}, /* gray91 */ + {235, 235, 235, 2666}, /* gray92 */ + {237, 237, 237, 2673}, /* gray93 */ + {240, 240, 240, 2680}, /* gray94 */ + {242, 242, 242, 2687}, /* gray95 */ + {245, 245, 245, 2694}, /* gray96 */ + {247, 247, 247, 2701}, /* gray97 */ + {250, 250, 250, 2708}, /* gray98 */ + {252, 252, 252, 2715}, /* gray99 */ + {0, 255, 0, 2722}, /* green */ + {173, 255, 47, 2728}, /* green yellow */ + {0, 255, 0, 2741}, /* green1 */ + {0, 238, 0, 2748}, /* green2 */ + {0, 205, 0, 2755}, /* green3 */ + {0, 139, 0, 2762}, /* green4 */ + {173, 255, 47, 2769}, /* GreenYellow */ + {190, 190, 190, 2781}, /* grey */ + {0, 0, 0, 2786}, /* grey0 */ + {3, 3, 3, 2792}, /* grey1 */ + {26, 26, 26, 2798}, /* grey10 */ + {255, 255, 255, 2805}, /* grey100 */ + {28, 28, 28, 2813}, /* grey11 */ + {31, 31, 31, 2820}, /* grey12 */ + {33, 33, 33, 2827}, /* grey13 */ + {36, 36, 36, 2834}, /* grey14 */ + {38, 38, 38, 2841}, /* grey15 */ + {41, 41, 41, 2848}, /* grey16 */ + {43, 43, 43, 2855}, /* grey17 */ + {46, 46, 46, 2862}, /* grey18 */ + {48, 48, 48, 2869}, /* grey19 */ + {5, 5, 5, 2876}, /* grey2 */ + {51, 51, 51, 2882}, /* grey20 */ + {54, 54, 54, 2889}, /* grey21 */ + {56, 56, 56, 2896}, /* grey22 */ + {59, 59, 59, 2903}, /* grey23 */ + {61, 61, 61, 2910}, /* grey24 */ + {64, 64, 64, 2917}, /* grey25 */ + {66, 66, 66, 2924}, /* grey26 */ + {69, 69, 69, 2931}, /* grey27 */ + {71, 71, 71, 2938}, /* grey28 */ + {74, 74, 74, 2945}, /* grey29 */ + {8, 8, 8, 2952}, /* grey3 */ + {77, 77, 77, 2958}, /* grey30 */ + {79, 79, 79, 2965}, /* grey31 */ + {82, 82, 82, 2972}, /* grey32 */ + {84, 84, 84, 2979}, /* grey33 */ + {87, 87, 87, 2986}, /* grey34 */ + {89, 89, 89, 2993}, /* grey35 */ + {92, 92, 92, 3000}, /* grey36 */ + {94, 94, 94, 3007}, /* grey37 */ + {97, 97, 97, 3014}, /* grey38 */ + {99, 99, 99, 3021}, /* grey39 */ + {10, 10, 10, 3028}, /* grey4 */ + {102, 102, 102, 3034}, /* grey40 */ + {105, 105, 105, 3041}, /* grey41 */ + {107, 107, 107, 3048}, /* grey42 */ + {110, 110, 110, 3055}, /* grey43 */ + {112, 112, 112, 3062}, /* grey44 */ + {115, 115, 115, 3069}, /* grey45 */ + {117, 117, 117, 3076}, /* grey46 */ + {120, 120, 120, 3083}, /* grey47 */ + {122, 122, 122, 3090}, /* grey48 */ + {125, 125, 125, 3097}, /* grey49 */ + {13, 13, 13, 3104}, /* grey5 */ + {127, 127, 127, 3110}, /* grey50 */ + {130, 130, 130, 3117}, /* grey51 */ + {133, 133, 133, 3124}, /* grey52 */ + {135, 135, 135, 3131}, /* grey53 */ + {138, 138, 138, 3138}, /* grey54 */ + {140, 140, 140, 3145}, /* grey55 */ + {143, 143, 143, 3152}, /* grey56 */ + {145, 145, 145, 3159}, /* grey57 */ + {148, 148, 148, 3166}, /* grey58 */ + {150, 150, 150, 3173}, /* grey59 */ + {15, 15, 15, 3180}, /* grey6 */ + {153, 153, 153, 3186}, /* grey60 */ + {156, 156, 156, 3193}, /* grey61 */ + {158, 158, 158, 3200}, /* grey62 */ + {161, 161, 161, 3207}, /* grey63 */ + {163, 163, 163, 3214}, /* grey64 */ + {166, 166, 166, 3221}, /* grey65 */ + {168, 168, 168, 3228}, /* grey66 */ + {171, 171, 171, 3235}, /* grey67 */ + {173, 173, 173, 3242}, /* grey68 */ + {176, 176, 176, 3249}, /* grey69 */ + {18, 18, 18, 3256}, /* grey7 */ + {179, 179, 179, 3262}, /* grey70 */ + {181, 181, 181, 3269}, /* grey71 */ + {184, 184, 184, 3276}, /* grey72 */ + {186, 186, 186, 3283}, /* grey73 */ + {189, 189, 189, 3290}, /* grey74 */ + {191, 191, 191, 3297}, /* grey75 */ + {194, 194, 194, 3304}, /* grey76 */ + {196, 196, 196, 3311}, /* grey77 */ + {199, 199, 199, 3318}, /* grey78 */ + {201, 201, 201, 3325}, /* grey79 */ + {20, 20, 20, 3332}, /* grey8 */ + {204, 204, 204, 3338}, /* grey80 */ + {207, 207, 207, 3345}, /* grey81 */ + {209, 209, 209, 3352}, /* grey82 */ + {212, 212, 212, 3359}, /* grey83 */ + {214, 214, 214, 3366}, /* grey84 */ + {217, 217, 217, 3373}, /* grey85 */ + {219, 219, 219, 3380}, /* grey86 */ + {222, 222, 222, 3387}, /* grey87 */ + {224, 224, 224, 3394}, /* grey88 */ + {227, 227, 227, 3401}, /* grey89 */ + {23, 23, 23, 3408}, /* grey9 */ + {229, 229, 229, 3414}, /* grey90 */ + {232, 232, 232, 3421}, /* grey91 */ + {235, 235, 235, 3428}, /* grey92 */ + {237, 237, 237, 3435}, /* grey93 */ + {240, 240, 240, 3442}, /* grey94 */ + {242, 242, 242, 3449}, /* grey95 */ + {245, 245, 245, 3456}, /* grey96 */ + {247, 247, 247, 3463}, /* grey97 */ + {250, 250, 250, 3470}, /* grey98 */ + {252, 252, 252, 3477}, /* grey99 */ + {240, 255, 240, 3484}, /* honeydew */ + {240, 255, 240, 3493}, /* honeydew1 */ + {224, 238, 224, 3503}, /* honeydew2 */ + {193, 205, 193, 3513}, /* honeydew3 */ + {131, 139, 131, 3523}, /* honeydew4 */ + {255, 105, 180, 3533}, /* hot pink */ + {255, 105, 180, 3542}, /* HotPink */ + {255, 110, 180, 3550}, /* HotPink1 */ + {238, 106, 167, 3559}, /* HotPink2 */ + {205, 96, 144, 3568}, /* HotPink3 */ + {139, 58, 98, 3577}, /* HotPink4 */ + {205, 92, 92, 3586}, /* indian red */ + {205, 92, 92, 3597}, /* IndianRed */ + {255, 106, 106, 3607}, /* IndianRed1 */ + {238, 99, 99, 3618}, /* IndianRed2 */ + {205, 85, 85, 3629}, /* IndianRed3 */ + {139, 58, 58, 3640}, /* IndianRed4 */ + {75, 0, 130, 3651}, /* indigo */ + {255, 255, 240, 3658}, /* ivory */ + {255, 255, 240, 3664}, /* ivory1 */ + {238, 238, 224, 3671}, /* ivory2 */ + {205, 205, 193, 3678}, /* ivory3 */ + {139, 139, 131, 3685}, /* ivory4 */ + {240, 230, 140, 3692}, /* khaki */ + {255, 246, 143, 3698}, /* khaki1 */ + {238, 230, 133, 3705}, /* khaki2 */ + {205, 198, 115, 3712}, /* khaki3 */ + {139, 134, 78, 3719}, /* khaki4 */ + {230, 230, 250, 3726}, /* lavender */ + {255, 240, 245, 3735}, /* lavender blush */ + {255, 240, 245, 3750}, /* LavenderBlush */ + {255, 240, 245, 3764}, /* LavenderBlush1 */ + {238, 224, 229, 3779}, /* LavenderBlush2 */ + {205, 193, 197, 3794}, /* LavenderBlush3 */ + {139, 131, 134, 3809}, /* LavenderBlush4 */ + {124, 252, 0, 3824}, /* lawn green */ + {124, 252, 0, 3835}, /* LawnGreen */ + {255, 250, 205, 3845}, /* lemon chiffon */ + {255, 250, 205, 3859}, /* LemonChiffon */ + {255, 250, 205, 3872}, /* LemonChiffon1 */ + {238, 233, 191, 3886}, /* LemonChiffon2 */ + {205, 201, 165, 3900}, /* LemonChiffon3 */ + {139, 137, 112, 3914}, /* LemonChiffon4 */ + {173, 216, 230, 3928}, /* light blue */ + {240, 128, 128, 3939}, /* light coral */ + {224, 255, 255, 3951}, /* light cyan */ + {238, 221, 130, 3962}, /* light goldenrod */ + {250, 250, 210, 3978}, /* light goldenrod yellow */ + {211, 211, 211, 4001}, /* light gray */ + {144, 238, 144, 4012}, /* light green */ + {211, 211, 211, 4024}, /* light grey */ + {255, 182, 193, 4035}, /* light pink */ + {255, 160, 122, 4046}, /* light salmon */ + {32, 178, 170, 4059}, /* light sea green */ + {135, 206, 250, 4075}, /* light sky blue */ + {132, 112, 255, 4090}, /* light slate blue */ + {119, 136, 153, 4107}, /* light slate gray */ + {119, 136, 153, 4124}, /* light slate grey */ + {176, 196, 222, 4141}, /* light steel blue */ + {255, 255, 224, 4158}, /* light yellow */ + {173, 216, 230, 4171}, /* LightBlue */ + {191, 239, 255, 4181}, /* LightBlue1 */ + {178, 223, 238, 4192}, /* LightBlue2 */ + {154, 192, 205, 4203}, /* LightBlue3 */ + {104, 131, 139, 4214}, /* LightBlue4 */ + {240, 128, 128, 4225}, /* LightCoral */ + {224, 255, 255, 4236}, /* LightCyan */ + {224, 255, 255, 4246}, /* LightCyan1 */ + {209, 238, 238, 4257}, /* LightCyan2 */ + {180, 205, 205, 4268}, /* LightCyan3 */ + {122, 139, 139, 4279}, /* LightCyan4 */ + {238, 221, 130, 4290}, /* LightGoldenrod */ + {255, 236, 139, 4305}, /* LightGoldenrod1 */ + {238, 220, 130, 4321}, /* LightGoldenrod2 */ + {205, 190, 112, 4337}, /* LightGoldenrod3 */ + {139, 129, 76, 4353}, /* LightGoldenrod4 */ + {250, 250, 210, 4369}, /* LightGoldenrodYellow */ + {211, 211, 211, 4390}, /* LightGray */ + {144, 238, 144, 4400}, /* LightGreen */ + {211, 211, 211, 4411}, /* LightGrey */ + {255, 182, 193, 4421}, /* LightPink */ + {255, 174, 185, 4431}, /* LightPink1 */ + {238, 162, 173, 4442}, /* LightPink2 */ + {205, 140, 149, 4453}, /* LightPink3 */ + {139, 95, 101, 4464}, /* LightPink4 */ + {255, 160, 122, 4475}, /* LightSalmon */ + {255, 160, 122, 4487}, /* LightSalmon1 */ + {238, 149, 114, 4500}, /* LightSalmon2 */ + {205, 129, 98, 4513}, /* LightSalmon3 */ + {139, 87, 66, 4526}, /* LightSalmon4 */ + {32, 178, 170, 4539}, /* LightSeaGreen */ + {135, 206, 250, 4553}, /* LightSkyBlue */ + {176, 226, 255, 4566}, /* LightSkyBlue1 */ + {164, 211, 238, 4580}, /* LightSkyBlue2 */ + {141, 182, 205, 4594}, /* LightSkyBlue3 */ + {96, 123, 139, 4608}, /* LightSkyBlue4 */ + {132, 112, 255, 4622}, /* LightSlateBlue */ + {119, 136, 153, 4637}, /* LightSlateGray */ + {119, 136, 153, 4652}, /* LightSlateGrey */ + {176, 196, 222, 4667}, /* LightSteelBlue */ + {202, 225, 255, 4682}, /* LightSteelBlue1 */ + {188, 210, 238, 4698}, /* LightSteelBlue2 */ + {162, 181, 205, 4714}, /* LightSteelBlue3 */ + {110, 123, 139, 4730}, /* LightSteelBlue4 */ + {255, 255, 224, 4746}, /* LightYellow */ + {255, 255, 224, 4758}, /* LightYellow1 */ + {238, 238, 209, 4771}, /* LightYellow2 */ + {205, 205, 180, 4784}, /* LightYellow3 */ + {139, 139, 122, 4797}, /* LightYellow4 */ + {0, 255, 0, 4810}, /* lime */ + {50, 205, 50, 4815}, /* lime green */ + {50, 205, 50, 4826}, /* LimeGreen */ + {250, 240, 230, 4836}, /* linen */ + {255, 0, 255, 4842}, /* magenta */ + {255, 0, 255, 4850}, /* magenta1 */ + {238, 0, 238, 4859}, /* magenta2 */ + {205, 0, 205, 4868}, /* magenta3 */ + {139, 0, 139, 4877}, /* magenta4 */ + {176, 48, 96, 4886}, /* maroon */ + {255, 52, 179, 4893}, /* maroon1 */ + {238, 48, 167, 4901}, /* maroon2 */ + {205, 41, 144, 4909}, /* maroon3 */ + {139, 28, 98, 4917}, /* maroon4 */ + {102, 205, 170, 4925}, /* medium aquamarine */ + {0, 0, 205, 4943}, /* medium blue */ + {186, 85, 211, 4955}, /* medium orchid */ + {147, 112, 219, 4969}, /* medium purple */ + {60, 179, 113, 4983}, /* medium sea green */ + {123, 104, 238, 5000}, /* medium slate blue */ + {0, 250, 154, 5018}, /* medium spring green */ + {72, 209, 204, 5038}, /* medium turquoise */ + {199, 21, 133, 5055}, /* medium violet red */ + {102, 205, 170, 5073}, /* MediumAquamarine */ + {0, 0, 205, 5090}, /* MediumBlue */ + {186, 85, 211, 5101}, /* MediumOrchid */ + {224, 102, 255, 5114}, /* MediumOrchid1 */ + {209, 95, 238, 5128}, /* MediumOrchid2 */ + {180, 82, 205, 5142}, /* MediumOrchid3 */ + {122, 55, 139, 5156}, /* MediumOrchid4 */ + {147, 112, 219, 5170}, /* MediumPurple */ + {171, 130, 255, 5183}, /* MediumPurple1 */ + {159, 121, 238, 5197}, /* MediumPurple2 */ + {137, 104, 205, 5211}, /* MediumPurple3 */ + {93, 71, 139, 5225}, /* MediumPurple4 */ + {60, 179, 113, 5239}, /* MediumSeaGreen */ + {123, 104, 238, 5254}, /* MediumSlateBlue */ + {0, 250, 154, 5270}, /* MediumSpringGreen */ + {72, 209, 204, 5288}, /* MediumTurquoise */ + {199, 21, 133, 5304}, /* MediumVioletRed */ + {25, 25, 112, 5320}, /* midnight blue */ + {25, 25, 112, 5334}, /* MidnightBlue */ + {245, 255, 250, 5347}, /* mint cream */ + {245, 255, 250, 5358}, /* MintCream */ + {255, 228, 225, 5368}, /* misty rose */ + {255, 228, 225, 5379}, /* MistyRose */ + {255, 228, 225, 5389}, /* MistyRose1 */ + {238, 213, 210, 5400}, /* MistyRose2 */ + {205, 183, 181, 5411}, /* MistyRose3 */ + {139, 125, 123, 5422}, /* MistyRose4 */ + {255, 228, 181, 5433}, /* moccasin */ + {255, 222, 173, 5442}, /* navajo white */ + {255, 222, 173, 5455}, /* NavajoWhite */ + {255, 222, 173, 5467}, /* NavajoWhite1 */ + {238, 207, 161, 5480}, /* NavajoWhite2 */ + {205, 179, 139, 5493}, /* NavajoWhite3 */ + {139, 121, 94, 5506}, /* NavajoWhite4 */ + {0, 0, 128, 5519}, /* navy */ + {0, 0, 128, 5524}, /* navy blue */ + {0, 0, 128, 5534}, /* NavyBlue */ + {253, 245, 230, 5543}, /* old lace */ + {253, 245, 230, 5552}, /* OldLace */ + {128, 128, 0, 5560}, /* olive */ + {107, 142, 35, 5566}, /* olive drab */ + {107, 142, 35, 5577}, /* OliveDrab */ + {192, 255, 62, 5587}, /* OliveDrab1 */ + {179, 238, 58, 5598}, /* OliveDrab2 */ + {154, 205, 50, 5609}, /* OliveDrab3 */ + {105, 139, 34, 5620}, /* OliveDrab4 */ + {255, 165, 0, 5631}, /* orange */ + {255, 69, 0, 5638}, /* orange red */ + {255, 165, 0, 5649}, /* orange1 */ + {238, 154, 0, 5657}, /* orange2 */ + {205, 133, 0, 5665}, /* orange3 */ + {139, 90, 0, 5673}, /* orange4 */ + {255, 69, 0, 5681}, /* OrangeRed */ + {255, 69, 0, 5691}, /* OrangeRed1 */ + {238, 64, 0, 5702}, /* OrangeRed2 */ + {205, 55, 0, 5713}, /* OrangeRed3 */ + {139, 37, 0, 5724}, /* OrangeRed4 */ + {218, 112, 214, 5735}, /* orchid */ + {255, 131, 250, 5742}, /* orchid1 */ + {238, 122, 233, 5750}, /* orchid2 */ + {205, 105, 201, 5758}, /* orchid3 */ + {139, 71, 137, 5766}, /* orchid4 */ + {238, 232, 170, 5774}, /* pale goldenrod */ + {152, 251, 152, 5789}, /* pale green */ + {175, 238, 238, 5800}, /* pale turquoise */ + {219, 112, 147, 5815}, /* pale violet red */ + {238, 232, 170, 5831}, /* PaleGoldenrod */ + {152, 251, 152, 5845}, /* PaleGreen */ + {154, 255, 154, 5855}, /* PaleGreen1 */ + {144, 238, 144, 5866}, /* PaleGreen2 */ + {124, 205, 124, 5877}, /* PaleGreen3 */ + {84, 139, 84, 5888}, /* PaleGreen4 */ + {175, 238, 238, 5899}, /* PaleTurquoise */ + {187, 255, 255, 5913}, /* PaleTurquoise1 */ + {174, 238, 238, 5928}, /* PaleTurquoise2 */ + {150, 205, 205, 5943}, /* PaleTurquoise3 */ + {102, 139, 139, 5958}, /* PaleTurquoise4 */ + {219, 112, 147, 5973}, /* PaleVioletRed */ + {255, 130, 171, 5987}, /* PaleVioletRed1 */ + {238, 121, 159, 6002}, /* PaleVioletRed2 */ + {205, 104, 137, 6017}, /* PaleVioletRed3 */ + {139, 71, 93, 6032}, /* PaleVioletRed4 */ + {255, 239, 213, 6047}, /* papaya whip */ + {255, 239, 213, 6059}, /* PapayaWhip */ + {255, 218, 185, 6070}, /* peach puff */ + {255, 218, 185, 6081}, /* PeachPuff */ + {255, 218, 185, 6091}, /* PeachPuff1 */ + {238, 203, 173, 6102}, /* PeachPuff2 */ + {205, 175, 149, 6113}, /* PeachPuff3 */ + {139, 119, 101, 6124}, /* PeachPuff4 */ + {205, 133, 63, 6135}, /* peru */ + {255, 192, 203, 6140}, /* pink */ + {255, 181, 197, 6145}, /* pink1 */ + {238, 169, 184, 6151}, /* pink2 */ + {205, 145, 158, 6157}, /* pink3 */ + {139, 99, 108, 6163}, /* pink4 */ + {221, 160, 221, 6169}, /* plum */ + {255, 187, 255, 6174}, /* plum1 */ + {238, 174, 238, 6180}, /* plum2 */ + {205, 150, 205, 6186}, /* plum3 */ + {139, 102, 139, 6192}, /* plum4 */ + {176, 224, 230, 6198}, /* powder blue */ + {176, 224, 230, 6210}, /* PowderBlue */ + {160, 32, 240, 6221}, /* purple */ + {155, 48, 255, 6228}, /* purple1 */ + {145, 44, 238, 6236}, /* purple2 */ + {125, 38, 205, 6244}, /* purple3 */ + {85, 26, 139, 6252}, /* purple4 */ + {102, 51, 153, 6260}, /* rebecca purple */ + {102, 51, 153, 6275}, /* RebeccaPurple */ + {255, 0, 0, 6289}, /* red */ + {255, 0, 0, 6293}, /* red1 */ + {238, 0, 0, 6298}, /* red2 */ + {205, 0, 0, 6303}, /* red3 */ + {139, 0, 0, 6308}, /* red4 */ + {188, 143, 143, 6313}, /* rosy brown */ + {188, 143, 143, 6324}, /* RosyBrown */ + {255, 193, 193, 6334}, /* RosyBrown1 */ + {238, 180, 180, 6345}, /* RosyBrown2 */ + {205, 155, 155, 6356}, /* RosyBrown3 */ + {139, 105, 105, 6367}, /* RosyBrown4 */ + {65, 105, 225, 6378}, /* royal blue */ + {65, 105, 225, 6389}, /* RoyalBlue */ + {72, 118, 255, 6399}, /* RoyalBlue1 */ + {67, 110, 238, 6410}, /* RoyalBlue2 */ + {58, 95, 205, 6421}, /* RoyalBlue3 */ + {39, 64, 139, 6432}, /* RoyalBlue4 */ + {139, 69, 19, 6443}, /* saddle brown */ + {139, 69, 19, 6456}, /* SaddleBrown */ + {250, 128, 114, 6468}, /* salmon */ + {255, 140, 105, 6475}, /* salmon1 */ + {238, 130, 98, 6483}, /* salmon2 */ + {205, 112, 84, 6491}, /* salmon3 */ + {139, 76, 57, 6499}, /* salmon4 */ + {244, 164, 96, 6507}, /* sandy brown */ + {244, 164, 96, 6519}, /* SandyBrown */ + {46, 139, 87, 6530}, /* sea green */ + {46, 139, 87, 6540}, /* SeaGreen */ + {84, 255, 159, 6549}, /* SeaGreen1 */ + {78, 238, 148, 6559}, /* SeaGreen2 */ + {67, 205, 128, 6569}, /* SeaGreen3 */ + {46, 139, 87, 6579}, /* SeaGreen4 */ + {255, 245, 238, 6589}, /* seashell */ + {255, 245, 238, 6598}, /* seashell1 */ + {238, 229, 222, 6608}, /* seashell2 */ + {205, 197, 191, 6618}, /* seashell3 */ + {139, 134, 130, 6628}, /* seashell4 */ + {160, 82, 45, 6638}, /* sienna */ + {255, 130, 71, 6645}, /* sienna1 */ + {238, 121, 66, 6653}, /* sienna2 */ + {205, 104, 57, 6661}, /* sienna3 */ + {139, 71, 38, 6669}, /* sienna4 */ + {192, 192, 192, 6677}, /* silver */ + {135, 206, 235, 6684}, /* sky blue */ + {135, 206, 235, 6693}, /* SkyBlue */ + {135, 206, 255, 6701}, /* SkyBlue1 */ + {126, 192, 238, 6710}, /* SkyBlue2 */ + {108, 166, 205, 6719}, /* SkyBlue3 */ + {74, 112, 139, 6728}, /* SkyBlue4 */ + {106, 90, 205, 6737}, /* slate blue */ + {112, 128, 144, 6748}, /* slate gray */ + {112, 128, 144, 6759}, /* slate grey */ + {106, 90, 205, 6770}, /* SlateBlue */ + {131, 111, 255, 6780}, /* SlateBlue1 */ + {122, 103, 238, 6791}, /* SlateBlue2 */ + {105, 89, 205, 6802}, /* SlateBlue3 */ + {71, 60, 139, 6813}, /* SlateBlue4 */ + {112, 128, 144, 6824}, /* SlateGray */ + {198, 226, 255, 6834}, /* SlateGray1 */ + {185, 211, 238, 6845}, /* SlateGray2 */ + {159, 182, 205, 6856}, /* SlateGray3 */ + {108, 123, 139, 6867}, /* SlateGray4 */ + {112, 128, 144, 6878}, /* SlateGrey */ + {255, 250, 250, 6888}, /* snow */ + {255, 250, 250, 6893}, /* snow1 */ + {238, 233, 233, 6899}, /* snow2 */ + {205, 201, 201, 6905}, /* snow3 */ + {139, 137, 137, 6911}, /* snow4 */ + {0, 255, 127, 6917}, /* spring green */ + {0, 255, 127, 6930}, /* SpringGreen */ + {0, 255, 127, 6942}, /* SpringGreen1 */ + {0, 238, 118, 6955}, /* SpringGreen2 */ + {0, 205, 102, 6968}, /* SpringGreen3 */ + {0, 139, 69, 6981}, /* SpringGreen4 */ + {70, 130, 180, 6994}, /* steel blue */ + {70, 130, 180, 7005}, /* SteelBlue */ + {99, 184, 255, 7015}, /* SteelBlue1 */ + {92, 172, 238, 7026}, /* SteelBlue2 */ + {79, 148, 205, 7037}, /* SteelBlue3 */ + {54, 100, 139, 7048}, /* SteelBlue4 */ + {210, 180, 140, 7059}, /* tan */ + {255, 165, 79, 7063}, /* tan1 */ + {238, 154, 73, 7068}, /* tan2 */ + {205, 133, 63, 7073}, /* tan3 */ + {139, 90, 43, 7078}, /* tan4 */ + {0, 128, 128, 7083}, /* teal */ + {216, 191, 216, 7088}, /* thistle */ + {255, 225, 255, 7096}, /* thistle1 */ + {238, 210, 238, 7105}, /* thistle2 */ + {205, 181, 205, 7114}, /* thistle3 */ + {139, 123, 139, 7123}, /* thistle4 */ + {255, 99, 71, 7132}, /* tomato */ + {255, 99, 71, 7139}, /* tomato1 */ + {238, 92, 66, 7147}, /* tomato2 */ + {205, 79, 57, 7155}, /* tomato3 */ + {139, 54, 38, 7163}, /* tomato4 */ + {64, 224, 208, 7171}, /* turquoise */ + {0, 245, 255, 7181}, /* turquoise1 */ + {0, 229, 238, 7192}, /* turquoise2 */ + {0, 197, 205, 7203}, /* turquoise3 */ + {0, 134, 139, 7214}, /* turquoise4 */ + {238, 130, 238, 7225}, /* violet */ + {208, 32, 144, 7232}, /* violet red */ + {208, 32, 144, 7243}, /* VioletRed */ + {255, 62, 150, 7253}, /* VioletRed1 */ + {238, 58, 140, 7264}, /* VioletRed2 */ + {205, 50, 120, 7275}, /* VioletRed3 */ + {139, 34, 82, 7286}, /* VioletRed4 */ + {128, 128, 128, 7297}, /* web gray */ + {0, 128, 0, 7306}, /* web green */ + {128, 128, 128, 7316}, /* web grey */ + {128, 0, 0, 7325}, /* web maroon */ + {128, 0, 128, 7336}, /* web purple */ + {128, 128, 128, 7347}, /* WebGray */ + {0, 128, 0, 7355}, /* WebGreen */ + {128, 128, 128, 7364}, /* WebGrey */ + {128, 0, 0, 7372}, /* WebMaroon */ + {128, 0, 128, 7382}, /* WebPurple */ + {245, 222, 179, 7392}, /* wheat */ + {255, 231, 186, 7398}, /* wheat1 */ + {238, 216, 174, 7405}, /* wheat2 */ + {205, 186, 150, 7412}, /* wheat3 */ + {139, 126, 102, 7419}, /* wheat4 */ + {255, 255, 255, 7426}, /* white */ + {245, 245, 245, 7432}, /* white smoke */ + {245, 245, 245, 7444}, /* WhiteSmoke */ + {190, 190, 190, 7455}, /* x11 gray */ + {0, 255, 0, 7464}, /* x11 green */ + {190, 190, 190, 7474}, /* x11 grey */ + {176, 48, 96, 7483}, /* x11 maroon */ + {160, 32, 240, 7494}, /* x11 purple */ + {190, 190, 190, 7505}, /* X11Gray */ + {0, 255, 0, 7513}, /* X11Green */ + {190, 190, 190, 7522}, /* X11Grey */ + {176, 48, 96, 7530}, /* X11Maroon */ + {160, 32, 240, 7540}, /* X11Purple */ + {255, 255, 0, 7550}, /* yellow */ + {154, 205, 50, 7557}, /* yellow green */ + {255, 255, 0, 7570}, /* yellow1 */ + {238, 238, 0, 7578}, /* yellow2 */ + {205, 205, 0, 7586}, /* yellow3 */ + {139, 139, 0, 7594}, /* yellow4 */ + {154, 205, 50, 7602}, /* YellowGreen */ +}; + +#define NUM_BUILTIN_COLORS (sizeof (BuiltinColors) / sizeof (BuiltinColors[0])) + +Bool +OsLookupColor(int screen, + char *name, + unsigned int len, + unsigned short *pred, + unsigned short *pgreen, unsigned short *pblue) +{ + const BuiltinColor *c; + int low, mid, high; + int r; + + low = 0; + high = NUM_BUILTIN_COLORS - 1; + while (high >= low) { + mid = (low + high) / 2; + c = &BuiltinColors[mid]; + r = strncasecmp(&BuiltinColorNames[c->name], name, len); + if (r == 0 && len == strlen(&BuiltinColorNames[c->name])) { + *pred = c->red * 0x101; + *pgreen = c->green * 0x101; + *pblue = c->blue * 0x101; + return TRUE; + } + if (r < 0) + low = mid + 1; + else + high = mid - 1; + } + return FALSE; +} diff --git a/nx-X11/programs/Xserver/os/osdep.h b/nx-X11/programs/Xserver/os/osdep.h new file mode 100644 index 000000000..d3e9d0b33 --- /dev/null +++ b/nx-X11/programs/Xserver/os/osdep.h @@ -0,0 +1,313 @@ +/*********************************************************** + +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 HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifndef _OSDEP_H_ +#define _OSDEP_H_ 1 + +#define BUFSIZE 4096 +#define BUFWATERMARK 8192 +#ifndef MAXBUFSIZE +#define MAXBUFSIZE (1 << 22) +#endif + +#include <X11/Xdmcp.h> + +#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 */ + +#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 +#if !defined(WIN32) +#define OPEN_MAX NOFILES_MAX +#else +#define OPEN_MAX 256 +#endif +#endif +#endif +#endif +#endif + +#include <nx-X11/Xpoll.h> + +/* + * MAXSOCKS is used only for initialising MaxClients when no other method + * like sysconf(_SC_OPEN_MAX) is not supported. + */ + +#if OPEN_MAX <= 256 +#define MAXSOCKS (OPEN_MAX - 1) +#else +#define MAXSOCKS 256 +#endif + +/* MAXSELECT is the number of fds that select() can handle */ +#define MAXSELECT (sizeof(fd_set) * NBBY) + +#if !defined(SVR4) && !defined(SYSV) +#define HAS_GETDTABLESIZE +#endif + +#include <stddef.h> + +typedef Bool (*ValidatorFunc)(ARRAY8Ptr Auth, ARRAY8Ptr Data, int packet_type); +typedef Bool (*GeneratorFunc)(ARRAY8Ptr Auth, ARRAY8Ptr Data, int packet_type); +typedef Bool (*AddAuthorFunc)(unsigned name_length, char *name, unsigned data_length, char *data); + +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; + unsigned int ignoreBytes; /* bytes to ignore before the next request */ +} ConnectionInput, *ConnectionInputPtr; + +typedef struct _connectionOutput { + struct _connectionOutput *next; + int size; + unsigned char *buf; + int count; +} ConnectionOutput, *ConnectionOutputPtr; + +struct _osComm; + +#define AuthInitArgs void +typedef void (*AuthInitFunc) (AuthInitArgs); + +#define AuthAddCArgs unsigned short data_length, char *data, XID id +typedef int (*AuthAddCFunc) (AuthAddCArgs); + +#define AuthCheckArgs unsigned short data_length, char *data, ClientPtr client, char **reason +typedef XID (*AuthCheckFunc) (AuthCheckArgs); + +#define AuthFromIDArgs XID id, unsigned short *data_lenp, char **datap +typedef int (*AuthFromIDFunc) (AuthFromIDArgs); + +#define AuthGenCArgs unsigned data_length, char *data, XID id, unsigned *data_length_return, char **data_return +typedef XID (*AuthGenCFunc) (AuthGenCArgs); + +#define AuthRemCArgs unsigned short data_length, char *data +typedef int (*AuthRemCFunc) (AuthRemCArgs); + +#define AuthRstCArgs void +typedef int (*AuthRstCFunc) (AuthRstCArgs); + +#define AuthToIDArgs unsigned short data_length, char *data +typedef XID (*AuthToIDFunc) (AuthToIDArgs); + +typedef void (*OsCloseFunc)(ClientPtr); + +typedef int (*OsFlushFunc)(ClientPtr who, struct _osComm * oc, char* extraBuf, int extraCount); + +typedef struct _osComm { + int fd; + ConnectionInputPtr input; + ConnectionOutputPtr output; + XID auth_id; /* authorization id */ + CARD32 conn_time; /* timestamp if not established, else 0 */ + struct _XtransConnInfo *trans_conn; /* transport connection object */ +} OsCommRec, *OsCommPtr; + +extern int FlushClient( + ClientPtr /*who*/, + OsCommPtr /*oc*/, + const void * /*__extraBuf*/, + int /*extraCount*/ +); + +extern void FreeOsBuffers( + OsCommPtr /*oc*/ +); + +extern void InitNotifyFds(void); + +extern void HandleNotifyFds(void); + +#include "dix.h" + +extern ConnectionInputPtr AllocateInputBuffer(void); + +extern ConnectionOutputPtr AllocateOutputBuffer(void); + +extern fd_set AllSockets; +extern fd_set AllClients; +extern fd_set LastSelectMask; +extern fd_set LastSelectWriteMask; +extern fd_set WellKnownConnections; +extern fd_set EnabledDevices; +extern fd_set NotifyReadFds; +extern fd_set NotifyWriteFds; +extern fd_set ClientsWithInput; +extern fd_set ClientsWriteBlocked; +extern fd_set OutputPending; +extern fd_set IgnoredClientsWithInput; + +#ifndef WIN32 +extern int *ConnectionTranslation; +#else +extern int GetConnectionTranslation(int conn); +extern void SetConnectionTranslation(int conn, int client); +extern void ClearConnectionTranslation(); +#endif + +extern Bool NewOutputPending; +extern Bool AnyWritesPending; +extern Bool NumNotifyWriteFd; +extern Bool CriticalOutputPending; + +extern int timesThisConnection; +extern ConnectionInputPtr FreeInputs; +extern ConnectionOutputPtr FreeOutputs; +extern OsCommPtr AvailableInput; + +extern WorkQueuePtr workQueue; + +/* added by raphael */ +#ifdef WIN32 +typedef long int fd_mask; +#endif +#define ffs mffs +extern int mffs(fd_mask); + +/* in access.c */ +extern Bool ComputeLocalClient(ClientPtr client); + +/* in auth.c */ +extern void GenerateRandomData (int len, char *buf); + +/* in mitauth.c */ +extern XID MitCheckCookie (AuthCheckArgs); +extern XID MitGenerateCookie (AuthGenCArgs); +extern XID MitToID (AuthToIDArgs); +extern int MitAddCookie (AuthAddCArgs); +extern int MitFromID (AuthFromIDArgs); +extern int MitRemoveCookie (AuthRemCArgs); +extern int MitResetCookie (AuthRstCArgs); + +/* in xdmauth.c */ +#ifdef HASXDMAUTH +extern XID XdmCheckCookie (AuthCheckArgs); +extern XID XdmToID (AuthToIDArgs); +extern int XdmAddCookie (AuthAddCArgs); +extern int XdmFromID (AuthFromIDArgs); +extern int XdmRemoveCookie (AuthRemCArgs); +extern int XdmResetCookie (AuthRstCArgs); +#endif + +/* in rpcauth.c */ +#ifdef SECURE_RPC +extern void SecureRPCInit (AuthInitArgs); +extern XID SecureRPCCheck (AuthCheckArgs); +extern XID SecureRPCToID (AuthToIDArgs); +extern int SecureRPCAdd (AuthAddCArgs); +extern int SecureRPCFromID (AuthFromIDArgs); +extern int SecureRPCRemove (AuthRemCArgs); +extern int SecureRPCReset (AuthRstCArgs); +#endif + +/* in secauth.c */ +extern XID AuthSecurityCheck (AuthCheckArgs); + +/* in xdmcp.c */ +extern void XdmcpUseMsg (void); +extern int XdmcpOptions(int argc, char **argv, int i); +extern void XdmcpSetAuthentication (ARRAY8Ptr name); +extern void XdmcpRegisterConnection ( + int type, + char *address, + int addrlen); +extern void XdmcpRegisterAuthorizations (void); +extern void XdmcpRegisterAuthorization (char *name, int namelen); +extern void XdmcpRegisterDisplayClass (char *name, int length); +extern void XdmcpInit (void); +extern void XdmcpReset (void); +extern void XdmcpOpenDisplay(int sock); +extern void XdmcpCloseDisplay(int sock); +extern void XdmcpRegisterAuthentication ( + char *name, + int namelen, + char *data, + int datalen, + ValidatorFunc Validator, + GeneratorFunc Generator, + AddAuthorFunc AddAuth); +extern int XdmcpCheckAuthentication (ARRAY8Ptr Name, ARRAY8Ptr Data, int packet_type); +extern int XdmcpAddAuthorization (ARRAY8Ptr name, ARRAY8Ptr data); + +struct sockaddr_in; +extern void XdmcpRegisterBroadcastAddress (struct sockaddr_in *addr); + +#ifdef HASXDMAUTH +extern void XdmAuthenticationInit (char *cookie, int cookie_length); +#endif + +#endif /* _OSDEP_H_ */ diff --git a/nx-X11/programs/Xserver/os/osinit.c b/nx-X11/programs/Xserver/os/osinit.c new file mode 100644 index 000000000..a660337ca --- /dev/null +++ b/nx-X11/programs/Xserver/os/osinit.c @@ -0,0 +1,234 @@ +/*********************************************************** + +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 HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stdio.h> +#include <nx-X11/X.h> +#include "os.h" +#include "osdep.h" +#include <nx-X11/Xos.h> + +#include "dixstruct.h" + +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif + +#if defined(__SCO__) +#include <sys/wait.h> +#endif + +#if !defined(SYSV) && !defined(WIN32) +#include <sys/resource.h> +#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 + +void +OsInit(void) +{ + 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) { + + InitNotifyFds(); + +#if !defined(__SCO__) && !defined(__CYGWIN__) && !defined(__UNIXWARE__) + fclose(stdin); + fclose(stdout); +#endif + + + /* + * 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) || defined(__CYGWIN__) + { + 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 0 + if (rlim.rlim_cur > MAXSOCKS) + rlim.rlim_cur = MAXSOCKS; +#endif + (void)setrlimit(RLIMIT_NOFILE, &rlim); + } + } +#endif +#ifdef SERVER_LOCK + LockServer(); +#endif + been_here = TRUE; + } + TimerInit(); +#ifdef DDXOSINIT + OsVendorInit(); +#endif + /* + * No log file by default. OsVendorInit() should call LogInit() with the + * log file name if logging to a file is desired. + */ + LogInit(NULL, NULL); + SmartScheduleInit(); + + OsInitAllocator(); +} + +void +OsCleanup(Bool terminating) +{ +#ifdef SERVER_LOCK + if (terminating) + { + UnlockServer(); + } +#endif +} diff --git a/nx-X11/programs/Xserver/os/reallocarray.c b/nx-X11/programs/Xserver/os/reallocarray.c new file mode 100644 index 000000000..c415e09af --- /dev/null +++ b/nx-X11/programs/Xserver/os/reallocarray.c @@ -0,0 +1,43 @@ +/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */ +/* + * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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 HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <sys/types.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include "os.h" + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) + +void * +reallocarray(void *optr, size_t nmemb, size_t size) +{ + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return NULL; + } + return realloc(optr, size * nmemb); +} diff --git a/nx-X11/programs/Xserver/os/rpcauth.c b/nx-X11/programs/Xserver/os/rpcauth.c new file mode 100644 index 000000000..678bedf6c --- /dev/null +++ b/nx-X11/programs/Xserver/os/rpcauth.c @@ -0,0 +1,201 @@ +/* + +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 HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef SECURE_RPC + +#include <nx-X11/X.h> +#include <nx-X11/Xauth.h> +#include "misc.h" +#include "os.h" +#include "dixstruct.h" + +#include <rpc/rpc.h> + +#ifdef sun +/* <rpc/auth.h> only includes this if _KERNEL is #defined... */ +extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *); +#endif + +#ifdef ultrix +#include <time.h> +#include <rpc/auth_des.h> +#endif + +static enum auth_stat why; + +static char * +authdes_ezdecode(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 *) malloc(len); + if (temp_inmsg == NULL) { + why = AUTH_FAILED; /* generic error, since there is no AUTH_BADALLOC */ + return NULL; + } + 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) malloc(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: + free(r.rq_clntcred); +bad1: + return ((char *)0); /* ((struct authdes_cred *) NULL); */ +} + +static XID rpc_id = (XID) ~0L; + +static Bool +CheckNetName ( + unsigned char *addr, + short len, + void * closure +) +{ + return (len == strlen ((char *) closure) && + strncmp ((char *) addr, (char *) closure, len) == 0); +} + +static char rpc_error[MAXNETNAMELEN+50]; + +XID +SecureRPCCheck (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, fullname)) + return rpc_id; + sprintf(rpc_error, "Principal \"%s\" is not authorized to connect", + fullname); + *reason = rpc_error; + } + } + return (XID) ~0L; +} + +void +SecureRPCInit (void) +{ + if (rpc_id == ~0L) + AddAuthorization (9, "SUN-DES-1", 0, (char *) 0); +} + +int +SecureRPCAdd (unsigned short data_length, char *data, XID id) +{ + if (data_length) + AddHost ((void *) 0, FamilyNetname, data_length, data); + rpc_id = id; + return 1; +} + +int +SecureRPCReset (void) +{ + rpc_id = (XID) ~0L; + return 1; +} + +XID +SecureRPCToID (unsigned short data_length, char *data) +{ + return rpc_id; +} + +int +SecureRPCFromID (XID id, unsigned short *data_lenp, char **datap) +{ + return 0; +} + +int +SecureRPCRemove (unsigned short data_length, char *data) +{ + return 0; +} +#endif /* SECURE_RPC */ diff --git a/nx-X11/programs/Xserver/os/secauth.c b/nx-X11/programs/Xserver/os/secauth.c new file mode 100644 index 000000000..5219b488a --- /dev/null +++ b/nx-X11/programs/Xserver/os/secauth.c @@ -0,0 +1,203 @@ +/* +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. +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <nx-X11/X.h> +#include "os.h" +#include "osdep.h" +#include "dixstruct.h" +#include "swaprep.h" + +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <nx-X11/extensions/security.h> +#endif + +static char InvalidPolicyReason[] = "invalid policy specification"; +static char PolicyViolationReason[] = "policy violation"; + +static Bool +AuthCheckSitePolicy( + 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) { + 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 ( + unsigned short data_length, + char *data, + ClientPtr client, + char **reason) +{ +#ifdef XCSECURITY + 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 + WriteToClient(client, sz_xConnSetupPrefix, &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/nx-X11/programs/Xserver/os/strlcat.c b/nx-X11/programs/Xserver/os/strlcat.c new file mode 100644 index 000000000..fc137cabb --- /dev/null +++ b/nx-X11/programs/Xserver/os/strlcat.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE + * FOR ANY SPECIAL, DIRECT, 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 HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <sys/types.h> +#include <string.h> + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} diff --git a/nx-X11/programs/Xserver/os/strlcpy.c b/nx-X11/programs/Xserver/os/strlcpy.c new file mode 100644 index 000000000..989d0385e --- /dev/null +++ b/nx-X11/programs/Xserver/os/strlcpy.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE + * FOR ANY SPECIAL, DIRECT, 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 HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include <sys/types.h> +#include <string.h> + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} diff --git a/nx-X11/programs/Xserver/os/timingsafe_memcmp.c b/nx-X11/programs/Xserver/os/timingsafe_memcmp.c new file mode 100644 index 000000000..fe87de7bc --- /dev/null +++ b/nx-X11/programs/Xserver/os/timingsafe_memcmp.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014 Google Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +#include <limits.h> +#include <string.h> +#include <nx-X11/Xfuncproto.h> +#include "os.h" + +int +timingsafe_memcmp(const void *b1, const void *b2, size_t len) +{ + const unsigned char *p1 = b1, *p2 = b2; + size_t i; + int res = 0, done = 0; + + for (i = 0; i < len; i++) { + /* lt is -1 if p1[i] < p2[i]; else 0. */ + int lt = (p1[i] - p2[i]) >> CHAR_BIT; + + /* gt is -1 if p1[i] > p2[i]; else 0. */ + int gt = (p2[i] - p1[i]) >> CHAR_BIT; + + /* cmp is 1 if p1[i] > p2[i]; -1 if p1[i] < p2[i]; else 0. */ + int cmp = lt - gt; + + /* set res = cmp if !done. */ + res |= cmp & ~done; + + /* set done if p1[i] != p2[i]. */ + done |= lt | gt; + } + + return (res); +} diff --git a/nx-X11/programs/Xserver/os/utils.c b/nx-X11/programs/Xserver/os/utils.c new file mode 100644 index 000000000..dd637ca4b --- /dev/null +++ b/nx-X11/programs/Xserver/os/utils.c @@ -0,0 +1,2260 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ +/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */ +/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/ +/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */ +/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */ +/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */ +/* */ +/* nx-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of the aforementioned persons and companies. */ +/* */ +/* Redistribution and use of the present software is allowed according */ +/* to terms specified in the file LICENSE which comes in the source */ +/* distribution. */ +/* */ +/* All rights reserved. */ +/* */ +/* NOTE: This software has received contributions from various other */ +/* contributors, only the core maintainers and supporters are listed as */ +/* copyright holders. Please contact us, if you feel you should be listed */ +/* as copyright holder, as well. */ +/* */ +/**************************************************************************/ + +/* + +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 HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef __CYGWIN__ +#include <stdlib.h> +#include <signal.h> +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) +#include <nx-X11/Xwinsock.h> +#endif +#include <nx-X11/Xos.h> +#include <stdio.h> +#include "misc.h" +#include <nx-X11/X.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <nx-X11/Xtrans/Xtrans.h> +#include "input.h" +#include "dixfont.h" +#ifdef HAS_XFONT2 +# include <X11/fonts/libxfont2.h> +#else +# include <X11/fonts/fontutil.h> +#endif /* HAS_XFONT2 */ +#include "osdep.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 +#include <sys/wait.h> +#endif +#if !defined(SYSV) && !defined(WIN32) +#include <sys/resource.h> +#endif +#include <time.h> +#include <sys/stat.h> +#include <ctype.h> /* for isspace */ +#include <stdarg.h> +#include <sys/types.h> +#include <grp.h> +#include <pwd.h> + +#include <stdlib.h> /* for malloc() */ + +#if defined(TCPCONN) +# ifndef WIN32 +# include <netdb.h> +# endif +#endif + +#include "opaque.h" + +#include "dixstruct.h" + +#ifdef XKB +#include "xkbsrv.h" +#endif +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <nx-X11/extensions/security.h> +#endif + +#ifdef RENDER +#include "picture.h" +#endif + +Bool noTestExtensions; +#ifdef BIGREQS +Bool noBigReqExtension = FALSE; +#endif +#ifdef COMPOSITE +/* COMPOSITE is disabled by default for now until the + * interface is stable */ +Bool noCompositeExtension = TRUE; +#endif +#ifdef DAMAGE +Bool noDamageExtension = FALSE; +#endif +#ifdef DBE +Bool noDbeExtension = FALSE; +#endif +#ifdef DPSEXT +Bool noDPSExtension = FALSE; +#endif +#ifdef DPMSExtension +Bool noDPMSExtension = FALSE; +#endif +#ifdef GLXEXT +Bool noGlxExtension = FALSE; +#endif +#ifdef SCREENSAVER +Bool noScreenSaverExtension = FALSE; +#endif +#ifdef MITSHM +Bool noMITShmExtension = FALSE; +#endif +#ifdef RANDR +Bool noRRExtension = FALSE; +Bool noRRXineramaExtension = FALSE; +#endif +#ifdef RENDER +Bool noRenderExtension = FALSE; +#endif +#ifdef SHAPE +Bool noShapeExtension = FALSE; +#endif +#ifdef XCSECURITY +Bool noSecurityExtension = FALSE; +#endif +#ifdef XSYNC +Bool noSyncExtension = FALSE; +#endif +#ifdef RES +Bool noResExtension = FALSE; +#endif +#ifdef XCMISC +Bool noXCMiscExtension = FALSE; +#endif +#ifdef XF86BIGFONT +Bool noXFree86BigfontExtension = FALSE; +#endif +#ifdef XF86DRI +Bool noXFree86DRIExtension = FALSE; +#endif +#ifdef XFIXES +Bool noXFixesExtension = FALSE; +#endif +/* |noXkbExtension| is defined in xc/programs/Xserver/xkb/xkbInit.c */ +#ifdef PANORAMIX +/* Xinerama is disabled by default unless enabled via +xinerama */ +Bool noPanoramiXExtension = TRUE; +#endif +#ifdef XINPUT +Bool noXInputExtension = FALSE; +#endif +#ifdef XIDLE +Bool noXIdleExtension = FALSE; +#endif +#ifdef XV +Bool noXvExtension = FALSE; +#endif + +#define X_INCLUDE_NETDB_H +#include <nx-X11/Xos_r.h> + +#include <errno.h> + +#ifdef NX_TRANS_SOCKET + +#include <nx/NX.h> +#include <nx/NXvars.h> + +#endif + +#ifdef NX_TRANS_EXIT + +void (*OsVendorStartRedirectErrorFProc)() = NULL; +void (*OsVendorEndRedirectErrorFProc)() = NULL; + +#endif + +Bool CoreDump; + +#ifdef PANORAMIX +Bool PanoramiXVisibilityNotifySent = FALSE; +Bool PanoramiXMapped = FALSE; +Bool PanoramiXWindowExposureSent = FALSE; +Bool PanoramiXOneExposeRequest = FALSE; +Bool PanoramiXExtensionDisabledHack = FALSE; +#endif + +int auditTrailLevel = 1; + +Bool Must_have_memory = FALSE; + +#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED) +#define HAS_SAVED_IDS_AND_SETEUID +#endif + +#ifdef MEMBUG +#define MEM_FAIL_SCALE 100000 +long Memory_fail = 0; +#include <stdlib.h> /* for random() */ +#endif + +char *dev_tty_from_init = NULL; /* since we need to parse it anyway */ + +extern char dispatchExceptionAtReset; + +/* Extension enable/disable in miinitext.c */ +extern Bool EnableDisableExtension(char *name, Bool enable); +extern void EnableDisableExtensionError(char *name, Bool enable); + +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; + if (sigaction(sig, &act, &oact)) + perror("sigaction"); + return oact.sa_handler; +#endif +} + +#ifdef SERVER_LOCK +/* + * Explicit support for a server lock file like the ones used for UUCP. + * For architectures with virtual terminals that can run more than one + * server at a time. This keeps the servers from stomping on each other + * if the user forgets to give them different display numbers. + */ +#define LOCK_DIR "/tmp" +#define LOCK_TMP_PREFIX "/.tX" +#define LOCK_PREFIX "/.X" +#define LOCK_SUFFIX "-lock" + +#ifndef PATH_MAX +#include <sys/param.h> +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif +#endif + +static Bool StillLocking = FALSE; +static char LockFile[PATH_MAX]; +static Bool nolock = FALSE; + +/* + * LockServer -- + * Check if the server lock file exists. If so, check if the PID + * contained inside is valid. If so, then die. Otherwise, create + * the lock file containing the PID. + */ +void +LockServer(void) +{ + char tmp[PATH_MAX], pid_str[12]; + int lfd, i, haslock, l_pid, t; + char *tmppath = NULL; + int len; + char port[20]; + + if (nolock || NoListenAll) return; + /* + * Path names + */ + tmppath = LOCK_DIR; + + sprintf(port, "%d", atoi(display)); + len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) : + strlen(LOCK_TMP_PREFIX); + len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1; + if (len > sizeof(LockFile)) + FatalError("Display name `%s' is too long\n", port); + (void)sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port); + (void)sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port); + + /* + * Create a temporary file containing our PID. Attempt three times + * to create the file. + */ + StillLocking = TRUE; + i = 0; + do { + i++; + lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); + if (lfd < 0) + sleep(2); + else + break; + } while (i < 3); + if (lfd < 0) { + unlink(tmp); + i = 0; + do { + i++; + lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); + if (lfd < 0) + sleep(2); + else + break; + } while (i < 3); + } + if (lfd < 0) + FatalError("Could not create lock file in %s\n", tmp); + (void) sprintf(pid_str, "%10ld\n", (long)getpid()); + if (write(lfd, pid_str, 11) != 11) + FatalError("Could not write pid to lock file in %s\n", tmp); + +#ifndef USE_CHMOD + (void) fchmod(lfd, 0444); +#else + (void) chmod(tmp, 0444); +#endif + (void) close(lfd); + + /* + * OK. Now the tmp file exists. Try three times to move it in place + * for the lock. + */ + i = 0; + haslock = 0; + while ((!haslock) && (i++ < 3)) { + haslock = (link(tmp,LockFile) == 0); + if (haslock) { + /* + * We're done. + */ + break; + } + else { + /* + * Read the pid from the existing file + */ + lfd = open(LockFile, O_RDONLY|O_NOFOLLOW); + if (lfd < 0) { + unlink(tmp); + FatalError("Can't read lock file %s\n", LockFile); + } + pid_str[0] = '\0'; + if (read(lfd, pid_str, 11) != 11) { + /* + * Bogus lock file. + */ + unlink(LockFile); + close(lfd); + continue; + } + pid_str[11] = '\0'; + sscanf(pid_str, "%d", &l_pid); + close(lfd); + + /* + * Now try to kill the PID to see if it exists. + */ + errno = 0; + t = kill(l_pid, 0); + if ((t< 0) && (errno == ESRCH)) { + /* + * Stale lock file. + */ + unlink(LockFile); + continue; + } + else if (((t < 0) && (errno == EPERM)) || (t == 0)) { + /* + * Process is still active. + */ + unlink(tmp); + FatalError("Server is already active for display %s\n%s %s\n%s\n", + port, "\tIf this server is no longer running, remove", + LockFile, "\tand start again."); + } + } + } + unlink(tmp); + if (!haslock) + FatalError("Could not create server lock file: %s\n", LockFile); + StillLocking = FALSE; +} + +/* + * UnlockServer -- + * Remove the server lock file. + */ +void +UnlockServer(void) +{ + if (nolock || NoListenAll) return; + + if (!StillLocking){ + + (void) unlink(LockFile); + } +} +#endif /* SERVER_LOCK */ + +/* Force connections to close on SIGHUP from init */ + +/*ARGSUSED*/ +SIGVAL +AutoResetServer (int sig) +{ + int olderrno = errno; + + dispatchException |= DE_RESET; + isItTimeToYield = TRUE; +#ifdef GPROF + chdir ("/tmp"); + exit (0); +#endif +#if defined(SYSV) && defined(X_NOT_POSIX) + OsSignal (SIGHUP, AutoResetServer); +#endif + errno = olderrno; +} + +/* Force connections to close and then exit on SIGTERM, SIGINT */ + +/*ARGSUSED*/ +SIGVAL +GiveUp(int sig) +{ + int olderrno = errno; + +#if defined(NX_TRANS_SOCKET) && defined(NX_TRANS_TEST) + fprintf(stderr, "GiveUp: Called with signal [%d].\n", sig); +#endif + + dispatchException |= DE_TERMINATE; + isItTimeToYield = TRUE; +#if defined(SYSV) && defined(X_NOT_POSIX) + if (sig) + OsSignal(sig, SIG_IGN); +#endif + errno = olderrno; +} + +#ifndef DDXTIME +CARD32 +GetTimeInMillis(void) +{ + struct timeval tp; + + X_GETTIMEOFDAY(&tp); + return(tp.tv_sec * 1000) + (tp.tv_usec / 1000); +} +#endif + +void +AdjustWaitForDelay (void * 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(void) +{ + 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("-br create root window with black background\n"); + ErrorF("+bs enable any backing store support\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"); +#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 +#ifdef SERVER_LOCK + ErrorF("-nolock disable the locking mechanism\n"); +#endif +#ifndef NOLOGOHACK + ErrorF("-logo enable logo in screen saver\n"); + ErrorF("nologo disable logo in screen saver\n"); +#endif + ErrorF("-nolisten string don't listen on protocol\n"); + ErrorF("-noreset don't reset after last client exists\n"); + ErrorF("-reset reset after last client exists\n"); + ErrorF("-p # screen-saver pattern duration (minutes)\n"); + ErrorF("-pn accept failure to listen on all ports\n"); + ErrorF("-nopn reject failure to listen on all ports\n"); + ErrorF("-r turns off auto-repeat\n"); + ErrorF("r turns on auto-repeat \n"); +#ifdef RENDER + ErrorF("-render [default|mono|gray|color] set render color alloc policy\n"); +#endif + 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"); + ErrorF("-maxbigreqsize set maximal bigrequest size \n"); +#ifdef PANORAMIX + ErrorF("+xinerama Enable XINERAMA (PanoramiX) extension\n"); + ErrorF("-xinerama Disable XINERAMA (PanoramiX) extension (default)\n"); + ErrorF("-disablexineramaextension Disable XINERAMA extension\n"); +#endif +#ifdef RANDR + ErrorF("+rrxinerama Enable XINERAMA (via RandR) extension (default)\n"); + ErrorF("-rrxinerama Disable XINERAMA (via RandR) extension\n"); +#endif + ErrorF("-dumbSched Disable smart scheduling, enable old behavior\n"); + ErrorF("-schedInterval int Set scheduler interval in msec\n"); + ErrorF("+extension name Enable extension\n"); + ErrorF("-extension name Disable extension\n"); +#ifdef XDMCP + XdmcpUseMsg(); +#endif +#ifdef XKB + XkbUseMsg(); +#endif + ddxUseMsg(); +} + +/* This function performs a rudimentary sanity check + * on the display name passed in on the command-line, + * since this string is used to generate filenames. + * It is especially important that the display name + * not contain a "/" and not start with a "-". + * --kvajk + */ +static int +VerifyDisplayName(const char *d) +{ + if ( d == (char *)0 ) return( 0 ); /* null */ + if ( *d == '\0' ) return( 0 ); /* empty */ + if ( *d == '-' ) return( 0 ); /* could be confused for an option */ + if ( *d == '.' ) return( 0 ); /* must not equal "." or ".." */ + if ( strchr(d, '/') != (char *)0 ) return( 0 ); /* very important!!! */ + return( 1 ); +} + +/* + * This function is responsible for doing initalisation of any global + * variables at an very early point of server startup (even before + * |ProcessCommandLine()|. + */ +void InitGlobals(void) +{ + ddxInitGlobals(); +} + + +/* + * 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(int argc, char *argv[]) +{ + int i, skip; + + defaultKeyboardControl.autoRepeat = TRUE; + +#ifdef NO_PART_NET + PartialNetwork = FALSE; +#else + PartialNetwork = TRUE; +#endif + + 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]; + explicit_display = TRUE; + display++; + if( ! VerifyDisplayName( display ) ) { + ErrorF("Bad display name: %s\n", display); + UseMsg(); + FatalError("Bad display name, exiting: %s\n", 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], "-br") == 0) + blackRoot = TRUE; + else if ( strcmp( argv[i], "+bs") == 0) + enableBackingStore = 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], "-core") == 0) + CoreDump = TRUE; + else if ( strcmp( argv[i], "-dpi") == 0) + { + if(++i < argc) + monitorResolution = atoi(argv[i]); + else + UseMsg(); + } + else if (strcmp(argv[i], "-displayfd") == 0) { + if (++i < argc) { + displayfd = atoi(argv[i]); + nolock = TRUE; + } + 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) + { +#ifdef HAS_XFONT2 + if(++i >= argc || !!xfont2_parse_glyph_caching_mode(argv[i])) +#else + if(++i >= argc || !ParseGlyphCachingMode(argv[i])) +#endif /* HAS_XFONT2 */ + 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) + { + 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 +#ifdef SERVER_LOCK + else if ( strcmp ( argv[i], "-nolock") == 0) + { +#if !defined(WIN32) && !defined(__CYGWIN__) + if (getuid() != 0) + ErrorF("Warning: the -nolock option can only be used by root\n"); + else +#endif + nolock = TRUE; + } +#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], "-nolisten") == 0) + { + if(++i < argc) { +#ifdef NXAGENT_SERVER + if (strcmp( argv[i], "ANY" ) == 0) + NoListenAll = TRUE; + else +#endif /* NXAGENT_SERVER */ + if (_XSERVTransNoListen(argv[i])) + FatalError ("Failed to disable listen for %s transport", + argv[i]); + } else + UseMsg(); + } + else if ( strcmp( argv[i], "-noreset") == 0) + { + dispatchExceptionAtReset = 0; + } + else if ( strcmp( argv[i], "-reset") == 0) + { + dispatchExceptionAtReset = DE_RESET; + } + 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], "-nopn") == 0) + PartialNetwork = FALSE; + 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) + { + dispatchExceptionAtReset = DE_TERMINATE; + } + 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; + else if ( strcmp( argv[i], "-maxbigreqsize") == 0) { + if(++i < argc) { + long reqSizeArg = atol(argv[i]); + + /* Request size > 128MB does not make much sense... */ + if( reqSizeArg > 0L && reqSizeArg < 128L ) { + maxBigRequestSize = (reqSizeArg * 1048576L) - 1L; + } + else + { + UseMsg(); + } + } + else + { + UseMsg(); + } + } +#ifdef PANORAMIX + else if ( strcmp( argv[i], "+xinerama") == 0){ + noPanoramiXExtension = FALSE; + } + else if ( strcmp( argv[i], "-xinerama") == 0){ + noPanoramiXExtension = TRUE; + } + else if ( strcmp( argv[i], "-disablexineramaextension") == 0){ + PanoramiXExtensionDisabledHack = TRUE; + } +#endif +#ifdef RANDR + else if ( strcmp( argv[i], "+rrxinerama") == 0){ + noRRXineramaExtension = FALSE; + } + else if ( strcmp( argv[i], "-rrxinerama") == 0){ + noRRXineramaExtension = TRUE; + } +#endif + 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 XCSECURITY + else if ((skip = XSecurityOptions(argc, argv, i)) != i) + { + i = skip - 1; + } +#endif +#if HAVE_SETITIMER + else if ( strcmp( argv[i], "-dumbSched") == 0) + { + SmartScheduleSignalEnable = FALSE; + } +#endif + else if ( strcmp( argv[i], "-schedInterval") == 0) + { + if (++i < argc) + { + SmartScheduleInterval = atoi(argv[i]); + SmartScheduleSlice = SmartScheduleInterval; + } + else + UseMsg(); + } + else if ( strcmp( argv[i], "-schedMax") == 0) + { + if (++i < argc) + { + SmartScheduleMaxSlice = atoi(argv[i]); + } + else + UseMsg(); + } +#ifdef RENDER + else if ( strcmp( argv[i], "-render" ) == 0) + { + if (++i < argc) + { + int policy = PictureParseCmapPolicy (argv[i]); + + if (policy != PictureCmapPolicyInvalid) + PictureCmapPolicy = policy; + else + UseMsg (); + } + else + UseMsg (); + } +#endif + else if ( strcmp( argv[i], "+extension") == 0) + { + if (++i < argc) + { + if (!EnableDisableExtension(argv[i], TRUE)) + EnableDisableExtensionError(argv[i], TRUE); + } + else + UseMsg(); + } + else if ( strcmp( argv[i], "-extension") == 0) + { + if (++i < argc) + { + if (!EnableDisableExtension(argv[i], FALSE)) + EnableDisableExtensionError(argv[i], FALSE); + } + else + UseMsg(); + } + else + { + ErrorF("Unrecognized option: %s\n", argv[i]); + UseMsg(); + FatalError("Unrecognized option: %s\n", argv[i]); + } + } +} + +#ifdef COMMANDLINE_CHALLENGED_OPERATING_SYSTEMS +static void +InsertFileIntoCommandLine( + 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 *) malloc((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 *) realloc(buf, q - buf); + if (!buf) + FatalError("Out of memory reallocing option buf\n"); + + *resargc = prefix_argc + insert_argc + suffix_argc; + *resargv = (char **) malloc((*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(int *pargc, char ***pargv) +{ + int i; + +#if !defined(WIN32) && !defined(__CYGWIN__) + if (getuid() != geteuid()) + return; +#endif + + 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(char **authorizations, int *authlen, void * client) +{ +#define AUTHORIZATION_NAME "hp-hostname-1" +#if defined(TCPCONN) + static char *result = NULL; + static char *p = NULL; + + if (p == NULL) + { + char hname[1024], *hnameptr; + unsigned int len; +#if defined(IPv6) && defined(AF_INET6) + struct addrinfo hints, *ai = NULL; +#else + struct hostent *host; +#ifdef XTHREADS_NEEDS_BYNAMEPARAMS + _Xgethostbynameparams hparams; +#endif +#endif + + gethostname(hname, 1024); +#if defined(IPv6) && defined(AF_INET6) + bzero(&hints, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + if (getaddrinfo(hname, NULL, &hints, &ai) == 0) { + hnameptr = ai->ai_canonname; + } else { + hnameptr = hname; + } +#else + host = _XGethostbyname(hname, hparams); + if (host == NULL) + hnameptr = hname; + else + hnameptr = host->h_name; +#endif + + len = strlen(hnameptr) + 1; + result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4); + + p = result; + *p++ = sizeof(AUTHORIZATION_NAME) >> 8; + *p++ = sizeof(AUTHORIZATION_NAME) & 0xff; + *p++ = (len) >> 8; + *p++ = (len & 0xff); + + memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME)); + p += sizeof(AUTHORIZATION_NAME); + memmove(p, hnameptr, len); + p += len; +#if defined(IPv6) && defined(AF_INET6) + if (ai) { + freeaddrinfo(ai); + } +#endif + } + *authlen = p - result; + *authorizations = result; + return 1; +#else /* TCPCONN */ + return 0; +#endif /* TCPCONN */ +} + +/***************** + * XNFalloc + * "no failure" alloc + *****************/ + +void * +XNFalloc(unsigned long amount) +{ + void *ptr = malloc(amount); + if (!ptr) + { + FatalError("Out of memory"); + } + return ptr; +} + +/***************** + * XNFcalloc + *****************/ + +void * +XNFcalloc(unsigned long amount) +{ + void *ret = calloc(1, amount); + if (!ret) + FatalError("XNFcalloc: Out of memory"); + return ret; +} + +/***************** + * XNFrealloc + * "no failure" realloc + *****************/ + +void * +XNFrealloc(void * ptr, unsigned long amount) +{ + void *ret = realloc(ptr, amount); + if (!ret) + FatalError("XNFrealloc: Out of memory"); + return ret; +} + +void +OsInitAllocator (void) +{ +#ifdef MEMBUG + static int been_here; + + /* Check the memory system after each generation */ + if (been_here) + CheckMemory (); + else + been_here = 1; +#endif +} + +char * +Xstrdup(const char *s) +{ + if (s == NULL) + return NULL; + return strdup(s); +} + + +char * +XNFstrdup(const char *s) +{ + char *ret; + + if (s == NULL) + return NULL; + + ret = strdup(s); + if (!ret) + FatalError("XNFstrdup: Out of memory"); + return ret; +} + +void +SmartScheduleStopTimer (void) +{ +#if HAVE_SETITIMER + struct itimerval timer; + + if (!SmartScheduleSignalEnable) + return; + + #ifdef NX_TRANS_TEST + fprintf(stderr, "SmartScheduleStopTimer: Stopping timer.\n"); + #endif + + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = 0; + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = 0; + (void) setitimer (ITIMER_REAL, &timer, 0); +#endif +} + +void +SmartScheduleStartTimer (void) +{ +#if HAVE_SETITIMER + struct itimerval timer; + + if (!SmartScheduleSignalEnable) + return; + + #ifdef NX_TRANS_TEST + fprintf(stderr, "SmartScheduleStartTimer: Starting timer with [%ld] ms.\n", + SmartScheduleInterval); + #endif + + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = SmartScheduleInterval * 1000; + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = SmartScheduleInterval * 1000; + setitimer (ITIMER_REAL, &timer, 0); +#endif +} + +#if HAVE_SETITIMER +static void +SmartScheduleTimer (int sig) +{ + SmartScheduleTime += SmartScheduleInterval; + + #ifdef NX_TRANS_TEST + fprintf(stderr, "SmartScheduleTimer: Got timer with time [%ld] ms.\n", + SmartScheduleTime); + #endif +} + +int +SmartScheduleEnable (void) +{ + int ret = 0; + struct sigaction act; + + if (!SmartScheduleSignalEnable) + return 0; + + #ifdef NX_TRANS_TEST + fprintf(stderr, "SmartScheduleEnable: Enabling the smart scheduler.\n"); + #endif + + memset((char *) &act, 0, sizeof(struct sigaction)); + + /* Set up the timer signal function */ + act.sa_flags = SA_RESTART; + act.sa_handler = SmartScheduleTimer; + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGALRM); + ret = sigaction(SIGALRM, &act, 0); + return ret; +} + +static int +SmartSchedulePause(void) +{ + int ret = 0; + struct sigaction act; + + if (!SmartScheduleSignalEnable) + return 0; + + #ifdef NX_TRANS_TEST + fprintf(stderr, "SmartSchedulePause: Pausing the smart scheduler.\n"); + #endif + + memset((char *) &act, 0, sizeof(struct sigaction)); + + act.sa_handler = SIG_IGN; + sigemptyset(&act.sa_mask); + ret = sigaction(SIGALRM, &act, 0); + return ret; +} +#endif + +void +SmartScheduleInit(void) +{ +#if HAVE_SETITIMER + #ifdef NX_TRANS_TEST + fprintf(stderr, "SmartScheduleInit: Initializing the smart scheduler.\n"); + #endif + + if (SmartScheduleEnable() < 0) { + perror("sigaction for smart scheduler"); + SmartScheduleSignalEnable = FALSE; + } +#endif +} + +#ifdef SIG_BLOCK +static sigset_t PreviousSignalMask; +static int BlockedSignalCount; +#endif + +void +OsBlockSignals (void) +{ +#ifdef SIG_BLOCK + if (BlockedSignalCount++ == 0) + { + sigset_t set; + + sigemptyset (&set); +#ifdef SIGALRM + sigaddset (&set, SIGALRM); +#endif +#ifdef SIGVTALRM + sigaddset (&set, SIGVTALRM); +#endif +#ifdef SIGWINCH + sigaddset (&set, SIGWINCH); +#endif +#ifdef SIGIO + sigaddset (&set, SIGIO); +#endif +#ifdef SIGTSTP + sigaddset (&set, SIGTSTP); +#endif +#ifdef SIGTTIN + sigaddset (&set, SIGTTIN); +#endif +#ifdef SIGTTOU + sigaddset (&set, SIGTTOU); +#endif +#ifdef SIGCHLD + sigaddset (&set, SIGCHLD); +#endif + sigprocmask (SIG_BLOCK, &set, &PreviousSignalMask); + } +#endif +} + +void +OsReleaseSignals (void) +{ +#ifdef SIG_BLOCK + if (--BlockedSignalCount == 0) + { + sigprocmask (SIG_SETMASK, &PreviousSignalMask, 0); + } +#endif +} + +#if !defined(WIN32) +/* + * "safer" versions of system(3), popen(3) and pclose(3) which give up + * all privs before running a command. + * + * This is based on the code in FreeBSD 2.2 libc. + * + * XXX It'd be good to redirect stderr so that it ends up in the log file + * as well. As it is now, xkbcomp messages don't end up in the log file. + */ + +int +System(char *command) +{ + int pid, p; +#ifdef SIGCHLD + void (*csig)(int); +#endif + int status; + struct passwd *pwent; + + if (!command) + return(1); + +#ifdef SIGCHLD + csig = OsSignal(SIGCHLD, SIG_DFL); + if (csig == SIG_ERR) { + perror("signal"); + return -1; + } +#endif + +#ifdef DEBUG + ErrorF("System: `%s'\n", command); +#endif + +#ifdef NX_TRANS_EXIT + if (OsVendorStartRedirectErrorFProc != NULL) { + OsVendorStartRedirectErrorFProc(); + } +#endif + switch (pid = fork()) { + case -1: /* error */ + p = -1; + case 0: /* child */ + pwent = getpwuid(getuid()); + if (initgroups(pwent->pw_name,getgid()) == -1) + _exit(127); + if (setgid(getgid()) == -1) + _exit(127); + if (setuid(getuid()) == -1) + _exit(127); + execl("/bin/sh", "sh", "-c", command, (char *)NULL); + _exit(127); + default: /* parent */ + do { + p = waitpid(pid, &status, 0); + } while (p == -1 && errno == EINTR); + + } +#ifdef NX_TRANS_EXIT + if (OsVendorEndRedirectErrorFProc != NULL) { + OsVendorEndRedirectErrorFProc(); + } +#endif + +#ifdef SIGCHLD + if (OsSignal(SIGCHLD, csig) == SIG_ERR) { + perror("signal"); + return -1; + } +#endif + + return p == -1 ? -1 : status; +} + +static struct pid { + struct pid *next; + FILE *fp; + int pid; +} *pidlist; + +void * +Popen(char *command, char *type) +{ + struct pid *cur; + FILE *iop; + int pdes[2], pid; + + if (command == NULL || type == NULL) + return NULL; + + if ((*type != 'r' && *type != 'w') || type[1]) + return NULL; + + if ((cur = (struct pid *)malloc(sizeof(struct pid))) == NULL) + return NULL; + + if (pipe(pdes) < 0) { + free(cur); + return NULL; + } + + /* Ignore the smart scheduler while this is going on */ +#if HAVE_SETITIMER + if (SmartSchedulePause() < 0) { + close(pdes[0]); + close(pdes[1]); + free(cur); + perror("signal"); + return NULL; + } +#endif + +#ifdef NX_TRANS_EXIT + if (OsVendorStartRedirectErrorFProc != NULL) { + OsVendorStartRedirectErrorFProc(); + } + OsBlockSignals (); +#endif + switch (pid = fork()) { + case -1: /* error */ + close(pdes[0]); + close(pdes[1]); + free(cur); +#if HAVE_SETITIMER + if (SmartScheduleEnable() < 0) + perror("signal"); +#endif +#ifdef NX_TRANS_EXIT + if (OsVendorEndRedirectErrorFProc != NULL) { + OsVendorEndRedirectErrorFProc(); + } + OsReleaseSignals (); +#endif + return NULL; + case 0: /* child */ + if (setgid(getgid()) == -1) + _exit(127); + if (setuid(getuid()) == -1) + _exit(127); + if (*type == 'r') { + if (pdes[1] != 1) { + /* stdout */ + dup2(pdes[1], 1); + close(pdes[1]); + } + close(pdes[0]); + } else { + if (pdes[0] != 0) { + /* stdin */ + dup2(pdes[0], 0); + close(pdes[0]); + } + close(pdes[1]); + } + + #ifdef NX_TRANS_SOCKET + + /* + * Check if the child process should not + * use the parent's libraries. + */ + + if (_NXUnsetLibraryPath) + { + #ifndef __sun + + unsetenv ("LD_LIBRARY_PATH"); + + #else + + extern char **environ; + + char **ep = environ; + + ep = environ; + + while (*ep) + { + if (!strncmp("LD_LIBRARY_PATH=", *ep, strlen("LD_LIBRARY_PATH="))) + { + break; + } + + *ep++; + } + + while (*ep) + { + *ep = *(ep + 1); + ep++; + } + + #endif + } + + #endif + + #ifdef NX_TRANS_EXIT + OsReleaseSignals (); + #endif + +#if HAVE_SETITIMER + if (SmartScheduleEnable() < 0) { + perror("signal"); + return NULL; + } +#endif + + execl("/bin/sh", "sh", "-c", command, (char *)NULL); + _exit(127); + } + +#ifndef NX_TRANS_EXIT + /* Avoid EINTR during stdio calls */ + OsBlockSignals (); +#endif + + /* parent */ + if (*type == 'r') { + iop = fdopen(pdes[0], type); + close(pdes[1]); + } else { + iop = fdopen(pdes[1], type); + close(pdes[0]); + } + + cur->fp = iop; + cur->pid = pid; + cur->next = pidlist; + pidlist = cur; + +#ifdef DEBUG + ErrorF("Popen: `%s', fp = %p\n", command, iop); +#endif + + return iop; +} + +/* fopen that drops privileges */ +void * +Fopen(char *file, char *type) +{ + FILE *iop; +#ifndef HAS_SAVED_IDS_AND_SETEUID + struct pid *cur; + int pdes[2], pid; + + if (file == NULL || type == NULL) + return NULL; + + if ((*type != 'r' && *type != 'w') || type[1]) + return NULL; + + if ((cur = (struct pid *)malloc(sizeof(struct pid))) == NULL) + return NULL; + + if (pipe(pdes) < 0) { + free(cur); + return NULL; + } + + switch (pid = fork()) { + case -1: /* error */ + close(pdes[0]); + close(pdes[1]); + free(cur); + return NULL; + case 0: /* child */ + if (setgid(getgid()) == -1) + _exit(127); + if (setuid(getuid()) == -1) + _exit(127); + if (*type == 'r') { + if (pdes[1] != 1) { + /* stdout */ + dup2(pdes[1], 1); + close(pdes[1]); + } + close(pdes[0]); + } else { + if (pdes[0] != 0) { + /* stdin */ + dup2(pdes[0], 0); + close(pdes[0]); + } + close(pdes[1]); + } + execl("/bin/cat", "cat", file, (char *)NULL); + _exit(127); + } + + /* Avoid EINTR during stdio calls */ + OsBlockSignals (); + + /* parent */ + if (*type == 'r') { + iop = fdopen(pdes[0], type); + close(pdes[1]); + } else { + iop = fdopen(pdes[1], type); + close(pdes[0]); + } + + cur->fp = iop; + cur->pid = pid; + cur->next = pidlist; + pidlist = cur; + +#ifdef DEBUG + ErrorF("Popen: `%s', fp = %p\n", command, iop); +#endif + + return iop; +#else + int ruid, euid; + + ruid = getuid(); + euid = geteuid(); + + if (seteuid(ruid) == -1) { + return NULL; + } + iop = fopen(file, type); + + if (seteuid(euid) == -1) { + fclose(iop); + return NULL; + } + return iop; +#endif /* HAS_SAVED_IDS_AND_SETEUID */ +} + +int +Pclose(void * iop) +{ + struct pid *cur, *last; + int pstat; + int pid; + +#ifdef DEBUG + ErrorF("Pclose: fp = %p\n", iop); +#endif + + fclose(iop); + + for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) + if (cur->fp == iop) + break; + if (cur == NULL) + return -1; + + do { + pid = waitpid(cur->pid, &pstat, 0); + } while (pid == -1 && errno == EINTR); + + if (last == NULL) + pidlist = cur->next; + else + last->next = cur->next; + free(cur); + + /* allow EINTR again */ + OsReleaseSignals (); + +#ifdef NX_TRANS_EXIT + if (OsVendorEndRedirectErrorFProc != NULL) { + OsVendorEndRedirectErrorFProc(); + } +#endif + return pid == -1 ? -1 : pstat; +} + +int +Fclose(void * iop) +{ +#ifdef HAS_SAVED_IDS_AND_SETEUID + return fclose(iop); +#else + return Pclose(iop); +#endif +} + +#endif /* !WIN32 */ + + +/* + * CheckUserParameters: check for long command line arguments and long + * environment variables. By default, these checks are only done when + * the server's euid != ruid. In 3.3.x, these checks were done in an + * external wrapper utility. + */ + +/* Consider LD* variables insecure? */ +#ifndef REMOVE_ENV_LD +#define REMOVE_ENV_LD 1 +#endif + +/* Remove long environment variables? */ +#ifndef REMOVE_LONG_ENV +#define REMOVE_LONG_ENV 1 +#endif + +/* + * Disallow stdout or stderr as pipes? It's possible to block the X server + * when piping stdout+stderr to a pipe. + * + * Don't enable this because it looks like it's going to cause problems. + */ +#ifndef NO_OUTPUT_PIPES +#define NO_OUTPUT_PIPES 0 +#endif + + +/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ +#ifndef CHECK_EUID +#ifndef WIN32 +#define CHECK_EUID 1 +#else +#define CHECK_EUID 0 +#endif +#endif + +/* + * Maybe the locale can be faked to make isprint(3) report that everything + * is printable? Avoid it by default. + */ +#ifndef USE_ISPRINT +#define USE_ISPRINT 0 +#endif + +#define MAX_ARG_LENGTH 128 +#define MAX_ENV_LENGTH 256 +#define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ + +#if USE_ISPRINT +#include <ctype.h> +#define checkPrintable(c) isprint(c) +#else +#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) +#endif + +enum BadCode { + NotBad = 0, + UnsafeArg, + ArgTooLong, + UnprintableArg, + EnvTooLong, + OutputIsPipe, + InternalError +}; + +#if defined(VENDORSUPPORT) +#define BUGADDRESS VENDORSUPPORT +#elif defined(BUILDERADDR) +#define BUGADDRESS BUILDERADDR +#else +#define BUGADDRESS "xorg@freedesktop.org" +#endif + +#define ARGMSG \ + "\nIf the arguments used are valid, and have been rejected incorrectly\n" \ + "please send details of the arguments and why they are valid to\n" \ + "%s. In the meantime, you can start the Xserver as\n" \ + "the \"super user\" (root).\n" + +#define ENVMSG \ + "\nIf the environment is valid, and have been rejected incorrectly\n" \ + "please send details of the environment and why it is valid to\n" \ + "%s. In the meantime, you can start the Xserver as\n" \ + "the \"super user\" (root).\n" + +void +CheckUserParameters(int argc, char **argv, char **envp) +{ + enum BadCode bad = NotBad; + int i = 0, j; + char *a, *e = NULL; + +#if CHECK_EUID + if (geteuid() == 0 && getuid() != geteuid()) +#endif + { + /* Check each argv[] */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-fp") == 0) + { + i++; /* continue with next argument. skip the length check */ + if (i >= argc) + break; + } else + { + if (strlen(argv[i]) > MAX_ARG_LENGTH) { + bad = ArgTooLong; + break; + } + } + a = argv[i]; + while (*a) { + if (checkPrintable(*a) == 0) { + bad = UnprintableArg; + break; + } + a++; + } + if (bad) + break; + } + if (!bad) { + /* Check each envp[] */ + for (i = 0; envp[i]; i++) { + + /* Check for bad environment variables and values */ +#if REMOVE_ENV_LD + while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { +#ifdef ENVDEBUG + ErrorF("CheckUserParameters: removing %s from the " + "environment\n", strtok(envp[i], "=")); +#endif + for (j = i; envp[j]; j++) { + envp[j] = envp[j+1]; + } + } +#endif + if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { +#if REMOVE_LONG_ENV +#ifdef ENVDEBUG + ErrorF("CheckUserParameters: removing %s from the " + "environment\n", strtok(envp[i], "=")); +#endif + for (j = i; envp[j]; j++) { + envp[j] = envp[j+1]; + } + i--; +#else + char *eq; + int len; + + eq = strchr(envp[i], '='); + if (!eq) + continue; + len = eq - envp[i]; + e = malloc(len + 1); + if (!e) { + bad = InternalError; + break; + } + strncpy(e, envp[i], len); + e[len] = 0; + if (len >= 4 && + (strcmp(e + len - 4, "PATH") == 0 || + strcmp(e, "TERMCAP") == 0)) { + if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { + bad = EnvTooLong; + break; + } else { + free(e); + } + } else { + bad = EnvTooLong; + break; + } +#endif + } + } + } +#if NO_OUTPUT_PIPES + if (!bad) { + struct stat buf; + + if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) + bad = OutputIsPipe; + if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) + bad = OutputIsPipe; + } +#endif + } + switch (bad) { + case NotBad: + return; + case UnsafeArg: + ErrorF("Command line argument number %d is unsafe\n", i); + ErrorF(ARGMSG, BUGADDRESS); + break; + case ArgTooLong: + ErrorF("Command line argument number %d is too long\n", i); + ErrorF(ARGMSG, BUGADDRESS); + break; + case UnprintableArg: + ErrorF("Command line argument number %d contains unprintable" + " characters\n", i); + ErrorF(ARGMSG, BUGADDRESS); + break; + case EnvTooLong: + ErrorF("Environment variable `%s' is too long\n", e); + ErrorF(ENVMSG, BUGADDRESS); + break; + case OutputIsPipe: + ErrorF("Stdout and/or stderr is a pipe\n"); + break; + case InternalError: + ErrorF("Internal Error\n"); + break; + default: + ErrorF("Unknown error\n"); + ErrorF(ARGMSG, BUGADDRESS); + ErrorF(ENVMSG, BUGADDRESS); + break; + } + FatalError("X server aborted because of unsafe environment\n"); +} + +/* + * CheckUserAuthorization: check if the user is allowed to start the + * X server. This usually means some sort of PAM checking, and it is + * usually only done for setuid servers (uid != euid). + */ + +#ifdef USE_PAM +#include <security/pam_appl.h> +#include <security/pam_misc.h> +#include <pwd.h> +#endif /* USE_PAM */ + +void +CheckUserAuthorization(void) +{ +#ifdef USE_PAM + static struct pam_conv conv = { + misc_conv, + NULL + }; + + pam_handle_t *pamh = NULL; + struct passwd *pw; + int retval; + + if (getuid() != geteuid()) { + pw = getpwuid(getuid()); + if (pw == NULL) + FatalError("getpwuid() failed for uid %d\n", getuid()); + + retval = pam_start("xserver", pw->pw_name, &conv, &pamh); + if (retval != PAM_SUCCESS) + FatalError("pam_start() failed.\n" + "\tMissing or mangled PAM config file or module?\n"); + + retval = pam_authenticate(pamh, 0); + if (retval != PAM_SUCCESS) { + pam_end(pamh, retval); + FatalError("PAM authentication failed, cannot start X server.\n" + "\tPerhaps you do not have console ownership?\n"); + } + + retval = pam_acct_mgmt(pamh, 0); + if (retval != PAM_SUCCESS) { + pam_end(pamh, retval); + FatalError("PAM authentication failed, cannot start X server.\n" + "\tPerhaps you do not have console ownership?\n"); + } + + /* this is not a session, so do not do session management */ + pam_end(pamh, PAM_SUCCESS); + } +#endif +} + +#ifdef __SCO__ +#include <fcntl.h> + +static void +lockit (int fd, short what) +{ + struct flock lck; + + lck.l_whence = 0; + lck.l_start = 0; + lck.l_len = 1; + lck.l_type = what; + + (void)fcntl (fd, F_SETLKW, &lck); +} + +/* SCO OpenServer 5 lacks pread/pwrite. Emulate them. */ +ssize_t +pread (int fd, void *buf, size_t nbytes, off_t offset) +{ + off_t saved; + ssize_t ret; + + lockit (fd, F_RDLCK); + saved = lseek (fd, 0, SEEK_CUR); + lseek (fd, offset, SEEK_SET); + ret = read (fd, buf, nbytes); + lseek (fd, saved, SEEK_SET); + lockit (fd, F_UNLCK); + + return ret; +} + +ssize_t +pwrite (int fd, const void *buf, size_t nbytes, off_t offset) +{ + off_t saved; + ssize_t ret; + + lockit (fd, F_WRLCK); + saved = lseek (fd, 0, SEEK_CUR); + lseek (fd, offset, SEEK_SET); + ret = write (fd, buf, nbytes); + lseek (fd, saved, SEEK_SET); + lockit (fd, F_UNLCK); + + return ret; +} +#endif /* __SCO__ */ diff --git a/nx-X11/programs/Xserver/os/xdmauth.c b/nx-X11/programs/Xserver/os/xdmauth.c new file mode 100644 index 000000000..4a59b48f2 --- /dev/null +++ b/nx-X11/programs/Xserver/os/xdmauth.c @@ -0,0 +1,501 @@ +/* + +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 + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stdio.h> +#include <nx-X11/X.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <nx-X11/Xtrans/Xtrans.h> +#include "os.h" +#include "osdep.h" +#include "dixstruct.h" + +#ifdef HASXDMAUTH + +static Bool authFromXDMCP; + +#ifdef XDMCP +#include <nx-X11/Xmd.h> +#undef REQUEST +#include <X11/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 (ARRAY8Ptr privateData, ARRAY8Ptr incomingData, + xdmOpCode packet_type) +{ + XdmAuthKeyPtr incoming; + + XdmcpUnwrap (incomingData->data, (unsigned char *)&privateKey, + incomingData->data,incomingData->length); + if (packet_type == ACCEPT) { + if (incomingData->length != 8) + return FALSE; + incoming = (XdmAuthKeyPtr) incomingData->data; + XdmcpDecrementKey (incoming); + return XdmcpCompareKeys (incoming, &rho); + } + return FALSE; +} + +static Bool +XdmAuthenticationGenerator (ARRAY8Ptr privateData, ARRAY8Ptr outgoingData, + xdmOpCode packet_type) +{ + outgoingData->length = 0; + outgoingData->data = 0; + if (packet_type == REQUEST) { + if (XdmcpAllocARRAY8 (outgoingData, 8)) + XdmcpWrap ((unsigned char *)&rho, (unsigned char *)&privateKey, + outgoingData->data, 8); + } + return TRUE; +} + +static Bool +XdmAuthenticationAddAuth (int name_len, char *name, + int data_len, char *data) +{ + Bool ret; + XdmcpUnwrap ((unsigned char *)data, (unsigned char *)&privateKey, + (unsigned char *)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 (char *in, char *out, 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 (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, + (char *)&rho, + sizeof (rho), + (ValidatorFunc)XdmAuthenticationValidator, + (GeneratorFunc)XdmAuthenticationGenerator, + (AddAuthorFunc)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 (XdmClientAuthPtr a, XdmClientAuthPtr 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 (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 (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; + free (client); + } + else + prev = client; + } +} + +static XdmClientAuthPtr +XdmAuthorizationValidate (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) malloc (sizeof (XdmClientAuthRec)); + if (!client) + return NULL; + XdmClientAuthDecode (plain, client); + if (!XdmcpCompareKeys (&client->rho, rho)) + { + free (client); + if (reason) + *reason = "Invalid XDM-AUTHORIZATION-1 key (failed key comparison)"; + return NULL; + } + for (i = 18; i < 24; i++) + if (plain[i] != 0) { + free (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) + if (family == FamilyInternet && + memcmp((char *)addr, client->client, 4) != 0) { + free (client); + free (addr); + if (reason) + *reason = "Invalid XDM-AUTHORIZATION-1 key (failed address comparison)"; + return NULL; + + } +#endif + free (addr); + } + } + now = time(0); + if (!gotClock) + { + clockOffset = client->time - now; + gotClock = TRUE; + } + now += clockOffset; + XdmClientAuthTimeout (now); + if (abs (client->time - now) > TwentyMinutes) + { + free (client); + if (reason) + *reason = "Excessive XDM-AUTHORIZATION-1 time offset"; + return NULL; + } + for (existing = xdmClients; existing; existing=existing->next) + { + if (XdmClientAuthCompare (existing, client)) + { + free (client); + if (reason) + *reason = "XDM authorization key matches an existing client!"; + return NULL; + } + } + return client; +} + +int +XdmAddCookie (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 */ +#ifdef XDMCP + 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 +#endif + { + rho_bits = (unsigned char *) data; + key_bits = (unsigned char *) (data + 8); + } + break; +#ifdef XDMCP + case 8: /* auth from XDMCP is 8 bytes long */ + rho_bits = rho.data; + key_bits = (unsigned char *) data; + break; +#endif + default: + return 0; + } + /* the first octet of the key must be zero */ + if (key_bits[0] != '\0') + return 0; + new = (XdmAuthorizationPtr) malloc (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 (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 *) malloc (cookie_length); + if (!plain) + return (XID) -1; + for (auth = xdmAuth; auth; auth=auth->next) { + XdmcpUnwrap ((unsigned char *)cookie, (unsigned char *)&auth->key, plain, cookie_length); + if ((client = XdmAuthorizationValidate (plain, cookie_length, &auth->rho, xclient, reason)) != NULL) + { + client->next = xdmClients; + xdmClients = client; + free (plain); + return auth->id; + } + } + free (plain); + return (XID) -1; +} + +int +XdmResetCookie (void) +{ + XdmAuthorizationPtr auth, next_auth; + XdmClientAuthPtr client, next_client; + + for (auth = xdmAuth; auth; auth=next_auth) + { + next_auth = auth->next; + free (auth); + } + xdmAuth = 0; + for (client = xdmClients; client; client=next_client) + { + next_client = client->next; + free (client); + } + xdmClients = (XdmClientAuthPtr) 0; + return 1; +} + +XID +XdmToID (unsigned short cookie_length, char *cookie) +{ + XdmAuthorizationPtr auth; + XdmClientAuthPtr client; + unsigned char *plain; + + plain = (unsigned char *) malloc (cookie_length); + if (!plain) + return (XID) -1; + for (auth = xdmAuth; auth; auth=auth->next) { + XdmcpUnwrap ((unsigned char *)cookie, (unsigned char *)&auth->key, plain, cookie_length); + if ((client = XdmAuthorizationValidate (plain, cookie_length, &auth->rho, NULL, NULL)) != NULL) + { + free (client); + free (cookie); + return auth->id; + } + } + free (cookie); + return (XID) -1; +} + +int +XdmFromID (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 (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; +#ifdef XDMCP + case 8: + rho_bits = ρ + key_bits = (XdmAuthKeyPtr) data; + break; +#endif + 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; + free (auth); + return 1; + } + } + return 0; +} + +#endif diff --git a/nx-X11/programs/Xserver/os/xdmcp.c b/nx-X11/programs/Xserver/os/xdmcp.c new file mode 100644 index 000000000..c1aa57e95 --- /dev/null +++ b/nx-X11/programs/Xserver/os/xdmcp.c @@ -0,0 +1,1629 @@ +/* + * 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 HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <nx-X11/Xwinsock.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <nx-X11/Xtrans/Xtrans.h> +#endif + +#include <nx-X11/Xos.h> + +#if !defined(WIN32) +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <nx-X11/X.h> +#include <nx-X11/Xmd.h> +#include "misc.h" +#include <nx-X11/Xpoll.h> +#include "osdep.h" +#include "input.h" +#include "dixstruct.h" +#include "opaque.h" + + +#ifndef NX_TRANS_SOCKET + +#define NX_TRANS_SOCKET +#define NX_TRANS_TEST + +#endif + +#ifdef XDMCP +#undef REQUEST + +#ifdef XDMCP_NO_IPV6 +#undef IPv6 +#endif + +#include <X11/Xdmcp.h> + +#define X_INCLUDE_NETDB_H +#include <nx-X11/Xos_r.h> + +#ifdef NX_TRANS_SOCKET + +xdmcp_states XdmcpState; + +int XdmcpStartTime; +int XdmcpTimeOutRtx; + +#endif + +extern char *defaultDisplayClass; + +static int xdmcpSocket, sessionSocket; +static xdmcp_states state; +#if defined(IPv6) && defined(AF_INET6) +static int xdmcpSocket6; +static struct sockaddr_storage req_sockaddr; +#else +static struct sockaddr_in req_sockaddr; +#endif +static int req_socklen; +static CARD32 SessionID; +static CARD32 timeOutTime; +static int timeOutRtx; +static CARD16 DisplayNumber; +static xdmcp_states XDM_INIT_STATE = XDM_OFF; +#ifdef HASXDMAUTH +static char *xdmAuthCookie; +#endif + +static XdmcpBuffer buffer; + +#if defined(IPv6) && defined(AF_INET6) + +static struct addrinfo *mgrAddr; +static struct addrinfo *mgrAddrFirst; + +#define SOCKADDR_TYPE struct sockaddr_storage +#define SOCKADDR_FAMILY(s) ((struct sockaddr *)&(s))->sa_family + +#ifdef BSD44SOCKETS +#define SOCKLEN_FIELD(s) ((struct sockaddr *)&(s))->sa_len +#define SOCKLEN_TYPE unsigned char +#else +#define SOCKLEN_TYPE unsigned int +#endif + +#else + +#define SOCKADDR_TYPE struct sockaddr_in +#define SOCKADDR_FAMILY(s) (s).sin_family + +#ifdef BSD44SOCKETS +#define SOCKLEN_FIELD(s) (s).sin_len +#define SOCKLEN_TYPE unsigned char +#else +#define SOCKLEN_TYPE size_t +#endif + +#endif + +static SOCKADDR_TYPE ManagerAddress; +static SOCKADDR_TYPE FromAddress; + +#ifdef SOCKLEN_FIELD +#define ManagerAddressLen SOCKLEN_FIELD(ManagerAddress) +#define FromAddressLen SOCKLEN_FIELD(FromAddress) +#else +static SOCKLEN_TYPE ManagerAddressLen, FromAddressLen; +#endif + +#if defined(IPv6) && defined(AF_INET6) +static struct multicastinfo { + struct multicastinfo *next; + struct addrinfo *ai; + int hops; +} *mcastlist; +#endif + +static void XdmcpAddHost( + struct sockaddr *from, + int fromlen, + ARRAY8Ptr AuthenticationName, + ARRAY8Ptr hostname, + ARRAY8Ptr status); + +static void XdmcpSelectHost( + struct sockaddr *host_sockaddr, + int host_len, + ARRAY8Ptr AuthenticationName); + +static void get_xdmcp_sock(void); + +static void send_query_msg(void); + +static void recv_willing_msg( + struct sockaddr * /*from*/, + int /*fromlen*/, + unsigned /*length*/); + +static void send_request_msg(void); + +static void recv_accept_msg(unsigned /*length*/); + +static void recv_decline_msg(unsigned /*length*/); + +static void send_manage_msg(void); + +static void recv_refuse_msg(unsigned /*length*/); + +static void recv_failed_msg(unsigned /*length*/); + +static void send_keepalive_msg(void); + +static void recv_alive_msg(unsigned /*length*/); + +static void XdmcpFatal( + char * /*type*/, + ARRAY8Ptr /*status*/); + +static void XdmcpWarning(char * /*str*/); + +static void get_manager_by_name( + int /*argc*/, + char ** /*argv*/, + int /*i*/); + +static void get_fromaddr_by_name(int /*argc*/, char ** /*argv*/, int /*i*/); + +#if defined(IPv6) && defined(AF_INET6) +static int get_mcast_options(int /*argc*/, char ** /*argv*/, int /*i*/); +#endif + +static void receive_packet(int /*socketfd*/); + +static void send_packet(void); + +extern void XdmcpDeadSession(char * /*reason*/); + +static void timeout(void); + +static void XdmcpBlockHandler( + void * /*data*/, + struct timeval ** /*wt*/, + void * /*LastSelectMask*/); + +static void XdmcpWakeupHandler( + void * /*data*/, + int /*i*/, + void * /*LastSelectMask*/); + +void XdmcpRegisterManufacturerDisplayID( + char * /*name*/, + int /*length*/); + + +static unsigned short xdm_udp_port = XDM_UDP_PORT; +static Bool OneSession = FALSE; +static const char *xdm_from = NULL; + +void +XdmcpUseMsg (void) +{ + ErrorF("-query host-name contact named host for XDMCP\n"); + ErrorF("-broadcast broadcast for XDMCP\n"); +#if defined(IPv6) && defined(AF_INET6) + ErrorF("-multicast [addr [hops]] IPv6 multicast for XDMCP\n"); +#endif + ErrorF("-indirect host-name contact named host for indirect XDMCP\n"); + ErrorF("-port port-num UDP port number to send messages to\n"); + ErrorF("-from local-address specify the local address to connect from\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(int argc, char **argv, int i) +{ + 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 defined(IPv6) && defined(AF_INET6) + if (strcmp(argv[i], "-multicast") == 0) { + i = get_mcast_options(argc, argv, ++i); + XDM_INIT_STATE = XDM_MULTICAST; + AccessUsingXdmcp (); + return (i + 1); + } +#endif + 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) { + if (++i == argc) { + FatalError("Xserver: missing port number in command line\n"); + } + xdm_udp_port = (unsigned short) atoi(argv[i]); + return (i + 1); + } + if (strcmp(argv[i], "-from") == 0) { + get_fromaddr_by_name(argc, argv, ++i); + return (i + 1); + } + if (strcmp(argv[i], "-once") == 0) { + OneSession = TRUE; + return (i + 1); + } + if (strcmp(argv[i], "-class") == 0) { + if (++i == argc) { + FatalError("Xserver: missing class name in command line\n"); + } + defaultDisplayClass = argv[i]; + return (i + 1); + } +#ifdef HASXDMAUTH + if (strcmp(argv[i], "-cookie") == 0) { + if (++i == argc) { + FatalError("Xserver: missing cookie data in command line\n"); + } + xdmAuthCookie = argv[i]; + return (i + 1); + } +#endif + if (strcmp(argv[i], "-displayID") == 0) { + if (++i == argc) { + FatalError("Xserver: missing displayID in command line\n"); + } + 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 + +/* This stays sockaddr_in since IPv6 doesn't support broadcast */ +static struct sockaddr_in BroadcastAddresses[MAX_BROADCAST]; +static int NumBroadcastAddresses; + +void +XdmcpRegisterBroadcastAddress (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 { + ValidatorFunc Validator; + GeneratorFunc Generator; + AddAuthorFunc AddAuth; +} AuthenticationFuncsRec, *AuthenticationFuncsPtr; + +static AuthenticationFuncsPtr AuthenticationFuncsList; + +void +XdmcpRegisterAuthentication ( + char *name, + int namelen, + char *data, + int datalen, + ValidatorFunc Validator, + GeneratorFunc Generator, + AddAuthorFunc 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) malloc ( + (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; + free (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 (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 ( + int type, + char *address, + int addrlen) +{ + int i; + CARD8 *newAddress; + + if (xdmcpGeneration != serverGeneration) + { + XdmcpDisposeARRAY16 (&ConnectionTypes); + XdmcpDisposeARRAYofARRAY8 (&ConnectionAddresses); + xdmcpGeneration = serverGeneration; + } + if (xdm_from != NULL) { /* Only register the requested address */ + const void *regAddr = address; + const void *fromAddr = NULL; + int regAddrlen = addrlen; + + if (addrlen == sizeof(struct in_addr)) { + if (SOCKADDR_FAMILY(FromAddress) == AF_INET) { + fromAddr = &((struct sockaddr_in *)&FromAddress)->sin_addr; + } +#if defined(IPv6) && defined(AF_INET6) + else if ((SOCKADDR_FAMILY(FromAddress) == AF_INET6) && + IN6_IS_ADDR_V4MAPPED( + &((struct sockaddr_in6 *)&FromAddress)->sin6_addr)) { + fromAddr = &((struct sockaddr_in6 *)&FromAddress)->sin6_addr.s6_addr[12]; + } +#endif + } +#if defined(IPv6) && defined(AF_INET6) + else if (addrlen == sizeof(struct in6_addr)) { + if (SOCKADDR_FAMILY(FromAddress) == AF_INET6) { + fromAddr = &((struct sockaddr_in6 *)&FromAddress)->sin6_addr; + } else if ((SOCKADDR_FAMILY(FromAddress) == AF_INET) && + IN6_IS_ADDR_V4MAPPED((struct in6_addr *) address)) { + fromAddr = &((struct sockaddr_in *)&FromAddress)->sin_addr; + regAddr = &((struct sockaddr_in6 *)&address)->sin6_addr.s6_addr[12]; + regAddrlen = sizeof(struct in_addr); + } + } +#endif + if (fromAddr && memcmp(regAddr, fromAddr, regAddrlen) != 0) { + return; + } + } + newAddress = (CARD8 *) malloc (addrlen * sizeof (CARD8)); + if (!newAddress) + return; + if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1)) + { + free (newAddress); + return; + } + if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses, + ConnectionAddresses.length + 1)) + { + free (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 (void) +{ + XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames); + RegisterAuthorizations (); +} + +void +XdmcpRegisterAuthorization (char *name, int namelen) +{ + ARRAY8 authName; + int i; + + authName.data = (CARD8 *) malloc (namelen * sizeof (CARD8)); + if (!authName.data) + return; + if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1)) + { + free (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 (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 (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(void) +{ +#ifdef NX_TRANS_SOCKET + + XdmcpStartTime = GetTimeInMillis(); + +#endif + + 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, + (void *) 0); + timeOutRtx = 0; + DisplayNumber = (CARD16) atoi(display); + get_xdmcp_sock(); + send_packet(); + } +} + +void +XdmcpReset (void) +{ + state = XDM_INIT_STATE; + if (state != XDM_OFF) + { + RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler, + (void *) 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(int sock) +{ + if (state != XDM_AWAIT_MANAGE_RESPONSE) + return; + state = XDM_RUN_SESSION; + timeOutTime = GetTimeInMillis() + XDM_DEF_DORMANCY * 1000; + sessionSocket = sock; +} + +void +XdmcpCloseDisplay(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( + void * data, /* unused */ + struct timeval **wt, + void * pReadmask) +{ + fd_set *LastSelectMask = (fd_set*)pReadmask; + CARD32 millisToGo; + + if (state == XDM_OFF) + return; + FD_SET(xdmcpSocket, LastSelectMask); +#if defined(IPv6) && defined(AF_INET6) + if (xdmcpSocket6 >= 0) + FD_SET(xdmcpSocket6, LastSelectMask); +#endif + if (timeOutTime == 0) + return; + millisToGo = timeOutTime - GetTimeInMillis(); + if ((int) millisToGo < 0) + millisToGo = 0; + AdjustWaitForDelay (wt, millisToGo); +} + +/* + * called after select returns; this routine will + * recognise when XDMCP packets await and + * process them appropriately + */ + +/*ARGSUSED*/ +static void +XdmcpWakeupHandler( + void * data, /* unused */ + int i, + void * pReadmask) +{ + fd_set* LastSelectMask = (fd_set*)pReadmask; + +#ifdef NX_TRANS_SOCKET + + XdmcpState = state; + XdmcpTimeOutRtx = timeOutRtx; + +#endif + + if (state == XDM_OFF) + return; + if (i > 0) + { + if (FD_ISSET(xdmcpSocket, LastSelectMask)) + { + receive_packet(xdmcpSocket); + FD_CLR(xdmcpSocket, LastSelectMask); + } +#if defined(IPv6) && defined(AF_INET6) + if (xdmcpSocket6 >= 0 && FD_ISSET(xdmcpSocket6, LastSelectMask)) + { + receive_packet(xdmcpSocket6); + FD_CLR(xdmcpSocket6, LastSelectMask); + } +#endif + } + else if (timeOutTime && (int) (GetTimeInMillis() - timeOutTime) >= 0) + { + 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 + */ + +static void +XdmcpSelectHost( + struct sockaddr *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*/ +static void +XdmcpAddHost( + struct sockaddr *from, + int fromlen, + ARRAY8Ptr AuthenticationName, + ARRAY8Ptr hostname, + ARRAY8Ptr 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(int socketfd) +{ +#if defined(IPv6) && defined(AF_INET6) + struct sockaddr_storage from; +#else + struct sockaddr_in from; +#endif + int fromlen = sizeof(from); + XdmcpHeader header; + + /* read message off socket */ + if (!XdmcpFill (socketfd, &buffer, (XdmcpNetaddr) &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((struct sockaddr *) &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 void +send_packet(void) +{ + int rtx; + switch (state) { + case XDM_QUERY: + case XDM_BROADCAST: + case XDM_INDIRECT: +#if defined(IPv6) && defined(AF_INET6) + case XDM_MULTICAST: +#endif + 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; + default: + 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. + */ + +void +XdmcpDeadSession (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(void) +{ + timeOutRtx++; + if (state == XDM_AWAIT_ALIVE_RESPONSE && timeOutRtx >= XDM_KA_RTX_LIMIT ) + { + XdmcpDeadSession ("too many keepalive retransmissions"); + return; + } + else if (timeOutRtx >= XDM_RTX_LIMIT) + { + /* Quit if "-once" specified, otherwise reset and try again. */ + if (OneSession) { + dispatchException |= DE_TERMINATE; + ErrorF("XDM: too many retransmissions\n"); + } else { + XdmcpDeadSession("too many retransmissions"); + } + return; + } + +#if defined(IPv6) && defined(AF_INET6) + if (state == XDM_COLLECT_QUERY || state == XDM_COLLECT_INDIRECT_QUERY) { + /* Try next address */ + for (mgrAddr = mgrAddr->ai_next; ; mgrAddr = mgrAddr->ai_next) { + if (mgrAddr == NULL) { + mgrAddr = mgrAddrFirst; + } + if (mgrAddr->ai_family == AF_INET + || mgrAddr->ai_family == AF_INET6) + break; + } +#ifndef SIN6_LEN + ManagerAddressLen = mgrAddr->ai_addrlen; +#endif + memcpy(&ManagerAddress, mgrAddr->ai_addr, mgrAddr->ai_addrlen); + } +#endif + + switch (state) { + case XDM_COLLECT_QUERY: + state = XDM_QUERY; + break; + case XDM_COLLECT_BROADCAST_QUERY: + state = XDM_BROADCAST; + break; +#if defined(IPv6) && defined(AF_INET6) + case XDM_COLLECT_MULTICAST_QUERY: + state = XDM_MULTICAST; + break; +#endif + 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; + default: + break; + } + send_packet(); +} + +int +XdmcpCheckAuthentication ( + ARRAY8Ptr Name, + ARRAY8Ptr Data, + int packet_type) +{ + return (XdmcpARRAY8Equal (Name, AuthenticationName) && + (AuthenticationName->length == 0 || + (*AuthenticationFuncs->Validator) (AuthenticationData, Data, packet_type))); +} + +int +XdmcpAddAuthorization ( + ARRAY8Ptr name, + ARRAY8Ptr data) +{ + AddAuthorFunc AddAuth; + + 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(void) +{ + int soopts = 1; + +#if defined(IPv6) && defined(AF_INET6) + if ((xdmcpSocket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + XdmcpWarning("INET6 UDP socket creation failed"); +#endif + 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 */ + if (xdmcpSocket >= 0 && xdm_from != NULL) { + if (bind(xdmcpSocket, (struct sockaddr *)&FromAddress, + FromAddressLen) < 0) { + FatalError("Xserver: failed to bind to -from address: %s\n", xdm_from); + } + } +} + +static void +send_query_msg(void) +{ + XdmcpHeader header; + Bool broadcast = FALSE; +#if defined(IPv6) && defined(AF_INET6) + Bool multicast = FALSE; +#endif + int i; + int socketfd = xdmcpSocket; + + 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; +#if defined(IPv6) && defined(AF_INET6) + case XDM_MULTICAST: + header.opcode = (CARD16) BROADCAST_QUERY; + state = XDM_COLLECT_MULTICAST_QUERY; + multicast = TRUE; + break; +#endif + case XDM_INDIRECT: + header.opcode = (CARD16) INDIRECT_QUERY; + state = XDM_COLLECT_INDIRECT_QUERY; + break; + default: + 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, (XdmcpNetaddr) &BroadcastAddresses[i], + sizeof (struct sockaddr_in)); + } +#if defined(IPv6) && defined(AF_INET6) + else if (multicast) + { + struct multicastinfo *mcl; + struct addrinfo *ai; + + for (mcl = mcastlist; mcl != NULL; mcl = mcl->next) { + for (ai = mcl->ai ; ai != NULL; ai = ai->ai_next) { + if (ai->ai_family == AF_INET) { + unsigned char hopflag = (unsigned char) mcl->hops; + socketfd = xdmcpSocket; + setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_TTL, + &hopflag, sizeof(hopflag)); + } else if (ai->ai_family == AF_INET6) { + int hopflag6 = mcl->hops; + socketfd = xdmcpSocket6; + setsockopt(socketfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &hopflag6, sizeof(hopflag6)); + } else { + continue; + } + XdmcpFlush (socketfd, &buffer, + (XdmcpNetaddr) ai->ai_addr, ai->ai_addrlen); + break; + } + } + } +#endif + else + { +#if defined(IPv6) && defined(AF_INET6) + if (SOCKADDR_FAMILY(ManagerAddress) == AF_INET6) + socketfd = xdmcpSocket6; +#endif + XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &ManagerAddress, + ManagerAddressLen); + } +} + +static void +recv_willing_msg( + struct sockaddr *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: +#if defined(IPv6) && defined(AF_INET6) + case XDM_COLLECT_MULTICAST_QUERY: +#endif + case XDM_COLLECT_INDIRECT_QUERY: + XdmcpAddHost(from, fromlen, &authenticationName, &hostname, &status); + break; + default: + break; + } + } + } + XdmcpDisposeARRAY8 (&authenticationName); + XdmcpDisposeARRAY8 (&hostname); + XdmcpDisposeARRAY8 (&status); +} + +static void +send_request_msg(void) +{ + XdmcpHeader header; + int length; + int i; + CARD16 XdmcpConnectionType; + ARRAY8 authenticationData; + int socketfd = xdmcpSocket; + + switch (SOCKADDR_FAMILY(ManagerAddress)) + { + case AF_INET: XdmcpConnectionType=FamilyInternet; break; +#if defined(IPv6) && defined(AF_INET6) + case AF_INET6: XdmcpConnectionType=FamilyInternet6; break; +#endif + default: XdmcpConnectionType=0xffff; break; + } + + 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); + XdmcpWriteCARD8 (&buffer, ConnectionTypes.length); + + /* The connection array is send reordered, so that connections of */ + /* the same address type as the XDMCP manager connection are send */ + /* first. This works around a bug in xdm. mario@klebsch.de */ + for (i = 0; i < (int)ConnectionTypes.length; i++) + if (ConnectionTypes.data[i]==XdmcpConnectionType) + XdmcpWriteCARD16 (&buffer, ConnectionTypes.data[i]); + for (i = 0; i < (int)ConnectionTypes.length; i++) + if (ConnectionTypes.data[i]!=XdmcpConnectionType) + XdmcpWriteCARD16 (&buffer, ConnectionTypes.data[i]); + + XdmcpWriteCARD8 (&buffer, ConnectionAddresses.length); + for (i = 0; i < (int)ConnectionAddresses.length; i++) + if ( (i<ConnectionTypes.length) && + (ConnectionTypes.data[i]==XdmcpConnectionType) ) + XdmcpWriteARRAY8 (&buffer, &ConnectionAddresses.data[i]); + for (i = 0; i < (int)ConnectionAddresses.length; i++) + if ( (i>=ConnectionTypes.length) || + (ConnectionTypes.data[i]!=XdmcpConnectionType) ) + XdmcpWriteARRAY8 (&buffer, &ConnectionAddresses.data[i]); + + XdmcpWriteARRAY8 (&buffer, AuthenticationName); + XdmcpWriteARRAY8 (&buffer, &authenticationData); + XdmcpDisposeARRAY8 (&authenticationData); + XdmcpWriteARRAYofARRAY8 (&buffer, &AuthorizationNames); + XdmcpWriteARRAY8 (&buffer, &ManufacturerDisplayID); +#if defined(IPv6) && defined(AF_INET6) + if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6) + socketfd = xdmcpSocket6; +#endif + if (XdmcpFlush (socketfd, &buffer, + (XdmcpNetaddr) &req_sockaddr, req_socklen)) + state = XDM_AWAIT_REQUEST_RESPONSE; +} + +static void +recv_accept_msg(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(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(void) +{ + XdmcpHeader header; + int socketfd = xdmcpSocket; + + 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; +#if defined(IPv6) && defined(AF_INET6) + if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6) + socketfd = xdmcpSocket6; +#endif + XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen); +} + +static void +recv_refuse_msg(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(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(void) +{ + XdmcpHeader header; + int socketfd = xdmcpSocket; + + 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; +#if defined(IPv6) && defined(AF_INET6) + if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6) + socketfd = xdmcpSocket6; +#endif + XdmcpFlush (socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen); +} + +static void +recv_alive_msg (unsigned length) +{ + CARD8 SessionRunning; + CARD32 AliveSessionID; + + if (state != XDM_AWAIT_ALIVE_RESPONSE) + return; + if (length != 5) + return; + if (XdmcpReadCARD8 (&buffer, &SessionRunning) && + XdmcpReadCARD32 (&buffer, &AliveSessionID)) + { + if (SessionRunning && AliveSessionID == SessionID) + { + state = XDM_RUN_SESSION; + timeOutTime = GetTimeInMillis() + XDM_DEF_DORMANCY * 1000; + } + else + { + XdmcpDeadSession ("Alive response indicates session dead"); + } + } +} + +static void +XdmcpFatal ( + char *type, + ARRAY8Ptr status) +{ + FatalError ("XDMCP fatal error: %s %*.*s\n", type, + status->length, status->length, status->data); +} + +static void +XdmcpWarning(char *str) +{ + ErrorF("XDMCP warning: %s\n", str); +} + +static void +get_addr_by_name( + char * argtype, + char * namestr, + int port, + int socktype, + SOCKADDR_TYPE *addr, + SOCKLEN_TYPE *addrlen +#if defined(IPv6) && defined(AF_INET6) + , + struct addrinfo **aip, + struct addrinfo **aifirstp +#endif + ) +{ +#if defined(IPv6) && defined(AF_INET6) + struct addrinfo *ai; + struct addrinfo hints; + char portstr[6]; + char *pport = portstr; + int gaierr; + + bzero(&hints, sizeof(hints)); + hints.ai_socktype = socktype; + + if (port == 0) { + pport = NULL; + } else if (port > 0 && port < 65535) { + sprintf(portstr, "%d", port); + } else { + FatalError("Xserver: port out of range: %d\n", port); + } + + if (*aifirstp != NULL) { + freeaddrinfo(*aifirstp); + *aifirstp = NULL; + } + + if ((gaierr = getaddrinfo(namestr, pport, &hints, aifirstp)) == 0) { + for (ai = *aifirstp; ai != NULL; ai = ai->ai_next) { + if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) + break; + } + if ((ai == NULL) || (ai->ai_addrlen > sizeof(SOCKADDR_TYPE))) { + FatalError ("Xserver: %s host %s not on supported network type\n", + argtype, namestr); + } else { + *aip = ai; + *addrlen = ai->ai_addrlen; + memcpy(addr, ai->ai_addr, ai->ai_addrlen); + } + } else { + FatalError("Xserver: %s: %s %s\n", gai_strerror(gaierr), argtype, namestr); + } +#else + struct hostent *hep; +#ifdef XTHREADS_NEEDS_BYNAMEPARAMS + _Xgethostbynameparams hparams; +#endif +#if defined(WIN32) && defined(TCPCONN) + _XSERVTransWSAStartup(); +#endif + if (!(hep = _XGethostbyname(namestr, hparams))) + { + FatalError("Xserver: %s unknown host: %s\n", argtype, namestr); + } + if (hep->h_length == sizeof (struct in_addr)) + { + memmove(&addr->sin_addr, hep->h_addr, hep->h_length); + *addrlen = sizeof(struct sockaddr_in); + addr->sin_family = AF_INET; + addr->sin_port = htons (port); + } + else + { + FatalError("Xserver: %s host on strange network %s\n", argtype, namestr); + } +#endif +} + +static void +get_manager_by_name( + int argc, + char **argv, + int i) +{ + + if ((i + 1) == argc) + { + FatalError("Xserver: missing %s host name in command line\n", argv[i]); + } + + get_addr_by_name(argv[i], argv[i+1], xdm_udp_port, SOCK_DGRAM, + &ManagerAddress, &ManagerAddressLen +#if defined(IPv6) && defined(AF_INET6) + , &mgrAddr, &mgrAddrFirst +#endif + ); +} + + +static void +get_fromaddr_by_name( + int argc, + char **argv, + int i) +{ +#if defined(IPv6) && defined(AF_INET6) + struct addrinfo *ai = NULL; + struct addrinfo *aifirst = NULL; +#endif + if (i == argc) + { + FatalError("Xserver: missing -from host name in command line\n"); + } + get_addr_by_name("-from", argv[i], 0, 0, &FromAddress, &FromAddressLen +#if defined(IPv6) && defined(AF_INET6) + , &ai, &aifirst +#endif + ); + xdm_from = argv[i]; +} + + +#if defined(IPv6) && defined(AF_INET6) +static int +get_mcast_options(argc, argv, i) + int argc, i; + char **argv; +{ + char *address = XDM_DEFAULT_MCAST_ADDR6; + int hopcount = 1; + struct addrinfo hints; + char portstr[6]; + int gaierr; + struct addrinfo *ai, *firstai; + + if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) { + address = argv[i++]; + if ((i < argc) && (argv[i][0] != '-') && (argv[i][0] != '+')) { + hopcount = strtol(argv[i++], NULL, 10); + if ((hopcount < 1) || (hopcount > 255)) { + FatalError("Xserver: multicast hop count out of range: %d\n", + hopcount); + } + } + } + + if (xdm_udp_port > 0 && xdm_udp_port < 65535) { + sprintf(portstr, "%d", xdm_udp_port); + } else { + FatalError("Xserver: port out of range: %d\n", xdm_udp_port); + } + bzero(&hints, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; + + if ((gaierr = getaddrinfo(address, portstr, &hints, &firstai)) == 0) { + for (ai = firstai; ai != NULL; ai = ai->ai_next) { + if (((ai->ai_family == AF_INET) && + IN_MULTICAST(((struct sockaddr_in *) ai->ai_addr) + ->sin_addr.s_addr)) + || ((ai->ai_family == AF_INET6) && + IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *) ai->ai_addr) + ->sin6_addr))) + break; + } + if (ai == NULL) { + FatalError ("Xserver: address not supported multicast type %s\n", + address); + } else { + struct multicastinfo *mcastinfo, *mcl; + + mcastinfo = malloc(sizeof(struct multicastinfo)); + mcastinfo->next = NULL; + mcastinfo->ai = firstai; + mcastinfo->hops = hopcount; + + if (mcastlist == NULL) { + mcastlist = mcastinfo; + } else { + for (mcl = mcastlist; mcl->next != NULL; mcl = mcl->next) { + /* Do nothing - just find end of list */ + } + mcl->next = mcastinfo; + } + } + } else { + FatalError("Xserver: %s: %s\n", gai_strerror(gaierr), address); + } + return i; +} +#endif + +#else +static int xdmcp_non_empty; /* avoid complaint by ranlib */ +#endif /* XDMCP */ diff --git a/nx-X11/programs/Xserver/os/xprintf.c b/nx-X11/programs/Xserver/os/xprintf.c new file mode 100644 index 000000000..1bcb36d3c --- /dev/null +++ b/nx-X11/programs/Xserver/os/xprintf.c @@ -0,0 +1,163 @@ +/* + * printf routines which malloc their buffer + */ +/* + * Copyright (c) 2004 Alexander Gottwald + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) 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(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <nx-X11/Xos.h> +#include "os.h" +#include <stdarg.h> +#include <stdio.h> + +#ifndef va_copy +# ifdef __va_copy +# define va_copy __va_copy +# else +# error "no working va_copy was found" +# endif +#endif + +#ifdef NX_TRANS_SOCKET + +#define PANIC +#define WARNING +#undef TEST +#undef DEBUG + +#define START_SIZE 256 +#define END_SIZE 2048 + +char * +Xvprintf(const char *format, va_list va) +{ + char *ret; + char *newret; + int size; + int r; + + size = 0; + + for (;;) + { + if (size == 0) + { + ret = (char *)malloc(START_SIZE); + if (ret == NULL) + return NULL; + size = START_SIZE; + } + else if (size < END_SIZE && + (newret = (char *) realloc(ret, 2 * size)) != NULL) + { + ret = newret; + size = 2 * size; + } + else + { + free(ret); + return NULL; + } + + r = vsnprintf(ret, size, format, va); + + if (r == -1 || r == size || r > size || r == size - 1) + { + continue; + } + else + { + ret[r] = 0; + return ret; + } + } +} + +#else + +char * +Xvprintf(const char *format, va_list va) +{ + char *ret; + int size; + va_list va2; + + va_copy(va2, va); + size = vsnprintf(NULL, 0, format, va2); + va_end(va2); + + ret = (char *)malloc(size + 1); + if (ret == NULL) + return NULL; + + vsnprintf(ret, size + 1, format, va); + ret[size] = 0; + return ret; +} + +#endif + +char *Xprintf(const char *format, ...) +{ + char *ret; + va_list va; + va_start(va, format); + ret = Xvprintf(format, va); + va_end(va); + return ret; +} + +char * +XNFvprintf(const char *format, va_list va) +{ + char *ret; + int size; + va_list va2; + + va_copy(va2, va); + size = vsnprintf(NULL, 0, format, va2); + va_end(va2); + + ret = (char *)XNFalloc(size + 1); + if (ret == NULL) + return NULL; + + vsnprintf(ret, size + 1, format, va); + ret[size] = 0; + return ret; +} + +char *XNFprintf(const char *format, ...) +{ + char *ret; + va_list va; + va_start(va, format); + ret = XNFvprintf(format, va); + va_end(va); + return ret; +} diff --git a/nx-X11/programs/Xserver/os/xstrans.c b/nx-X11/programs/Xserver/os/xstrans.c new file mode 100644 index 000000000..cdb664430 --- /dev/null +++ b/nx-X11/programs/Xserver/os/xstrans.c @@ -0,0 +1,17 @@ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <nx-X11/Xfuncproto.h> + +/* ErrorF is used by xtrans */ +#ifndef HAVE_DIX_CONFIG_H +extern _X_EXPORT void +ErrorF(const char *f, ...) +_X_ATTRIBUTE_PRINTF(1, 2); +#endif + +#define TRANS_REOPEN +#define TRANS_SERVER +#define XSERV_t +#include <nx-X11/Xtrans/transport.c> |