diff options
Diffstat (limited to 'nx-X11/programs/Xserver/os')
36 files changed, 32336 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..1f46c2934 --- /dev/null +++ b/nx-X11/programs/Xserver/os/Imakefile @@ -0,0 +1,235 @@ +XCOMM $Xorg: Imakefile,v 1.3 2000/08/17 19:53:40 cpqbld Exp $ + + + + +XCOMM $XFree86: xc/programs/Xserver/os/Imakefile,v 3.40 2003/09/09 03:20:41 dawes Exp $ + +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NX-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of NoMachine S.r.l. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +#include <Server.tmpl> + +/* + * If you have any extra files to be put into the library, define them here. + */ + +#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 + +# -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 HasKrb5 +KRB5OBJS = k5auth.o k5encode.o +KRB5SRCS = k5auth.c k5encode.c +#endif + +#if HasBSD44Sockets + SOCK_DEFINES = -DBSD44SOCKETS +#endif + +#if HasGetIfAddrs + IFADDRS_DEFINES = -DHAS_GETIFADDRS +#endif + +#if BuildLBX + LBX_SRCS = lbxio.c + LBX_OBJS = lbxio.o +#else + LBX_SRCS = + LBX_OBJS = +#endif + +#if !defined(DDXOsColor) +COLOR_SRCS=oscolor.c +COLOR_OBJS=oscolor.o +#endif + +#if UseInternalMalloc +MALLOC_SRCS=xalloc.c +MALLOC_OBJS=xalloc.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 HasGetpeerucred +GETPEER_DEFINES = -DHAS_GETPEERUCRED +#else +# if HasGetpeereid +GETPEER_DEFINES = -DHAS_GETPEEREID +# endif +#endif + +BOOTSTRAPCFLAGS = + SRCS = WaitFor.c access.c connection.c io.c $(COLOR_SRCS) \ + osinit.c utils.c log.c auth.c mitauth.c secauth.c \ + $(XDMAUTHSRCS) $(RPCSRCS) $(KRB5SRCS) xdmcp.c OtherSources \ + transport.c $(SNPRINTF_SRCS) $(STRLCAT_SRCS) \ + $(MALLOC_SRCS) $(LBX_SRCS) xprintf.c + OBJS = WaitFor.o access.o connection.o io.o $(COLOR_OBJS) \ + osinit.o utils.o log.o auth.o mitauth.o secauth.o \ + $(XDMAUTHOBJS) $(RPCOBJS) $(KRB5OBJS) xdmcp.o OtherObjects \ + transport.o $(SNPRINTF_OBJS) $(STRLCAT_OBJS) \ + $(MALLOC_OBJS) $(LBX_OBJS) xprintf.o + +#if SpecialMalloc + MEM_DEFINES = -DSPECIAL_MALLOC +#endif /* SpecialMalloc */ +#if UseInternalMalloc + MEM_DEFINES = -DINTERNAL_MALLOC +#endif +#if UseMemLeak + MEM_DEFINES = -DMEMBUG +#endif +#if UseRgbTxt + RGB_DEFINES = -DUSE_RGB_TXT +#endif + DBM_DEFINES = NdbmDefines + ADM_DEFINES = -DADMPATH=\"$(ADMDIR)/X\%smsgs\" + XDMCP_DEFINES = ServerXdmcpDefines + KRB5_DEFINES = Krb5Defines + XALLOC_DEFINES = XallocDefines + ERROR_DEFINES = ServerErrorDefines +#if HasPam && HasPamMisc + PAM_DEFINES = -DUSE_PAM +#endif + DEFINES = -DXSERV_t -DTRANS_SERVER $(CONNECTION_FLAGS) $(MEM_DEFINES) \ + $(XDMAUTHDEFS) $(RPCDEFS) $(SIGNAL_DEFINES) $(OS_DEFINES) \ + $(KRB5_DEFINES) $(RGB_DEFINES) $(GETPEER_DEFINES) \ + $(RANDOM_DEFINES) $(BUGMSG) $(XTRANS_FAILDEFINES) $(NX_DEFINES) + INCLUDES = -I. -I../include -I$(XINCLUDESRC) -I$(EXTINCSRC) \ + -I$(SERVERSRC)/Xext -I$(FONTINCSRC) -I$(SERVERSRC)/render \ + -I$(TOP)/lib/Xau -I../lbx -I../Xprint Krb5Includes $(NX_INCLUDES) + DEPEND_DEFINES = $(DBM_DEFINES) $(XDMCP_DEFINES) $(EXT_DEFINES) \ + $(TRANS_INCLUDES) $(CONNECTION_FLAGS) $(GETPEER_DEFINES) \ + DependDefines + 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)) +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(transport,$(ICONFIGFILES),$(TRANS_INCLUDES) $(CONN_DEFINES) $(SOCK_DEFINES)) +LinkSourceFile(transport.c,$(TRANSCOMMSRC)) +SpecialCObjectRule(osinit,$(ICONFIGFILES),$(ADM_DEFINES)) +SpecialCObjectRule(WaitFor,$(ICONFIGFILES),$(EXT_DEFINES)) +SpecialCObjectRule(io,$(ICONFIGFILES),$(EXT_DEFINES)) +#if BuildLBX +SpecialCObjectRule(lbxio,$(ICONFIGFILES),$(EXT_DEFINES)) +#endif +SpecialCObjectRule(utils,$(ICONFIGFILES),$(XDMCP_DEFINES) $(EXT_DEFINES) $(ERROR_DEFINES) $(PAM_DEFINES)) +SpecialCObjectRule(xalloc,$(ICONFIGFILES),$(XALLOC_DEFINES)) +#if defined(SparcArchitecture) && HasGcc && !HasGcc2 +oscolor.o: oscolor.c $(ICONFIGFILES) + $(RM) $@ + cc -c $(DBM_DEFINES) $(CDEBUGFLAGS) $(ALLDEFINES) $*.c +#else +SpecialCObjectRule(oscolor,$(ICONFIGFILES),$(DBM_DEFINES)) +#endif + +#if HasKrb5 +LinkSourceFile(k5encode.c,$(XAUTHSRC)) +#endif + +#if !HasSnprintf +LinkSourceFile(snprintf.c,$(LIBSRC)/misc) +#endif + +#if !HasStrlcat +LinkSourceFile(strlcat.c,$(LIBSRC)/misc) +LinkSourceFile(strlcpy.c,$(LIBSRC)/misc) +#endif + +#if DoLoadableServer +AllTarget(libcwrapper.o) +ObjectFromSpecialSource(libcwrapper,$(XF86OSSRC)/shared/libc_wrapper,-DSELF_CONTAINED_WRAPPER) +#endif + +DependTarget() diff --git a/nx-X11/programs/Xserver/os/Imakefile.NX.original b/nx-X11/programs/Xserver/os/Imakefile.NX.original new file mode 100644 index 000000000..1f46c2934 --- /dev/null +++ b/nx-X11/programs/Xserver/os/Imakefile.NX.original @@ -0,0 +1,235 @@ +XCOMM $Xorg: Imakefile,v 1.3 2000/08/17 19:53:40 cpqbld Exp $ + + + + +XCOMM $XFree86: xc/programs/Xserver/os/Imakefile,v 3.40 2003/09/09 03:20:41 dawes Exp $ + +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NX-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of NoMachine S.r.l. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +#include <Server.tmpl> + +/* + * If you have any extra files to be put into the library, define them here. + */ + +#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 + +# -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 HasKrb5 +KRB5OBJS = k5auth.o k5encode.o +KRB5SRCS = k5auth.c k5encode.c +#endif + +#if HasBSD44Sockets + SOCK_DEFINES = -DBSD44SOCKETS +#endif + +#if HasGetIfAddrs + IFADDRS_DEFINES = -DHAS_GETIFADDRS +#endif + +#if BuildLBX + LBX_SRCS = lbxio.c + LBX_OBJS = lbxio.o +#else + LBX_SRCS = + LBX_OBJS = +#endif + +#if !defined(DDXOsColor) +COLOR_SRCS=oscolor.c +COLOR_OBJS=oscolor.o +#endif + +#if UseInternalMalloc +MALLOC_SRCS=xalloc.c +MALLOC_OBJS=xalloc.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 HasGetpeerucred +GETPEER_DEFINES = -DHAS_GETPEERUCRED +#else +# if HasGetpeereid +GETPEER_DEFINES = -DHAS_GETPEEREID +# endif +#endif + +BOOTSTRAPCFLAGS = + SRCS = WaitFor.c access.c connection.c io.c $(COLOR_SRCS) \ + osinit.c utils.c log.c auth.c mitauth.c secauth.c \ + $(XDMAUTHSRCS) $(RPCSRCS) $(KRB5SRCS) xdmcp.c OtherSources \ + transport.c $(SNPRINTF_SRCS) $(STRLCAT_SRCS) \ + $(MALLOC_SRCS) $(LBX_SRCS) xprintf.c + OBJS = WaitFor.o access.o connection.o io.o $(COLOR_OBJS) \ + osinit.o utils.o log.o auth.o mitauth.o secauth.o \ + $(XDMAUTHOBJS) $(RPCOBJS) $(KRB5OBJS) xdmcp.o OtherObjects \ + transport.o $(SNPRINTF_OBJS) $(STRLCAT_OBJS) \ + $(MALLOC_OBJS) $(LBX_OBJS) xprintf.o + +#if SpecialMalloc + MEM_DEFINES = -DSPECIAL_MALLOC +#endif /* SpecialMalloc */ +#if UseInternalMalloc + MEM_DEFINES = -DINTERNAL_MALLOC +#endif +#if UseMemLeak + MEM_DEFINES = -DMEMBUG +#endif +#if UseRgbTxt + RGB_DEFINES = -DUSE_RGB_TXT +#endif + DBM_DEFINES = NdbmDefines + ADM_DEFINES = -DADMPATH=\"$(ADMDIR)/X\%smsgs\" + XDMCP_DEFINES = ServerXdmcpDefines + KRB5_DEFINES = Krb5Defines + XALLOC_DEFINES = XallocDefines + ERROR_DEFINES = ServerErrorDefines +#if HasPam && HasPamMisc + PAM_DEFINES = -DUSE_PAM +#endif + DEFINES = -DXSERV_t -DTRANS_SERVER $(CONNECTION_FLAGS) $(MEM_DEFINES) \ + $(XDMAUTHDEFS) $(RPCDEFS) $(SIGNAL_DEFINES) $(OS_DEFINES) \ + $(KRB5_DEFINES) $(RGB_DEFINES) $(GETPEER_DEFINES) \ + $(RANDOM_DEFINES) $(BUGMSG) $(XTRANS_FAILDEFINES) $(NX_DEFINES) + INCLUDES = -I. -I../include -I$(XINCLUDESRC) -I$(EXTINCSRC) \ + -I$(SERVERSRC)/Xext -I$(FONTINCSRC) -I$(SERVERSRC)/render \ + -I$(TOP)/lib/Xau -I../lbx -I../Xprint Krb5Includes $(NX_INCLUDES) + DEPEND_DEFINES = $(DBM_DEFINES) $(XDMCP_DEFINES) $(EXT_DEFINES) \ + $(TRANS_INCLUDES) $(CONNECTION_FLAGS) $(GETPEER_DEFINES) \ + DependDefines + 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)) +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(transport,$(ICONFIGFILES),$(TRANS_INCLUDES) $(CONN_DEFINES) $(SOCK_DEFINES)) +LinkSourceFile(transport.c,$(TRANSCOMMSRC)) +SpecialCObjectRule(osinit,$(ICONFIGFILES),$(ADM_DEFINES)) +SpecialCObjectRule(WaitFor,$(ICONFIGFILES),$(EXT_DEFINES)) +SpecialCObjectRule(io,$(ICONFIGFILES),$(EXT_DEFINES)) +#if BuildLBX +SpecialCObjectRule(lbxio,$(ICONFIGFILES),$(EXT_DEFINES)) +#endif +SpecialCObjectRule(utils,$(ICONFIGFILES),$(XDMCP_DEFINES) $(EXT_DEFINES) $(ERROR_DEFINES) $(PAM_DEFINES)) +SpecialCObjectRule(xalloc,$(ICONFIGFILES),$(XALLOC_DEFINES)) +#if defined(SparcArchitecture) && HasGcc && !HasGcc2 +oscolor.o: oscolor.c $(ICONFIGFILES) + $(RM) $@ + cc -c $(DBM_DEFINES) $(CDEBUGFLAGS) $(ALLDEFINES) $*.c +#else +SpecialCObjectRule(oscolor,$(ICONFIGFILES),$(DBM_DEFINES)) +#endif + +#if HasKrb5 +LinkSourceFile(k5encode.c,$(XAUTHSRC)) +#endif + +#if !HasSnprintf +LinkSourceFile(snprintf.c,$(LIBSRC)/misc) +#endif + +#if !HasStrlcat +LinkSourceFile(strlcat.c,$(LIBSRC)/misc) +LinkSourceFile(strlcpy.c,$(LIBSRC)/misc) +#endif + +#if DoLoadableServer +AllTarget(libcwrapper.o) +ObjectFromSpecialSource(libcwrapper,$(XF86OSSRC)/shared/libc_wrapper,-DSELF_CONTAINED_WRAPPER) +#endif + +DependTarget() diff --git a/nx-X11/programs/Xserver/os/Imakefile.X.original b/nx-X11/programs/Xserver/os/Imakefile.X.original new file mode 100644 index 000000000..c24a016dc --- /dev/null +++ b/nx-X11/programs/Xserver/os/Imakefile.X.original @@ -0,0 +1,200 @@ +XCOMM $Xorg: Imakefile,v 1.3 2000/08/17 19:53:40 cpqbld Exp $ + + + + +XCOMM $XFree86: xc/programs/Xserver/os/Imakefile,v 3.40 2003/09/09 03:20:41 dawes Exp $ + +#include <Server.tmpl> + +/* + * If you have any extra files to be put into the library, define them here. + */ + +/* + * 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 HasKrb5 +KRB5OBJS = k5auth.o k5encode.o +KRB5SRCS = k5auth.c k5encode.c +#endif + +#if HasBSD44Sockets + SOCK_DEFINES = -DBSD44SOCKETS +#endif + +#if HasGetIfAddrs + IFADDRS_DEFINES = -DHAS_GETIFADDRS +#endif + +#if BuildLBX + LBX_SRCS = lbxio.c + LBX_OBJS = lbxio.o +#else + LBX_SRCS = + LBX_OBJS = +#endif + +#if !defined(DDXOsColor) +COLOR_SRCS=oscolor.c +COLOR_OBJS=oscolor.o +#endif + +#if UseInternalMalloc +MALLOC_SRCS=xalloc.c +MALLOC_OBJS=xalloc.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 HasGetpeerucred +GETPEER_DEFINES = -DHAS_GETPEERUCRED +#else +# if HasGetpeereid +GETPEER_DEFINES = -DHAS_GETPEEREID +# endif +#endif + +BOOTSTRAPCFLAGS = + SRCS = WaitFor.c access.c connection.c io.c $(COLOR_SRCS) \ + osinit.c utils.c log.c auth.c mitauth.c secauth.c \ + $(XDMAUTHSRCS) $(RPCSRCS) $(KRB5SRCS) xdmcp.c OtherSources \ + transport.c $(SNPRINTF_SRCS) $(STRLCAT_SRCS) \ + $(MALLOC_SRCS) $(LBX_SRCS) xprintf.c + OBJS = WaitFor.o access.o connection.o io.o $(COLOR_OBJS) \ + osinit.o utils.o log.o auth.o mitauth.o secauth.o \ + $(XDMAUTHOBJS) $(RPCOBJS) $(KRB5OBJS) xdmcp.o OtherObjects \ + transport.o $(SNPRINTF_OBJS) $(STRLCAT_OBJS) \ + $(MALLOC_OBJS) $(LBX_OBJS) xprintf.o + +#if SpecialMalloc + MEM_DEFINES = -DSPECIAL_MALLOC +#endif /* SpecialMalloc */ +#if UseInternalMalloc + MEM_DEFINES = -DINTERNAL_MALLOC +#endif +#if UseMemLeak + MEM_DEFINES = -DMEMBUG +#endif +#if UseRgbTxt + RGB_DEFINES = -DUSE_RGB_TXT +#endif + DBM_DEFINES = NdbmDefines + ADM_DEFINES = -DADMPATH=\"$(ADMDIR)/X\%smsgs\" + XDMCP_DEFINES = ServerXdmcpDefines + KRB5_DEFINES = Krb5Defines + XALLOC_DEFINES = XallocDefines + ERROR_DEFINES = ServerErrorDefines +#if HasPam && HasPamMisc + PAM_DEFINES = -DUSE_PAM +#endif + DEFINES = -DXSERV_t -DTRANS_SERVER $(CONNECTION_FLAGS) $(MEM_DEFINES) \ + $(XDMAUTHDEFS) $(RPCDEFS) $(SIGNAL_DEFINES) $(OS_DEFINES) \ + $(KRB5_DEFINES) $(RGB_DEFINES) $(GETPEER_DEFINES) \ + $(RANDOM_DEFINES) $(BUGMSG) $(XTRANS_FAILDEFINES) + INCLUDES = -I. -I../include -I$(XINCLUDESRC) -I$(EXTINCSRC) \ + -I$(SERVERSRC)/Xext -I$(FONTINCSRC) -I$(SERVERSRC)/render \ + -I$(TOP)/lib/Xau -I../lbx -I../Xprint Krb5Includes + DEPEND_DEFINES = $(DBM_DEFINES) $(XDMCP_DEFINES) $(EXT_DEFINES) \ + $(TRANS_INCLUDES) $(CONNECTION_FLAGS) $(GETPEER_DEFINES) \ + DependDefines + 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)) +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(transport,$(ICONFIGFILES),$(TRANS_INCLUDES) $(CONN_DEFINES) $(SOCK_DEFINES)) +LinkSourceFile(transport.c,$(TRANSCOMMSRC)) +SpecialCObjectRule(osinit,$(ICONFIGFILES),$(ADM_DEFINES)) +SpecialCObjectRule(WaitFor,$(ICONFIGFILES),$(EXT_DEFINES)) +SpecialCObjectRule(io,$(ICONFIGFILES),$(EXT_DEFINES)) +#if BuildLBX +SpecialCObjectRule(lbxio,$(ICONFIGFILES),$(EXT_DEFINES)) +#endif +SpecialCObjectRule(utils,$(ICONFIGFILES),$(XDMCP_DEFINES) $(EXT_DEFINES) $(ERROR_DEFINES) $(PAM_DEFINES)) +SpecialCObjectRule(xalloc,$(ICONFIGFILES),$(XALLOC_DEFINES)) +#if defined(SparcArchitecture) && HasGcc && !HasGcc2 +oscolor.o: oscolor.c $(ICONFIGFILES) + $(RM) $@ + cc -c $(DBM_DEFINES) $(CDEBUGFLAGS) $(ALLDEFINES) $*.c +#else +SpecialCObjectRule(oscolor,$(ICONFIGFILES),$(DBM_DEFINES)) +#endif + +#if HasKrb5 +LinkSourceFile(k5encode.c,$(XAUTHSRC)) +#endif + +#if !HasSnprintf +LinkSourceFile(snprintf.c,$(LIBSRC)/misc) +#endif + +#if !HasStrlcat +LinkSourceFile(strlcat.c,$(LIBSRC)/misc) +LinkSourceFile(strlcpy.c,$(LIBSRC)/misc) +#endif + +#if DoLoadableServer +AllTarget(libcwrapper.o) +ObjectFromSpecialSource(libcwrapper,$(XF86OSSRC)/shared/libc_wrapper,-DSELF_CONTAINED_WRAPPER) +#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..b4991d4ed --- /dev/null +++ b/nx-X11/programs/Xserver/os/WaitFor.c @@ -0,0 +1,882 @@ +/* $XFree86: xc/programs/Xserver/os/WaitFor.c,v 3.42 2003/10/16 01:33:35 dawes Exp $ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* $Xorg: WaitFor.c,v 1.4 2001/02/09 02:05:22 xorgcvs Exp $ */ + +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NX-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of NoMachine S.r.l. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +/***************************************************************** + * OS Dependent input routines: + * + * WaitForSomething + * TimerForce, TimerSet, TimerCheck, TimerFree + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif +#include <X11/Xos.h> /* for strings, fcntl, time */ +#include <errno.h> +#include <stdio.h> +#include <X11/X.h> +#include "misc.h" + +#ifdef __UNIXOS2__ +#define select(n,r,w,x,t) os2PseudoSelect(n,r,w,x,t) +#endif +#include "osdep.h" +#include <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 <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; + pointer 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; + fd_set devicesReadable; + CARD32 now = 0; +#ifdef SMART_SCHEDULE + Bool someReady = FALSE; +#endif + +#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)) + { +#ifdef SMART_SCHEDULE + if (!SmartScheduleDisable) + { + someReady = TRUE; + waittime.tv_sec = 0; + waittime.tv_usec = 0; + wt = &waittime; + } + else +#endif + { + XFD_COPYSET (&ClientsWithInput, &clientsReadable); + break; + } + } +#ifdef SMART_SCHEDULE + if (someReady) + { + XFD_COPYSET(&AllSockets, &LastSelectMask); + XFD_UNSET(&LastSelectMask, &ClientsWithInput); + } + else + { +#endif + 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); +#ifdef SMART_SCHEDULE + } + SmartScheduleIdle = TRUE; +#endif + BlockHandler((pointer)&wt, (pointer)&LastSelectMask); + if (NewOutputPending) + FlushAllOutput(); +#ifdef XTESTEXT1 + /* XXX how does this interact with new write block handling? */ + if (playback_on) { + wt = &waittime; + XTestComputeWaitTime (&waittime); + } +#endif /* XTESTEXT1 */ + +#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 (AnyClientsWriteBlocked) + { +#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, &clientsWritable); + i = Select (MaxClients, &LastSelectMask, &clientsWritable, 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, (pointer)&LastSelectMask); +#ifdef XTESTEXT1 + if (playback_on) { + i = XTestProcessInputAction (i, &waittime); + } +#endif /* XTESTEXT1 */ +#ifdef SMART_SCHEDULE + if (i >= 0) + { + SmartScheduleIdle = FALSE; + SmartScheduleIdleCount = 0; + if (SmartScheduleTimerStopped) + (void) SmartScheduleStartTimer (); + } +#endif + 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); + } + } +#ifdef SMART_SCHEDULE + else if (someReady) + { + /* + * If no-one else is home, bail quickly + */ + XFD_COPYSET(&ClientsWithInput, &LastSelectMask); + XFD_COPYSET(&ClientsWithInput, &clientsReadable); + break; + } +#endif +#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; + } + } +#ifdef SMART_SCHEDULE + if (someReady) + XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask); +#endif + if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable)) + { + NewOutputPending = TRUE; + XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending); + XFD_UNSET(&ClientsWriteBlocked, &clientsWritable); + if (! XFD_ANYSET(&ClientsWriteBlocked)) + AnyClientsWriteBlocked = FALSE; + } + + XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices); + XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients); + XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections); + if (XFD_ANYSET(&tmp_set)) + QueueWorkProc(EstablishNewConnections, NULL, + (pointer)&LastSelectMask); +#ifdef DPMSExtension + if (XFD_ANYSET (&devicesReadable) && (DPMSPowerLevel != DPMSModeOn)) + DPMSSet(DPMSModeOn); +#endif + if (XFD_ANYSET (&devicesReadable) || 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++) + { + int highest_priority = 0; + + while (clientsReadable.fds_bits[i]) + { + int client_priority, client_index; + + curclient = ffs (clientsReadable.fds_bits[i]) - 1; + client_index = /* raphael: modified */ + ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))]; +#else + int highest_priority = 0; + 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 +#ifdef XSYNC + /* We implement "strict" priorities. + * Only the highest priority client is returned to + * dix. If multiple clients at the same priority are + * ready, they are all returned. This means that an + * aggressive client could take over the server. + * This was not considered a big problem because + * aggressive clients can hose the server in so many + * other ways :) + */ + client_priority = clients[client_index]->priority; + if (nready == 0 || client_priority > highest_priority) + { + /* Either we found the first client, or we found + * a client whose priority is greater than all others + * that have been found so far. Either way, we want + * to initialize the list of clients to contain just + * this client. + */ + pClientsReady[0] = client_index; + highest_priority = client_priority; + nready = 1; + } + /* the following if makes sure that multiple same-priority + * clients get batched together + */ + else if (client_priority == highest_priority) +#endif + { + pClientsReady[nready++] = client_index; + } +#ifndef WIN32 + clientsReadable.fds_bits[i] &= ~(((fd_mask)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, pointer arg) +{ + register OsTimerPtr *prev; + CARD32 now = GetTimeInMillis(); + + if (!timer) + { + timer = (OsTimerPtr)xalloc(sizeof(struct _OsTimerRec)); + if (!timer) + return NULL; + } + else + { + for (prev = &timers; *prev; prev = &(*prev)->next) + { + if (*prev == timer) + { + *prev = timer->next; + if (flags & TimerForceOld) + (void)(*timer->callback)(timer, now, timer->arg); + break; + } + } + } + if (!millis) + return timer; + if (!(flags & TimerAbsolute)) + millis += now; + timer->expires = millis; + timer->callback = func; + timer->arg = arg; + if ((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); + xfree(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; + xfree(timer); + } +} + +static CARD32 +ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer 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,pointer 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,pointer 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,pointer 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/WaitFor.c.NX.original b/nx-X11/programs/Xserver/os/WaitFor.c.NX.original new file mode 100644 index 000000000..b4991d4ed --- /dev/null +++ b/nx-X11/programs/Xserver/os/WaitFor.c.NX.original @@ -0,0 +1,882 @@ +/* $XFree86: xc/programs/Xserver/os/WaitFor.c,v 3.42 2003/10/16 01:33:35 dawes Exp $ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* $Xorg: WaitFor.c,v 1.4 2001/02/09 02:05:22 xorgcvs Exp $ */ + +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NX-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of NoMachine S.r.l. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +/***************************************************************** + * OS Dependent input routines: + * + * WaitForSomething + * TimerForce, TimerSet, TimerCheck, TimerFree + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif +#include <X11/Xos.h> /* for strings, fcntl, time */ +#include <errno.h> +#include <stdio.h> +#include <X11/X.h> +#include "misc.h" + +#ifdef __UNIXOS2__ +#define select(n,r,w,x,t) os2PseudoSelect(n,r,w,x,t) +#endif +#include "osdep.h" +#include <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 <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; + pointer 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; + fd_set devicesReadable; + CARD32 now = 0; +#ifdef SMART_SCHEDULE + Bool someReady = FALSE; +#endif + +#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)) + { +#ifdef SMART_SCHEDULE + if (!SmartScheduleDisable) + { + someReady = TRUE; + waittime.tv_sec = 0; + waittime.tv_usec = 0; + wt = &waittime; + } + else +#endif + { + XFD_COPYSET (&ClientsWithInput, &clientsReadable); + break; + } + } +#ifdef SMART_SCHEDULE + if (someReady) + { + XFD_COPYSET(&AllSockets, &LastSelectMask); + XFD_UNSET(&LastSelectMask, &ClientsWithInput); + } + else + { +#endif + 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); +#ifdef SMART_SCHEDULE + } + SmartScheduleIdle = TRUE; +#endif + BlockHandler((pointer)&wt, (pointer)&LastSelectMask); + if (NewOutputPending) + FlushAllOutput(); +#ifdef XTESTEXT1 + /* XXX how does this interact with new write block handling? */ + if (playback_on) { + wt = &waittime; + XTestComputeWaitTime (&waittime); + } +#endif /* XTESTEXT1 */ + +#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 (AnyClientsWriteBlocked) + { +#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, &clientsWritable); + i = Select (MaxClients, &LastSelectMask, &clientsWritable, 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, (pointer)&LastSelectMask); +#ifdef XTESTEXT1 + if (playback_on) { + i = XTestProcessInputAction (i, &waittime); + } +#endif /* XTESTEXT1 */ +#ifdef SMART_SCHEDULE + if (i >= 0) + { + SmartScheduleIdle = FALSE; + SmartScheduleIdleCount = 0; + if (SmartScheduleTimerStopped) + (void) SmartScheduleStartTimer (); + } +#endif + 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); + } + } +#ifdef SMART_SCHEDULE + else if (someReady) + { + /* + * If no-one else is home, bail quickly + */ + XFD_COPYSET(&ClientsWithInput, &LastSelectMask); + XFD_COPYSET(&ClientsWithInput, &clientsReadable); + break; + } +#endif +#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; + } + } +#ifdef SMART_SCHEDULE + if (someReady) + XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask); +#endif + if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable)) + { + NewOutputPending = TRUE; + XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending); + XFD_UNSET(&ClientsWriteBlocked, &clientsWritable); + if (! XFD_ANYSET(&ClientsWriteBlocked)) + AnyClientsWriteBlocked = FALSE; + } + + XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices); + XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients); + XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections); + if (XFD_ANYSET(&tmp_set)) + QueueWorkProc(EstablishNewConnections, NULL, + (pointer)&LastSelectMask); +#ifdef DPMSExtension + if (XFD_ANYSET (&devicesReadable) && (DPMSPowerLevel != DPMSModeOn)) + DPMSSet(DPMSModeOn); +#endif + if (XFD_ANYSET (&devicesReadable) || 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++) + { + int highest_priority = 0; + + while (clientsReadable.fds_bits[i]) + { + int client_priority, client_index; + + curclient = ffs (clientsReadable.fds_bits[i]) - 1; + client_index = /* raphael: modified */ + ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))]; +#else + int highest_priority = 0; + 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 +#ifdef XSYNC + /* We implement "strict" priorities. + * Only the highest priority client is returned to + * dix. If multiple clients at the same priority are + * ready, they are all returned. This means that an + * aggressive client could take over the server. + * This was not considered a big problem because + * aggressive clients can hose the server in so many + * other ways :) + */ + client_priority = clients[client_index]->priority; + if (nready == 0 || client_priority > highest_priority) + { + /* Either we found the first client, or we found + * a client whose priority is greater than all others + * that have been found so far. Either way, we want + * to initialize the list of clients to contain just + * this client. + */ + pClientsReady[0] = client_index; + highest_priority = client_priority; + nready = 1; + } + /* the following if makes sure that multiple same-priority + * clients get batched together + */ + else if (client_priority == highest_priority) +#endif + { + pClientsReady[nready++] = client_index; + } +#ifndef WIN32 + clientsReadable.fds_bits[i] &= ~(((fd_mask)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, pointer arg) +{ + register OsTimerPtr *prev; + CARD32 now = GetTimeInMillis(); + + if (!timer) + { + timer = (OsTimerPtr)xalloc(sizeof(struct _OsTimerRec)); + if (!timer) + return NULL; + } + else + { + for (prev = &timers; *prev; prev = &(*prev)->next) + { + if (*prev == timer) + { + *prev = timer->next; + if (flags & TimerForceOld) + (void)(*timer->callback)(timer, now, timer->arg); + break; + } + } + } + if (!millis) + return timer; + if (!(flags & TimerAbsolute)) + millis += now; + timer->expires = millis; + timer->callback = func; + timer->arg = arg; + if ((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); + xfree(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; + xfree(timer); + } +} + +static CARD32 +ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer 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,pointer 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,pointer 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,pointer 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/WaitFor.c.X.original b/nx-X11/programs/Xserver/os/WaitFor.c.X.original new file mode 100644 index 000000000..31e16210b --- /dev/null +++ b/nx-X11/programs/Xserver/os/WaitFor.c.X.original @@ -0,0 +1,701 @@ +/* $XFree86: xc/programs/Xserver/os/WaitFor.c,v 3.42 2003/10/16 01:33:35 dawes Exp $ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* $Xorg: WaitFor.c,v 1.4 2001/02/09 02:05:22 xorgcvs Exp $ */ + +/***************************************************************** + * OS Dependent input routines: + * + * WaitForSomething + * TimerForce, TimerSet, TimerCheck, TimerFree + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif +#include <X11/Xos.h> /* for strings, fcntl, time */ +#include <errno.h> +#include <stdio.h> +#include <X11/X.h> +#include "misc.h" + +#ifdef __UNIXOS2__ +#define select(n,r,w,x,t) os2PseudoSelect(n,r,w,x,t) +#endif +#include "osdep.h" +#include <X11/Xpoll.h> +#include "dixstruct.h" +#include "opaque.h" +#ifdef DPMSExtension +#include "dpmsproc.h" +#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 <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; + pointer 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; + fd_set devicesReadable; + CARD32 now = 0; +#ifdef SMART_SCHEDULE + Bool someReady = FALSE; +#endif + + FD_ZERO(&clientsReadable); + + /* We need a while loop here to handle + crashed connections and the screen saver timeout */ + while (1) + { + /* deal with any blocked jobs */ + if (workQueue) + ProcessWorkQueue(); + if (XFD_ANYSET (&ClientsWithInput)) + { +#ifdef SMART_SCHEDULE + if (!SmartScheduleDisable) + { + someReady = TRUE; + waittime.tv_sec = 0; + waittime.tv_usec = 0; + wt = &waittime; + } + else +#endif + { + XFD_COPYSET (&ClientsWithInput, &clientsReadable); + break; + } + } +#ifdef SMART_SCHEDULE + if (someReady) + { + XFD_COPYSET(&AllSockets, &LastSelectMask); + XFD_UNSET(&LastSelectMask, &ClientsWithInput); + } + else + { +#endif + 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); +#ifdef SMART_SCHEDULE + } + SmartScheduleIdle = TRUE; +#endif + BlockHandler((pointer)&wt, (pointer)&LastSelectMask); + if (NewOutputPending) + FlushAllOutput(); +#ifdef XTESTEXT1 + /* XXX how does this interact with new write block handling? */ + if (playback_on) { + wt = &waittime; + XTestComputeWaitTime (&waittime); + } +#endif /* XTESTEXT1 */ + /* keep this check close to select() call to minimize race */ + if (dispatchException) + i = -1; + else if (AnyClientsWriteBlocked) + { + XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable); + i = Select (MaxClients, &LastSelectMask, &clientsWritable, NULL, wt); + } + else + { + i = Select (MaxClients, &LastSelectMask, NULL, NULL, wt); + } + selecterr = GetErrno(); + WakeupHandler(i, (pointer)&LastSelectMask); +#ifdef XTESTEXT1 + if (playback_on) { + i = XTestProcessInputAction (i, &waittime); + } +#endif /* XTESTEXT1 */ +#ifdef SMART_SCHEDULE + if (i >= 0) + { + SmartScheduleIdle = FALSE; + SmartScheduleIdleCount = 0; + if (SmartScheduleTimerStopped) + (void) SmartScheduleStartTimer (); + } +#endif + if (i <= 0) /* An error or timeout occurred */ + { + if (dispatchException) + return 0; + if (i < 0) + { + if (selecterr == EBADF) /* Some client disconnected */ + { + CheckConnections (); + if (! XFD_ANYSET (&AllClients)) + return 0; + } + else if (selecterr == EINVAL) + { + FatalError("WaitForSomething(): select: errno=%d\n", + selecterr); + } + else if (selecterr != EINTR) + { + ErrorF("WaitForSomething(): select: errno=%d\n", + selecterr); + } + } +#ifdef SMART_SCHEDULE + else if (someReady) + { + /* + * If no-one else is home, bail quickly + */ + XFD_COPYSET(&ClientsWithInput, &LastSelectMask); + XFD_COPYSET(&ClientsWithInput, &clientsReadable); + break; + } +#endif + if (*checkForInput[0] != *checkForInput[1]) + return 0; + + 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; + } + } +#ifdef SMART_SCHEDULE + if (someReady) + XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask); +#endif + if (AnyClientsWriteBlocked && XFD_ANYSET (&clientsWritable)) + { + NewOutputPending = TRUE; + XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending); + XFD_UNSET(&ClientsWriteBlocked, &clientsWritable); + if (! XFD_ANYSET(&ClientsWriteBlocked)) + AnyClientsWriteBlocked = FALSE; + } + + XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices); + XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients); + XFD_ANDSET(&tmp_set, &LastSelectMask, &WellKnownConnections); + if (XFD_ANYSET(&tmp_set)) + QueueWorkProc(EstablishNewConnections, NULL, + (pointer)&LastSelectMask); +#ifdef DPMSExtension + if (XFD_ANYSET (&devicesReadable) && (DPMSPowerLevel != DPMSModeOn)) + DPMSSet(DPMSModeOn); +#endif + if (XFD_ANYSET (&devicesReadable) || 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 (*checkForInput[0] != *checkForInput[1]) + return 0; +#endif + } + } + + nready = 0; + if (XFD_ANYSET (&clientsReadable)) + { +#ifndef WIN32 + for (i=0; i<howmany(XFD_SETSIZE, NFDBITS); i++) + { + int highest_priority = 0; + + while (clientsReadable.fds_bits[i]) + { + int client_priority, client_index; + + curclient = ffs (clientsReadable.fds_bits[i]) - 1; + client_index = /* raphael: modified */ + ConnectionTranslation[curclient + (i * (sizeof(fd_mask) * 8))]; +#else + int highest_priority = 0; + 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 +#ifdef XSYNC + /* We implement "strict" priorities. + * Only the highest priority client is returned to + * dix. If multiple clients at the same priority are + * ready, they are all returned. This means that an + * aggressive client could take over the server. + * This was not considered a big problem because + * aggressive clients can hose the server in so many + * other ways :) + */ + client_priority = clients[client_index]->priority; + if (nready == 0 || client_priority > highest_priority) + { + /* Either we found the first client, or we found + * a client whose priority is greater than all others + * that have been found so far. Either way, we want + * to initialize the list of clients to contain just + * this client. + */ + pClientsReady[0] = client_index; + highest_priority = client_priority; + nready = 1; + } + /* the following if makes sure that multiple same-priority + * clients get batched together + */ + else if (client_priority == highest_priority) +#endif + { + pClientsReady[nready++] = client_index; + } +#ifndef WIN32 + clientsReadable.fds_bits[i] &= ~(((fd_mask)1L) << curclient); + } +#else + FD_CLR(curclient, &clientsReadable); +#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, pointer arg) +{ + register OsTimerPtr *prev; + CARD32 now = GetTimeInMillis(); + + if (!timer) + { + timer = (OsTimerPtr)xalloc(sizeof(struct _OsTimerRec)); + if (!timer) + return NULL; + } + else + { + for (prev = &timers; *prev; prev = &(*prev)->next) + { + if (*prev == timer) + { + *prev = timer->next; + if (flags & TimerForceOld) + (void)(*timer->callback)(timer, now, timer->arg); + break; + } + } + } + if (!millis) + return timer; + if (!(flags & TimerAbsolute)) + millis += now; + timer->expires = millis; + timer->callback = func; + timer->arg = arg; + if ((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); + xfree(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; + xfree(timer); + } +} + +static CARD32 +ScreenSaverTimeoutExpire(OsTimerPtr timer,CARD32 now,pointer 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,pointer 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,pointer 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,pointer 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..b6a70a703 --- /dev/null +++ b/nx-X11/programs/Xserver/os/access.c @@ -0,0 +1,2429 @@ +/* $Xorg: access.c,v 1.5 2001/02/09 02:05:23 xorgcvs Exp $ */ +/* $XdotOrg: xc/programs/Xserver/os/access.c,v 1.13 2005/11/08 06:33:30 jkj Exp $ */ +/*********************************************************** + +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. + +******************************************************************/ +/* $XFree86: xc/programs/Xserver/os/access.c,v 3.53 2004/01/02 18:23:19 tsi Exp $ */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <X11/Xtrans/Xtrans.h> +#include <X11/Xauth.h> +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "site.h" +#include <errno.h> +#include <sys/types.h> +#ifndef WIN32 +#ifndef Lynx +#include <sys/socket.h> +#else +#include <socket.h> +#endif +#include <sys/ioctl.h> +#include <ctype.h> + +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(ISC) || defined(__SCO__) +#include <netinet/in.h> +#endif /* TCPCONN || STREAMSCONN || ISC || __SCO__ */ +#ifdef DNETCONN +#include <netdnet/dn.h> +#include <netdnet/dnetdb.h> +#endif + +#ifdef HAS_GETPEERUCRED +# include <ucred.h> +# ifdef sun +# include <zone.h> +# endif +#endif + +#if defined(DGUX) +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <ctype.h> +#include <sys/utsname.h> +#include <sys/stream.h> +#include <sys/stropts.h> +#include <sys/param.h> +#include <sys/sockio.h> +#endif + + +#if defined(hpux) || defined(QNX4) +# include <sys/utsname.h> +# ifdef HAS_IFREQ +# include <net/if.h> +# endif +#else +#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__ */ +#endif /* hpux */ + +#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 +#ifndef Lynx +#include <sys/param.h> +#else +#include <param.h> +#endif +#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 <X11/Xos_r.h> + +#include "dixstruct.h" +#include "osdep.h" + +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <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*/, + pointer * /*addr*/); + +static int CheckAddr(int /*family*/, + pointer /*pAddr*/, + unsigned /*length*/); + +static Bool NewHost(int /*family*/, + pointer /*addr*/, + int /*len*/, + int /* addingLocalHosts */); + +int LocalClientCredAndGroups(ClientPtr client, int *pUid, int *pGid, + int **pSuppGids, int *nSuppGids); + + +/* 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 *) xalloc(sizeof *(h)+(l));\ + if (h) { \ + (h)->addr=(unsigned char *) ((h) + 1);\ + (h)->requested = FALSE; \ + } +#define FreeHost(h) xfree(h) +static HOST *selfhosts = NULL; +static HOST *validhosts = NULL; +static int AccessEnabled = DEFAULT_ACCESS_CONTROL; +static int LocalHostEnabled = FALSE; +static int LocalHostRequested = FALSE; +static int UsingXdmcp = FALSE; + +/* FamilyServerInterpreted implementation */ +static Bool siAddrMatch(int family, pointer 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, (pointer)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(DGUX) && !defined(SCO325) && !defined(sun) && !defined(NCR)) || defined(ISC)) && !defined(__sgi) && 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 DGUX, sun, SCO325 NCR and others */ +#define ifioctl ioctl +#endif /* ((SVR4 && !DGUX !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, (pointer *)&addr); + if (family == -1 || family == FamilyLocal) + continue; + for (host = selfhosts; + host && !addrEqual (family, addr, len, host); + host = host->next) + ; + if (host) + continue; + MakeHost(host,len) + if (host) + { + host->family = family; + host->len = len; + acopy(addr, host->addr, len); + host->next = selfhosts; + selfhosts = host; + } +#ifdef XDMCP + { + struct sockaddr broad_addr; + + /* + * If this isn't an Internet Address, don't register it. + */ + if (family != FamilyInternet) + continue; + + /* + * Ignore 'localhost' entries as they're not useful + * on the other end of the wire. + */ + if (len == 4 && + addr[0] == 127 && addr[1] == 0 && + addr[2] == 0 && addr[3] == 1) + continue; + + /* + * 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) || (defined (hpux) && ! defined (HAS_IFREQ)) || defined(QNX4) +void +DefineSelf (int fd) +{ +#if !defined(TCPCONN) && !defined(STREAMSCONN) && !defined(UNIXCONN) && !defined(MNX_TCPCONN) + 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 QNX4 +#ifndef WIN32 + uname(&name); +#else + gethostname(name.nodename, sizeof(name.nodename)); +#endif +#else + /* QNX4's uname returns node number in name.nodename, not the hostname + have to overwrite it */ + char hname[1024]; + gethostname(hname, 1024); + name.nodename = hname; +#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, (pointer *)&addr); + if ( family != -1 && family != FamilyLocal ) + { + for (host = selfhosts; + host && !addrEqual (family, addr, len, host); + host = host->next) ; + if (!host) + { + /* add this host to the host list. */ + MakeHost(host,len) + if (host) + { + host->family = family; + host->len = len; + acopy ( addr, host->addr, len); + host->next = selfhosts; + selfhosts = host; + } +#ifdef XDMCP + /* + * If this is an Internet Address, but not the localhost + * address (127.0.0.1), 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 && !STREAMSCONN && !UNIXCONN && !MNX_TCPCONN */ +} + +#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 +#ifdef QNX4 +#define ifr_size(p) (p->ifr_addr.sa_len + IFNAMSIZ) +#define ifraddr_size(a) (a.sa_len) +#else +#define ifr_size(p) (sizeof (ifr_type)) +#define ifraddr_size(a) (sizeof (a)) +#endif +#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; + +#ifdef DNETCONN + struct dn_naddr *dnaddr = getnodeadd(); + /* + * AF_DECnet may not be listed in the interface list. Instead use + * the supported library call to find out the local address (if any). + */ + if (dnaddr) + { + addr = (unsigned char *) dnaddr; + len = dnaddr->a_len + sizeof(dnaddr->a_len); + family = FamilyDECnet; + for (host = selfhosts; + host && !addrEqual (family, addr, len, host); + host = host->next) + ; + if (!host) + { + MakeHost(host,len) + if (host) + { + host->family = family; + host->len = len; + acopy(addr, host->addr, len); + host->next = selfhosts; + selfhosts = host; + } + } + } +#endif /* DNETCONN */ +#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 = xalloc(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, (pointer) &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, (pointer *)&addr); +#ifdef DNETCONN + /* + * DECnet was handled up above. + */ + if (family == AF_DECnet) + continue; +#endif /* DNETCONN */ + 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, (pointer) &broad_req) != -1 && + (broad_req.ifr_flags & IFF_BROADCAST) && + (broad_req.ifr_flags & IFF_UP) + ) + { + broad_req = *ifr; + if (ifioctl (fd, SIOCGIFBRDADDR, (pointer) &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) { +#ifdef DNETCONN + if (ifr->ifa_addr.sa_family == AF_DECnet) + continue; +#endif /* DNETCONN */ + len = sizeof(*(ifr->ifa_addr)); + family = ConvertAddr(ifr->ifa_addr, &len, (pointer *)&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 /* hpux && !HAS_IFREQ */ +#endif /* WINTCP */ + +#ifdef XDMCP +void +AugmentSelf(pointer from, int len) +{ + int family; + pointer addr; + register HOST *host; + + family = ConvertAddr(from, &len, (pointer *)&addr); + if (family == -1 || family == FamilyLocal) + return; + for (host = selfhosts; host; host = host->next) + { + if (addrEqual(family, addr, len, host)) + return; + } + MakeHost(host,len) + if (!host) + return; + host->family = family; + host->len = len; + acopy(addr, host->addr, len); + host->next = selfhosts; + selfhosts = host; +} +#endif + +void +AddLocalHosts (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(STREAMSCONN) || defined(MNX_TCPCONN)) && \ + (!defined(IPv6) || !defined(AF_INET6))) || defined(DNETCONN) + union { + struct sockaddr sa; +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_TCPCONN) + struct sockaddr_in in; +#endif /* TCPCONN || STREAMSCONN */ +#ifdef DNETCONN + struct sockaddr_dn dn; +#endif + } saddr; +#endif +#ifdef DNETCONN + struct nodeent *np; + struct dn_naddr dnaddr, *dnaddrp, *dnet_addr(); +#endif +#ifdef K5AUTH + krb5_principal princ; + krb5_data kbuf; +#endif + int family = 0; + pointer addr; + 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); +#ifdef __UNIXOS2__ + strcpy(fname, (char*)__XOS2RedirRoot(fname)); +#endif /* __UNIXOS2__ */ + + 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; +#ifdef __UNIXOS2__ + if ((ptr = strchr(ohostname, '\r')) != 0) + *ptr = 0; +#endif + 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) || defined(STREAMSCONN) || defined(MNX_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 DNETCONN + else if (!strncmp("dnet:", lhostname, 5)) + { + family = FamilyDECnet; + hostname = ohostname + 5; + } +#endif +#ifdef SECURE_RPC + else if (!strncmp("nis:", lhostname, 4)) + { + family = FamilyNetname; + hostname = ohostname + 4; + } +#endif +#ifdef K5AUTH + else if (!strncmp("krb:", lhostname, 4)) + { + family = FamilyKrb5Principal; + hostname = ohostname + 4; + } +#endif + 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 DNETCONN + if ((family == FamilyDECnet) || ((family == FamilyWild) && + (ptr = strchr(hostname, ':')) && (*(ptr + 1) == ':') && + !(*ptr = '\0'))) /* bash trailing colons if necessary */ + { + /* node name (DECnet names end in "::") */ + dnaddrp = dnet_addr(hostname); + if (!dnaddrp && (np = getnodebyname (hostname))) + { + /* node was specified by name */ + saddr.sa.sa_family = np->n_addrtype; + len = sizeof(saddr.sa); + if (ConvertAddr (&saddr.sa, &len, (pointer *)&addr) == FamilyDECnet) + { + bzero ((char *) &dnaddr, sizeof (dnaddr)); + dnaddr.a_len = np->n_length; + acopy (np->n_addr, dnaddr.a_addr, np->n_length); + dnaddrp = &dnaddr; + } + } + if (dnaddrp) + (void) NewHost(FamilyDECnet, (pointer)dnaddrp, + (int)(dnaddrp->a_len + sizeof(dnaddrp->a_len)), FALSE); + } + else +#endif /* DNETCONN */ +#ifdef K5AUTH + if (family == FamilyKrb5Principal) + { + krb5_parse_name(hostname, &princ); + XauKrb5Encode(princ, &kbuf); + (void) NewHost(FamilyKrb5Principal, kbuf.data, kbuf.length, FALSE); + krb5_free_principal(princ); + } + else +#endif +#ifdef SECURE_RPC + if ((family == FamilyNetname) || (strchr(hostname, '@'))) + { + SecureRPCInit (); + (void) NewHost (FamilyNetname, hostname, strlen (hostname), FALSE); + } + else +#endif /* SECURE_RPC */ +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_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,(pointer *)&addr); + if ( (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, (pointer *)&addr)) != -1) + { +#ifdef h_addr /* new 4.3bsd version of gethostent */ + char **list; + + /* iterate over the addresses */ + for (list = hp->h_addr_list; *list; list++) + (void) NewHost (family, (pointer)*list, len, FALSE); +#else + (void) NewHost (family, (pointer)hp->h_addr, len, FALSE); +#endif + } + } +#endif /* IPv6 */ + } +#endif /* TCPCONN || STREAMSCONN */ + family = FamilyWild; + } + fclose (fd); + } +} + +/* Is client on the local host */ +Bool LocalClient(ClientPtr client) +{ + int alen, family, notused; + Xtransaddr *from = NULL; + pointer addr; + register HOST *host; + +#ifdef XCSECURITY + /* untrusted clients can't change host access */ + if (client->trustLevel != XSecurityClientTrusted) + { + SecurityAudit("client %d attempted to change host access\n", + client->index); + return FALSE; + } +#endif +#ifdef LBX + if (!((OsCommPtr)client->osPrivate)->trans_conn) + return FALSE; +#endif + if (!_XSERVTransGetPeerAddr (((OsCommPtr)client->osPrivate)->trans_conn, + ¬used, &alen, &from)) + { + family = ConvertAddr ((struct sockaddr *) from, + &alen, (pointer *)&addr); + if (family == -1) + { + xfree ((char *) from); + return FALSE; + } + if (family == FamilyLocal) + { + xfree ((char *) from); + return TRUE; + } + for (host = selfhosts; host; host = host->next) + { + if (addrEqual (family, addr, alen, host)) + return TRUE; + } + xfree ((char *) from); + } + return FALSE; +} + +/* + * Return the uid and gid of a connected local client + * or the uid/gid for nobody those ids cannot be determined + * + * Used by XShm to test access rights to shared memory segments + */ +int +LocalClientCred(ClientPtr client, int *pUid, int *pGid) +{ + return LocalClientCredAndGroups(client, pUid, pGid, NULL, NULL); +} + +/* + * Return the uid and all gids of a connected local client + * or the uid/gid for nobody those ids cannot be determined + * + * If the caller passes non-NULL values for pSuppGids & nSuppGids, + * they are responsible for calling XFree(*pSuppGids) to release the + * memory allocated for the supplemental group ids list. + * + * Used by localuser & localgroup ServerInterpreted access control forms below + */ +int +LocalClientCredAndGroups(ClientPtr client, int *pUid, int *pGid, + int **pSuppGids, int *nSuppGids) +{ +#if defined(HAS_GETPEEREID) || defined(HAS_GETPEERUCRED) || defined(SO_PEERCRED) + int fd; + XtransConnInfo ci; +#ifdef HAS_GETPEEREID + uid_t uid; + gid_t gid; +#elif defined(HAS_GETPEERUCRED) + ucred_t *peercred = NULL; +#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 + + if (pSuppGids != NULL) + *pSuppGids = NULL; + if (nSuppGids != NULL) + *nSuppGids = 0; + + fd = _XSERVTransGetConnectionNumber(ci); +#ifdef HAS_GETPEEREID + if (getpeereid(fd, &uid, &gid) == -1) + return -1; + if (pUid != NULL) + *pUid = uid; + if (pGid != NULL) + *pGid = gid; + return 0; +#elif defined(HAS_GETPEERUCRED) + if (getpeerucred(fd, &peercred) < 0) + return -1; +#ifdef sun /* Ensure process is in the same zone */ + if (getzoneid() != ucred_getzoneid(peercred)) { + ucred_free(peercred); + return -1; + } +#endif + if (pUid != NULL) + *pUid = ucred_geteuid(peercred); + if (pGid != NULL) + *pGid = ucred_getegid(peercred); + if (pSuppGids != NULL && nSuppGids != NULL) { + const gid_t *gids; + *nSuppGids = ucred_getgroups(peercred, &gids); + if (*nSuppGids > 0) { + *pSuppGids = xalloc(sizeof(int) * (*nSuppGids)); + if (*pSuppGids == NULL) { + *nSuppGids = 0; + } else { + int i; + for (i = 0 ; i < *nSuppGids; i++) { + (*pSuppGids)[i] = (int) gids[i]; + } + } + } + } + ucred_free(peercred); + return 0; +#elif defined(SO_PEERCRED) + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) == -1) + return -1; + if (pUid != NULL) + *pUid = peercred.uid; + if (pGid != NULL) + *pGid = peercred.gid; + return 0; +#endif +#else + /* No system call available to get the credentials of the peer */ +#define NO_LOCAL_CLIENT_CRED + return -1; +#endif +} + +static Bool +AuthorizedClient(ClientPtr client) +{ + if (!client || defeatAccessControl) + return TRUE; + return LocalClient(client); +} + +/* Add a host to the access control list. This is the external interface + * called from the dispatcher */ + +int +AddHost (ClientPtr client, + int family, + unsigned length, /* of bytes in pAddr */ + pointer pAddr) +{ + int len; + + if (!AuthorizedClient(client)) + return(BadAccess); + switch (family) { + case FamilyLocalHost: + len = length; + LocalHostEnabled = TRUE; + break; +#ifdef K5AUTH + case FamilyKrb5Principal: + len = length; + break; +#endif +#ifdef SECURE_RPC + case FamilyNetname: + len = length; + SecureRPCInit (); + break; +#endif + case FamilyInternet: +#if defined(IPv6) && defined(AF_INET6) + case FamilyInternet6: +#endif + case FamilyDECnet: + 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 */, + pointer /* closure */), + pointer closure) +{ + HOST *host; + + for (host = validhosts; host; host = host->next) + if (family == host->family && func (host->addr, host->len, closure)) + return TRUE; + return FALSE; +} + +/* Add a host to the access control list. This is the internal interface + * called when starting or resetting the server */ +static Bool +NewHost (int family, + pointer 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 */ + pointer pAddr) +{ + int len; + register HOST *host, **prev; + + if (!AuthorizedClient(client)) + return(BadAccess); + switch (family) { + case FamilyLocalHost: + len = length; + LocalHostEnabled = FALSE; + break; +#ifdef K5AUTH + case FamilyKrb5Principal: + len = length; + break; +#endif +#ifdef SECURE_RPC + case FamilyNetname: + len = length; + break; +#endif + case FamilyInternet: +#if defined(IPv6) && defined(AF_INET6) + case FamilyInternet6: +#endif + case FamilyDECnet: + 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 ( + pointer *data, + int *pnHosts, + int *pLen, + BOOL *pEnabled) +{ + int len; + register int n = 0; + register unsigned char *ptr; + register HOST *host; + int nHosts = 0; + + *pEnabled = AccessEnabled ? EnableAccess : DisableAccess; + for (host = validhosts; host; host = host->next) + { + nHosts++; + n += (((host->len + 3) >> 2) << 2) + sizeof(xHostEntry); + } + if (n) + { + *data = ptr = (pointer) xalloc (n); + if (!ptr) + { + return(BadAlloc); + } + for (host = validhosts; host; host = host->next) + { + len = host->len; + ((xHostEntry *)ptr)->family = host->family; + ((xHostEntry *)ptr)->length = len; + ptr += sizeof(xHostEntry); + acopy (host->addr, ptr, len); + ptr += ((len + 3) >> 2) << 2; + } + } else { + *data = NULL; + } + *pnHosts = nHosts; + *pLen = n; + return(Success); +} + +/* Check for valid address family and length, and return address length. */ + +/*ARGSUSED*/ +static int +CheckAddr ( + int family, + pointer pAddr, + unsigned length) +{ + int len; + + switch (family) + { +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_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 +#ifdef DNETCONN + case FamilyDECnet: + { + struct dn_naddr *dnaddr = (struct dn_naddr *) pAddr; + + if ((length < sizeof(dnaddr->a_len)) || + (length < dnaddr->a_len + sizeof(dnaddr->a_len))) + len = -1; + else + len = dnaddr->a_len + sizeof(dnaddr->a_len); + if (len > sizeof(struct dn_naddr)) + len = -1; + } + break; +#endif + 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; + pointer addr; + register HOST *selfhost, *host; + + if (!AccessEnabled) /* just let them in */ + return(0); + family = ConvertAddr (saddr, &len, (pointer *)&addr); + if (family == -1) + return 1; + if (family == FamilyLocal) + { + if (!LocalHostEnabled) + { + /* + * check to see if any local address is enabled. This + * implicitly enables local connections. + */ + for (selfhost = selfhosts; selfhost; selfhost=selfhost->next) + { + for (host = validhosts; host; host=host->next) + { + if (addrEqual (selfhost->family, selfhost->addr, + selfhost->len, host)) + return 0; + } + } + } 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 (addrEqual (family, addr, len, host)) + return (0); + } + + } + return (1); +} + +static int +ConvertAddr ( + register struct sockaddr *saddr, + int *len, + pointer *addr) +{ + if (*len == 0) + return (FamilyLocal); + switch (saddr->sa_family) + { + case AF_UNSPEC: +#if defined(UNIXCONN) || defined(LOCALCONN) || defined(OS2PIPECONN) + case AF_UNIX: +#endif + return FamilyLocal; +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_TCPCONN) + case AF_INET: +#ifdef WIN32 + if (16777343 == *(long*)&((struct sockaddr_in *) saddr)->sin_addr) + return FamilyLocal; +#endif + *len = sizeof (struct in_addr); + *addr = (pointer) &(((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 = (pointer) &(saddr6->sin6_addr.s6_addr[12]); + return FamilyInternet; + } else { + *len = sizeof (struct in6_addr); + *addr = (pointer) &(saddr6->sin6_addr); + return FamilyInternet6; + } + } +#endif +#endif +#ifdef DNETCONN + case AF_DECnet: + { + struct sockaddr_dn *sdn = (struct sockaddr_dn *) saddr; + *len = sdn->sdn_nodeaddrl + sizeof(sdn->sdn_nodeaddrl); + *addr = (pointer) &(sdn->sdn_add); + } + return FamilyDECnet; +#endif +#ifdef CHAOSCONN + case AF_CHAOS: + { + not implemented + } + return FamilyChaos; +#endif + default: + return -1; + } +} + +int +ChangeAccessControl( + 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, pointer 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 *) xalloc(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, pointer 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, pointer 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; + pointer hostaddr; + + 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) && + (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; + pointer 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, pointer 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 = xalloc(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; + } + } + } + + xfree(addrbuf); + return parsedOK; +} + +static Bool +siLocalCredAddrMatch(int family, pointer addr, int len, + const char *siAddr, int siAddrlen, ClientPtr client, void *typePriv) +{ + int connUid, connGid, *connSuppGids, connNumSuppGids, siAddrId; + siLocalCredPrivPtr lcPriv = (siLocalCredPrivPtr) typePriv; + + if (LocalClientCredAndGroups(client, &connUid, &connGid, + &connSuppGids, &connNumSuppGids) == -1) { + return FALSE; + } + + if (siLocalCredGetId(siAddr, siAddrlen, lcPriv, &siAddrId) == FALSE) { + return FALSE; + } + + if (lcPriv->credType == LOCAL_USER) { + if (connUid == siAddrId) { + return TRUE; + } + } else { + if (connGid == siAddrId) { + return TRUE; + } + if (connSuppGids != NULL) { + int i; + + for (i = 0 ; i < connNumSuppGids; i++) { + if (connSuppGids[i] == siAddrId) { + xfree(connSuppGids); + return TRUE; + } + } + xfree(connSuppGids); + } + } + 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..dc72fe3a2 --- /dev/null +++ b/nx-X11/programs/Xserver/os/auth.c @@ -0,0 +1,608 @@ +/* $Xorg: auth.c,v 1.5 2001/02/09 02:05:23 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ +/* $XFree86: auth.c,v 1.13 2003/04/27 21:31:08 herrb Exp $ */ + +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NX-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of NoMachine S.r.l. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +/* + * authorization hooks for the server + * Author: Keith Packard, MIT X Consortium + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef K5AUTH +# include <krb5/krb5.h> +#endif +# include <X11/X.h> +# include <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 <X11/extensions/security.h> +#endif +#ifdef WIN32 +#include <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 K5AUTH +{ (unsigned short) 14, "MIT-KERBEROS-5", + K5Add, K5Check, K5Reset, + K5ToID, K5FromID, K5Remove, +#ifdef XCSECURITY + NULL +#endif +}, +#endif +#ifdef XCSECURITY +{ (unsigned short) XSecurityAuthorizationNameLen, + XSecurityAuthorizationName, + NULL, AuthSecurityCheck, NULL, + NULL, NULL, NULL, + NULL +}, +#endif +}; + +# define NUM_AUTHORIZATION (sizeof (protocols) /\ + sizeof (struct protocol)) + +/* + * Initialize all classes of authorization by reading the + * specified authorization file + */ + +static char *authorization_file = (char *)NULL; + +static Bool ShouldLoadAuth = TRUE; + +void +InitAuthorization (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/auth.c.NX.original b/nx-X11/programs/Xserver/os/auth.c.NX.original new file mode 100644 index 000000000..dc72fe3a2 --- /dev/null +++ b/nx-X11/programs/Xserver/os/auth.c.NX.original @@ -0,0 +1,608 @@ +/* $Xorg: auth.c,v 1.5 2001/02/09 02:05:23 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ +/* $XFree86: auth.c,v 1.13 2003/04/27 21:31:08 herrb Exp $ */ + +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NX-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of NoMachine S.r.l. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +/* + * authorization hooks for the server + * Author: Keith Packard, MIT X Consortium + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef K5AUTH +# include <krb5/krb5.h> +#endif +# include <X11/X.h> +# include <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 <X11/extensions/security.h> +#endif +#ifdef WIN32 +#include <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 K5AUTH +{ (unsigned short) 14, "MIT-KERBEROS-5", + K5Add, K5Check, K5Reset, + K5ToID, K5FromID, K5Remove, +#ifdef XCSECURITY + NULL +#endif +}, +#endif +#ifdef XCSECURITY +{ (unsigned short) XSecurityAuthorizationNameLen, + XSecurityAuthorizationName, + NULL, AuthSecurityCheck, NULL, + NULL, NULL, NULL, + NULL +}, +#endif +}; + +# define NUM_AUTHORIZATION (sizeof (protocols) /\ + sizeof (struct protocol)) + +/* + * Initialize all classes of authorization by reading the + * specified authorization file + */ + +static char *authorization_file = (char *)NULL; + +static Bool ShouldLoadAuth = TRUE; + +void +InitAuthorization (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/auth.c.X.original b/nx-X11/programs/Xserver/os/auth.c.X.original new file mode 100644 index 000000000..19c5534d3 --- /dev/null +++ b/nx-X11/programs/Xserver/os/auth.c.X.original @@ -0,0 +1,400 @@ +/* $Xorg: auth.c,v 1.5 2001/02/09 02:05:23 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ +/* $XFree86: auth.c,v 1.13 2003/04/27 21:31:08 herrb Exp $ */ + +/* + * authorization hooks for the server + * Author: Keith Packard, MIT X Consortium + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef K5AUTH +# include <krb5/krb5.h> +#endif +# include <X11/X.h> +# include <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 <X11/extensions/security.h> +#endif +#ifdef WIN32 +#include <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 K5AUTH +{ (unsigned short) 14, "MIT-KERBEROS-5", + K5Add, K5Check, K5Reset, + K5ToID, K5FromID, K5Remove, +#ifdef XCSECURITY + NULL +#endif +}, +#endif +#ifdef XCSECURITY +{ (unsigned short) XSecurityAuthorizationNameLen, + XSecurityAuthorizationName, + NULL, AuthSecurityCheck, NULL, + NULL, NULL, NULL, + NULL +}, +#endif +}; + +# define NUM_AUTHORIZATION (sizeof (protocols) /\ + sizeof (struct protocol)) + +/* + * Initialize all classes of authorization by reading the + * specified authorization file + */ + +static char *authorization_file = (char *)NULL; + +static Bool ShouldLoadAuth = TRUE; + +void +InitAuthorization (char *file_name) +{ + authorization_file = file_name; +} + +static int +LoadAuthorization (void) +{ + FILE *f; + Xauth *auth; + int i; + int count = 0; + + ShouldLoadAuth = FALSE; + if (!authorization_file) + return 0; + + 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) + { + ++count; + (*protocols[i].Add) (auth->data_length, auth->data, + FakeClientID(0)); + } + } + XauDisposeAuth (auth); + } + + Fclose (f); + return count; +} + +#ifdef XDMCP +/* + * XdmcpInit calls this function to discover all authorization + * schemes supported by the display + */ +void +RegisterAuthorizations (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; + static Bool loaded = FALSE; + + 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) + */ + + if (loadauth > 0) + { + DisableLocalHost(); /* got at least one */ + loaded = TRUE; + } + else if (loadauth == 0 || !loaded) + EnableLocalHost (); + } + if (name_length) { + for (i = 0; i < NUM_AUTHORIZATION; i++) { + if (protocols[i].name_length == name_length && + memcmp (protocols[i].name, name, (int) name_length) == 0) + { + return (*protocols[i].Check) (data_length, data, client, reason); + } + *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/connection.c b/nx-X11/programs/Xserver/os/connection.c new file mode 100644 index 000000000..e3319b338 --- /dev/null +++ b/nx-X11/programs/Xserver/os/connection.c @@ -0,0 +1,1424 @@ +/* $Xorg: connection.c,v 1.6 2001/02/09 02:05:23 xorgcvs Exp $ */ +/*********************************************************** + +Copyright 1987, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* $XFree86: xc/programs/Xserver/os/connection.c,v 3.64 2003/10/07 22:50:42 herrb Exp $ */ +/***************************************************************** + * Stuff to create connections --- OS dependent + * + * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets, + * CloseDownConnection, CheckConnections, AddEnabledDevice, + * RemoveEnabledDevice, OnlyListToOneClient, + * ListenToAllClients, + * + * (WaitForSomething is in its own file) + * + * In this implementation, a client socket table is not kept. + * Instead, what would be the index into the table is just the + * file descriptor of the socket. This won't work for if the + * socket ids aren't small nums (0 - 2^8) + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif +#include <X11/X.h> +#include <X11/Xproto.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <X11/Xtrans/Xtrans.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef WIN32 +#if defined(Lynx) +#include <socket.h> +#else +#include <sys/socket.h> +#endif + +#ifdef hpux +#include <sys/utsname.h> +#include <sys/ioctl.h> +#endif + +#if defined(DGUX) +#include <sys/ioctl.h> +#include <sys/utsname.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/param.h> +#include <unistd.h> +#endif + + +#ifdef AIXV3 +#include <sys/ioctl.h> +#endif + +#ifdef __UNIXOS2__ +#define select(n,r,w,x,t) os2PseudoSelect(n,r,w,x,t) +extern __const__ int _nfiles; +#endif + +#if defined(TCPCONN) || defined(STREAMSCONN) +# include <netinet/in.h> +# include <arpa/inet.h> +# if !defined(hpux) +# ifdef apollo +# ifndef NO_TCP_H +# include <netinet/tcp.h> +# endif +# else +# ifdef CSRG_BASED +# include <sys/param.h> +# endif +# ifndef __UNIXOS2__ +# include <netinet/tcp.h> +# endif +# endif +# endif +# include <arpa/inet.h> +#endif + +#if !defined(__UNIXOS2__) +#ifndef Lynx +#include <sys/uio.h> +#else +#include <uio.h> +#endif +#endif +#endif /* WIN32 */ +#include "misc.h" /* for typedef of pointer */ +#include "osdep.h" +#include <X11/Xpoll.h> +#include "opaque.h" +#include "dixstruct.h" +#ifdef XAPPGROUP +#include <X11/extensions/Xagsrv.h> +#endif +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <X11/extensions/security.h> +#endif +#ifdef LBX +#include "colormapst.h" +#include "propertyst.h" +#include "lbxserve.h" +#include "osdep.h" +#endif + +#ifdef X_NOT_POSIX +#define Pid_t int +#else +#define Pid_t pid_t +#endif + +#ifdef DNETCONN +#include <netdnet/dn.h> +#endif /* DNETCONN */ + +int lastfdesc; /* maximum file descriptor */ + +fd_set WellKnownConnections; /* Listener mask */ +fd_set EnabledDevices; /* mask for input devices that are on */ +fd_set AllSockets; /* select on this */ +fd_set AllClients; /* available clients */ +fd_set LastSelectMask; /* mask returned from last select call */ +fd_set ClientsWithInput; /* clients with FULL requests in buffer */ +fd_set ClientsWriteBlocked; /* clients who cannot receive output */ +fd_set OutputPending; /* clients with reply/event data ready to go */ +int MaxClients = 0; +Bool NewOutputPending; /* not yet attempted to write some new output */ +Bool AnyClientsWriteBlocked; /* true if some client blocked on write */ + +Bool RunFromSmartParent; /* send SIGUSR1 to parent process */ +Bool PartialNetwork; /* continue even if unable to bind all addrs */ +static Pid_t ParentProcess; +#ifdef __UNIXOS2__ +Pid_t GetPPID(Pid_t pid); +#endif + +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; + +#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*)xalloc(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; + xfree(temp); + } + } +} +#endif + +XtransConnInfo *ListenTransConns = NULL; +int *ListenTransFds = NULL; +int ListenTransCount; + +static void ErrorConnMax(XtransConnInfo /* trans_conn */); + +#ifndef LBX +static +void CloseDownFileDescriptor( + OsCommPtr /*oc*/ +); +#endif + + +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__ + +#ifndef __UNIXOS2__ + +#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 + +#else /* __UNIXOS2__ */ + lastfdesc = _nfiles - 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 +} + + +/***************** + * CreateWellKnownSockets + * At initialization, create the sockets to listen on for new clients. + *****************/ + +void +CreateWellKnownSockets(void) +{ + int i; + int partial; + char port[20]; + OsSigHandlerPtr handler; + + 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 + + FD_ZERO (&WellKnownConnections); + + sprintf (port, "%d", atoi (display)); + + if ((_XSERVTransMakeAllCOTSServerListeners (port, &partial, + &ListenTransCount, &ListenTransConns) >= 0) && + (ListenTransCount >= 1)) + { + if (!PartialNetwork && partial) + { + FatalError ("Failed to establish all listening sockets"); + } + else + { + ListenTransFds = (int *) xalloc (ListenTransCount * sizeof (int)); + + for (i = 0; i < ListenTransCount; i++) + { + int fd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); + + ListenTransFds[i] = fd; + FD_SET (fd, &WellKnownConnections); + + if (!_XSERVTransIsLocal (ListenTransConns[i])) + { + DefineSelf (fd); + } + } + } + } + + if (!XFD_ANYSET (&WellKnownConnections)) + FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running"); +#if !defined(WIN32) + OsSignal (SIGPIPE, SIG_IGN); + OsSignal (SIGHUP, AutoResetServer); +#endif + OsSignal (SIGINT, GiveUp); + OsSignal (SIGTERM, GiveUp); + XFD_COPYSET (&WellKnownConnections, &AllSockets); + ResetHosts(display); + /* + * Magic: If SIGUSR1 was set to SIG_IGN when + * the server started, assume that either + * + * a- The parent process is ignoring SIGUSR1 + * + * or + * + * b- The parent process is expecting a SIGUSR1 + * when the server is ready to accept connections + * + * In the first case, the signal will be harmless, + * in the second case, the signal will be quite + * useful + */ +#if !defined(WIN32) + 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__ */ + if (RunFromSmartParent) { + if (ParentProcess > 1) { + kill (ParentProcess, SIGUSR1); + } + } +#endif +#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. + */ + + FD_CLR (ListenTransFds[i], &WellKnownConnections); + ListenTransFds[i] = ListenTransFds[ListenTransCount - 1]; + ListenTransConns[i] = ListenTransConns[ListenTransCount - 1]; + ListenTransCount -= 1; + i -= 1; + } + else if (status == TRANS_RESET_NEW_FD) + { + /* + * A new file descriptor was allocated (the old one was closed) + */ + + int newfd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); + + FD_CLR (ListenTransFds[i], &WellKnownConnections); + ListenTransFds[i] = newfd; + FD_SET(newfd, &WellKnownConnections); + } + } + } + + ResetAuthorization (); + ResetHosts(display); + /* + * See above in CreateWellKnownSockets about SIGUSR1 + */ +#if !defined(WIN32) + if (RunFromSmartParent) { + if (ParentProcess > 1) { + kill (ParentProcess, SIGUSR1); + } + } +#endif + /* + * restart XDMCP + */ +#ifdef XDMCP + XdmcpReset (); +#endif +} + +void +CloseWellKnownConnections(void) +{ + int i; + + for (i = 0; i < ListenTransCount; i++) + _XSERVTransClose (ListenTransConns[i]); +} + +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; + + if (!((OsCommPtr)client->osPrivate)->trans_conn) { + strcpy(addr, "LBX proxy at "); + out += strlen(addr); + } + if (!len) + strcpy(out, "local host"); + else + switch (saddr->sa_family) + { + case AF_UNSPEC: +#if defined(UNIXCONN) || defined(LOCALCONN) || defined(OS2PIPECONN) + case AF_UNIX: +#endif + strcpy(out, "local host"); + break; +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_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 +#ifdef DNETCONN + case AF_DECnet: + sprintf(out, "DN %s", + dnet_ntoa(&((struct sockaddr_dn *) saddr)->sdn_add)); + break; +#endif + default: + strcpy(out, "unknown address"); + } + + if (proto_n) + AuditF("client %d %s from %s\n Auth name: %.*s ID: %d\n", + client->index, letin ? "connected" : "rejected", addr, + (int)proto_n, auth_proto, auth_id); + else + AuditF("client %d %s from %s\n", + client->index, letin ? "connected" : "rejected", addr); +} + +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; + int restore_trans_conn = 0; + ClientPtr lbxpc = NULL; + + priv = (OsCommPtr)client->osPrivate; + trans_conn = priv->trans_conn; + +#ifdef LBX + if (!trans_conn) { + /* + * Since trans_conn is NULL, this must be a proxy's client for + * which we have NO address. Therefore, we will temporarily + * set the client's trans_conn to the proxy's trans_conn and + * after CheckAuthorization the client's trans_conn will be + * restored. + * + * If XDM-AUTHORIZATION-1 is being used, CheckAuthorization + * will eventually call XdmAuthorizationValidate and this + * later function may use the client's trans_conn to get the + * client's address. Since a XDM-AUTH-1 auth string includes + * the client's address, this address is compared to the address + * in the client's trans_conn. If the proxy and client are + * on the same host, the comparison will fail; otherwise the + * comparison will fail and the client will not be authorized + * to connect to the server. + * + * The basis for this additional code is to prevent a + * NULL pointer dereference of the client's trans_conn. + * The fundamental problem - the fact that the client's + * trans_conn is NULL - is because the NewClient + * request in version 1.0 of the LBX protocol does not + * send the client's address to the server. When the + * spec is changed and the client's address is sent to + * server in the NewClient request, this additional code + * should be removed. + * + * See defect number XWSog08218 for more information. + */ + lbxpc = LbxProxyClient(priv->proxy); + trans_conn = ((OsCommPtr)lbxpc->osPrivate)->trans_conn; + priv->trans_conn = trans_conn; + restore_trans_conn = 1; + } +#endif + + auth_id = CheckAuthorization (proto_n, auth_proto, + string_n, auth_string, client, &reason); + +#ifdef LBX + if (! priv->trans_conn) { + if (auth_id == (XID) ~0L && !GetAccessControl()) + auth_id = ((OsCommPtr)lbxpc->osPrivate)->auth_id; +#ifdef XCSECURITY + else if (auth_id != (XID) ~0L && !SecuritySameLevel(lbxpc, auth_id)) { + auth_id = (XID) ~0L; + reason = "Client trust level differs from that of LBX Proxy"; + } +#endif + } +#endif + if (auth_id == (XID) ~0L) + { + if ( +#ifdef XCSECURITY + (proto_n == 0 || + strncmp (auth_proto, XSecurityAuthorizationName, proto_n) != 0) && +#endif + _XSERVTransGetPeerAddr (trans_conn, + &family, &fromlen, &from) != -1) + { + if ( +#ifdef LBX + !trans_conn || +#endif + 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); + } + + xfree ((char *) from); + } + + if (auth_id == (XID) ~0L) { +#ifdef LBX + /* + * Restore client's trans_conn state + */ + if (restore_trans_conn) { + priv->trans_conn = NULL; + } +#endif + 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); + + xfree ((char *) from); + } + } + priv->auth_id = auth_id; + priv->conn_time = 0; + +#ifdef XDMCP + /* indicate to Xdmcp protocol that we've opened new client */ + XdmcpOpenDisplay(priv->fd); +#endif /* XDMCP */ +#ifdef XAPPGROUP + if (ClientStateCallback) + XagCallClientStateChange (client); +#endif + /* At this point, if the client is authorized to change the access control + * list, we should getpeername() information, and add the client to + * the selfhosts list. It's not really the host machine, but the + * true purpose of the selfhosts list is to see who may change the + * access control list. + */ +#ifdef LBX + if (restore_trans_conn) { + priv->trans_conn = NULL; + } +#endif + return((char *)NULL); +} + +static ClientPtr +#ifdef LBX +AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time, + int (*Flush)( + ClientPtr /*who*/, OsCommPtr /*oc*/, + char * /*extraBuf*/, int /*extraCount*/), + void (*Close)( + ClientPtr /*client*/), + LbxProxyPtr proxy) +#else +AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time) +#endif +{ + OsCommPtr oc; + ClientPtr client; + + if ( +#ifdef LBX + trans_conn && +#endif +#ifndef WIN32 + fd >= lastfdesc +#else + XFD_SETCOUNT(&AllClients) >= MaxClients +#endif + ) + return NullClient; + oc = (OsCommPtr)xalloc(sizeof(OsCommRec)); + if (!oc) + return NullClient; + oc->trans_conn = trans_conn; + oc->fd = fd; + oc->input = (ConnectionInputPtr)NULL; + oc->output = (ConnectionOutputPtr)NULL; + oc->auth_id = None; + oc->conn_time = conn_time; +#ifdef LBX + oc->proxy = proxy; + oc->Flush = Flush; + oc->Close = Close; + oc->largereq = (ConnectionInputPtr) NULL; +#endif + if (!(client = NextAvailableClient((pointer)oc))) + { + xfree (oc); + return NullClient; + } +#ifdef LBX + if (trans_conn) +#endif + { +#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; +} + +#ifdef LBX + +int +ClientConnectionNumber (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr) client->osPrivate; + + return oc->fd; +} + +ClientPtr +AllocLbxClientConnection (ClientPtr client, LbxProxyPtr proxy) +{ + OsCommPtr oc = (OsCommPtr) client->osPrivate; + + return AllocNewConnection ((XtransConnInfo)NULL, oc->fd, GetTimeInMillis(), + LbxFlushClient, LbxCloseClient, proxy); +} + +void +LbxProxyConnection (ClientPtr client, LbxProxyPtr proxy) +{ + OsCommPtr oc = (OsCommPtr) client->osPrivate; + + FlushClient(client, oc, (char *)NULL, 0); + oc->proxy = proxy; + oc->Flush = LbxFlushClient; + oc->Close = LbxCloseClient; + LbxPrimeInput(client, proxy); +} + +#endif + +/***************** + * EstablishNewConnections + * If anyone is waiting on listened sockets, accept them. + * Returns a mask with indices of new clients. Updates AllClients + * and AllSockets. + *****************/ + +/*ARGSUSED*/ +Bool +EstablishNewConnections(ClientPtr clientUnused, pointer closure) +{ + fd_set readyconnections; /* set of listeners that are ready */ + int curconn; /* fd of listener that's ready */ + register int newconn; /* fd of new client */ + CARD32 connect_time; + register int i; + register ClientPtr client; + register OsCommPtr oc; + fd_set tmask; + + XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections); + XFD_COPYSET(&tmask, &readyconnections); + if (!XFD_ANYSET(&readyconnections)) + return TRUE; + connect_time = GetTimeInMillis(); + /* kill off stragglers */ + for (i=1; i<currentMaxClients; i++) + { + if ((client = clients[i])) + { + oc = (OsCommPtr)(client->osPrivate); + if ((oc && (oc->conn_time != 0) && + (connect_time - oc->conn_time) >= TimeOutValue) || + (client->noClientException != Success && !client->clientGone)) + CloseDownClient(client); + } + } +#ifndef WIN32 + for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) + { + while (readyconnections.fds_bits[i]) +#else + for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++) +#endif + { + XtransConnInfo trans_conn, new_trans_conn; + int status; + +#ifndef WIN32 + curconn = ffs (readyconnections.fds_bits[i]) - 1; + readyconnections.fds_bits[i] &= ~((fd_mask)1 << curconn); + curconn += (i * (sizeof(fd_mask)*8)); +#else + curconn = XFD_FD(&readyconnections, i); +#endif + + if ((trans_conn = lookup_trans_conn (curconn)) == NULL) + continue; + + if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL) + continue; + + newconn = _XSERVTransGetConnectionNumber (new_trans_conn); + + if (newconn < lastfdesc) + { + int clientid; +#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 (!AllocNewConnection (new_trans_conn, newconn, connect_time +#ifdef LBX + , StandardFlushClient, + CloseDownFileDescriptor, (LbxProxyPtr)NULL +#endif + )) + { + ErrorConnMax(new_trans_conn); + _XSERVTransClose(new_trans_conn); + } + } +#ifndef WIN32 + } +#endif + return TRUE; +} + +#define NOROOM "Maximum number of clients reached" + +/************ + * ErrorConnMax + * Fail a connection due to lack of client or file descriptor space + ************/ + +static void +ErrorConnMax(XtransConnInfo trans_conn) +{ + int fd = _XSERVTransGetConnectionNumber (trans_conn); + xConnSetupPrefix csp; + char pad[3]; + struct iovec iov[3]; + char byteOrder = 0; + int whichbyte = 1; + struct timeval waittime; + fd_set mask; + + /* if these seems like a lot of trouble to go to, it probably is */ + waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND; + waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) * + (1000000 / MILLI_PER_SECOND); + FD_ZERO(&mask); + FD_SET(fd, &mask); + (void)Select(fd + 1, &mask, NULL, NULL, &waittime); + /* try to read the byte-order of the connection */ + (void)_XSERVTransRead(trans_conn, &byteOrder, 1); + if ((byteOrder == 'l') || (byteOrder == 'B')) + { + csp.success = xFalse; + csp.lengthReason = sizeof(NOROOM) - 1; + csp.length = (sizeof(NOROOM) + 2) >> 2; + csp.majorVersion = X_PROTOCOL; + csp.minorVersion = X_PROTOCOL_REVISION; + if (((*(char *) &whichbyte) && (byteOrder == 'B')) || + (!(*(char *) &whichbyte) && (byteOrder == 'l'))) + { + swaps(&csp.majorVersion, whichbyte); + swaps(&csp.minorVersion, whichbyte); + swaps(&csp.length, whichbyte); + } + iov[0].iov_len = sz_xConnSetupPrefix; + iov[0].iov_base = (char *) &csp; + iov[1].iov_len = csp.lengthReason; + iov[1].iov_base = NOROOM; + iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3; + iov[2].iov_base = pad; + (void)_XSERVTransWritev(trans_conn, iov, 3); + } +} + +/************ + * CloseDownFileDescriptor: + * Remove this file descriptor and it's I/O buffers, etc. + ************/ + +#ifdef LBX +void +CloseDownFileDescriptor(ClientPtr client) +#else +static void +CloseDownFileDescriptor(OsCommPtr oc) +#endif +{ +#ifdef LBX + OsCommPtr oc = (OsCommPtr) client->osPrivate; +#endif + int connection = oc->fd; + + if (oc->trans_conn) { + _XSERVTransDisconnect(oc->trans_conn); + _XSERVTransClose(oc->trans_conn); + } +#ifndef LBX + FreeOsBuffers(oc); + xfree(oc); +#endif +#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)) + AnyClientsWriteBlocked = 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 (oc->output && oc->output->count) + FlushClient(client, oc, (char *)NULL, 0); +#ifdef XDMCP + XdmcpCloseDisplay(oc->fd); +#endif +#ifndef LBX + CloseDownFileDescriptor(oc); +#else + (*oc->Close) (client); + FreeOsBuffers(oc); + xfree(oc); +#endif + client->osPrivate = (pointer)NULL; + if (auditTrailLevel > 1) + AuditF("client %d disconnected\n", client->index); +} + +void +AddEnabledDevice(int fd) +{ + FD_SET(fd, &EnabledDevices); + FD_SET(fd, &AllSockets); + if (GrabInProgress) + FD_SET(fd, &SavedAllSockets); +} + +void +RemoveEnabledDevice(int fd) +{ + FD_CLR(fd, &EnabledDevices); + FD_CLR(fd, &AllSockets); + if (GrabInProgress) + FD_CLR(fd, &SavedAllSockets); +} + +/***************** + * 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; +#ifdef LBX + LbxClientPtr lbxClient = LbxClient(client); +#endif + + isItTimeToYield = TRUE; +#ifdef LBX + if (lbxClient) { + lbxClient->ignored = TRUE; + return; + } +#endif + if (!GrabInProgress || FD_ISSET(connection, &AllClients)) + { + if (FD_ISSET (connection, &ClientsWithInput)) + FD_SET(connection, &IgnoredClientsWithInput); + else + FD_CLR(connection, &IgnoredClientsWithInput); + FD_CLR(connection, &ClientsWithInput); + FD_CLR(connection, &AllSockets); + FD_CLR(connection, &AllClients); + FD_CLR(connection, &LastSelectMask); + } + else + { + if (FD_ISSET (connection, &SavedClientsWithInput)) + FD_SET(connection, &IgnoredClientsWithInput); + else + FD_CLR(connection, &IgnoredClientsWithInput); + FD_CLR(connection, &SavedClientsWithInput); + FD_CLR(connection, &SavedAllSockets); + FD_CLR(connection, &SavedAllClients); + } +} + +/**************** + * AttendClient + * Adds one client back into the input masks. + ****************/ + +void +AttendClient (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; +#ifdef LBX + LbxClientPtr lbxClient = LbxClient(client); + + if (lbxClient) { + lbxClient->ignored = FALSE; + return; + } +#endif + if (!GrabInProgress || GrabInProgress == client->index || + FD_ISSET(connection, &GrabImperviousClients)) + { + FD_SET(connection, &AllClients); + FD_SET(connection, &AllSockets); + FD_SET(connection, &LastSelectMask); + if (FD_ISSET (connection, &IgnoredClientsWithInput)) + FD_SET(connection, &ClientsWithInput); + } + else + { + FD_SET(connection, &SavedAllClients); + FD_SET(connection, &SavedAllSockets); + if (FD_ISSET(connection, &IgnoredClientsWithInput)) + FD_SET(connection, &SavedClientsWithInput); + } +} + +/* make client impervious to grabs; assume only executing client calls this */ + +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/connection.c.NX.original b/nx-X11/programs/Xserver/os/connection.c.NX.original new file mode 100644 index 000000000..e3319b338 --- /dev/null +++ b/nx-X11/programs/Xserver/os/connection.c.NX.original @@ -0,0 +1,1424 @@ +/* $Xorg: connection.c,v 1.6 2001/02/09 02:05:23 xorgcvs Exp $ */ +/*********************************************************** + +Copyright 1987, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* $XFree86: xc/programs/Xserver/os/connection.c,v 3.64 2003/10/07 22:50:42 herrb Exp $ */ +/***************************************************************** + * Stuff to create connections --- OS dependent + * + * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets, + * CloseDownConnection, CheckConnections, AddEnabledDevice, + * RemoveEnabledDevice, OnlyListToOneClient, + * ListenToAllClients, + * + * (WaitForSomething is in its own file) + * + * In this implementation, a client socket table is not kept. + * Instead, what would be the index into the table is just the + * file descriptor of the socket. This won't work for if the + * socket ids aren't small nums (0 - 2^8) + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif +#include <X11/X.h> +#include <X11/Xproto.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <X11/Xtrans/Xtrans.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef WIN32 +#if defined(Lynx) +#include <socket.h> +#else +#include <sys/socket.h> +#endif + +#ifdef hpux +#include <sys/utsname.h> +#include <sys/ioctl.h> +#endif + +#if defined(DGUX) +#include <sys/ioctl.h> +#include <sys/utsname.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/param.h> +#include <unistd.h> +#endif + + +#ifdef AIXV3 +#include <sys/ioctl.h> +#endif + +#ifdef __UNIXOS2__ +#define select(n,r,w,x,t) os2PseudoSelect(n,r,w,x,t) +extern __const__ int _nfiles; +#endif + +#if defined(TCPCONN) || defined(STREAMSCONN) +# include <netinet/in.h> +# include <arpa/inet.h> +# if !defined(hpux) +# ifdef apollo +# ifndef NO_TCP_H +# include <netinet/tcp.h> +# endif +# else +# ifdef CSRG_BASED +# include <sys/param.h> +# endif +# ifndef __UNIXOS2__ +# include <netinet/tcp.h> +# endif +# endif +# endif +# include <arpa/inet.h> +#endif + +#if !defined(__UNIXOS2__) +#ifndef Lynx +#include <sys/uio.h> +#else +#include <uio.h> +#endif +#endif +#endif /* WIN32 */ +#include "misc.h" /* for typedef of pointer */ +#include "osdep.h" +#include <X11/Xpoll.h> +#include "opaque.h" +#include "dixstruct.h" +#ifdef XAPPGROUP +#include <X11/extensions/Xagsrv.h> +#endif +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <X11/extensions/security.h> +#endif +#ifdef LBX +#include "colormapst.h" +#include "propertyst.h" +#include "lbxserve.h" +#include "osdep.h" +#endif + +#ifdef X_NOT_POSIX +#define Pid_t int +#else +#define Pid_t pid_t +#endif + +#ifdef DNETCONN +#include <netdnet/dn.h> +#endif /* DNETCONN */ + +int lastfdesc; /* maximum file descriptor */ + +fd_set WellKnownConnections; /* Listener mask */ +fd_set EnabledDevices; /* mask for input devices that are on */ +fd_set AllSockets; /* select on this */ +fd_set AllClients; /* available clients */ +fd_set LastSelectMask; /* mask returned from last select call */ +fd_set ClientsWithInput; /* clients with FULL requests in buffer */ +fd_set ClientsWriteBlocked; /* clients who cannot receive output */ +fd_set OutputPending; /* clients with reply/event data ready to go */ +int MaxClients = 0; +Bool NewOutputPending; /* not yet attempted to write some new output */ +Bool AnyClientsWriteBlocked; /* true if some client blocked on write */ + +Bool RunFromSmartParent; /* send SIGUSR1 to parent process */ +Bool PartialNetwork; /* continue even if unable to bind all addrs */ +static Pid_t ParentProcess; +#ifdef __UNIXOS2__ +Pid_t GetPPID(Pid_t pid); +#endif + +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; + +#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*)xalloc(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; + xfree(temp); + } + } +} +#endif + +XtransConnInfo *ListenTransConns = NULL; +int *ListenTransFds = NULL; +int ListenTransCount; + +static void ErrorConnMax(XtransConnInfo /* trans_conn */); + +#ifndef LBX +static +void CloseDownFileDescriptor( + OsCommPtr /*oc*/ +); +#endif + + +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__ + +#ifndef __UNIXOS2__ + +#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 + +#else /* __UNIXOS2__ */ + lastfdesc = _nfiles - 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 +} + + +/***************** + * CreateWellKnownSockets + * At initialization, create the sockets to listen on for new clients. + *****************/ + +void +CreateWellKnownSockets(void) +{ + int i; + int partial; + char port[20]; + OsSigHandlerPtr handler; + + 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 + + FD_ZERO (&WellKnownConnections); + + sprintf (port, "%d", atoi (display)); + + if ((_XSERVTransMakeAllCOTSServerListeners (port, &partial, + &ListenTransCount, &ListenTransConns) >= 0) && + (ListenTransCount >= 1)) + { + if (!PartialNetwork && partial) + { + FatalError ("Failed to establish all listening sockets"); + } + else + { + ListenTransFds = (int *) xalloc (ListenTransCount * sizeof (int)); + + for (i = 0; i < ListenTransCount; i++) + { + int fd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); + + ListenTransFds[i] = fd; + FD_SET (fd, &WellKnownConnections); + + if (!_XSERVTransIsLocal (ListenTransConns[i])) + { + DefineSelf (fd); + } + } + } + } + + if (!XFD_ANYSET (&WellKnownConnections)) + FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running"); +#if !defined(WIN32) + OsSignal (SIGPIPE, SIG_IGN); + OsSignal (SIGHUP, AutoResetServer); +#endif + OsSignal (SIGINT, GiveUp); + OsSignal (SIGTERM, GiveUp); + XFD_COPYSET (&WellKnownConnections, &AllSockets); + ResetHosts(display); + /* + * Magic: If SIGUSR1 was set to SIG_IGN when + * the server started, assume that either + * + * a- The parent process is ignoring SIGUSR1 + * + * or + * + * b- The parent process is expecting a SIGUSR1 + * when the server is ready to accept connections + * + * In the first case, the signal will be harmless, + * in the second case, the signal will be quite + * useful + */ +#if !defined(WIN32) + 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__ */ + if (RunFromSmartParent) { + if (ParentProcess > 1) { + kill (ParentProcess, SIGUSR1); + } + } +#endif +#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. + */ + + FD_CLR (ListenTransFds[i], &WellKnownConnections); + ListenTransFds[i] = ListenTransFds[ListenTransCount - 1]; + ListenTransConns[i] = ListenTransConns[ListenTransCount - 1]; + ListenTransCount -= 1; + i -= 1; + } + else if (status == TRANS_RESET_NEW_FD) + { + /* + * A new file descriptor was allocated (the old one was closed) + */ + + int newfd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); + + FD_CLR (ListenTransFds[i], &WellKnownConnections); + ListenTransFds[i] = newfd; + FD_SET(newfd, &WellKnownConnections); + } + } + } + + ResetAuthorization (); + ResetHosts(display); + /* + * See above in CreateWellKnownSockets about SIGUSR1 + */ +#if !defined(WIN32) + if (RunFromSmartParent) { + if (ParentProcess > 1) { + kill (ParentProcess, SIGUSR1); + } + } +#endif + /* + * restart XDMCP + */ +#ifdef XDMCP + XdmcpReset (); +#endif +} + +void +CloseWellKnownConnections(void) +{ + int i; + + for (i = 0; i < ListenTransCount; i++) + _XSERVTransClose (ListenTransConns[i]); +} + +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; + + if (!((OsCommPtr)client->osPrivate)->trans_conn) { + strcpy(addr, "LBX proxy at "); + out += strlen(addr); + } + if (!len) + strcpy(out, "local host"); + else + switch (saddr->sa_family) + { + case AF_UNSPEC: +#if defined(UNIXCONN) || defined(LOCALCONN) || defined(OS2PIPECONN) + case AF_UNIX: +#endif + strcpy(out, "local host"); + break; +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_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 +#ifdef DNETCONN + case AF_DECnet: + sprintf(out, "DN %s", + dnet_ntoa(&((struct sockaddr_dn *) saddr)->sdn_add)); + break; +#endif + default: + strcpy(out, "unknown address"); + } + + if (proto_n) + AuditF("client %d %s from %s\n Auth name: %.*s ID: %d\n", + client->index, letin ? "connected" : "rejected", addr, + (int)proto_n, auth_proto, auth_id); + else + AuditF("client %d %s from %s\n", + client->index, letin ? "connected" : "rejected", addr); +} + +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; + int restore_trans_conn = 0; + ClientPtr lbxpc = NULL; + + priv = (OsCommPtr)client->osPrivate; + trans_conn = priv->trans_conn; + +#ifdef LBX + if (!trans_conn) { + /* + * Since trans_conn is NULL, this must be a proxy's client for + * which we have NO address. Therefore, we will temporarily + * set the client's trans_conn to the proxy's trans_conn and + * after CheckAuthorization the client's trans_conn will be + * restored. + * + * If XDM-AUTHORIZATION-1 is being used, CheckAuthorization + * will eventually call XdmAuthorizationValidate and this + * later function may use the client's trans_conn to get the + * client's address. Since a XDM-AUTH-1 auth string includes + * the client's address, this address is compared to the address + * in the client's trans_conn. If the proxy and client are + * on the same host, the comparison will fail; otherwise the + * comparison will fail and the client will not be authorized + * to connect to the server. + * + * The basis for this additional code is to prevent a + * NULL pointer dereference of the client's trans_conn. + * The fundamental problem - the fact that the client's + * trans_conn is NULL - is because the NewClient + * request in version 1.0 of the LBX protocol does not + * send the client's address to the server. When the + * spec is changed and the client's address is sent to + * server in the NewClient request, this additional code + * should be removed. + * + * See defect number XWSog08218 for more information. + */ + lbxpc = LbxProxyClient(priv->proxy); + trans_conn = ((OsCommPtr)lbxpc->osPrivate)->trans_conn; + priv->trans_conn = trans_conn; + restore_trans_conn = 1; + } +#endif + + auth_id = CheckAuthorization (proto_n, auth_proto, + string_n, auth_string, client, &reason); + +#ifdef LBX + if (! priv->trans_conn) { + if (auth_id == (XID) ~0L && !GetAccessControl()) + auth_id = ((OsCommPtr)lbxpc->osPrivate)->auth_id; +#ifdef XCSECURITY + else if (auth_id != (XID) ~0L && !SecuritySameLevel(lbxpc, auth_id)) { + auth_id = (XID) ~0L; + reason = "Client trust level differs from that of LBX Proxy"; + } +#endif + } +#endif + if (auth_id == (XID) ~0L) + { + if ( +#ifdef XCSECURITY + (proto_n == 0 || + strncmp (auth_proto, XSecurityAuthorizationName, proto_n) != 0) && +#endif + _XSERVTransGetPeerAddr (trans_conn, + &family, &fromlen, &from) != -1) + { + if ( +#ifdef LBX + !trans_conn || +#endif + 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); + } + + xfree ((char *) from); + } + + if (auth_id == (XID) ~0L) { +#ifdef LBX + /* + * Restore client's trans_conn state + */ + if (restore_trans_conn) { + priv->trans_conn = NULL; + } +#endif + 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); + + xfree ((char *) from); + } + } + priv->auth_id = auth_id; + priv->conn_time = 0; + +#ifdef XDMCP + /* indicate to Xdmcp protocol that we've opened new client */ + XdmcpOpenDisplay(priv->fd); +#endif /* XDMCP */ +#ifdef XAPPGROUP + if (ClientStateCallback) + XagCallClientStateChange (client); +#endif + /* At this point, if the client is authorized to change the access control + * list, we should getpeername() information, and add the client to + * the selfhosts list. It's not really the host machine, but the + * true purpose of the selfhosts list is to see who may change the + * access control list. + */ +#ifdef LBX + if (restore_trans_conn) { + priv->trans_conn = NULL; + } +#endif + return((char *)NULL); +} + +static ClientPtr +#ifdef LBX +AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time, + int (*Flush)( + ClientPtr /*who*/, OsCommPtr /*oc*/, + char * /*extraBuf*/, int /*extraCount*/), + void (*Close)( + ClientPtr /*client*/), + LbxProxyPtr proxy) +#else +AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time) +#endif +{ + OsCommPtr oc; + ClientPtr client; + + if ( +#ifdef LBX + trans_conn && +#endif +#ifndef WIN32 + fd >= lastfdesc +#else + XFD_SETCOUNT(&AllClients) >= MaxClients +#endif + ) + return NullClient; + oc = (OsCommPtr)xalloc(sizeof(OsCommRec)); + if (!oc) + return NullClient; + oc->trans_conn = trans_conn; + oc->fd = fd; + oc->input = (ConnectionInputPtr)NULL; + oc->output = (ConnectionOutputPtr)NULL; + oc->auth_id = None; + oc->conn_time = conn_time; +#ifdef LBX + oc->proxy = proxy; + oc->Flush = Flush; + oc->Close = Close; + oc->largereq = (ConnectionInputPtr) NULL; +#endif + if (!(client = NextAvailableClient((pointer)oc))) + { + xfree (oc); + return NullClient; + } +#ifdef LBX + if (trans_conn) +#endif + { +#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; +} + +#ifdef LBX + +int +ClientConnectionNumber (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr) client->osPrivate; + + return oc->fd; +} + +ClientPtr +AllocLbxClientConnection (ClientPtr client, LbxProxyPtr proxy) +{ + OsCommPtr oc = (OsCommPtr) client->osPrivate; + + return AllocNewConnection ((XtransConnInfo)NULL, oc->fd, GetTimeInMillis(), + LbxFlushClient, LbxCloseClient, proxy); +} + +void +LbxProxyConnection (ClientPtr client, LbxProxyPtr proxy) +{ + OsCommPtr oc = (OsCommPtr) client->osPrivate; + + FlushClient(client, oc, (char *)NULL, 0); + oc->proxy = proxy; + oc->Flush = LbxFlushClient; + oc->Close = LbxCloseClient; + LbxPrimeInput(client, proxy); +} + +#endif + +/***************** + * EstablishNewConnections + * If anyone is waiting on listened sockets, accept them. + * Returns a mask with indices of new clients. Updates AllClients + * and AllSockets. + *****************/ + +/*ARGSUSED*/ +Bool +EstablishNewConnections(ClientPtr clientUnused, pointer closure) +{ + fd_set readyconnections; /* set of listeners that are ready */ + int curconn; /* fd of listener that's ready */ + register int newconn; /* fd of new client */ + CARD32 connect_time; + register int i; + register ClientPtr client; + register OsCommPtr oc; + fd_set tmask; + + XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections); + XFD_COPYSET(&tmask, &readyconnections); + if (!XFD_ANYSET(&readyconnections)) + return TRUE; + connect_time = GetTimeInMillis(); + /* kill off stragglers */ + for (i=1; i<currentMaxClients; i++) + { + if ((client = clients[i])) + { + oc = (OsCommPtr)(client->osPrivate); + if ((oc && (oc->conn_time != 0) && + (connect_time - oc->conn_time) >= TimeOutValue) || + (client->noClientException != Success && !client->clientGone)) + CloseDownClient(client); + } + } +#ifndef WIN32 + for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) + { + while (readyconnections.fds_bits[i]) +#else + for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++) +#endif + { + XtransConnInfo trans_conn, new_trans_conn; + int status; + +#ifndef WIN32 + curconn = ffs (readyconnections.fds_bits[i]) - 1; + readyconnections.fds_bits[i] &= ~((fd_mask)1 << curconn); + curconn += (i * (sizeof(fd_mask)*8)); +#else + curconn = XFD_FD(&readyconnections, i); +#endif + + if ((trans_conn = lookup_trans_conn (curconn)) == NULL) + continue; + + if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL) + continue; + + newconn = _XSERVTransGetConnectionNumber (new_trans_conn); + + if (newconn < lastfdesc) + { + int clientid; +#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 (!AllocNewConnection (new_trans_conn, newconn, connect_time +#ifdef LBX + , StandardFlushClient, + CloseDownFileDescriptor, (LbxProxyPtr)NULL +#endif + )) + { + ErrorConnMax(new_trans_conn); + _XSERVTransClose(new_trans_conn); + } + } +#ifndef WIN32 + } +#endif + return TRUE; +} + +#define NOROOM "Maximum number of clients reached" + +/************ + * ErrorConnMax + * Fail a connection due to lack of client or file descriptor space + ************/ + +static void +ErrorConnMax(XtransConnInfo trans_conn) +{ + int fd = _XSERVTransGetConnectionNumber (trans_conn); + xConnSetupPrefix csp; + char pad[3]; + struct iovec iov[3]; + char byteOrder = 0; + int whichbyte = 1; + struct timeval waittime; + fd_set mask; + + /* if these seems like a lot of trouble to go to, it probably is */ + waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND; + waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) * + (1000000 / MILLI_PER_SECOND); + FD_ZERO(&mask); + FD_SET(fd, &mask); + (void)Select(fd + 1, &mask, NULL, NULL, &waittime); + /* try to read the byte-order of the connection */ + (void)_XSERVTransRead(trans_conn, &byteOrder, 1); + if ((byteOrder == 'l') || (byteOrder == 'B')) + { + csp.success = xFalse; + csp.lengthReason = sizeof(NOROOM) - 1; + csp.length = (sizeof(NOROOM) + 2) >> 2; + csp.majorVersion = X_PROTOCOL; + csp.minorVersion = X_PROTOCOL_REVISION; + if (((*(char *) &whichbyte) && (byteOrder == 'B')) || + (!(*(char *) &whichbyte) && (byteOrder == 'l'))) + { + swaps(&csp.majorVersion, whichbyte); + swaps(&csp.minorVersion, whichbyte); + swaps(&csp.length, whichbyte); + } + iov[0].iov_len = sz_xConnSetupPrefix; + iov[0].iov_base = (char *) &csp; + iov[1].iov_len = csp.lengthReason; + iov[1].iov_base = NOROOM; + iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3; + iov[2].iov_base = pad; + (void)_XSERVTransWritev(trans_conn, iov, 3); + } +} + +/************ + * CloseDownFileDescriptor: + * Remove this file descriptor and it's I/O buffers, etc. + ************/ + +#ifdef LBX +void +CloseDownFileDescriptor(ClientPtr client) +#else +static void +CloseDownFileDescriptor(OsCommPtr oc) +#endif +{ +#ifdef LBX + OsCommPtr oc = (OsCommPtr) client->osPrivate; +#endif + int connection = oc->fd; + + if (oc->trans_conn) { + _XSERVTransDisconnect(oc->trans_conn); + _XSERVTransClose(oc->trans_conn); + } +#ifndef LBX + FreeOsBuffers(oc); + xfree(oc); +#endif +#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)) + AnyClientsWriteBlocked = 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 (oc->output && oc->output->count) + FlushClient(client, oc, (char *)NULL, 0); +#ifdef XDMCP + XdmcpCloseDisplay(oc->fd); +#endif +#ifndef LBX + CloseDownFileDescriptor(oc); +#else + (*oc->Close) (client); + FreeOsBuffers(oc); + xfree(oc); +#endif + client->osPrivate = (pointer)NULL; + if (auditTrailLevel > 1) + AuditF("client %d disconnected\n", client->index); +} + +void +AddEnabledDevice(int fd) +{ + FD_SET(fd, &EnabledDevices); + FD_SET(fd, &AllSockets); + if (GrabInProgress) + FD_SET(fd, &SavedAllSockets); +} + +void +RemoveEnabledDevice(int fd) +{ + FD_CLR(fd, &EnabledDevices); + FD_CLR(fd, &AllSockets); + if (GrabInProgress) + FD_CLR(fd, &SavedAllSockets); +} + +/***************** + * 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; +#ifdef LBX + LbxClientPtr lbxClient = LbxClient(client); +#endif + + isItTimeToYield = TRUE; +#ifdef LBX + if (lbxClient) { + lbxClient->ignored = TRUE; + return; + } +#endif + if (!GrabInProgress || FD_ISSET(connection, &AllClients)) + { + if (FD_ISSET (connection, &ClientsWithInput)) + FD_SET(connection, &IgnoredClientsWithInput); + else + FD_CLR(connection, &IgnoredClientsWithInput); + FD_CLR(connection, &ClientsWithInput); + FD_CLR(connection, &AllSockets); + FD_CLR(connection, &AllClients); + FD_CLR(connection, &LastSelectMask); + } + else + { + if (FD_ISSET (connection, &SavedClientsWithInput)) + FD_SET(connection, &IgnoredClientsWithInput); + else + FD_CLR(connection, &IgnoredClientsWithInput); + FD_CLR(connection, &SavedClientsWithInput); + FD_CLR(connection, &SavedAllSockets); + FD_CLR(connection, &SavedAllClients); + } +} + +/**************** + * AttendClient + * Adds one client back into the input masks. + ****************/ + +void +AttendClient (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; +#ifdef LBX + LbxClientPtr lbxClient = LbxClient(client); + + if (lbxClient) { + lbxClient->ignored = FALSE; + return; + } +#endif + if (!GrabInProgress || GrabInProgress == client->index || + FD_ISSET(connection, &GrabImperviousClients)) + { + FD_SET(connection, &AllClients); + FD_SET(connection, &AllSockets); + FD_SET(connection, &LastSelectMask); + if (FD_ISSET (connection, &IgnoredClientsWithInput)) + FD_SET(connection, &ClientsWithInput); + } + else + { + FD_SET(connection, &SavedAllClients); + FD_SET(connection, &SavedAllSockets); + if (FD_ISSET(connection, &IgnoredClientsWithInput)) + FD_SET(connection, &SavedClientsWithInput); + } +} + +/* make client impervious to grabs; assume only executing client calls this */ + +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/connection.c.X.original b/nx-X11/programs/Xserver/os/connection.c.X.original new file mode 100644 index 000000000..0a12c655d --- /dev/null +++ b/nx-X11/programs/Xserver/os/connection.c.X.original @@ -0,0 +1,1385 @@ +/* $Xorg: connection.c,v 1.6 2001/02/09 02:05:23 xorgcvs Exp $ */ +/*********************************************************** + +Copyright 1987, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* $XFree86: xc/programs/Xserver/os/connection.c,v 3.64 2003/10/07 22:50:42 herrb Exp $ */ +/***************************************************************** + * Stuff to create connections --- OS dependent + * + * EstablishNewConnections, CreateWellKnownSockets, ResetWellKnownSockets, + * CloseDownConnection, CheckConnections, AddEnabledDevice, + * RemoveEnabledDevice, OnlyListToOneClient, + * ListenToAllClients, + * + * (WaitForSomething is in its own file) + * + * In this implementation, a client socket table is not kept. + * Instead, what would be the index into the table is just the + * file descriptor of the socket. This won't work for if the + * socket ids aren't small nums (0 - 2^8) + * + *****************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif +#include <X11/X.h> +#include <X11/Xproto.h> +#define XSERV_t +#define TRANS_SERVER +#define TRANS_REOPEN +#include <X11/Xtrans/Xtrans.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef WIN32 +#if defined(Lynx) +#include <socket.h> +#else +#include <sys/socket.h> +#endif + +#ifdef hpux +#include <sys/utsname.h> +#include <sys/ioctl.h> +#endif + +#if defined(DGUX) +#include <sys/ioctl.h> +#include <sys/utsname.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/param.h> +#include <unistd.h> +#endif + + +#ifdef AIXV3 +#include <sys/ioctl.h> +#endif + +#ifdef __UNIXOS2__ +#define select(n,r,w,x,t) os2PseudoSelect(n,r,w,x,t) +extern __const__ int _nfiles; +#endif + +#if defined(TCPCONN) || defined(STREAMSCONN) +# include <netinet/in.h> +# include <arpa/inet.h> +# if !defined(hpux) +# ifdef apollo +# ifndef NO_TCP_H +# include <netinet/tcp.h> +# endif +# else +# ifdef CSRG_BASED +# include <sys/param.h> +# endif +# ifndef __UNIXOS2__ +# include <netinet/tcp.h> +# endif +# endif +# endif +# include <arpa/inet.h> +#endif + +#if !defined(__UNIXOS2__) +#ifndef Lynx +#include <sys/uio.h> +#else +#include <uio.h> +#endif +#endif +#endif /* WIN32 */ +#include "misc.h" /* for typedef of pointer */ +#include "osdep.h" +#include <X11/Xpoll.h> +#include "opaque.h" +#include "dixstruct.h" +#ifdef XAPPGROUP +#include <X11/extensions/Xagsrv.h> +#endif +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <X11/extensions/security.h> +#endif +#ifdef LBX +#include "colormapst.h" +#include "propertyst.h" +#include "lbxserve.h" +#include "osdep.h" +#endif + +#ifdef X_NOT_POSIX +#define Pid_t int +#else +#define Pid_t pid_t +#endif + +#ifdef DNETCONN +#include <netdnet/dn.h> +#endif /* DNETCONN */ + +int lastfdesc; /* maximum file descriptor */ + +fd_set WellKnownConnections; /* Listener mask */ +fd_set EnabledDevices; /* mask for input devices that are on */ +fd_set AllSockets; /* select on this */ +fd_set AllClients; /* available clients */ +fd_set LastSelectMask; /* mask returned from last select call */ +fd_set ClientsWithInput; /* clients with FULL requests in buffer */ +fd_set ClientsWriteBlocked; /* clients who cannot receive output */ +fd_set OutputPending; /* clients with reply/event data ready to go */ +int MaxClients = 0; +Bool NewOutputPending; /* not yet attempted to write some new output */ +Bool AnyClientsWriteBlocked; /* true if some client blocked on write */ + +Bool RunFromSmartParent; /* send SIGUSR1 to parent process */ +Bool PartialNetwork; /* continue even if unable to bind all addrs */ +static Pid_t ParentProcess; +#ifdef __UNIXOS2__ +Pid_t GetPPID(Pid_t pid); +#endif + +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; + +#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*)xalloc(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; + xfree(temp); + } + } +} +#endif + +XtransConnInfo *ListenTransConns = NULL; +int *ListenTransFds = NULL; +int ListenTransCount; + +static void ErrorConnMax(XtransConnInfo /* trans_conn */); + +#ifndef LBX +static +void CloseDownFileDescriptor( + OsCommPtr /*oc*/ +); +#endif + + +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__ + +#ifndef __UNIXOS2__ + +#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 + +#else /* __UNIXOS2__ */ + lastfdesc = _nfiles - 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 +} + + +/***************** + * CreateWellKnownSockets + * At initialization, create the sockets to listen on for new clients. + *****************/ + +void +CreateWellKnownSockets(void) +{ + int i; + int partial; + char port[20]; + OsSigHandlerPtr handler; + + 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 + + FD_ZERO (&WellKnownConnections); + + sprintf (port, "%d", atoi (display)); + + if ((_XSERVTransMakeAllCOTSServerListeners (port, &partial, + &ListenTransCount, &ListenTransConns) >= 0) && + (ListenTransCount >= 1)) + { + if (!PartialNetwork && partial) + { + FatalError ("Failed to establish all listening sockets"); + } + else + { + ListenTransFds = (int *) xalloc (ListenTransCount * sizeof (int)); + + for (i = 0; i < ListenTransCount; i++) + { + int fd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); + + ListenTransFds[i] = fd; + FD_SET (fd, &WellKnownConnections); + + if (!_XSERVTransIsLocal (ListenTransConns[i])) + { + DefineSelf (fd); + } + } + } + } + + if (!XFD_ANYSET (&WellKnownConnections)) + FatalError ("Cannot establish any listening sockets - Make sure an X server isn't already running"); +#if !defined(WIN32) + OsSignal (SIGPIPE, SIG_IGN); + OsSignal (SIGHUP, AutoResetServer); +#endif + OsSignal (SIGINT, GiveUp); + OsSignal (SIGTERM, GiveUp); + XFD_COPYSET (&WellKnownConnections, &AllSockets); + ResetHosts(display); + /* + * Magic: If SIGUSR1 was set to SIG_IGN when + * the server started, assume that either + * + * a- The parent process is ignoring SIGUSR1 + * + * or + * + * b- The parent process is expecting a SIGUSR1 + * when the server is ready to accept connections + * + * In the first case, the signal will be harmless, + * in the second case, the signal will be quite + * useful + */ +#if !defined(WIN32) + 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__ */ + if (RunFromSmartParent) { + if (ParentProcess > 1) { + kill (ParentProcess, SIGUSR1); + } + } +#endif +#ifdef XDMCP + XdmcpInit (); +#endif +} + +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. + */ + + FD_CLR (ListenTransFds[i], &WellKnownConnections); + ListenTransFds[i] = ListenTransFds[ListenTransCount - 1]; + ListenTransConns[i] = ListenTransConns[ListenTransCount - 1]; + ListenTransCount -= 1; + i -= 1; + } + else if (status == TRANS_RESET_NEW_FD) + { + /* + * A new file descriptor was allocated (the old one was closed) + */ + + int newfd = _XSERVTransGetConnectionNumber (ListenTransConns[i]); + + FD_CLR (ListenTransFds[i], &WellKnownConnections); + ListenTransFds[i] = newfd; + FD_SET(newfd, &WellKnownConnections); + } + } + } + + ResetAuthorization (); + ResetHosts(display); + /* + * See above in CreateWellKnownSockets about SIGUSR1 + */ +#if !defined(WIN32) + if (RunFromSmartParent) { + if (ParentProcess > 1) { + kill (ParentProcess, SIGUSR1); + } + } +#endif + /* + * restart XDMCP + */ +#ifdef XDMCP + XdmcpReset (); +#endif +} + +void +CloseWellKnownConnections(void) +{ + int i; + + for (i = 0; i < ListenTransCount; i++) + _XSERVTransClose (ListenTransConns[i]); +} + +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; + + if (!((OsCommPtr)client->osPrivate)->trans_conn) { + strcpy(addr, "LBX proxy at "); + out += strlen(addr); + } + if (!len) + strcpy(out, "local host"); + else + switch (saddr->sa_family) + { + case AF_UNSPEC: +#if defined(UNIXCONN) || defined(LOCALCONN) || defined(OS2PIPECONN) + case AF_UNIX: +#endif + strcpy(out, "local host"); + break; +#if defined(TCPCONN) || defined(STREAMSCONN) || defined(MNX_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 +#ifdef DNETCONN + case AF_DECnet: + sprintf(out, "DN %s", + dnet_ntoa(&((struct sockaddr_dn *) saddr)->sdn_add)); + break; +#endif + default: + strcpy(out, "unknown address"); + } + + if (proto_n) + AuditF("client %d %s from %s\n Auth name: %.*s ID: %d\n", + client->index, letin ? "connected" : "rejected", addr, + (int)proto_n, auth_proto, auth_id); + else + AuditF("client %d %s from %s\n", + client->index, letin ? "connected" : "rejected", addr); +} + +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; + int restore_trans_conn = 0; + ClientPtr lbxpc = NULL; + + priv = (OsCommPtr)client->osPrivate; + trans_conn = priv->trans_conn; + +#ifdef LBX + if (!trans_conn) { + /* + * Since trans_conn is NULL, this must be a proxy's client for + * which we have NO address. Therefore, we will temporarily + * set the client's trans_conn to the proxy's trans_conn and + * after CheckAuthorization the client's trans_conn will be + * restored. + * + * If XDM-AUTHORIZATION-1 is being used, CheckAuthorization + * will eventually call XdmAuthorizationValidate and this + * later function may use the client's trans_conn to get the + * client's address. Since a XDM-AUTH-1 auth string includes + * the client's address, this address is compared to the address + * in the client's trans_conn. If the proxy and client are + * on the same host, the comparison will fail; otherwise the + * comparison will fail and the client will not be authorized + * to connect to the server. + * + * The basis for this additional code is to prevent a + * NULL pointer dereference of the client's trans_conn. + * The fundamental problem - the fact that the client's + * trans_conn is NULL - is because the NewClient + * request in version 1.0 of the LBX protocol does not + * send the client's address to the server. When the + * spec is changed and the client's address is sent to + * server in the NewClient request, this additional code + * should be removed. + * + * See defect number XWSog08218 for more information. + */ + lbxpc = LbxProxyClient(priv->proxy); + trans_conn = ((OsCommPtr)lbxpc->osPrivate)->trans_conn; + priv->trans_conn = trans_conn; + restore_trans_conn = 1; + } +#endif + + auth_id = CheckAuthorization (proto_n, auth_proto, + string_n, auth_string, client, &reason); + +#ifdef LBX + if (! priv->trans_conn) { + if (auth_id == (XID) ~0L && !GetAccessControl()) + auth_id = ((OsCommPtr)lbxpc->osPrivate)->auth_id; +#ifdef XCSECURITY + else if (auth_id != (XID) ~0L && !SecuritySameLevel(lbxpc, auth_id)) { + auth_id = (XID) ~0L; + reason = "Client trust level differs from that of LBX Proxy"; + } +#endif + } +#endif + if (auth_id == (XID) ~0L) + { + if ( +#ifdef XCSECURITY + (proto_n == 0 || + strncmp (auth_proto, XSecurityAuthorizationName, proto_n) != 0) && +#endif + _XSERVTransGetPeerAddr (trans_conn, + &family, &fromlen, &from) != -1) + { + if ( +#ifdef LBX + !trans_conn || +#endif + 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); + } + + xfree ((char *) from); + } + + if (auth_id == (XID) ~0L) { +#ifdef LBX + /* + * Restore client's trans_conn state + */ + if (restore_trans_conn) { + priv->trans_conn = NULL; + } +#endif + 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); + + xfree ((char *) from); + } + } + priv->auth_id = auth_id; + priv->conn_time = 0; + +#ifdef XDMCP + /* indicate to Xdmcp protocol that we've opened new client */ + XdmcpOpenDisplay(priv->fd); +#endif /* XDMCP */ +#ifdef XAPPGROUP + if (ClientStateCallback) + XagCallClientStateChange (client); +#endif + /* At this point, if the client is authorized to change the access control + * list, we should getpeername() information, and add the client to + * the selfhosts list. It's not really the host machine, but the + * true purpose of the selfhosts list is to see who may change the + * access control list. + */ +#ifdef LBX + if (restore_trans_conn) { + priv->trans_conn = NULL; + } +#endif + return((char *)NULL); +} + +static ClientPtr +#ifdef LBX +AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time, + int (*Flush)( + ClientPtr /*who*/, OsCommPtr /*oc*/, + char * /*extraBuf*/, int /*extraCount*/), + void (*Close)( + ClientPtr /*client*/), + LbxProxyPtr proxy) +#else +AllocNewConnection (XtransConnInfo trans_conn, int fd, CARD32 conn_time) +#endif +{ + OsCommPtr oc; + ClientPtr client; + + if ( +#ifdef LBX + trans_conn && +#endif +#ifndef WIN32 + fd >= lastfdesc +#else + XFD_SETCOUNT(&AllClients) >= MaxClients +#endif + ) + return NullClient; + oc = (OsCommPtr)xalloc(sizeof(OsCommRec)); + if (!oc) + return NullClient; + oc->trans_conn = trans_conn; + oc->fd = fd; + oc->input = (ConnectionInputPtr)NULL; + oc->output = (ConnectionOutputPtr)NULL; + oc->auth_id = None; + oc->conn_time = conn_time; +#ifdef LBX + oc->proxy = proxy; + oc->Flush = Flush; + oc->Close = Close; + oc->largereq = (ConnectionInputPtr) NULL; +#endif + if (!(client = NextAvailableClient((pointer)oc))) + { + xfree (oc); + return NullClient; + } +#ifdef LBX + if (trans_conn) +#endif + { +#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; +} + +#ifdef LBX + +int +ClientConnectionNumber (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr) client->osPrivate; + + return oc->fd; +} + +ClientPtr +AllocLbxClientConnection (ClientPtr client, LbxProxyPtr proxy) +{ + OsCommPtr oc = (OsCommPtr) client->osPrivate; + + return AllocNewConnection ((XtransConnInfo)NULL, oc->fd, GetTimeInMillis(), + LbxFlushClient, LbxCloseClient, proxy); +} + +void +LbxProxyConnection (ClientPtr client, LbxProxyPtr proxy) +{ + OsCommPtr oc = (OsCommPtr) client->osPrivate; + + FlushClient(client, oc, (char *)NULL, 0); + oc->proxy = proxy; + oc->Flush = LbxFlushClient; + oc->Close = LbxCloseClient; + LbxPrimeInput(client, proxy); +} + +#endif + +/***************** + * EstablishNewConnections + * If anyone is waiting on listened sockets, accept them. + * Returns a mask with indices of new clients. Updates AllClients + * and AllSockets. + *****************/ + +/*ARGSUSED*/ +Bool +EstablishNewConnections(ClientPtr clientUnused, pointer closure) +{ + fd_set readyconnections; /* set of listeners that are ready */ + int curconn; /* fd of listener that's ready */ + register int newconn; /* fd of new client */ + CARD32 connect_time; + register int i; + register ClientPtr client; + register OsCommPtr oc; + fd_set tmask; + + XFD_ANDSET (&tmask, (fd_set*)closure, &WellKnownConnections); + XFD_COPYSET(&tmask, &readyconnections); + if (!XFD_ANYSET(&readyconnections)) + return TRUE; + connect_time = GetTimeInMillis(); + /* kill off stragglers */ + for (i=1; i<currentMaxClients; i++) + { + if ((client = clients[i])) + { + oc = (OsCommPtr)(client->osPrivate); + if ((oc && (oc->conn_time != 0) && + (connect_time - oc->conn_time) >= TimeOutValue) || + (client->noClientException != Success && !client->clientGone)) + CloseDownClient(client); + } + } +#ifndef WIN32 + for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) + { + while (readyconnections.fds_bits[i]) +#else + for (i = 0; i < XFD_SETCOUNT(&readyconnections); i++) +#endif + { + XtransConnInfo trans_conn, new_trans_conn; + int status; + +#ifndef WIN32 + curconn = ffs (readyconnections.fds_bits[i]) - 1; + readyconnections.fds_bits[i] &= ~((fd_mask)1 << curconn); + curconn += (i * (sizeof(fd_mask)*8)); +#else + curconn = XFD_FD(&readyconnections, i); +#endif + + if ((trans_conn = lookup_trans_conn (curconn)) == NULL) + continue; + + if ((new_trans_conn = _XSERVTransAccept (trans_conn, &status)) == NULL) + continue; + + newconn = _XSERVTransGetConnectionNumber (new_trans_conn); + + if (newconn < lastfdesc) + { + int clientid; +#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 (!AllocNewConnection (new_trans_conn, newconn, connect_time +#ifdef LBX + , StandardFlushClient, + CloseDownFileDescriptor, (LbxProxyPtr)NULL +#endif + )) + { + ErrorConnMax(new_trans_conn); + _XSERVTransClose(new_trans_conn); + } + } +#ifndef WIN32 + } +#endif + return TRUE; +} + +#define NOROOM "Maximum number of clients reached" + +/************ + * ErrorConnMax + * Fail a connection due to lack of client or file descriptor space + ************/ + +static void +ErrorConnMax(XtransConnInfo trans_conn) +{ + int fd = _XSERVTransGetConnectionNumber (trans_conn); + xConnSetupPrefix csp; + char pad[3]; + struct iovec iov[3]; + char byteOrder = 0; + int whichbyte = 1; + struct timeval waittime; + fd_set mask; + + /* if these seems like a lot of trouble to go to, it probably is */ + waittime.tv_sec = BOTIMEOUT / MILLI_PER_SECOND; + waittime.tv_usec = (BOTIMEOUT % MILLI_PER_SECOND) * + (1000000 / MILLI_PER_SECOND); + FD_ZERO(&mask); + FD_SET(fd, &mask); + (void)Select(fd + 1, &mask, NULL, NULL, &waittime); + /* try to read the byte-order of the connection */ + (void)_XSERVTransRead(trans_conn, &byteOrder, 1); + if ((byteOrder == 'l') || (byteOrder == 'B')) + { + csp.success = xFalse; + csp.lengthReason = sizeof(NOROOM) - 1; + csp.length = (sizeof(NOROOM) + 2) >> 2; + csp.majorVersion = X_PROTOCOL; + csp.minorVersion = X_PROTOCOL_REVISION; + if (((*(char *) &whichbyte) && (byteOrder == 'B')) || + (!(*(char *) &whichbyte) && (byteOrder == 'l'))) + { + swaps(&csp.majorVersion, whichbyte); + swaps(&csp.minorVersion, whichbyte); + swaps(&csp.length, whichbyte); + } + iov[0].iov_len = sz_xConnSetupPrefix; + iov[0].iov_base = (char *) &csp; + iov[1].iov_len = csp.lengthReason; + iov[1].iov_base = NOROOM; + iov[2].iov_len = (4 - (csp.lengthReason & 3)) & 3; + iov[2].iov_base = pad; + (void)_XSERVTransWritev(trans_conn, iov, 3); + } +} + +/************ + * CloseDownFileDescriptor: + * Remove this file descriptor and it's I/O buffers, etc. + ************/ + +#ifdef LBX +void +CloseDownFileDescriptor(ClientPtr client) +#else +static void +CloseDownFileDescriptor(OsCommPtr oc) +#endif +{ +#ifdef LBX + OsCommPtr oc = (OsCommPtr) client->osPrivate; +#endif + int connection = oc->fd; + + if (oc->trans_conn) { + _XSERVTransDisconnect(oc->trans_conn); + _XSERVTransClose(oc->trans_conn); + } +#ifndef LBX + FreeOsBuffers(oc); + xfree(oc); +#endif +#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)) + AnyClientsWriteBlocked = 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 (oc->output && oc->output->count) + FlushClient(client, oc, (char *)NULL, 0); +#ifdef XDMCP + XdmcpCloseDisplay(oc->fd); +#endif +#ifndef LBX + CloseDownFileDescriptor(oc); +#else + (*oc->Close) (client); + FreeOsBuffers(oc); + xfree(oc); +#endif + client->osPrivate = (pointer)NULL; + if (auditTrailLevel > 1) + AuditF("client %d disconnected\n", client->index); +} + +void +AddEnabledDevice(int fd) +{ + FD_SET(fd, &EnabledDevices); + FD_SET(fd, &AllSockets); + if (GrabInProgress) + FD_SET(fd, &SavedAllSockets); +} + +void +RemoveEnabledDevice(int fd) +{ + FD_CLR(fd, &EnabledDevices); + FD_CLR(fd, &AllSockets); + if (GrabInProgress) + FD_CLR(fd, &SavedAllSockets); +} + +/***************** + * 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; +#ifdef LBX + LbxClientPtr lbxClient = LbxClient(client); +#endif + + isItTimeToYield = TRUE; +#ifdef LBX + if (lbxClient) { + lbxClient->ignored = TRUE; + return; + } +#endif + if (!GrabInProgress || FD_ISSET(connection, &AllClients)) + { + if (FD_ISSET (connection, &ClientsWithInput)) + FD_SET(connection, &IgnoredClientsWithInput); + else + FD_CLR(connection, &IgnoredClientsWithInput); + FD_CLR(connection, &ClientsWithInput); + FD_CLR(connection, &AllSockets); + FD_CLR(connection, &AllClients); + FD_CLR(connection, &LastSelectMask); + } + else + { + if (FD_ISSET (connection, &SavedClientsWithInput)) + FD_SET(connection, &IgnoredClientsWithInput); + else + FD_CLR(connection, &IgnoredClientsWithInput); + FD_CLR(connection, &SavedClientsWithInput); + FD_CLR(connection, &SavedAllSockets); + FD_CLR(connection, &SavedAllClients); + } +} + +/**************** + * AttendClient + * Adds one client back into the input masks. + ****************/ + +void +AttendClient (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + int connection = oc->fd; +#ifdef LBX + LbxClientPtr lbxClient = LbxClient(client); + + if (lbxClient) { + lbxClient->ignored = FALSE; + return; + } +#endif + if (!GrabInProgress || GrabInProgress == client->index || + FD_ISSET(connection, &GrabImperviousClients)) + { + FD_SET(connection, &AllClients); + FD_SET(connection, &AllSockets); + FD_SET(connection, &LastSelectMask); + if (FD_ISSET (connection, &IgnoredClientsWithInput)) + FD_SET(connection, &ClientsWithInput); + } + else + { + FD_SET(connection, &SavedAllClients); + FD_SET(connection, &SavedAllSockets); + if (FD_ISSET(connection, &IgnoredClientsWithInput)) + FD_SET(connection, &SavedClientsWithInput); + } +} + +/* make client impervious to grabs; assume only executing client calls this */ + +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..76edbaeee --- /dev/null +++ b/nx-X11/programs/Xserver/os/io.c @@ -0,0 +1,1347 @@ +/*********************************************************** + +Copyright 1987, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + + +******************************************************************/ +/* $Xorg: io.c,v 1.6 2001/02/09 02:05:23 xorgcvs Exp $ */ +/***************************************************************** + * i/o functions + * + * WriteToClient, ReadRequestFromClient + * InsertFakeRequest, ResetCurrentRequest + * + *****************************************************************/ +/* $XFree86: xc/programs/Xserver/os/io.c,v 3.34 2002/05/31 18:46:05 dawes Exp $ */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#if 0 +#define DEBUG_COMMUNICATION +#endif +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif +#include <stdio.h> +#include <X11/Xtrans/Xtrans.h> +#include <X11/Xmd.h> +#include <errno.h> +#if !defined(__UNIXOS2__) && !defined(WIN32) +#ifndef Lynx +#include <sys/uio.h> +#else +#include <uio.h> +#endif +#endif +#include <X11/X.h> +#define NEED_REPLIES +#include <X11/Xproto.h> +#include "os.h" +#include "osdep.h" +#include <X11/Xpoll.h> +#include "opaque.h" +#include "dixstruct.h" +#include "misc.h" +#ifdef LBX +#include "colormapst.h" +#include "propertyst.h" +#include "lbxserve.h" +#endif + +CallbackListPtr ReplyCallback; +CallbackListPtr FlushCallback; + +/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX + * systems are broken and return EWOULDBLOCK when they should return EAGAIN + */ +#ifndef __UNIXOS2__ +#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 +#else /* __UNIXOS2__ Writing to full pipes may return ENOSPC */ +#define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK || err == ENOSPC) +#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 <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; } + +#ifdef hpux_not_tog +#define LBX_NEED_OLD_SYMBOL_FOR_LOADABLES +#endif + +#ifdef LBX +#ifdef LBX_NEED_OLD_SYMBOL_FOR_LOADABLES +#undef ReadRequestFromClient +int +ReadRequestFromClient(ClientPtr client) +{ + return (*client->readRequest)(client); +} +#endif +int +StandardReadRequestFromClient(ClientPtr client) +#else +int +ReadRequestFromClient(ClientPtr client) +#endif +{ + 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) + { + xfree(aci->buffer); + xfree(aci); + } + else + { + aci->next = FreeInputs; + FreeInputs = aci; + } + AvailableInput->input = (ConnectionInputPtr)NULL; + } + AvailableInput = (OsCommPtr)NULL; + } + + /* make sure we have an input buffer */ + + if (!oci) + { + if ((oci = FreeInputs)) + { + FreeInputs = oci->next; + } + else if (!(oci = AllocateInputBuffer())) + { + YieldControlDeath(); + return -1; + } + oc->input = oci; + } + + /* advance to start of next request */ + + oci->bufptr += oci->lenLastReq; + + need_header = FALSE; +#ifdef BIGREQS + move_header = FALSE; +#endif + gotnow = oci->bufcnt + oci->buffer - oci->bufptr; + if (gotnow < sizeof(xReq)) + { + /* We don't have an entire xReq yet. Can't tell how big + * the request will be until we get the whole xReq. + */ + needed = sizeof(xReq); + need_header = TRUE; + } + else + { + /* We have a whole xReq. We can tell how big the whole + * request will be unless it is a Big Request. + */ + request = (xReq *)oci->bufptr; + needed = get_req_len(request, client); +#ifdef BIGREQS + if (!needed && client->big_requests) + { + /* It's a Big Request. */ + move_header = TRUE; + if (gotnow < sizeof(xBigReq)) + { + /* Still need more data to tell just how big. */ + needed = sizeof(xBigReq) >> 2; /* needed is in CARD32s now */ + need_header = TRUE; + } + else + needed = get_big_req_len(request, client); + } +#endif + client->req_len = needed; + needed <<= 2; /* needed is in bytes now */ + } + if (gotnow < needed) + { + /* Need to read more data, either so that we can get a + * complete xReq (if need_header is TRUE), a complete + * xBigReq (if move_header is TRUE), or the rest of the + * request (if need_header and move_header are both FALSE). + */ + + oci->lenLastReq = 0; + if (needed > MAXBUFSIZE) + { + /* request is too big for us to handle */ + YieldControlDeath(); + return -1; + } + if ((gotnow == 0) || + ((oci->bufptr - oci->buffer + needed) > oci->size)) + { + /* no data, or the request is too big to fit in the buffer */ + + if ((gotnow > 0) && (oci->bufptr != oci->buffer)) + /* save the data we've already read */ + memmove(oci->buffer, oci->bufptr, gotnow); + if (needed > oci->size) + { + /* make buffer bigger to accomodate request */ + char *ibuf; + + ibuf = (char *)xrealloc(oci->buffer, needed); + if (!ibuf) + { + YieldControlDeath(); + return -1; + } + oci->size = needed; + oci->buffer = ibuf; + } + oci->bufptr = oci->buffer; + oci->bufcnt = gotnow; + } + /* XXX this is a workaround. This function is sometimes called + * after the trans_conn has been freed. In this case trans_conn + * will be null. Really ought to restructure things so that we + * never get here in those circumstances. + */ + if (!oc->trans_conn) + { + /* treat as if an error occured on the read, which is what + * used to happen + */ + YieldControlDeath(); + return -1; + } +#ifdef LBX + if (oc->proxy && oc->proxy->compHandle) + result = (*oc->proxy->streamOpts.streamCompRead)(fd, + (unsigned char *)oci->buffer + oci->bufcnt, + oci->size - oci->bufcnt); + else +#endif + result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt, + oci->size - oci->bufcnt); + if (result <= 0) + { + if ((result < 0) && ETEST(errno)) + { +#if defined(SVR4) && defined(i386) && !defined(sun) +#if defined(LBX) && 0 + /* + * For LBX connections, we can get a valid EWOULDBLOCK + * There is probably a better way of distinguishing LBX + * connections, but this works. (DHD) + */ + extern int LbxRead(); + if (oc->Read == LbxRead) +#else + if (0) +#endif +#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 *)xrealloc(oci->buffer, BUFSIZE); + if (ibuf) + { + oci->size = BUFSIZE; + oci->buffer = ibuf; + oci->bufptr = ibuf + oci->bufcnt - gotnow; + } + } + if (need_header && gotnow >= needed) + { + /* We wanted an xReq, now we've gotten it. */ + request = (xReq *)oci->bufptr; + needed = get_req_len(request, client); +#ifdef BIGREQS + if (!needed && client->big_requests) + { + move_header = TRUE; + if (gotnow < sizeof(xBigReq)) + needed = sizeof(xBigReq) >> 2; + else + needed = get_big_req_len(request, client); + } +#endif + client->req_len = needed; + needed <<= 2; + } + if (gotnow < needed) + { + /* Still don't have enough; punt. */ + YieldControlNoInput(); + return 0; + } + } + if (needed == 0) + { +#ifdef BIGREQS + if (client->big_requests) + needed = sizeof(xBigReq); + else +#endif + needed = sizeof(xReq); + } + oci->lenLastReq = needed; + + /* + * Check to see if client has at least one whole request in the + * buffer beyond the request we're returning to the caller. + * If there is only a partial request, treat like buffer + * is empty so that select() will be called again and other clients + * can get into the queue. + */ + + gotnow -= needed; + if (gotnow >= sizeof(xReq)) + { + request = (xReq *)(oci->bufptr + needed); + if (gotnow >= (result = (get_req_len(request, client) << 2)) +#ifdef BIGREQS + && (result || + (client->big_requests && + (gotnow >= sizeof(xBigReq) && + gotnow >= (get_big_req_len(request, client) << 2)))) +#endif + ) + FD_SET(fd, &ClientsWithInput); + else + { +#ifdef SMART_SCHEDULE + if (!SmartScheduleDisable) + FD_CLR(fd, &ClientsWithInput); + else +#endif + YieldControlNoInput(); + } + } + else + { + if (!gotnow) + AvailableInput = oc; +#ifdef SMART_SCHEDULE + if (!SmartScheduleDisable) + FD_CLR(fd, &ClientsWithInput); + else +#endif + YieldControlNoInput(); + } +#ifdef SMART_SCHEDULE + if (SmartScheduleDisable) +#endif + if (++timesThisConnection >= MAX_TIMES_PER) + YieldControl(); +#ifdef BIGREQS + if (move_header) + { + request = (xReq *)oci->bufptr; + oci->bufptr += (sizeof(xBigReq) - sizeof(xReq)); + *(xReq *)oci->bufptr = *request; + oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq)); + client->req_len -= (sizeof(xBigReq) - sizeof(xReq)) >> 2; + } +#endif + client->requestBuffer = (pointer)oci->bufptr; +#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) + { + xfree(aci->buffer); + xfree(aci); + } + else + { + aci->next = FreeInputs; + FreeInputs = aci; + } + AvailableInput->input = (ConnectionInputPtr)NULL; + } + AvailableInput = (OsCommPtr)NULL; + } + if (!oci) + { + if ((oci = FreeInputs)) + FreeInputs = oci->next; + else if (!(oci = AllocateInputBuffer())) + return FALSE; + oc->input = oci; + } + oci->bufptr += oci->lenLastReq; + oci->lenLastReq = 0; + gotnow = oci->bufcnt + oci->buffer - oci->bufptr; + if ((gotnow + count) > oci->size) + { + char *ibuf; + + ibuf = (char *)xrealloc(oci->buffer, gotnow + count); + if (!ibuf) + return(FALSE); + oci->size = gotnow + count; + oci->buffer = ibuf; + oci->bufptr = ibuf + oci->bufcnt - gotnow; + } + moveup = count - (oci->bufptr - oci->buffer); + if (moveup > 0) + { + if (gotnow > 0) + memmove(oci->bufptr + moveup, oci->bufptr, gotnow); + oci->bufptr += moveup; + oci->bufcnt += moveup; + } + memmove(oci->bufptr - count, data, count); + oci->bufptr -= count; + gotnow += count; + if ((gotnow >= sizeof(xReq)) && + (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2))) + FD_SET(fd, &ClientsWithInput); + else + YieldControlNoInput(); + return(TRUE); +} + +/***************************************************************** + * ResetRequestFromClient + * Reset to reexecute the current request, and yield. + * + **********************/ + +void +ResetCurrentRequest(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + register ConnectionInputPtr oci = oc->input; + int fd = oc->fd; + register xReq *request; + int gotnow, needed; +#ifdef LBX + LbxClientPtr lbxClient = LbxClient(client); + + if (lbxClient) { + LbxSetForBlock(lbxClient); + if (!oci) { + AppendFakeRequest(client, + client->requestBuffer, client->req_len << 2); + return; + } + } +#endif + if (AvailableInput == oc) + AvailableInput = (OsCommPtr)NULL; + oci->lenLastReq = 0; + gotnow = oci->bufcnt + oci->buffer - oci->bufptr; + if (gotnow < sizeof(xReq)) + { + YieldControlNoInput(); + } + else + { + request = (xReq *)oci->bufptr; + needed = get_req_len(request, client); +#ifdef BIGREQS + if (!needed && client->big_requests) + { + oci->bufptr -= sizeof(xBigReq) - sizeof(xReq); + *(xReq *)oci->bufptr = *request; + ((xBigReq *)oci->bufptr)->length = client->req_len; + if (client->swapped) + { + char n; + swapl(&((xBigReq *)oci->bufptr)->length, n); + } + } +#endif + if (gotnow >= (needed << 2)) + { + if (FD_ISSET(fd, &AllClients)) + { + FD_SET(fd, &ClientsWithInput); + } + else + { + FD_SET(fd, &IgnoredClientsWithInput); + } + YieldControl(); + } + else + YieldControlNoInput(); + } +} + + + +/***************************************************************** + * PeekNextRequest and SkipRequests were implemented to support DBE + * idioms, but can certainly be used outside of DBE. There are two + * related macros in os.h, ReqLen and CastxReq. See the porting + * layer document for more details. + * + **********************/ + + +/***************************************************************** + * PeekNextRequest + * lets you look ahead at the unexecuted requests in a + * client's request buffer. + * + * Note: this implementation of PeekNextRequest ignores the + * readmore parameter. + * + **********************/ + +xReqPtr +PeekNextRequest( + 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 (FlushCallback) + CallCallbacks(&FlushCallback, NULL); + + if (!newoutput) + return; + + /* + * It may be that some client still has critical output pending, + * but he is not yet ready to receive it anyway, so we will + * simply wait for the select to tell us when he's ready to receive. + */ + CriticalOutputPending = FALSE; + NewOutputPending = FALSE; + +#ifndef WIN32 + for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++) + { + mask = OutputPending.fds_bits[ base ]; + OutputPending.fds_bits[ base ] = 0; + while (mask) + { + index = ffs(mask) - 1; + mask &= ~lowbit(mask); + if ((index = ConnectionTranslation[(base * (sizeof(fd_mask)*8)) + index]) == 0) + continue; + client = clients[index]; + if (client->clientGone) + continue; + oc = (OsCommPtr)client->osPrivate; + if ( +#ifdef LBX + !oc->proxy && +#endif + FD_ISSET(oc->fd, &ClientsWithInput)) + { + FD_SET(oc->fd, &OutputPending); /* set the bit again */ + NewOutputPending = TRUE; + } + else + (void)FlushClient(client, oc, (char *)NULL, 0); + } + } +#else /* WIN32 */ + FD_ZERO(&newOutputPending); + for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++) + { + index = XFD_FD(&OutputPending, base); + if ((index = GetConnectionTranslation(index)) == 0) + continue; + client = clients[index]; + if (client->clientGone) + continue; + oc = (OsCommPtr)client->osPrivate; + if ( +#ifdef LBX + !oc->proxy && +#endif + FD_ISSET(oc->fd, &ClientsWithInput)) + { + FD_SET(oc->fd, &newOutputPending); /* set the bit again */ + NewOutputPending = TRUE; + } + else + (void)FlushClient(client, oc, (char *)NULL, 0); + } + XFD_COPYSET(&newOutputPending, &OutputPending); +#endif /* WIN32 */ +} + +void +FlushIfCriticalOutputPending(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, char *buf) +{ + OsCommPtr oc = (OsCommPtr)who->osPrivate; + ConnectionOutputPtr oco = oc->output; + int padBytes; +#ifdef DEBUG_COMMUNICATION + Bool multicount = FALSE; +#endif + if (!count) + return(0); +#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), (pointer)&replyinfo); + } + else if (who->clientState == ClientStateRunning + && buf[0] == X_Reply) + { /* start of new reply */ + CARD32 replylen; + unsigned long bytesleft; + char n; + + replylen = ((xGenericReply *)buf)->length; + if (who->swapped) + swapl(&replylen, n); + bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes; + replyinfo.startOfReply = TRUE; + replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft; + CallCallbacks((&ReplyCallback), (pointer)&replyinfo); + } + } +#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 + count + padBytes > oco->size) + { + FD_CLR(oc->fd, &OutputPending); + if(!XFD_ANYSET(&OutputPending)) { + CriticalOutputPending = FALSE; + NewOutputPending = FALSE; + } + return FlushClient(who, oc, buf, count); + } + + NewOutputPending = TRUE; + FD_SET(oc->fd, &OutputPending); + memmove((char *)oco->buf + oco->count, buf, count); + oco->count += count + padBytes; + return(count); +} + + /******************** + * FlushClient() + * If the client isn't keeping up with us, then we try to continue + * buffering the data and set the apropriate bit in ClientsWritable + * (which is used by WaitFor in the select). If the connection yields + * a permanent error, or we can't allocate any more space, we then + * close the connection. + * + **********************/ + +#ifdef LBX +#ifdef LBX_NEED_OLD_SYMBOL_FOR_LOADABLES +#undef FlushClient +int +FlushClient(ClientPtr who, OsCommPtr oc, char *extraBuf, int extraCount) +{ + return (*oc->Flush)(who, oc, extraBuf, extraCount); +} +#endif +int +StandardFlushClient(ClientPtr who, OsCommPtr oc, + char *extraBuf, int extraCount) +#else +int +FlushClient(ClientPtr who, OsCommPtr oc, char *extraBuf, int extraCount) +#endif +{ + ConnectionOutputPtr oco = oc->output; + int connection = oc->fd; + XtransConnInfo trans_conn = oc->trans_conn; + struct iovec iov[3]; + static char padBuffer[3]; + long written; + long padsize; + long notWritten; + long todo; + + if (!oco) + return 0; + written = 0; + padsize = padlength[extraCount & 3]; + notWritten = oco->count + extraCount + padsize; + todo = notWritten; + while (notWritten) { + long before = written; /* amount of whole thing written */ + long remain = todo; /* amount to try this time, <= notWritten */ + int i = 0; + long len; + + /* You could be very general here and have "in" and "out" iovecs + * and write a loop without using a macro, but what the heck. This + * translates to: + * + * how much of this piece is new? + * if more new then we are trying this time, clamp + * if nothing new + * then bump down amount already written, for next piece + * else put new stuff in iovec, will need all of next piece + * + * Note that todo had better be at least 1 or else we'll end up + * writing 0 iovecs. + */ +#define InsertIOV(pointer, length) \ + len = (length) - before; \ + if (len > remain) \ + len = remain; \ + if (len <= 0) { \ + before = (-len); \ + } else { \ + iov[i].iov_len = len; \ + iov[i].iov_base = (pointer) + before; \ + i++; \ + remain -= len; \ + before = 0; \ + } + + InsertIOV ((char *)oco->buf, oco->count) + InsertIOV (extraBuf, extraCount) + InsertIOV (padBuffer, padsize) + + errno = 0; + if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0) + { + written += len; + notWritten -= len; + todo = notWritten; + } + else if (ETEST(errno) +#ifdef SUNSYSV /* check for another brain-damaged OS bug */ + || (errno == 0) +#endif +#ifdef EMSGSIZE /* check for another brain-damaged OS bug */ + || ((errno == EMSGSIZE) && (todo == 1)) +#endif + ) + { + /* If we've arrived here, then the client is stuffed to the gills + and not ready to accept more. Make a note of it and buffer + the rest. */ + FD_SET(connection, &ClientsWriteBlocked); + AnyClientsWriteBlocked = TRUE; + + if (written < oco->count) + { + if (written > 0) + { + oco->count -= written; + memmove((char *)oco->buf, + (char *)oco->buf + written, + oco->count); + written = 0; + } + } + else + { + written -= oco->count; + oco->count = 0; + } + + if (notWritten > oco->size) + { + unsigned char *obuf; + + obuf = (unsigned char *)xrealloc(oco->buf, + notWritten + BUFSIZE); + if (!obuf) + { + _XSERVTransDisconnect(oc->trans_conn); + _XSERVTransClose(oc->trans_conn); + oc->trans_conn = NULL; + MarkClientException(who); + oco->count = 0; + return(-1); + } + oco->size = notWritten + BUFSIZE; + oco->buf = obuf; + } + + /* If the amount written extended into the padBuffer, then the + difference "extraCount - written" may be less than 0 */ + if ((len = extraCount - written) > 0) + memmove ((char *)oco->buf + oco->count, + extraBuf + written, + len); + + oco->count = notWritten; /* this will include the pad */ + /* return only the amount explicitly requested */ + return extraCount; + } +#ifdef EMSGSIZE /* check for another brain-damaged OS bug */ + else if (errno == EMSGSIZE) + { + todo >>= 1; + } +#endif + else + { + if (oc->trans_conn) + { + _XSERVTransDisconnect(oc->trans_conn); + _XSERVTransClose(oc->trans_conn); + oc->trans_conn = NULL; + } + MarkClientException(who); + oco->count = 0; + return(-1); + } + } + + /* everything was flushed out */ + oco->count = 0; + /* check to see if this client was write blocked */ + if (AnyClientsWriteBlocked) + { + FD_CLR(oc->fd, &ClientsWriteBlocked); + if (! XFD_ANYSET(&ClientsWriteBlocked)) + AnyClientsWriteBlocked = FALSE; + } + if (oco->size > BUFWATERMARK) + { + xfree(oco->buf); + xfree(oco); + } + else + { + oco->next = FreeOutputs; + FreeOutputs = oco; + } + oc->output = (ConnectionOutputPtr)NULL; + return extraCount; /* return only the amount explicitly requested */ +} + +ConnectionInputPtr +AllocateInputBuffer(void) +{ + ConnectionInputPtr oci; + + oci = (ConnectionInputPtr)xalloc(sizeof(ConnectionInput)); + if (!oci) + return (ConnectionInputPtr)NULL; + oci->buffer = (char *)xalloc(BUFSIZE); + if (!oci->buffer) + { + xfree(oci); + return (ConnectionInputPtr)NULL; + } + oci->size = BUFSIZE; + oci->bufptr = oci->buffer; + oci->bufcnt = 0; + oci->lenLastReq = 0; + return oci; +} + +ConnectionOutputPtr +AllocateOutputBuffer(void) +{ + ConnectionOutputPtr oco; + + oco = (ConnectionOutputPtr)xalloc(sizeof(ConnectionOutput)); + if (!oco) + return (ConnectionOutputPtr)NULL; + oco->buf = (unsigned char *) xalloc(BUFSIZE); + if (!oco->buf) + { + xfree(oco); + return (ConnectionOutputPtr)NULL; + } + oco->size = BUFSIZE; + oco->count = 0; +#ifdef LBX + oco->nocompress = FALSE; +#endif + return oco; +} + +void +FreeOsBuffers(OsCommPtr oc) +{ + ConnectionInputPtr oci; + ConnectionOutputPtr oco; + + if (AvailableInput == oc) + AvailableInput = (OsCommPtr)NULL; + if ((oci = oc->input)) + { + if (FreeInputs) + { + xfree(oci->buffer); + xfree(oci); + } + else + { + FreeInputs = oci; + oci->next = (ConnectionInputPtr)NULL; + oci->bufptr = oci->buffer; + oci->bufcnt = 0; + oci->lenLastReq = 0; + } + } + if ((oco = oc->output)) + { + if (FreeOutputs) + { + xfree(oco->buf); + xfree(oco); + } + else + { + FreeOutputs = oco; + oco->next = (ConnectionOutputPtr)NULL; + oco->count = 0; + } + } +#ifdef LBX + if ((oci = oc->largereq)) { + xfree(oci->buffer); + xfree(oci); + } +#endif +} + +void +ResetOsBuffers(void) +{ + ConnectionInputPtr oci; + ConnectionOutputPtr oco; + + while ((oci = FreeInputs)) + { + FreeInputs = oci->next; + xfree(oci->buffer); + xfree(oci); + } + while ((oco = FreeOutputs)) + { + FreeOutputs = oco->next; + xfree(oco->buf); + xfree(oco); + } +} diff --git a/nx-X11/programs/Xserver/os/k5auth.c b/nx-X11/programs/Xserver/os/k5auth.c new file mode 100644 index 000000000..78301ad10 --- /dev/null +++ b/nx-X11/programs/Xserver/os/k5auth.c @@ -0,0 +1,801 @@ +/* $Xorg: k5auth.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */ +/* + +Copyright 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ +/* $XFree86: xc/programs/Xserver/os/k5auth.c,v 3.4 2001/01/17 22:37:10 dawes Exp $ */ + +/* + * Kerberos V5 authentication scheme + * Author: Tom Yu <tlyu@MIT.EDU> + * + * Mostly snarfed wholesale from the user_user demo in the + * krb5 distribution. (At least the checking part) + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#ifdef TCPCONN +#include <netinet/in.h> +#endif +#ifdef DNETCONN +#include <netdnet/dn.h> +#endif +#include <arpa/inet.h> +#include <krb5/krb5.h> +/* 9/93: krb5.h leaks some symbols */ +#undef BITS32 +#undef xfree +#include <krb5/los-proto.h> +#include <X11/X.h> +#include "os.h" +#include "osdep.h" +#include <X11/Xproto.h> +#include <X11/Xfuncs.h> +#include "dixstruct.h" +#include <com_err.h> +#include "Xauth.h" + +extern int (*k5_Vector[256])(); +extern int SendConnSetup(); +extern char *display; /* need this to generate rcache name */ + +static XID krb5_id = ~0L; +static krb5_principal srvname = NULL; /* service name */ +static char *ccname = NULL; +static char *ktname = NULL; /* key table name */ +static char kerror[256]; + +/* + * tgt_keyproc: + * + * extract session key from a credentials struct + */ +krb5_error_code tgt_keyproc(keyprocarg, principal, vno, key) + krb5_pointer keyprocarg; + krb5_principal principal; + krb5_kvno vno; + krb5_keyblock **key; +{ + krb5_creds *creds = (krb5_creds *)keyprocarg; + + return krb5_copy_keyblock(&creds->keyblock, key); +} + +/* + * k5_cmpenc: + * + * compare "encoded" principals + */ +Bool k5_cmpenc(pname, plen, buf) + unsigned char *pname; + short plen; + krb5_data *buf; +{ + return (plen == buf->length && + memcmp(pname, buf->data, plen) == 0); +} + +/* + * K5Check: + * + * This is stage 0 of the krb5 authentication protocol. It + * goes through the current credentials cache and extracts the + * primary principal and tgt to send to the client, or as + * appropriate, extracts from a keytab. + * + * The packet sent to the client has the following format: + * + * CARD8 reqType = 2 + * CARD8 data = 0 + * CARD16 length = total length of packet (in 32 bit units) + * CARD16 plen = length of encoded principal following + * STRING8 princ = encoded principal + * STRING8 ticket = server tgt + * + * For client-server authentication, the packet is as follows: + * + * CARD8 reqType = 3 + * CARD8 data = 0 + * CARD16 length = total length + * STRING8 princ = encoded principal of server + */ +XID K5Check(data_length, data, client, reason) + unsigned short data_length; + char *data; + ClientPtr client; + char **reason; +{ + krb5_error_code retval; + CARD16 tlen; + krb5_principal sprinc, cprinc; + krb5_ccache cc; + krb5_creds *creds; + char *outbuf, *cp; + krb5_data princ; + register char n; + xReq prefix; + + if (krb5_id == ~0L) + return ~0L; + if (!ccname && !srvname) + return ~0L; + if (ccname) + { + if ((creds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) + return ~0L; + if (retval = krb5_cc_resolve(ccname, &cc)) + return ~0L; + bzero((char*)creds, sizeof (krb5_creds)); + if (retval = krb5_cc_get_principal(cc, &cprinc)) + { + krb5_free_creds(creds); + krb5_cc_close(cc); + return ~0L; + } + creds->client = cprinc; + if (retval = + krb5_build_principal_ext(&sprinc, + krb5_princ_realm(creds->client)->length, + krb5_princ_realm(creds->client)->data, + 6, "krbtgt", + krb5_princ_realm(creds->client)->length, + krb5_princ_realm(creds->client)->data, + 0)) + { + krb5_free_creds(creds); + krb5_cc_close(cc); + return ~0L; + } + creds->server = sprinc; + retval = krb5_get_credentials(KRB5_GC_CACHED, cc, creds); + krb5_cc_close(cc); + if (retval) + { + krb5_free_creds(creds); + return ~0L; + } + if (retval = XauKrb5Encode(cprinc, &princ)) + { + krb5_free_creds(creds); + return ~0L; + } + tlen = sz_xReq + 2 + princ.length + creds->ticket.length; + prefix.reqType = 2; /* opcode = authenticate user-to-user */ + } + else if (srvname) + { + if (retval = XauKrb5Encode(srvname, &princ)) + { + return ~0L; + } + tlen = sz_xReq + princ.length; + prefix.reqType = 3; /* opcode = authenticate client-server */ + } + prefix.data = 0; /* stage = 0 */ + prefix.length = (tlen + 3) >> 2; /* round up to nearest multiple + of 4 bytes */ + if (client->swapped) + { + swaps(&prefix.length, n); + } + if ((cp = outbuf = (char *)malloc(tlen)) == NULL) + { + if (ccname) + { + krb5_free_creds(creds); + } + free(princ.data); + return ~0L; + } + memcpy(cp, &prefix, sz_xReq); + cp += sz_xReq; + if (ccname) + { + memcpy(cp, &princ.length, 2); + if (client->swapped) + { + swaps((CARD16 *)cp, n); + } + cp += 2; + } + memcpy(cp, princ.data, princ.length); + cp += princ.length; + free(princ.data); /* we don't need that anymore */ + if (ccname) + memcpy(cp, creds->ticket.data, creds->ticket.length); + WriteToClient(client, tlen, outbuf); + free(outbuf); + client->requestVector = k5_Vector; /* hack in our dispatch vector */ + client->clientState = ClientStateAuthenticating; + if (ccname) + { + ((OsCommPtr)client->osPrivate)->authstate.srvcreds = (pointer)creds; /* save tgt creds */ + ((OsCommPtr)client->osPrivate)->authstate.ktname = NULL; + ((OsCommPtr)client->osPrivate)->authstate.srvname = NULL; + } + if (srvname) + { + ((OsCommPtr)client->osPrivate)->authstate.srvcreds = NULL; + ((OsCommPtr)client->osPrivate)->authstate.ktname = (pointer)ktname; + ((OsCommPtr)client->osPrivate)->authstate.srvname = (pointer)srvname; + } + ((OsCommPtr)client->osPrivate)->authstate.stageno = 1; /* next stage is 1 */ + return krb5_id; +} + +/* + * k5_stage1: + * + * This gets called out of the dispatcher after K5Check frobs with the + * client->requestVector. It accepts the ap_req from the client and verifies + * it. In addition, if the client has set AP_OPTS_MUTUAL_REQUIRED, it then + * sends an ap_rep to the client to achieve mutual authentication. + * + * client stage1 packet format is as follows: + * + * CARD8 reqType = 1 + * CARD8 data = ignored + * CARD16 length = total length + * STRING8 data = the actual ap_req + * + * stage2 packet sent back to client for mutual authentication: + * + * CARD8 reqType = 2 + * CARD8 data = 2 + * CARD16 length = total length + * STRING8 data = the ap_rep + */ +int k5_stage1(client) + register ClientPtr client; +{ + long addrlen; + krb5_error_code retval, retval2; + register char n; + struct sockaddr cli_net_addr; + xReq prefix; + krb5_principal cprinc; + krb5_data buf; + krb5_creds *creds = (krb5_creds *)((OsCommPtr)client->osPrivate)->authstate.srvcreds; + krb5_keyblock *skey; + krb5_address cli_addr, **localaddrs = NULL; + krb5_tkt_authent *authdat; + krb5_ap_rep_enc_part rep; + krb5_int32 ctime, cusec; + krb5_rcache rcache = NULL; + char *cachename = NULL, *rc_type = NULL, *rc_base = "rcX", *kt = NULL; + REQUEST(xReq); + + if (((OsCommPtr)client->osPrivate)->authstate.stageno != 1) + { + if (creds) + krb5_free_creds(creds); + return(SendConnSetup(client, "expected Krb5 stage1 packet")); + } + addrlen = sizeof (cli_net_addr); + if (getpeername(((OsCommPtr)client->osPrivate)->fd, + &cli_net_addr, &addrlen) == -1) + { + if (creds) + krb5_free_creds(creds); + return(SendConnSetup(client, "Krb5 stage1: getpeername failed")); + } + if (cli_net_addr.sa_family == AF_UNSPEC +#if defined(UNIXCONN) || defined(LOCALCONN) || defined(OS2PIPECONN) + || cli_net_addr.sa_family == AF_UNIX +#endif + ) /* assume local host */ + { + krb5_os_localaddr(&localaddrs); + if (!localaddrs || !localaddrs[0]) + { + if (creds) + krb5_free_creds(creds); + return(SendConnSetup(client, "Krb5 failed to get localaddrs")); + } + cli_addr.addrtype = localaddrs[0]->addrtype; + cli_addr.length = localaddrs[0]->length; + cli_addr.contents = localaddrs[0]->contents; + } + else + { + cli_addr.addrtype = cli_net_addr.sa_family; /* the values + are compatible */ + switch (cli_net_addr.sa_family) + { +#ifdef TCPCONN + case AF_INET: + cli_addr.length = sizeof (struct in_addr); + cli_addr.contents = + (krb5_octet *)&((struct sockaddr_in *)&cli_net_addr)->sin_addr; + break; +#endif +#ifdef DNETCONN + case AF_DECnet: + cli_addr.length = sizeof (struct dn_naddr); + cli_addr.contents = + (krb5_octet *)&((struct sockaddr_dn *)&cli_net_addr)->sdn_add; + break; +#endif + default: + if (localaddrs) + krb5_free_addresses(localaddrs); + if (creds) + krb5_free_creds(creds); + sprintf(kerror, "Krb5 stage1: unknown address family %d from getpeername", + cli_net_addr.sa_family); + return(SendConnSetup(client, kerror)); + } + } + if ((rcache = (krb5_rcache)malloc(sizeof(*rcache))) == NULL) + { + if (localaddrs) + krb5_free_addresses(localaddrs); + if (creds) + krb5_free_creds(creds); + return(SendConnSetup(client, "malloc bombed for krb5_rcache")); + } + if ((rc_type = krb5_rc_default_type()) == NULL) + rc_type = "dfl"; + if (retval = krb5_rc_resolve_type(&rcache, rc_type)) + { + if (localaddrs) + krb5_free_addresses(localaddrs); + if (creds) + krb5_free_creds(creds); + free(rcache); + strcpy(kerror, "krb5_rc_resolve_type failed: "); + strncat(kerror, error_message(retval), 231); + return(SendConnSetup(client, kerror)); + } + if ((cachename = (char *)malloc(strlen(rc_base) + strlen(display) + 1)) + == NULL) + { + if (localaddrs) + krb5_free_addresses(localaddrs); + if (creds) + krb5_free_creds(creds); + free(rcache); + return(SendConnSetup(client, "Krb5: malloc bombed for cachename")); + } + strcpy(cachename, rc_base); + strcat(cachename, display); + if (retval = krb5_rc_resolve(rcache, cachename)) + { + if (localaddrs) + krb5_free_addresses(localaddrs); + if (creds) + krb5_free_creds(creds); + free(rcache); + free(cachename); + strcpy(kerror, "krb5_rc_resolve failed: "); + strncat(kerror, error_message(retval), 236); + return(SendConnSetup(client, kerror)); + } + free(cachename); + if (krb5_rc_recover(rcache)) + { + extern krb5_deltat krb5_clockskew; + if (retval = krb5_rc_initialize(rcache, krb5_clockskew)) + { + if (localaddrs) + krb5_free_addresses(localaddrs); + if (creds) + krb5_free_creds(creds); + if (retval2 = krb5_rc_close(rcache)) + { + strcpy(kerror, "krb5_rc_close failed: "); + strncat(kerror, error_message(retval2), 238); + return(SendConnSetup(client, kerror)); + } + free(rcache); + strcpy(kerror, "krb5_rc_initialize failed: "); + strncat(kerror, error_message(retval), 233); + return(SendConnSetup(client, kerror)); + } + } + buf.length = (stuff->length << 2) - sz_xReq; + buf.data = (char *)stuff + sz_xReq; + if (creds) + { + retval = krb5_rd_req(&buf, + NULL, /* don't bother with server name */ + &cli_addr, + NULL, /* no fetchfrom */ + tgt_keyproc, + creds, /* credentials as arg to + keyproc */ + rcache, + &authdat); + krb5_free_creds(creds); + } + else if (kt = (char *)((OsCommPtr)client->osPrivate)->authstate.ktname) + { + retval = krb5_rd_req(&buf, srvname, &cli_addr, kt, NULL, NULL, + rcache, &authdat); + ((OsCommPtr)client->osPrivate)->authstate.ktname = NULL; + } + else + { + if (localaddrs) + krb5_free_addresses(localaddrs); + return(SendConnSetup(client, "Krb5: neither srvcreds nor ktname set")); + } + if (localaddrs) + krb5_free_addresses(localaddrs); + if (rcache) + { + if (retval2 = krb5_rc_close(rcache)) + { + strcpy(kerror, "krb5_rc_close failed (2): "); + strncat(kerror, error_message(retval2), 230); + return(SendConnSetup(client, kerror)); + } + free(rcache); + } + if (retval) + { + strcpy(kerror, "Krb5: Bad application request: "); + strncat(kerror, error_message(retval), 224); + return(SendConnSetup(client, kerror)); + } + cprinc = authdat->ticket->enc_part2->client; + skey = authdat->ticket->enc_part2->session; + if (XauKrb5Encode(cprinc, &buf)) + { + krb5_free_tkt_authent(authdat); + return(SendConnSetup(client, "XauKrb5Encode bombed")); + } + /* + * Now check to see if the principal we got is one that we want to let in + */ + if (ForEachHostInFamily(FamilyKrb5Principal, k5_cmpenc, (pointer)&buf)) + { + free(buf.data); + /* + * The following deals with sending an ap_rep to the client to + * achieve mutual authentication. The client sends back a stage 3 + * packet if all is ok. + */ + if (authdat->ap_options | AP_OPTS_MUTUAL_REQUIRED) + { + /* + * stage 2: send ap_rep to client + */ + if (retval = krb5_us_timeofday(&ctime, &cusec)) + { + krb5_free_tkt_authent(authdat); + strcpy(kerror, "error in krb5_us_timeofday: "); + strncat(kerror, error_message(retval), 234); + return(SendConnSetup(client, kerror)); + } + rep.ctime = ctime; + rep.cusec = cusec; + rep.subkey = NULL; + rep.seq_number = 0; + if (retval = krb5_mk_rep(&rep, skey, &buf)) + { + krb5_free_tkt_authent(authdat); + strcpy(kerror, "error in krb5_mk_rep: "); + strncat(kerror, error_message(retval), 238); + return(SendConnSetup(client, kerror)); + } + prefix.reqType = 2; /* opcode = authenticate */ + prefix.data = 2; /* stage = 2 */ + prefix.length = (buf.length + sz_xReq + 3) >> 2; + if (client->swapped) + { + swaps(&prefix.length, n); + } + WriteToClient(client, sz_xReq, (char *)&prefix); + WriteToClient(client, buf.length, buf.data); + free(buf.data); + krb5_free_tkt_authent(authdat); + ((OsCommPtr)client->osPrivate)->authstate.stageno = 3; /* expect stage3 packet */ + return(Success); + } + else + { + free(buf.data); + krb5_free_tkt_authent(authdat); + return(SendConnSetup(client, NULL)); /* success! */ + } + } + else + { + char *kname; + + krb5_free_tkt_authent(authdat); + free(buf.data); + retval = krb5_unparse_name(cprinc, &kname); + if (retval == 0) + { + sprintf(kerror, "Principal \"%s\" is not authorized to connect", + kname); + if (kname) + free(kname); + return(SendConnSetup(client, kerror)); + } + else + return(SendConnSetup(client,"Principal is not authorized to connect to Server")); + } +} + +/* + * k5_stage3: + * + * Get the short ack packet from the client. This packet can conceivably + * be expanded to allow for switching on end-to-end encryption. + * + * stage3 packet format: + * + * CARD8 reqType = 3 + * CARD8 data = ignored (for now) + * CARD16 length = should be zero + */ +int k5_stage3(client) + register ClientPtr client; +{ + REQUEST(xReq); + + if (((OsCommPtr)client->osPrivate)->authstate.stageno != 3) + { + return(SendConnSetup(client, "expected Krb5 stage3 packet")); + } + else + return(SendConnSetup(client, NULL)); /* success! */ +} + +k5_bad(client) + register ClientPtr client; +{ + if (((OsCommPtr)client->osPrivate)->authstate.srvcreds) + krb5_free_creds((krb5_creds *)((OsCommPtr)client->osPrivate)->authstate.srvcreds); + sprintf(kerror, "unrecognized Krb5 auth packet %d, expecting %d", + ((xReq *)client->requestBuffer)->reqType, + ((OsCommPtr)client->osPrivate)->authstate.stageno); + return(SendConnSetup(client, kerror)); +} + +/* + * K5Add: + * + * Takes the name of a credentials cache and resolves it. Also adds the + * primary principal of the ccache to the acl. + * + * Now will also take a service name. + */ +int K5Add(data_length, data, id) + unsigned short data_length; + char *data; + XID id; +{ + krb5_principal princ; + krb5_error_code retval; + krb5_keytab_entry tmp_entry; + krb5_keytab keytab; + krb5_kvno kvno = 0; + krb5_ccache cc; + char *nbuf, *cp; + krb5_data kbuf; + int i, ktlen; + + krb5_init_ets(); /* can't think of a better place to put it */ + krb5_id = ~0L; + if (data_length < 3) + return 0; + if ((nbuf = (char *)malloc(data_length - 2)) == NULL) + return 0; + memcpy(nbuf, data + 3, data_length - 3); + nbuf[data_length - 3] = '\0'; + if (ccname) + { + free(ccname); + ccname = NULL; + } + if (srvname) + { + krb5_free_principal(srvname); + srvname = NULL; + } + if (ktname) + { + free(ktname); + ktname = NULL; + } + if (!strncmp(data, "UU:", 3)) + { + if (retval = krb5_cc_resolve(nbuf, &cc)) + { + ErrorF("K5Add: krb5_cc_resolve of \"%s\" failed: %s\n", + nbuf, error_message(retval)); + free(nbuf); + return 0; + } + if (cc && !(retval = krb5_cc_get_principal(cc, &princ))) + { + if (XauKrb5Encode(princ, &kbuf)) + { + free(nbuf); + krb5_free_principal(princ); + krb5_cc_close(cc); + return 0; + } + if (krb5_cc_close(cc)) + return 0; + AddHost(NULL, FamilyKrb5Principal, kbuf.length, kbuf.data); + krb5_free_principal(princ); + free(kbuf.data); + ccname = nbuf; + krb5_id = id; + return 1; + } + else + { + ErrorF("K5Add: getting principal from cache \"%s\" failed: %s\n", + nbuf, error_message(retval)); + } + } + else if (!strncmp(data, "CS:", 3)) + { + if ((cp = strchr(nbuf, ',')) == NULL) + { + free(nbuf); + return 0; + } + *cp = '\0'; /* gross but it works :-) */ + ktlen = strlen(cp + 1); + if ((ktname = (char *)malloc(ktlen + 1)) == NULL) + { + free(nbuf); + return 0; + } + strcpy(ktname, cp + 1); + retval = krb5_sname_to_principal(NULL, /* NULL for hostname uses + local host name*/ + nbuf, KRB5_NT_SRV_HST, + &srvname); + free(nbuf); + if (retval) + { + free(ktname); + ktname = NULL; + return 0; + } + if (retval = krb5_kt_resolve(ktname, &keytab)) + { + free(ktname); + ktname = NULL; + krb5_free_principal(srvname); + srvname = NULL; + return 0; + } + retval = krb5_kt_get_entry(keytab, srvname, kvno, &tmp_entry); + krb5_kt_free_entry(&tmp_entry); + if (retval) + { + free(ktname); + ktname = NULL; + krb5_free_principal(srvname); + srvname = NULL; + return 0; + } + if (XauKrb5Encode(srvname, &kbuf)) + { + free(ktname); + ktname = NULL; + krb5_free_principal(srvname); + srvname = NULL; + return 0; + } + AddHost(NULL, FamilyKrb5Principal, kbuf.length, kbuf.data); + krb5_id = id; + return 1; + } + else + { + ErrorF("K5Add: credentials cache name \"%.*s\" in auth file: unknown type\n", + data_length, data); + } + return 0; +} + +/* + * K5Reset: + * + * Reset krb5_id, also nuke the current principal from the acl. + */ +int K5Reset() +{ + krb5_principal princ; + krb5_error_code retval; + krb5_ccache cc; + krb5_data kbuf; + int i; + + if (ccname) + { + if (retval = krb5_cc_resolve(ccname, &cc)) + { + free(ccname); + ccname = NULL; + } + if (cc && !(retval = krb5_cc_get_principal(cc, &princ))) + { + if (XauKrb5Encode(princ, &kbuf)) + return 1; + RemoveHost(NULL, FamilyKrb5Principal, kbuf.length, kbuf.data); + krb5_free_principal(princ); + free(kbuf.data); + if (krb5_cc_close(cc)) + return 1; + free(ccname); + ccname = NULL; + } + } + if (srvname) + { + if (XauKrb5Encode(srvname, &kbuf)) + return 1; + RemoveHost(NULL, FamilyKrb5Principal, kbuf.length, kbuf.data); + krb5_free_principal(srvname); + free(kbuf.data); + srvname = NULL; + } + if (ktname) + { + free(ktname); + ktname = NULL; + } + krb5_id = ~0L; + return 0; +} + +XID K5ToID(data_length, data) + unsigned short data_length; + char *data; +{ + return krb5_id; +} + +int K5FromID(id, data_lenp, datap) + XID id; + unsigned short *data_lenp; + char **datap; +{ + return 0; +} + +int K5Remove(data_length, data) + unsigned short data_length; + char *data; +{ + return 0; +} diff --git a/nx-X11/programs/Xserver/os/lbxio.c b/nx-X11/programs/Xserver/os/lbxio.c new file mode 100644 index 000000000..97ae958e3 --- /dev/null +++ b/nx-X11/programs/Xserver/os/lbxio.c @@ -0,0 +1,555 @@ +/* $XFree86: xc/programs/Xserver/os/lbxio.c,v 3.17 2002/05/31 18:46:06 dawes Exp $ */ +/* + +Copyright 1996, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/*********************************************************** +Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts, +and the Massachusetts Institute of Technology, Cambridge, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or MIT not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* $Xorg: lbxio.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stdio.h> +#include <X11/Xtrans/Xtrans.h> +#include <X11/Xmd.h> +#include <errno.h> +#ifndef Lynx +#include <sys/param.h> +#ifndef __UNIXOS2__ +#include <sys/uio.h> +#endif +#else +#include <uio.h> +#endif +#include <X11/X.h> +#include <X11/Xproto.h> +#include "os.h" +#include <X11/Xpoll.h> +#include "osdep.h" +#include "opaque.h" +#include "dixstruct.h" +#include "misc.h" +#include "colormapst.h" +#include "propertyst.h" +#include "lbxserve.h" + +/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX + * systems are broken and return EWOULDBLOCK when they should return EAGAIN + */ +#if defined(EAGAIN) && defined(EWOULDBLOCK) +#define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK) +#else +#ifdef EAGAIN +#define ETEST(err) (err == EAGAIN) +#else +#define ETEST(err) (err == EWOULDBLOCK) +#endif +#endif + +#define get_req_len(req,cli) ((cli)->swapped ? \ + lswaps((req)->length) : (req)->length) + +#define YieldControl() \ + { isItTimeToYield = TRUE; \ + timesThisConnection = 0; } +#define YieldControlNoInput() \ + { YieldControl(); \ + FD_CLR(fd, &ClientsWithInput); } + +void +SwitchClientInput (ClientPtr client, Bool pending) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + +#ifndef WIN32 + ConnectionTranslation[oc->fd] = client->index; +#else + SetConnectionTranslation(oc->fd, client->index); +#endif + if (pending) + FD_SET(oc->fd, &ClientsWithInput); + else + YieldControl(); +} + +void +LbxPrimeInput(ClientPtr client, LbxProxyPtr proxy) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + ConnectionInputPtr oci = oc->input; + + if (oci && proxy->compHandle) { + char *extra = oci->bufptr + oci->lenLastReq; + int left = oci->bufcnt + oci->buffer - extra; + + (*proxy->streamOpts.streamCompStuffInput)(oc->fd, + (unsigned char *)extra, + left); + oci->bufcnt -= left; + AvailableInput = oc; + } +} + +void +AvailableClientInput (ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + + if (FD_ISSET(oc->fd, &AllSockets)) + FD_SET(oc->fd, &ClientsWithInput); +} + +/***************************************************************** + * AppendFakeRequest + * Append a (possibly partial) request in as the last request. + * + **********************/ + +Bool +AppendFakeRequest (ClientPtr client, char *data, int count) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + ConnectionInputPtr oci = oc->input; + int fd = oc->fd; + int gotnow; + + if (!oci) + { + if ((oci = FreeInputs)) + FreeInputs = oci->next; + else if (!(oci = AllocateInputBuffer())) + return FALSE; + oc->input = oci; + } else if (AvailableInput == oc) + AvailableInput = (OsCommPtr)NULL; + /* do not free AvailableInput here, it could be proxy's */ + oci->bufptr += oci->lenLastReq; + oci->lenLastReq = 0; + gotnow = oci->bufcnt + oci->buffer - oci->bufptr; + if ((gotnow + count) > oci->size) + { + char *ibuf; + + ibuf = (char *)xrealloc(oci->buffer, gotnow + count); + if (!ibuf) + return(FALSE); + oci->size = gotnow + count; + oci->buffer = ibuf; + oci->bufptr = ibuf + oci->bufcnt - gotnow; + } + if (oci->bufcnt + count > oci->size) { + memmove(oci->buffer, oci->bufptr, gotnow); + oci->bufcnt = gotnow; + oci->bufptr = oci->buffer; + } + memmove(oci->bufptr + gotnow, data, count); + oci->bufcnt += count; + gotnow += count; + if ((gotnow >= sizeof(xReq)) && + (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2))) + FD_SET(fd, &ClientsWithInput); + else + YieldControlNoInput(); + return(TRUE); +} + +static int +LbxWrite(XtransConnInfo trans_conn, LbxProxyPtr proxy, + char *buf, int len) +{ + struct iovec iov; + int n; + int notWritten; + + notWritten = len; + iov.iov_base = buf; + iov.iov_len = len; + while (notWritten) { + errno = 0; + if (proxy->compHandle) + n = (*proxy->streamOpts.streamCompWriteV)(proxy->fd, &iov, 1); + else + n = _XSERVTransWritev(trans_conn, &iov, 1); + if (n >= 0) { + iov.iov_base = (char *)iov.iov_base + n; + notWritten -= n; + iov.iov_len = notWritten; + } + else if (ETEST(errno) +#ifdef SUNSYSV /* check for another brain-damaged OS bug */ + || (errno == 0) +#endif +#ifdef EMSGSIZE /* check for another brain-damaged OS bug */ + || ((errno == EMSGSIZE) && (iov.iov_len == 1)) +#endif + ) + break; +#ifdef EMSGSIZE /* check for another brain-damaged OS bug */ + else if (errno == EMSGSIZE) + iov.iov_len >>= 1; +#endif + else + return -1; + } + return len - notWritten; +} + +static Bool +LbxAppendOutput(LbxProxyPtr proxy, ClientPtr client, ConnectionOutputPtr oco) +{ + ConnectionOutputPtr noco = proxy->olast; + LbxClientPtr lbxClient = LbxClient(client); + + if (!lbxClient) { + xfree(oco->buf); + xfree(oco); + return TRUE; + } + if (noco) + LbxReencodeOutput(client, + (char *)noco->buf, &noco->count, + (char *)oco->buf, &oco->count); + else + LbxReencodeOutput(client, + (char *)NULL, (int *)NULL, + (char *)oco->buf, &oco->count); + if (!oco->count) { + if (oco->size > BUFWATERMARK) + { + xfree(oco->buf); + xfree(oco); + } + else + { + oco->next = FreeOutputs; + FreeOutputs = oco; + } + return TRUE; + } + if ((lbxClient->id != proxy->cur_send_id) && proxy->lbxClients[0]) { + xLbxSwitchEvent *ev; + int n; + + if (!noco || (noco->size - noco->count) < sz_xLbxSwitchEvent) { + if ((noco = FreeOutputs)) + FreeOutputs = noco->next; + else + noco = AllocateOutputBuffer(); + if (!noco) { + MarkClientException(client); + return FALSE; + } + noco->next = NULL; + if (proxy->olast) + proxy->olast->next = noco; + else + proxy->ofirst = noco; + proxy->olast = noco; + } + ev = (xLbxSwitchEvent *) (noco->buf + noco->count); + noco->count += sz_xLbxSwitchEvent; + proxy->cur_send_id = lbxClient->id; + ev->type = LbxEventCode; + ev->lbxType = LbxSwitchEvent; + ev->pad = 0; + ev->client = proxy->cur_send_id; + if (LbxProxyClient(proxy)->swapped) { + swapl(&ev->client, n); + } + } + oco->next = NULL; + if (proxy->olast) + proxy->olast->next = oco; + else + proxy->ofirst = oco; + proxy->olast = oco; + return TRUE; +} + +static int +LbxClientOutput(ClientPtr client, OsCommPtr oc, + char *extraBuf, int extraCount, Bool nocompress) +{ + ConnectionOutputPtr oco; + int len; + + if ((oco = oc->output)) { + oc->output = NULL; + if (!LbxAppendOutput(oc->proxy, client, oco)) + return -1; + } + + if (extraCount) { + NewOutputPending = TRUE; + FD_SET(oc->fd, &OutputPending); + len = (extraCount + 3) & ~3; + if ((oco = FreeOutputs) && (oco->size >= len)) + FreeOutputs = oco->next; + else { + oco = (ConnectionOutputPtr)xalloc(sizeof(ConnectionOutput)); + if (!oco) { + MarkClientException(client); + return -1; + } + oco->size = len; + if (oco->size < BUFSIZE) + oco->size = BUFSIZE; + oco->buf = (unsigned char *) xalloc(oco->size); + if (!oco->buf) { + xfree(oco); + MarkClientException(client); + return -1; + } + } + oco->count = len; + oco->nocompress = nocompress; + memmove((char *)oco->buf, extraBuf, extraCount); + if (!nocompress && oco->count < oco->size) + oc->output = oco; + else if (!LbxAppendOutput(oc->proxy, client, oco)) + return -1; + } + return extraCount; +} + +void +LbxForceOutput(LbxProxyPtr proxy) +{ + int i; + LbxClientPtr lbxClient; + OsCommPtr coc; + ConnectionOutputPtr oco; + + for (i = proxy->maxIndex; i >= 0; i--) { /* proxy must be last */ + lbxClient = proxy->lbxClients[i]; + if (!lbxClient) + continue; + coc = (OsCommPtr)lbxClient->client->osPrivate; + if ((oco = coc->output)) { + coc->output = NULL; + LbxAppendOutput(proxy, lbxClient->client, oco); + } + } +} + +int +LbxFlushClient(ClientPtr who, OsCommPtr oc, + char *extraBuf, int extraCount) +{ + LbxProxyPtr proxy; + ConnectionOutputPtr oco; + int n; + XtransConnInfo trans_conn = NULL; + + if (extraBuf) + return LbxClientOutput(who, oc, extraBuf, extraCount, FALSE); + proxy = oc->proxy; + if (!proxy->lbxClients[0]) + return 0; + LbxForceOutput(proxy); + if (!proxy->compHandle) + trans_conn = ((OsCommPtr)LbxProxyClient(proxy)->osPrivate)->trans_conn; + while ((oco = proxy->ofirst)) { + /* XXX bundle up into writev someday */ + if (proxy->compHandle) { + if (oco->nocompress) + (*proxy->streamOpts.streamCompOff)(proxy->fd); + n = LbxWrite(NULL, proxy, (char *)oco->buf, oco->count); + if (oco->nocompress) + (*proxy->streamOpts.streamCompOn)(proxy->fd); + } else + n = LbxWrite(trans_conn, proxy, (char *)oco->buf, oco->count); + if (n < 0) { + ClientPtr pclient = LbxProxyClient(proxy); + if (proxy->compHandle) + trans_conn = ((OsCommPtr)pclient->osPrivate)->trans_conn; + _XSERVTransDisconnect(trans_conn); + _XSERVTransClose(trans_conn); + ((OsCommPtr)pclient->osPrivate)->trans_conn = NULL; + MarkClientException(pclient); + return 0; + } else if (n == oco->count) { + proxy->ofirst = oco->next; + if (!proxy->ofirst) + proxy->olast = NULL; + if (oco->size > BUFWATERMARK) + { + xfree(oco->buf); + xfree(oco); + } + else + { + oco->next = FreeOutputs; + oco->count = 0; + FreeOutputs = oco; + } + } else { + if (n) { + oco->count -= n; + memmove((char *)oco->buf, (char *)oco->buf + n, oco->count); + } + break; + } + } + if ((proxy->compHandle && + (*proxy->streamOpts.streamCompFlush)(proxy->fd)) || + proxy->ofirst) { + FD_SET(proxy->fd, &ClientsWriteBlocked); + AnyClientsWriteBlocked = TRUE; + } + return 0; +} + +int +UncompressedWriteToClient (ClientPtr who, int count, char *buf) +{ + return LbxClientOutput(who, (OsCommPtr)who->osPrivate, buf, count, TRUE); +} + +void +LbxFreeOsBuffers(LbxProxyPtr proxy) +{ + ConnectionOutputPtr oco; + + while ((oco = proxy->ofirst)) { + proxy->ofirst = oco->next; + xfree(oco->buf); + xfree(oco); + } +} + +Bool +AllocateLargeReqBuffer(ClientPtr client, int size) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + ConnectionInputPtr oci; + + if (!(oci = oc->largereq)) { + if ((oci = FreeInputs)) + FreeInputs = oci->next; + else { + oci = (ConnectionInputPtr)xalloc(sizeof(ConnectionInput)); + if (!oci) + return FALSE; + oci->buffer = NULL; + oci->size = 0; + } + } + if (oci->size < size) { + char *ibuf; + + oci->size = size; + if (size < BUFSIZE) + oci->size = BUFSIZE; + if (!(ibuf = (char *)xrealloc(oci->buffer, oci->size))) + { + xfree(oci->buffer); + xfree(oci); + oc->largereq = NULL; + return FALSE; + } + oci->buffer = ibuf; + } + oci->bufptr = oci->buffer; + oci->bufcnt = 0; + oci->lenLastReq = size; + oc->largereq = oci; + return TRUE; +} + +Bool +AddToLargeReqBuffer(ClientPtr client, char *data, int size) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + ConnectionInputPtr oci = oc->largereq; + + if (!oci || (oci->bufcnt + size > oci->lenLastReq)) + return FALSE; + memcpy(oci->buffer + oci->bufcnt, data, size); + oci->bufcnt += size; + return TRUE; +} + +static OsCommRec lbxAvailableInput; + +int +PrepareLargeReqBuffer(ClientPtr client) +{ + OsCommPtr oc = (OsCommPtr)client->osPrivate; + ConnectionInputPtr oci = oc->largereq; + + if (!oci) + return client->req_len << 2; + oc->largereq = NULL; + if (oci->bufcnt != oci->lenLastReq) { + xfree(oci->buffer); + xfree(oci); + return client->req_len << 2; + } + client->requestBuffer = oci->buffer; + client->req_len = oci->lenLastReq >> 2; + oci->bufcnt = 0; + oci->lenLastReq = 0; + if (AvailableInput) + { + ConnectionInputPtr aci = AvailableInput->input; + if (aci->size > BUFWATERMARK) + { + xfree(aci->buffer); + xfree(aci); + } + else + { + aci->next = FreeInputs; + FreeInputs = aci; + } + AvailableInput->input = (ConnectionInputPtr)NULL; + } + lbxAvailableInput.input = oci; + AvailableInput = &lbxAvailableInput; + return client->req_len << 2; +} diff --git a/nx-X11/programs/Xserver/os/log.c b/nx-X11/programs/Xserver/os/log.c new file mode 100644 index 000000000..e09943723 --- /dev/null +++ b/nx-X11/programs/Xserver/os/log.c @@ -0,0 +1,716 @@ +/* + +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). + */ + +/* $XFree86: xc/programs/Xserver/os/log.c,v 1.6 2003/11/07 13:45:27 tsi Exp $ */ + +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NX-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of NoMachine S.r.l. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <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 "site.h" +#include "opaque.h" + +#ifdef WIN32 +#include <process.h> +#define getpid(x) _getpid(x) +#endif + +#ifdef NX_TRANS_SOCKET + +#include "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 + +/* + * 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. + */ + +const char * +LogInit(const char *fname, const char *backup) +{ + char *logFileName = NULL; + + if (fname && *fname) { + /* xalloc() can't be used yet. */ + logFileName = malloc(strlen(fname) + strlen(display) + 1); + if (!logFileName) + FatalError("Cannot allocate space for the log file name\n"); + sprintf(logFileName, fname, display); + + if (backup && *backup) { + struct stat buf; + + if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) { + char *suffix; + char *oldLog; + + oldLog = malloc(strlen(logFileName) + strlen(backup) + + strlen(display) + 1); + suffix = malloc(strlen(backup) + strlen(display) + 1); + if (!oldLog || !suffix) + FatalError("Cannot allocate space for the log file name\n"); + sprintf(suffix, backup, display); + sprintf(oldLog, "%s%s", logFileName, suffix); + free(suffix); +#ifdef __UNIXOS2__ + remove(oldLog); +#endif + if (rename(logFileName, oldLog) == -1) { + FatalError("Cannot move old log file (\"%s\" to \"%s\"\n", + logFileName, oldLog); + } + free(oldLog); + } + } + 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 xfree() */ + saveBuffer = NULL; + bufferSize = 0; + } + needBuffer = FALSE; + + return logFileName; +} + +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 + * xalloc() 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, pointer 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 1 + /* XXX Compressing duplicated messages is temporarily disabled to + * work around bugzilla 964: + * https://freedesktop.org/bugzilla/show_bug.cgi?id=964 + */ + ErrorF("%s%s", prefix != NULL ? prefix : "", buf); + oldlen = -1; + nrepeat = 0; +#else + 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); + } +#endif + 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, err); + } else + LogWrite(-1, 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/log.c.NX.original b/nx-X11/programs/Xserver/os/log.c.NX.original new file mode 100644 index 000000000..e09943723 --- /dev/null +++ b/nx-X11/programs/Xserver/os/log.c.NX.original @@ -0,0 +1,716 @@ +/* + +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). + */ + +/* $XFree86: xc/programs/Xserver/os/log.c,v 1.6 2003/11/07 13:45:27 tsi Exp $ */ + +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NX-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of NoMachine S.r.l. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <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 "site.h" +#include "opaque.h" + +#ifdef WIN32 +#include <process.h> +#define getpid(x) _getpid(x) +#endif + +#ifdef NX_TRANS_SOCKET + +#include "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 + +/* + * 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. + */ + +const char * +LogInit(const char *fname, const char *backup) +{ + char *logFileName = NULL; + + if (fname && *fname) { + /* xalloc() can't be used yet. */ + logFileName = malloc(strlen(fname) + strlen(display) + 1); + if (!logFileName) + FatalError("Cannot allocate space for the log file name\n"); + sprintf(logFileName, fname, display); + + if (backup && *backup) { + struct stat buf; + + if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) { + char *suffix; + char *oldLog; + + oldLog = malloc(strlen(logFileName) + strlen(backup) + + strlen(display) + 1); + suffix = malloc(strlen(backup) + strlen(display) + 1); + if (!oldLog || !suffix) + FatalError("Cannot allocate space for the log file name\n"); + sprintf(suffix, backup, display); + sprintf(oldLog, "%s%s", logFileName, suffix); + free(suffix); +#ifdef __UNIXOS2__ + remove(oldLog); +#endif + if (rename(logFileName, oldLog) == -1) { + FatalError("Cannot move old log file (\"%s\" to \"%s\"\n", + logFileName, oldLog); + } + free(oldLog); + } + } + 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 xfree() */ + saveBuffer = NULL; + bufferSize = 0; + } + needBuffer = FALSE; + + return logFileName; +} + +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 + * xalloc() 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, pointer 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 1 + /* XXX Compressing duplicated messages is temporarily disabled to + * work around bugzilla 964: + * https://freedesktop.org/bugzilla/show_bug.cgi?id=964 + */ + ErrorF("%s%s", prefix != NULL ? prefix : "", buf); + oldlen = -1; + nrepeat = 0; +#else + 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); + } +#endif + 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, err); + } else + LogWrite(-1, 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/log.c.X.original b/nx-X11/programs/Xserver/os/log.c.X.original new file mode 100644 index 000000000..4bebbe784 --- /dev/null +++ b/nx-X11/programs/Xserver/os/log.c.X.original @@ -0,0 +1,633 @@ +/* + +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). + */ + +/* $XFree86: xc/programs/Xserver/os/log.c,v 1.6 2003/11/07 13:45:27 tsi Exp $ */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <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 "site.h" +#include "opaque.h" + +#ifdef WIN32 +#include <process.h> +#define getpid(x) _getpid(x) +#endif + + +#ifdef DDXOSVERRORF +void (*OsVendorVErrorFProc)(const char *, va_list args) = NULL; +#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 + +/* + * 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. + */ + +const char * +LogInit(const char *fname, const char *backup) +{ + char *logFileName = NULL; + + if (fname && *fname) { + /* xalloc() can't be used yet. */ + logFileName = malloc(strlen(fname) + strlen(display) + 1); + if (!logFileName) + FatalError("Cannot allocate space for the log file name\n"); + sprintf(logFileName, fname, display); + + if (backup && *backup) { + struct stat buf; + + if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) { + char *suffix; + char *oldLog; + + oldLog = malloc(strlen(logFileName) + strlen(backup) + + strlen(display) + 1); + suffix = malloc(strlen(backup) + strlen(display) + 1); + if (!oldLog || !suffix) + FatalError("Cannot allocate space for the log file name\n"); + sprintf(suffix, backup, display); + sprintf(oldLog, "%s%s", logFileName, suffix); + free(suffix); +#ifdef __UNIXOS2__ + remove(oldLog); +#endif + if (rename(logFileName, oldLog) == -1) { + FatalError("Cannot move old log file (\"%s\" to \"%s\"\n", + logFileName, oldLog); + } + free(oldLog); + } + } + 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 xfree() */ + saveBuffer = NULL; + bufferSize = 0; + } + needBuffer = FALSE; + + return logFileName; +} + +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); + 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 + * xalloc() 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) +{ + OsCleanup(TRUE); + AbortDDX(); + fflush(stderr); + if (CoreDump) + abort(); + exit (1); +} + +#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, pointer 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 1 + /* XXX Compressing duplicated messages is temporarily disabled to + * work around bugzilla 964: + * https://freedesktop.org/bugzilla/show_bug.cgi?id=964 + */ + ErrorF("%s%s", prefix != NULL ? prefix : "", buf); + oldlen = -1; + nrepeat = 0; +#else + 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); + } +#endif + if (prefix != NULL) + free(prefix); +} + +void +FatalError(const char *f, ...) +{ + va_list args; + static Bool beenhere = FALSE; + + 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"); +#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, err); + } else + LogWrite(-1, 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..2f42fd41f --- /dev/null +++ b/nx-X11/programs/Xserver/os/mitauth.c @@ -0,0 +1,199 @@ +/* $Xorg: mitauth.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ +/* $XFree86: xc/programs/Xserver/os/mitauth.c,v 1.4 2001/01/17 22:37:11 dawes Exp $ */ + +/* + * MIT-MAGIC-COOKIE-1 authorization scheme + * Author: Keith Packard, MIT X Consortium + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <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 *) xalloc (sizeof (struct auth)); + if (!new) + return 0; + new->data = (char *) xalloc ((unsigned) data_length); + if (!new->data) { + xfree(new); + return 0; + } + new->next = mit_auth; + mit_auth = new; + memmove(new->data, data, (int) data_length); + new->len = data_length; + new->id = id; + return 1; +} + +XID +MitCheckCookie ( + unsigned short data_length, + char *data, + ClientPtr client, + char **reason) +{ + struct auth *auth; + + for (auth = mit_auth; auth; auth=auth->next) { + if (data_length == auth->len && + memcmp (data, auth->data, (int) data_length) == 0) + return auth->id; + } + *reason = "Invalid MIT-MAGIC-COOKIE-1 key"; + return (XID) -1; +} + +int +MitResetCookie (void) +{ + struct auth *auth, *next; + + for (auth = mit_auth; auth; auth=next) { + next = auth->next; + xfree (auth->data); + xfree (auth); + } + mit_auth = 0; + return 0; +} + +XID +MitToID ( + 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; + xfree (auth->data); + xfree (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..ecb76ccd6 --- /dev/null +++ b/nx-X11/programs/Xserver/os/oscolor.c @@ -0,0 +1,483 @@ +/* $XFree86: xc/programs/Xserver/os/oscolor.c,v 3.10 2003/07/16 01:39:03 dawes Exp $ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* $Xorg: oscolor.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */ + +#ifdef NX_TRANS_SOCKET + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +static char* nxAltRgbPaths[] = {"/usr/share/X11/rgb", "/etc/X11/rgb"}; +static char _NXRgbPath[1024]; + +#endif + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifndef USE_RGB_TXT + +#ifdef NDBM +#include <ndbm.h> +#else +#ifdef SVR4 +#include <rpcsvc/dbm.h> +#else +#include <dbm.h> +#endif +#endif +#include "rgb.h" +#include "os.h" +#include "opaque.h" + +/* Note that we are assuming there is only one database for all the screens. */ + +#ifdef NDBM +DBM *rgb_dbm = (DBM *)NULL; +#else +int rgb_dbm = 0; +#endif + +extern void CopyISOLatin1Lowered( + unsigned char * /*dest*/, + unsigned char * /*source*/, + int /*length*/); + +int +OsInitColors(void) +{ + if (!rgb_dbm) + { +#ifdef NDBM + rgb_dbm = dbm_open(rgbPath, 0, 0); +#else + if (dbminit(rgbPath) == 0) + rgb_dbm = 1; +#endif + if (!rgb_dbm) { + ErrorF( "Couldn't open RGB_DB '%s'\n", rgbPath ); + return FALSE; + } + } + return TRUE; +} + +/*ARGSUSED*/ +int +OsLookupColor(int screen, char *name, unsigned int len, + unsigned short *pred, unsigned short *pgreen, unsigned short *pblue) +{ + datum dbent; + RGB rgb; + char buf[64]; + char *lowername; + + if(!rgb_dbm) + return(0); + + /* we use xalloc here so that we can compile with cc without alloca + * when otherwise using gcc */ + if (len < sizeof(buf)) + lowername = buf; + else if (!(lowername = (char *)xalloc(len + 1))) + return(0); + CopyISOLatin1Lowered ((unsigned char *) lowername, (unsigned char *) name, + (int)len); + + dbent.dptr = lowername; + dbent.dsize = len; +#ifdef NDBM + dbent = dbm_fetch(rgb_dbm, dbent); +#else + dbent = fetch (dbent); +#endif + + if (len >= sizeof(buf)) + xfree(lowername); + + if(dbent.dptr) + { + memmove((char *) &rgb, dbent.dptr, sizeof (RGB)); + *pred = rgb.red; + *pgreen = rgb.green; + *pblue = rgb.blue; + return (1); + } + return(0); +} + +#else /* USE_RGB_TXT */ + + +/* + * The dbm routines are a porting hassle. This implementation will do + * the same thing by reading the rgb.txt file directly, which is much + * more portable. + */ + +#include <stdio.h> +#include "os.h" +#include "opaque.h" + +#define HASHSIZE 511 + +typedef struct _dbEntry * dbEntryPtr; +typedef struct _dbEntry { + dbEntryPtr link; + unsigned short red; + unsigned short green; + unsigned short blue; + char name[1]; /* some compilers complain if [0] */ +} dbEntry; + + +extern void CopyISOLatin1Lowered( + unsigned char * /*dest*/, + unsigned char * /*source*/, + int /*length*/); + +static dbEntryPtr hashTab[HASHSIZE]; + +#ifdef NX_TRANS_SOCKET + +static int NXVerifyRgbPath(char *path) +{ + int size; + char *rgbPath; + struct stat rgbFileStat; + + /* + * Check if rgb file is present. + */ + + size = strlen(path) + strlen(".txt") + 1; + + rgbPath = (char *) ALLOCATE_LOCAL(size + 1); + + strcpy(rgbPath, path); + + #ifdef NX_TRANS_TEST + fprintf(stderr, "NXVerifyRgbPath: Looking for [%s] file.\n", + rgbPath); + #endif + + if (stat(rgbPath, &rgbFileStat) != 0) + { + + #ifdef NX_TRANS_TEST + fprintf(stderr, "NXVerifyRgbPath: Can't find the rgb file [%s].\n", + rgbPath); + #endif + + strcat(rgbPath, ".txt"); + + #ifdef NX_TRANS_TEST + fprintf(stderr, "NXVerifyRgbPath: Looking for [%s] file.\n", + rgbPath); + #endif + + if (stat(rgbPath, &rgbFileStat) != 0) + { + + #ifdef NX_TRANS_TEST + fprintf(stderr, "NXVerifyRgbPath: Can't find the rgb file [%s].\n", + rgbPath); + #endif + + DEALLOCATE_LOCAL(rgbPath); + + return 0; + } + } + + #ifdef NX_TRANS_TEST + fprintf(stderr, "NXVerifyRgbPath: rgb path [%s] is valid.\n", + path); + #endif + + DEALLOCATE_LOCAL(rgbPath); + + return 1; +} + +static const char *_NXGetRgbPath(const char *path) +{ + const char *systemEnv; + char rgbPath[1024]; + int numAltRgbPaths; + int i; + + /* + * Check the environment only once. + */ + + if (*_NXRgbPath != '\0') + { + return _NXRgbPath; + } + + systemEnv = getenv("NX_SYSTEM"); + + if (systemEnv != NULL && *systemEnv != '\0') + { + if (strlen(systemEnv) + strlen("/share/rgb") + 1 > 1024) + { + + #ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetRgbPath: WARNING! Maximum length of rgb file path exceeded.\n"); + #endif + + goto _NXGetRgbPathError; + } + + strcpy(rgbPath, systemEnv); + strcat(rgbPath, "/share/rgb"); + + if (NXVerifyRgbPath(rgbPath) == 1) + { + strcpy(_NXRgbPath, systemEnv); + strcat(_NXRgbPath, "/share/rgb"); + + #ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetRgbPath: Using rgb file path [%s].\n", + _NXRgbPath); + #endif + + return _NXRgbPath; + } + } + + numAltRgbPaths = sizeof(nxAltRgbPaths) / sizeof(*nxAltRgbPaths); + + for (i = 0; i < numAltRgbPaths; i++) + { + if (NXVerifyRgbPath(nxAltRgbPaths[i]) == 1) + { + if (strlen(nxAltRgbPaths[i]) + 1 > 1024) + { + #ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetRgbPath: WARNING! Maximum length of rgb file path exceeded.\n"); + #endif + + goto _NXGetRgbPathError; + } + + strcpy(_NXRgbPath, nxAltRgbPaths[i]); + + #ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetRgbPath: Using rgb file path [%s].\n", + _NXRgbPath); + #endif + + return _NXRgbPath; + } + } + +_NXGetRgbPathError: + + strcpy(_NXRgbPath, path); + + #ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetRgbPath: Using default rgb file path [%s].\n", + _NXRgbPath); + #endif + + return _NXRgbPath; +} + +#endif + +static dbEntryPtr +lookup(char *name, int len, Bool create) +{ + unsigned int h = 0, g; + dbEntryPtr entry, *prev = NULL; + char *str = name; + + if (!(name = (char*)ALLOCATE_LOCAL(len +1))) return NULL; + CopyISOLatin1Lowered((unsigned char *)name, (unsigned char *)str, len); + name[len] = '\0'; + + for(str = name; *str; str++) { + h = (h << 4) + *str; + if ((g = h) & 0xf0000000) h ^= (g >> 24); + h &= g; + } + h %= HASHSIZE; + + if ( (entry = hashTab[h]) ) + { + for( ; entry; prev = (dbEntryPtr*)entry, entry = entry->link ) + if (! strcmp(name, entry->name) ) break; + } + else + prev = &(hashTab[h]); + + if (!entry && create && (entry = (dbEntryPtr)xalloc(sizeof(dbEntry) +len))) + { + *prev = entry; + entry->link = NULL; + strcpy( entry->name, name ); + } + + DEALLOCATE_LOCAL(name); + + return entry; +} + + +Bool +OsInitColors(void) +{ + FILE *rgb; + char *path; + char line[BUFSIZ]; + char name[BUFSIZ]; + int red, green, blue, lineno = 0; + dbEntryPtr entry; + + static Bool was_here = FALSE; + + if (!was_here) + { +#ifndef __UNIXOS2__ +#ifdef NX_TRANS_SOCKET + /* + * Add the trailing '.txt' if a + * 'rgb' file is not found. + */ + + struct stat statbuf; + + path = (char*)ALLOCATE_LOCAL(strlen(_NXGetRgbPath(rgbPath)) + 5); + strcpy(path, _NXGetRgbPath(rgbPath)); + + if (stat(path, &statbuf) != 0) + { + strcat(path, ".txt"); + } +#else + path = (char*)ALLOCATE_LOCAL(strlen(rgbPath) +5); + strcpy(path, rgbPath); + strcat(path, ".txt"); +#endif +#else + char *tmp = (char*)__XOS2RedirRoot(rgbPath); + path = (char*)ALLOCATE_LOCAL(strlen(tmp) +5); + strcpy(path, tmp); + strcat(path, ".txt"); +#endif + if (!(rgb = fopen(path, "r"))) + { +#ifdef NX_TRANS_SOCKET + ErrorF( "Couldn't open RGB_DB '%s'\n", _NXGetRgbPath(rgbPath)); +#else + ErrorF( "Couldn't open RGB_DB '%s'\n", rgbPath ); +#endif + DEALLOCATE_LOCAL(path); + return FALSE; + } + + while(fgets(line, sizeof(line), rgb)) + { + lineno++; +#ifndef __UNIXOS2__ + if (sscanf(line,"%d %d %d %[^\n]\n", &red, &green, &blue, name) == 4) +#else + if (sscanf(line,"%d %d %d %[^\n\r]\n", &red, &green, &blue, name) == 4) +#endif + { + if (red >= 0 && red <= 0xff && + green >= 0 && green <= 0xff && + blue >= 0 && blue <= 0xff) + { + if ((entry = lookup(name, strlen(name), TRUE))) + { + entry->red = (red * 65535) / 255; + entry->green = (green * 65535) / 255; + entry->blue = (blue * 65535) / 255; + } + } + else + ErrorF("Value out of range: %s:%d\n", path, lineno); + } + else if (*line && *line != '#' && *line != '!') + ErrorF("Syntax Error: %s:%d\n", path, lineno); + } + + fclose(rgb); + DEALLOCATE_LOCAL(path); + + was_here = TRUE; + } + + return TRUE; +} + + + +Bool +OsLookupColor(int screen, char *name, unsigned int len, + unsigned short *pred, unsigned short *pgreen, unsigned short *pblue) +{ + dbEntryPtr entry; + + if ((entry = lookup(name, len, FALSE))) + { + *pred = entry->red; + *pgreen = entry->green; + *pblue = entry->blue; + return TRUE; + } + + return FALSE; +} + +#endif /* USE_RGB_TXT */ diff --git a/nx-X11/programs/Xserver/os/oscolor.c.NX.original b/nx-X11/programs/Xserver/os/oscolor.c.NX.original new file mode 100644 index 000000000..ecb76ccd6 --- /dev/null +++ b/nx-X11/programs/Xserver/os/oscolor.c.NX.original @@ -0,0 +1,483 @@ +/* $XFree86: xc/programs/Xserver/os/oscolor.c,v 3.10 2003/07/16 01:39:03 dawes Exp $ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* $Xorg: oscolor.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */ + +#ifdef NX_TRANS_SOCKET + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +static char* nxAltRgbPaths[] = {"/usr/share/X11/rgb", "/etc/X11/rgb"}; +static char _NXRgbPath[1024]; + +#endif + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifndef USE_RGB_TXT + +#ifdef NDBM +#include <ndbm.h> +#else +#ifdef SVR4 +#include <rpcsvc/dbm.h> +#else +#include <dbm.h> +#endif +#endif +#include "rgb.h" +#include "os.h" +#include "opaque.h" + +/* Note that we are assuming there is only one database for all the screens. */ + +#ifdef NDBM +DBM *rgb_dbm = (DBM *)NULL; +#else +int rgb_dbm = 0; +#endif + +extern void CopyISOLatin1Lowered( + unsigned char * /*dest*/, + unsigned char * /*source*/, + int /*length*/); + +int +OsInitColors(void) +{ + if (!rgb_dbm) + { +#ifdef NDBM + rgb_dbm = dbm_open(rgbPath, 0, 0); +#else + if (dbminit(rgbPath) == 0) + rgb_dbm = 1; +#endif + if (!rgb_dbm) { + ErrorF( "Couldn't open RGB_DB '%s'\n", rgbPath ); + return FALSE; + } + } + return TRUE; +} + +/*ARGSUSED*/ +int +OsLookupColor(int screen, char *name, unsigned int len, + unsigned short *pred, unsigned short *pgreen, unsigned short *pblue) +{ + datum dbent; + RGB rgb; + char buf[64]; + char *lowername; + + if(!rgb_dbm) + return(0); + + /* we use xalloc here so that we can compile with cc without alloca + * when otherwise using gcc */ + if (len < sizeof(buf)) + lowername = buf; + else if (!(lowername = (char *)xalloc(len + 1))) + return(0); + CopyISOLatin1Lowered ((unsigned char *) lowername, (unsigned char *) name, + (int)len); + + dbent.dptr = lowername; + dbent.dsize = len; +#ifdef NDBM + dbent = dbm_fetch(rgb_dbm, dbent); +#else + dbent = fetch (dbent); +#endif + + if (len >= sizeof(buf)) + xfree(lowername); + + if(dbent.dptr) + { + memmove((char *) &rgb, dbent.dptr, sizeof (RGB)); + *pred = rgb.red; + *pgreen = rgb.green; + *pblue = rgb.blue; + return (1); + } + return(0); +} + +#else /* USE_RGB_TXT */ + + +/* + * The dbm routines are a porting hassle. This implementation will do + * the same thing by reading the rgb.txt file directly, which is much + * more portable. + */ + +#include <stdio.h> +#include "os.h" +#include "opaque.h" + +#define HASHSIZE 511 + +typedef struct _dbEntry * dbEntryPtr; +typedef struct _dbEntry { + dbEntryPtr link; + unsigned short red; + unsigned short green; + unsigned short blue; + char name[1]; /* some compilers complain if [0] */ +} dbEntry; + + +extern void CopyISOLatin1Lowered( + unsigned char * /*dest*/, + unsigned char * /*source*/, + int /*length*/); + +static dbEntryPtr hashTab[HASHSIZE]; + +#ifdef NX_TRANS_SOCKET + +static int NXVerifyRgbPath(char *path) +{ + int size; + char *rgbPath; + struct stat rgbFileStat; + + /* + * Check if rgb file is present. + */ + + size = strlen(path) + strlen(".txt") + 1; + + rgbPath = (char *) ALLOCATE_LOCAL(size + 1); + + strcpy(rgbPath, path); + + #ifdef NX_TRANS_TEST + fprintf(stderr, "NXVerifyRgbPath: Looking for [%s] file.\n", + rgbPath); + #endif + + if (stat(rgbPath, &rgbFileStat) != 0) + { + + #ifdef NX_TRANS_TEST + fprintf(stderr, "NXVerifyRgbPath: Can't find the rgb file [%s].\n", + rgbPath); + #endif + + strcat(rgbPath, ".txt"); + + #ifdef NX_TRANS_TEST + fprintf(stderr, "NXVerifyRgbPath: Looking for [%s] file.\n", + rgbPath); + #endif + + if (stat(rgbPath, &rgbFileStat) != 0) + { + + #ifdef NX_TRANS_TEST + fprintf(stderr, "NXVerifyRgbPath: Can't find the rgb file [%s].\n", + rgbPath); + #endif + + DEALLOCATE_LOCAL(rgbPath); + + return 0; + } + } + + #ifdef NX_TRANS_TEST + fprintf(stderr, "NXVerifyRgbPath: rgb path [%s] is valid.\n", + path); + #endif + + DEALLOCATE_LOCAL(rgbPath); + + return 1; +} + +static const char *_NXGetRgbPath(const char *path) +{ + const char *systemEnv; + char rgbPath[1024]; + int numAltRgbPaths; + int i; + + /* + * Check the environment only once. + */ + + if (*_NXRgbPath != '\0') + { + return _NXRgbPath; + } + + systemEnv = getenv("NX_SYSTEM"); + + if (systemEnv != NULL && *systemEnv != '\0') + { + if (strlen(systemEnv) + strlen("/share/rgb") + 1 > 1024) + { + + #ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetRgbPath: WARNING! Maximum length of rgb file path exceeded.\n"); + #endif + + goto _NXGetRgbPathError; + } + + strcpy(rgbPath, systemEnv); + strcat(rgbPath, "/share/rgb"); + + if (NXVerifyRgbPath(rgbPath) == 1) + { + strcpy(_NXRgbPath, systemEnv); + strcat(_NXRgbPath, "/share/rgb"); + + #ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetRgbPath: Using rgb file path [%s].\n", + _NXRgbPath); + #endif + + return _NXRgbPath; + } + } + + numAltRgbPaths = sizeof(nxAltRgbPaths) / sizeof(*nxAltRgbPaths); + + for (i = 0; i < numAltRgbPaths; i++) + { + if (NXVerifyRgbPath(nxAltRgbPaths[i]) == 1) + { + if (strlen(nxAltRgbPaths[i]) + 1 > 1024) + { + #ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetRgbPath: WARNING! Maximum length of rgb file path exceeded.\n"); + #endif + + goto _NXGetRgbPathError; + } + + strcpy(_NXRgbPath, nxAltRgbPaths[i]); + + #ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetRgbPath: Using rgb file path [%s].\n", + _NXRgbPath); + #endif + + return _NXRgbPath; + } + } + +_NXGetRgbPathError: + + strcpy(_NXRgbPath, path); + + #ifdef NX_TRANS_TEST + fprintf(stderr, "_NXGetRgbPath: Using default rgb file path [%s].\n", + _NXRgbPath); + #endif + + return _NXRgbPath; +} + +#endif + +static dbEntryPtr +lookup(char *name, int len, Bool create) +{ + unsigned int h = 0, g; + dbEntryPtr entry, *prev = NULL; + char *str = name; + + if (!(name = (char*)ALLOCATE_LOCAL(len +1))) return NULL; + CopyISOLatin1Lowered((unsigned char *)name, (unsigned char *)str, len); + name[len] = '\0'; + + for(str = name; *str; str++) { + h = (h << 4) + *str; + if ((g = h) & 0xf0000000) h ^= (g >> 24); + h &= g; + } + h %= HASHSIZE; + + if ( (entry = hashTab[h]) ) + { + for( ; entry; prev = (dbEntryPtr*)entry, entry = entry->link ) + if (! strcmp(name, entry->name) ) break; + } + else + prev = &(hashTab[h]); + + if (!entry && create && (entry = (dbEntryPtr)xalloc(sizeof(dbEntry) +len))) + { + *prev = entry; + entry->link = NULL; + strcpy( entry->name, name ); + } + + DEALLOCATE_LOCAL(name); + + return entry; +} + + +Bool +OsInitColors(void) +{ + FILE *rgb; + char *path; + char line[BUFSIZ]; + char name[BUFSIZ]; + int red, green, blue, lineno = 0; + dbEntryPtr entry; + + static Bool was_here = FALSE; + + if (!was_here) + { +#ifndef __UNIXOS2__ +#ifdef NX_TRANS_SOCKET + /* + * Add the trailing '.txt' if a + * 'rgb' file is not found. + */ + + struct stat statbuf; + + path = (char*)ALLOCATE_LOCAL(strlen(_NXGetRgbPath(rgbPath)) + 5); + strcpy(path, _NXGetRgbPath(rgbPath)); + + if (stat(path, &statbuf) != 0) + { + strcat(path, ".txt"); + } +#else + path = (char*)ALLOCATE_LOCAL(strlen(rgbPath) +5); + strcpy(path, rgbPath); + strcat(path, ".txt"); +#endif +#else + char *tmp = (char*)__XOS2RedirRoot(rgbPath); + path = (char*)ALLOCATE_LOCAL(strlen(tmp) +5); + strcpy(path, tmp); + strcat(path, ".txt"); +#endif + if (!(rgb = fopen(path, "r"))) + { +#ifdef NX_TRANS_SOCKET + ErrorF( "Couldn't open RGB_DB '%s'\n", _NXGetRgbPath(rgbPath)); +#else + ErrorF( "Couldn't open RGB_DB '%s'\n", rgbPath ); +#endif + DEALLOCATE_LOCAL(path); + return FALSE; + } + + while(fgets(line, sizeof(line), rgb)) + { + lineno++; +#ifndef __UNIXOS2__ + if (sscanf(line,"%d %d %d %[^\n]\n", &red, &green, &blue, name) == 4) +#else + if (sscanf(line,"%d %d %d %[^\n\r]\n", &red, &green, &blue, name) == 4) +#endif + { + if (red >= 0 && red <= 0xff && + green >= 0 && green <= 0xff && + blue >= 0 && blue <= 0xff) + { + if ((entry = lookup(name, strlen(name), TRUE))) + { + entry->red = (red * 65535) / 255; + entry->green = (green * 65535) / 255; + entry->blue = (blue * 65535) / 255; + } + } + else + ErrorF("Value out of range: %s:%d\n", path, lineno); + } + else if (*line && *line != '#' && *line != '!') + ErrorF("Syntax Error: %s:%d\n", path, lineno); + } + + fclose(rgb); + DEALLOCATE_LOCAL(path); + + was_here = TRUE; + } + + return TRUE; +} + + + +Bool +OsLookupColor(int screen, char *name, unsigned int len, + unsigned short *pred, unsigned short *pgreen, unsigned short *pblue) +{ + dbEntryPtr entry; + + if ((entry = lookup(name, len, FALSE))) + { + *pred = entry->red; + *pgreen = entry->green; + *pblue = entry->blue; + return TRUE; + } + + return FALSE; +} + +#endif /* USE_RGB_TXT */ diff --git a/nx-X11/programs/Xserver/os/oscolor.c.X.original b/nx-X11/programs/Xserver/os/oscolor.c.X.original new file mode 100644 index 000000000..fdbde7906 --- /dev/null +++ b/nx-X11/programs/Xserver/os/oscolor.c.X.original @@ -0,0 +1,303 @@ +/* $XFree86: xc/programs/Xserver/os/oscolor.c,v 3.10 2003/07/16 01:39:03 dawes Exp $ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* $Xorg: oscolor.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifndef USE_RGB_TXT + +#ifdef NDBM +#include <ndbm.h> +#else +#ifdef SVR4 +#include <rpcsvc/dbm.h> +#else +#include <dbm.h> +#endif +#endif +#include "rgb.h" +#include "os.h" +#include "opaque.h" + +/* Note that we are assuming there is only one database for all the screens. */ + +#ifdef NDBM +DBM *rgb_dbm = (DBM *)NULL; +#else +int rgb_dbm = 0; +#endif + +extern void CopyISOLatin1Lowered( + unsigned char * /*dest*/, + unsigned char * /*source*/, + int /*length*/); + +int +OsInitColors(void) +{ + if (!rgb_dbm) + { +#ifdef NDBM + rgb_dbm = dbm_open(rgbPath, 0, 0); +#else + if (dbminit(rgbPath) == 0) + rgb_dbm = 1; +#endif + if (!rgb_dbm) { + ErrorF( "Couldn't open RGB_DB '%s'\n", rgbPath ); + return FALSE; + } + } + return TRUE; +} + +/*ARGSUSED*/ +int +OsLookupColor(int screen, char *name, unsigned int len, + unsigned short *pred, unsigned short *pgreen, unsigned short *pblue) +{ + datum dbent; + RGB rgb; + char buf[64]; + char *lowername; + + if(!rgb_dbm) + return(0); + + /* we use xalloc here so that we can compile with cc without alloca + * when otherwise using gcc */ + if (len < sizeof(buf)) + lowername = buf; + else if (!(lowername = (char *)xalloc(len + 1))) + return(0); + CopyISOLatin1Lowered ((unsigned char *) lowername, (unsigned char *) name, + (int)len); + + dbent.dptr = lowername; + dbent.dsize = len; +#ifdef NDBM + dbent = dbm_fetch(rgb_dbm, dbent); +#else + dbent = fetch (dbent); +#endif + + if (len >= sizeof(buf)) + xfree(lowername); + + if(dbent.dptr) + { + memmove((char *) &rgb, dbent.dptr, sizeof (RGB)); + *pred = rgb.red; + *pgreen = rgb.green; + *pblue = rgb.blue; + return (1); + } + return(0); +} + +#else /* USE_RGB_TXT */ + + +/* + * The dbm routines are a porting hassle. This implementation will do + * the same thing by reading the rgb.txt file directly, which is much + * more portable. + */ + +#include <stdio.h> +#include "os.h" +#include "opaque.h" + +#define HASHSIZE 511 + +typedef struct _dbEntry * dbEntryPtr; +typedef struct _dbEntry { + dbEntryPtr link; + unsigned short red; + unsigned short green; + unsigned short blue; + char name[1]; /* some compilers complain if [0] */ +} dbEntry; + + +extern void CopyISOLatin1Lowered( + unsigned char * /*dest*/, + unsigned char * /*source*/, + int /*length*/); + +static dbEntryPtr hashTab[HASHSIZE]; + + +static dbEntryPtr +lookup(char *name, int len, Bool create) +{ + unsigned int h = 0, g; + dbEntryPtr entry, *prev = NULL; + char *str = name; + + if (!(name = (char*)ALLOCATE_LOCAL(len +1))) return NULL; + CopyISOLatin1Lowered((unsigned char *)name, (unsigned char *)str, len); + name[len] = '\0'; + + for(str = name; *str; str++) { + h = (h << 4) + *str; + if ((g = h) & 0xf0000000) h ^= (g >> 24); + h &= g; + } + h %= HASHSIZE; + + if ( (entry = hashTab[h]) ) + { + for( ; entry; prev = (dbEntryPtr*)entry, entry = entry->link ) + if (! strcmp(name, entry->name) ) break; + } + else + prev = &(hashTab[h]); + + if (!entry && create && (entry = (dbEntryPtr)xalloc(sizeof(dbEntry) +len))) + { + *prev = entry; + entry->link = NULL; + strcpy( entry->name, name ); + } + + DEALLOCATE_LOCAL(name); + + return entry; +} + + +Bool +OsInitColors(void) +{ + FILE *rgb; + char *path; + char line[BUFSIZ]; + char name[BUFSIZ]; + int red, green, blue, lineno = 0; + dbEntryPtr entry; + + static Bool was_here = FALSE; + + if (!was_here) + { +#ifndef __UNIXOS2__ + path = (char*)ALLOCATE_LOCAL(strlen(rgbPath) +5); + strcpy(path, rgbPath); + strcat(path, ".txt"); +#else + char *tmp = (char*)__XOS2RedirRoot(rgbPath); + path = (char*)ALLOCATE_LOCAL(strlen(tmp) +5); + strcpy(path, tmp); + strcat(path, ".txt"); +#endif + if (!(rgb = fopen(path, "r"))) + { + ErrorF( "Couldn't open RGB_DB '%s'\n", rgbPath ); + DEALLOCATE_LOCAL(path); + return FALSE; + } + + while(fgets(line, sizeof(line), rgb)) + { + lineno++; +#ifndef __UNIXOS2__ + if (sscanf(line,"%d %d %d %[^\n]\n", &red, &green, &blue, name) == 4) +#else + if (sscanf(line,"%d %d %d %[^\n\r]\n", &red, &green, &blue, name) == 4) +#endif + { + if (red >= 0 && red <= 0xff && + green >= 0 && green <= 0xff && + blue >= 0 && blue <= 0xff) + { + if ((entry = lookup(name, strlen(name), TRUE))) + { + entry->red = (red * 65535) / 255; + entry->green = (green * 65535) / 255; + entry->blue = (blue * 65535) / 255; + } + } + else + ErrorF("Value out of range: %s:%d\n", path, lineno); + } + else if (*line && *line != '#' && *line != '!') + ErrorF("Syntax Error: %s:%d\n", path, lineno); + } + + fclose(rgb); + DEALLOCATE_LOCAL(path); + + was_here = TRUE; + } + + return TRUE; +} + + + +Bool +OsLookupColor(int screen, char *name, unsigned int len, + unsigned short *pred, unsigned short *pgreen, unsigned short *pblue) +{ + dbEntryPtr entry; + + if ((entry = lookup(name, len, FALSE))) + { + *pred = entry->red; + *pgreen = entry->green; + *pblue = entry->blue; + return TRUE; + } + + return FALSE; +} + +#endif /* USE_RGB_TXT */ diff --git a/nx-X11/programs/Xserver/os/osdep.h b/nx-X11/programs/Xserver/os/osdep.h new file mode 100644 index 000000000..b837d7605 --- /dev/null +++ b/nx-X11/programs/Xserver/os/osdep.h @@ -0,0 +1,358 @@ +/* $XFree86: xc/programs/Xserver/os/osdep.h,v 3.17 2002/05/31 18:46:06 dawes Exp $ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* $Xorg: osdep.h,v 1.5 2001/02/09 02:05:23 xorgcvs Exp $ */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifndef _OSDEP_H_ +#define _OSDEP_H_ 1 + +#define BOTIMEOUT 200 /* in milliseconds */ +#define BUFSIZE 4096 +#define BUFWATERMARK 8192 +#ifndef MAXBUFSIZE +#define MAXBUFSIZE (1 << 22) +#endif + +#include <X11/Xdmcp.h> + +#ifndef sgi /* SGI defines OPEN_MAX in a useless way */ +#ifndef X_NOT_POSIX +#ifdef _POSIX_SOURCE +#include <limits.h> +#else +#define _POSIX_SOURCE +#include <limits.h> +#undef _POSIX_SOURCE +#endif +#else /* X_NOT_POSIX */ +#ifdef WIN32 +#define _POSIX_ +#include <limits.h> +#undef _POSIX_ +#endif +#endif /* X_NOT_POSIX */ +#endif + +#ifdef __QNX__ +#define NOFILES_MAX 256 +#endif +#ifndef OPEN_MAX +#ifdef SVR4 +#define OPEN_MAX 256 +#else +#include <sys/param.h> +#ifndef OPEN_MAX +#if defined(NOFILE) && !defined(NOFILES_MAX) +#define OPEN_MAX NOFILE +#else +#if !defined(__UNIXOS2__) && !defined(WIN32) +#define OPEN_MAX NOFILES_MAX +#else +#define OPEN_MAX 256 +#endif +#endif +#endif +#endif +#endif + +#include <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(hpux) && !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; +} ConnectionInput, *ConnectionInputPtr; + +typedef struct _connectionOutput { + struct _connectionOutput *next; + int size; + unsigned char *buf; + int count; +#ifdef LBX + Bool nocompress; +#endif +} ConnectionOutput, *ConnectionOutputPtr; + +#ifdef K5AUTH +typedef struct _k5_state { + int stageno; /* current stage of auth protocol */ + pointer srvcreds; /* server credentials */ + pointer srvname; /* server principal name */ + pointer ktname; /* key table: principal-key pairs */ + pointer skey; /* session key */ +} k5_state; +#endif + +#ifdef LBX +typedef struct _LbxProxy *OsProxyPtr; +#endif + +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 */ +#ifdef K5AUTH + k5_state authstate; /* state of setup auth conversation */ +#endif + CARD32 conn_time; /* timestamp if not established, else 0 */ + struct _XtransConnInfo *trans_conn; /* transport connection object */ +#ifdef LBX + OsProxyPtr proxy; + ConnectionInputPtr largereq; + OsCloseFunc Close; + OsFlushFunc Flush; +#endif +} OsCommRec, *OsCommPtr; + +#ifdef LBX +#define FlushClient(who, oc, extraBuf, extraCount) \ + (*(oc)->Flush)(who, oc, extraBuf, extraCount) +extern int StandardFlushClient( + ClientPtr /*who*/, + OsCommPtr /*oc*/, + char* /*extraBuf*/, + int /*extraCount*/ +); +extern int LbxFlushClient(ClientPtr /*who*/, OsCommPtr /*oc*/, + char * /*extraBuf*/, int /*extraCount*/); +#else +extern int FlushClient( + ClientPtr /*who*/, + OsCommPtr /*oc*/, + char* /*extraBuf*/, + int /*extraCount*/ +); +#endif + +extern void FreeOsBuffers( + OsCommPtr /*oc*/ +); + +#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 WellKnownConnections; +extern fd_set EnabledDevices; +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 AnyClientsWriteBlocked; +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 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 k5auth.c */ +#ifdef K5AUTH +extern XID K5Check (AuthCheckArgs); +extern XID K5ToID (AuthToIDArgs); +extern int K5Add (AuthAddCArgs); +extern int K5FromID (AuthFromIDArgs); +extern int K5Remove (AuthRemCArgs); +extern int K5Reset (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..ea99ace21 --- /dev/null +++ b/nx-X11/programs/Xserver/os/osinit.c @@ -0,0 +1,246 @@ +/* $XFree86: xc/programs/Xserver/os/osinit.c,v 3.29 2003/09/09 03:20:41 dawes Exp $ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +/* $Xorg: osinit.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <stdio.h> +#include <X11/X.h> +#include "os.h" +#include "osdep.h" +#include <X11/Xos.h> + +#ifdef SMART_SCHEDULE +#include "dixstruct.h" +#endif + +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif + +#if defined(Lynx) || defined(__SCO__) +#include <sys/wait.h> +#endif + +#if !defined(SYSV) && !defined(WIN32) && !defined(Lynx) && !defined(QNX4) +#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 + +Bool OsDelayInitColors = FALSE; + +#ifdef XFree86LOADER +extern void xf86WrapperInit(void); +#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) { +#ifdef XFree86LOADER + xf86WrapperInit(); +#endif +#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(__UNIXOS2__) || 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); +#ifdef SMART_SCHEDULE + if (!SmartScheduleDisable) + if (!SmartScheduleInit ()) + SmartScheduleDisable = TRUE; +#endif + OsInitAllocator(); + if (!OsDelayInitColors) OsInitColors(); +} + +void +OsCleanup(Bool terminating) +{ +#ifdef SERVER_LOCK + if (terminating) + { + UnlockServer(); + } +#endif +} diff --git a/nx-X11/programs/Xserver/os/rpcauth.c b/nx-X11/programs/Xserver/os/rpcauth.c new file mode 100644 index 000000000..3c5cb5946 --- /dev/null +++ b/nx-X11/programs/Xserver/os/rpcauth.c @@ -0,0 +1,204 @@ +/* $Xorg: rpcauth.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */ +/* + +Copyright 1991, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ +/* $XFree86: xc/programs/Xserver/os/rpcauth.c,v 3.7 2001/12/14 20:00:35 dawes Exp $ */ + +/* + * SUN-DES-1 authentication mechanism + * Author: Mayank Choudhary, Sun Microsystems + */ + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef SECURE_RPC + +#include <X11/X.h> +#include "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 + +#if defined(DGUX) +#include <time.h> +#include <rpc/auth_des.h> +#endif /* DGUX */ + +#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 *) xalloc(len); + memmove(temp_inmsg, inmsg, len); + + memset((char *)&msg, 0, sizeof(msg)); + memset((char *)&r, 0, sizeof(r)); + memset(cred_area, 0, sizeof(cred_area)); + memset(verf_area, 0, sizeof(verf_area)); + + msg.rm_call.cb_cred.oa_base = cred_area; + msg.rm_call.cb_verf.oa_base = verf_area; + why = AUTH_FAILED; + xdrmem_create(&xdr, temp_inmsg, len, XDR_DECODE); + + if ((r.rq_clntcred = (caddr_t) xalloc(MAX_AUTH_BYTES)) == NULL) + goto bad1; + r.rq_xprt = &xprt; + + /* decode into msg */ + res0 = xdr_opaque_auth(&xdr, &(msg.rm_call.cb_cred)); + res1 = xdr_opaque_auth(&xdr, &(msg.rm_call.cb_verf)); + if ( ! (res0 && res1) ) + goto bad2; + + /* do the authentication */ + + r.rq_cred = msg.rm_call.cb_cred; /* read by opaque stuff */ + if (r.rq_cred.oa_flavor != AUTH_DES) { + why = AUTH_TOOWEAK; + goto bad2; + } +#ifdef SVR4 + if ((why = __authenticate(&r, &msg)) != AUTH_OK) { +#else + if ((why = _authenticate(&r, &msg)) != AUTH_OK) { +#endif + goto bad2; + } + return (((struct authdes_cred *) r.rq_clntcred)->adc_fullname.name); + +bad2: + xfree(r.rq_clntcred); +bad1: + return ((char *)0); /* ((struct authdes_cred *) NULL); */ +} + +static XID rpc_id = (XID) ~0L; + +static Bool +CheckNetName ( + unsigned char *addr, + short len, + pointer 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 ((pointer) 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..1000b4e79 --- /dev/null +++ b/nx-X11/programs/Xserver/os/secauth.c @@ -0,0 +1,205 @@ +/* $Xorg: secauth.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */ +/* +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. +*/ +/* $XFree86: xc/programs/Xserver/os/secauth.c,v 1.10 2001/08/01 00:44:59 tsi Exp $ */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "os.h" +#include "osdep.h" +#include "dixstruct.h" +#include "swaprep.h" + +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <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 + (void)WriteToClient(client, sz_xConnSetupPrefix, (char *) &csp); + + /* + * Next time the client sends the real auth data, we want + * ProcEstablishConnection to be called. + */ + + freq.reqType = 1; + freq.length = (sz_xReq + sz_xConnClientPrefix) >> 2; + client->swapped = FALSE; + if (!InsertFakeRequest(client, (char *)&freq, sz_xReq)) + { + *reason = "internal error"; + return (XID) -1; + } + + return (XID) 0; +#else + *reason = "method not supported"; + return (XID) -1; +#endif +} diff --git a/nx-X11/programs/Xserver/os/utils.c b/nx-X11/programs/Xserver/os/utils.c new file mode 100644 index 000000000..c806621ff --- /dev/null +++ b/nx-X11/programs/Xserver/os/utils.c @@ -0,0 +1,2427 @@ +/* $XdotOrg: xc/programs/Xserver/os/utils.c,v 1.21 2005/11/08 06:33:30 jkj Exp $ */ +/* $Xorg: utils.c,v 1.5 2001/02/09 02:05:24 xorgcvs Exp $ */ +/* + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1994 Quarterdeck Office Systems. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital and +Quarterdeck not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT +OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE +OR PERFORMANCE OF THIS SOFTWARE. + +*/ +/* $XFree86: xc/programs/Xserver/os/utils.c,v 3.96 2004/01/07 04:16:37 dawes Exp $ */ + +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NX-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of NoMachine S.r.l. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +#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 <X11/Xwinsock.h> +#endif +#include <X11/Xos.h> +#include <stdio.h> +#include "misc.h" +#include <X11/X.h> +#include <X11/Xtrans/Xtrans.h> +#include "input.h" +#include "dixfont.h" +#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) && !defined(Lynx) && !defined(QNX4) +#include <sys/resource.h> +#endif +#include <time.h> +#include <sys/stat.h> +#include <ctype.h> /* for isspace */ +#include <stdarg.h> + +#if defined(DGUX) +#include <sys/resource.h> +#include <netdb.h> +#endif + +#include <stdlib.h> /* for malloc() */ + +#if defined(TCPCONN) || defined(STREAMSCONN) +# ifndef WIN32 +# include <netdb.h> +# endif +#endif + +#include "opaque.h" + +#ifdef SMART_SCHEDULE +#include "dixstruct.h" +#endif + +#ifdef XKB +#include <X11/extensions/XKBsrv.h> +#endif +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <X11/extensions/security.h> +#endif + +#ifdef RENDER +#include "picture.h" +#endif + +#ifdef XPRINT +#include "DiPrint.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 EVI +Bool noEVIExtension = FALSE; +#endif +#ifdef FONTCACHE +Bool noFontCacheExtension = FALSE; +#endif +#ifdef GLXEXT +Bool noGlxExtension = FALSE; +#endif +#ifdef LBX +Bool noLbxExtension = FALSE; +#endif +#ifdef SCREENSAVER +Bool noScreenSaverExtension = FALSE; +#endif +#ifdef MITSHM +Bool noMITShmExtension = FALSE; +#endif +#ifdef MITMISC +Bool noMITMiscExtension = FALSE; +#endif +#ifdef MULTIBUFFER +Bool noMultibufferExtension = FALSE; +#endif +#ifdef RANDR +Bool noRRExtension = 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 TOGCUP +Bool noXcupExtension = FALSE; +#endif +#ifdef RES +Bool noResExtension = FALSE; +#endif +#ifdef XAPPGROUP +Bool noXagExtension = FALSE; +#endif +#ifdef XCMISC +Bool noXCMiscExtension = FALSE; +#endif +#ifdef XEVIE +/* Xevie is disabled by default for now until the + * interface is stable */ +Bool noXevieExtension = TRUE; +#endif +#ifdef XF86BIGFONT +Bool noXFree86BigfontExtension = FALSE; +#endif +#ifdef XFreeXDGA +Bool noXFree86DGAExtension = FALSE; +#endif +#ifdef XF86DRI +Bool noXFree86DRIExtension = FALSE; +#endif +#ifdef XF86MISC +Bool noXFree86MiscExtension = FALSE; +#endif +#ifdef XF86VIDMODE +Bool noXFree86VidModeExtension = 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 <X11/Xos_r.h> + +#include <errno.h> + +#ifdef NX_TRANS_SOCKET + +#include "NX.h" +#include "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; + +#ifdef AIXV3 +int SyncOn = 0; +extern int SelectWaitTime; +#endif + +#ifdef DEBUG +#ifndef SPECIAL_MALLOC +#define MEMBUG +#endif +#endif + +#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 + +#ifdef sgi +int userdefinedfontpath = 0; +#endif /* sgi */ + +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; + sigaction(sig, &act, &oact); + 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. + */ +#ifndef __UNIXOS2__ +#define LOCK_DIR "/tmp" +#endif +#define LOCK_TMP_PREFIX "/.tX" +#define LOCK_PREFIX "/.X" +#define LOCK_SUFFIX "-lock" + +#if defined(DGUX) +#include <limits.h> +#include <sys/param.h> +#endif + +#ifdef __UNIXOS2__ +#define link rename +#endif + +#ifndef PATH_MAX +#ifndef Lynx +#include <sys/param.h> +#else +#include <param.h> +#endif +#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) return; + /* + * Path names + */ +#ifndef __UNIXOS2__ + tmppath = LOCK_DIR; +#else + /* OS/2 uses TMP directory, must also prepare for 8.3 names */ + tmppath = getenv("TMP"); + if (!tmppath) + FatalError("No TMP dir found\n"); +#endif + + 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()); + (void) write(lfd, pid_str, 11); +#ifndef __UNIXOS2__ +#ifndef USE_CHMOD + (void) fchmod(lfd, 0444); +#else + (void) chmod(tmp, 0444); +#endif +#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); + 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) return; + + if (!StillLocking){ + +#ifdef __UNIXOS2__ + (void) chmod(LockFile,S_IREAD|S_IWRITE); +#endif /* __UNIXOS2__ */ + (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 (pointer waitTime, unsigned long newdelay) +{ + static struct timeval delay_val; + struct timeval **wt = (struct timeval **) waitTime; + unsigned long olddelay; + + if (*wt == NULL) + { + delay_val.tv_sec = newdelay / 1000; + delay_val.tv_usec = 1000 * (newdelay % 1000); + *wt = &delay_val; + } + else + { + olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000; + if (newdelay < olddelay) + { + (*wt)->tv_sec = newdelay / 1000; + (*wt)->tv_usec = 1000 * (newdelay % 1000); + } + } +} + +void UseMsg(void) +{ +#if !defined(AIXrt) && !defined(AIX386) + ErrorF("use: X [:<display>] [option]\n"); + ErrorF("-a # mouse acceleration (pixels)\n"); + ErrorF("-ac disable access control restrictions\n"); +#ifdef MEMBUG + ErrorF("-alloc int chance alloc should fail\n"); +#endif + ErrorF("-audit int set audit trail level\n"); + ErrorF("-auth file select authorization file\n"); + ErrorF("bc enable bug compatibility\n"); + ErrorF("-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"); + ErrorF("-co file color database file\n"); +#ifdef COMMANDLINE_CHALLENGED_OPERATING_SYSTEMS + ErrorF("-config file read options from file\n"); +#endif + ErrorF("-core generate core dump on fatal error\n"); + ErrorF("-dpi int screen resolution in dots per inch\n"); +#ifdef DPMSExtension + ErrorF("dpms enables VESA DPMS monitor control\n"); + ErrorF("-dpms disables VESA DPMS monitor control\n"); +#endif + ErrorF("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n"); + ErrorF("-f # bell base (0-100)\n"); + ErrorF("-fc string cursor font\n"); + ErrorF("-fn string default font name\n"); + ErrorF("-fp string default font path\n"); + ErrorF("-help prints message with these options\n"); + ErrorF("-I ignore all remaining arguments\n"); +#ifdef RLIMIT_DATA + ErrorF("-ld int limit data space to N Kb\n"); +#endif +#ifdef RLIMIT_NOFILE + ErrorF("-lf int limit number of open files to N\n"); +#endif +#ifdef RLIMIT_STACK + ErrorF("-ls int limit stack space to N Kb\n"); +#endif +#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 +#ifdef XPRINT + PrinterUseMsg(); +#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("-x string loads named extension at init time \n"); + ErrorF("-maxbigreqsize set maximal bigrequest size \n"); +#ifdef PANORAMIX + ErrorF("+xinerama Enable XINERAMA extension\n"); + ErrorF("-xinerama Disable XINERAMA extension\n"); +#endif +#ifdef SMART_SCHEDULE + ErrorF("-dumbSched Disable smart scheduling, enable old behavior\n"); + ErrorF("-schedInterval int Set scheduler interval in msec\n"); +#endif + ErrorF("+extension name Enable extension\n"); + ErrorF("-extension name Disable extension\n"); +#ifdef XDMCP + XdmcpUseMsg(); +#endif +#endif /* !AIXrt && ! AIX386 */ +#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]; + 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], "-co") == 0) + { + if(++i < argc) + rgbPath = argv[i]; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-core") == 0) + CoreDump = TRUE; + else if ( strcmp( argv[i], "-dpi") == 0) + { + if(++i < argc) + monitorResolution = atoi(argv[i]); + else + UseMsg(); + } +#ifdef DPMSExtension + else if ( strcmp( argv[i], "dpms") == 0) + DPMSEnabledSwitch = TRUE; + else if ( strcmp( argv[i], "-dpms") == 0) + DPMSDisabledSwitch = TRUE; +#endif + else if ( strcmp( argv[i], "-deferglyphs") == 0) + { + if(++i >= argc || !ParseGlyphCachingMode(argv[i])) + UseMsg(); + } + else if ( strcmp( argv[i], "-f") == 0) + { + if(++i < argc) + defaultKeyboardControl.bell = atoi(argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-fc") == 0) + { + if(++i < argc) + defaultCursorFont = argv[i]; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-fn") == 0) + { + if(++i < argc) + defaultTextFont = argv[i]; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-fp") == 0) + { + if(++i < argc) + { +#ifdef sgi + userdefinedfontpath = 1; +#endif /* sgi */ + defaultFontPath = argv[i]; + } + else + UseMsg(); + } + else if ( strcmp( argv[i], "-help") == 0) + { + UseMsg(); + exit(0); + } +#ifdef XKB + else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) { + if (skip>0) + i+= skip-1; + else UseMsg(); + } +#endif +#ifdef RLIMIT_DATA + else if ( strcmp( argv[i], "-ld") == 0) + { + if(++i < argc) + { + limitDataSpace = atoi(argv[i]); + if (limitDataSpace > 0) + limitDataSpace *= 1024; + } + else + UseMsg(); + } +#endif +#ifdef RLIMIT_NOFILE + else if ( strcmp( argv[i], "-lf") == 0) + { + if(++i < argc) + limitNoFile = atoi(argv[i]); + else + UseMsg(); + } +#endif +#ifdef RLIMIT_STACK + else if ( strcmp( argv[i], "-ls") == 0) + { + if(++i < argc) + { + limitStackSpace = atoi(argv[i]); + if (limitStackSpace > 0) + limitStackSpace *= 1024; + } + else + UseMsg(); + } +#endif +#ifdef SERVER_LOCK + else if ( strcmp ( argv[i], "-nolock") == 0) + { +#if !defined(WIN32) && !defined(__UNIXOS2__) && !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) { + 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 + else if ( strcmp( argv[i], "-x") == 0) + { + if(++i >= argc) + UseMsg(); + /* For U**x, which doesn't support dynamic loading, there's nothing + * to do when we see a -x. Either the extension is linked in or + * it isn't */ + } + else if ( strcmp( argv[i], "-I") == 0) + { + /* ignore all remaining arguments */ + break; + } + else if (strncmp (argv[i], "tty", 3) == 0) + { + /* just in case any body is interested */ + dev_tty_from_init = argv[i]; + } +#ifdef XDMCP + else if ((skip = XdmcpOptions(argc, argv, i)) != i) + { + i = skip - 1; + } +#endif +#ifdef XPRINT + else if ((skip = PrinterOptions(argc, argv, i)) != i) + { + i = skip - 1; + } +#endif +#ifdef XCSECURITY + else if ((skip = XSecurityOptions(argc, argv, i)) != i) + { + i = skip - 1; + } +#endif +#ifdef AIXV3 + else if ( strcmp( argv[i], "-timeout") == 0) + { + if(++i < argc) + SelectWaitTime = atoi(argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-sync") == 0) + { + SyncOn++; + } +#endif +#ifdef SMART_SCHEDULE + else if ( strcmp( argv[i], "-dumbSched") == 0) + { + SmartScheduleDisable = TRUE; + } + 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(); + } +#endif +#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 *) xalloc((unsigned) st.st_size + 1); + if (!buf) + FatalError("Out of Memory\n"); + + len = fread(buf, 1, (unsigned) st.st_size, f); + + fclose(f); + + if (len < 0) + FatalError("Error reading option file %s\n", filename); + + buf[len] = '\0'; + + p = buf; + q = buf; + insert_argc = 0; + + while (*p) + { + while (isspace(*p)) + p++; + if (!*p) + break; + if (*p == '#') + { + while (*p && *p != '\n') + p++; + } else + { + while (*p && !isspace(*p)) + *q++ = *p++; + /* Since p and q might still be pointing at the same place, we */ + /* need to step p over the whitespace now before we add the null. */ + if (*p) + p++; + *q++ = '\0'; + insert_argc++; + } + } + + buf = (char *) xrealloc(buf, q - buf); + if (!buf) + FatalError("Out of memory reallocing option buf\n"); + + *resargc = prefix_argc + insert_argc + suffix_argc; + *resargv = (char **) xalloc((*resargc + 1) * sizeof(char *)); + if (!*resargv) + FatalError("Out of Memory\n"); + + memcpy(*resargv, prefix_argv, prefix_argc * sizeof(char *)); + + p = buf; + for (i = 0; i < insert_argc; i++) + { + (*resargv)[prefix_argc + i] = p; + p += strlen(p) + 1; + } + + memcpy(*resargv + prefix_argc + insert_argc, + suffix_argv, suffix_argc * sizeof(char *)); + + (*resargv)[*resargc] = NULL; +} /* end InsertFileIntoCommandLine */ + + +void +ExpandCommandLine(int *pargc, char ***pargv) +{ + int i; + +#if !defined(WIN32) && !defined(__UNIXOS2__) && !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, pointer client) +{ +#define AUTHORIZATION_NAME "hp-hostname-1" +#if defined(TCPCONN) || defined(STREAMSCONN) + 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 = xalloc(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 */ +} + +/* XALLOC -- X's internal memory allocator. Why does it return unsigned + * long * instead of the more common char *? Well, if you read K&R you'll + * see they say that alloc must return a pointer "suitable for conversion" + * to whatever type you really want. In a full-blown generic allocator + * there's no way to solve the alignment problems without potentially + * wasting lots of space. But we have a more limited problem. We know + * we're only ever returning pointers to structures which will have to + * be long word aligned. So we are making a stronger guarantee. It might + * have made sense to make Xalloc return char * to conform with people's + * expectations of malloc, but this makes lint happier. + */ + +#ifndef INTERNAL_MALLOC + +void * +Xalloc(unsigned long amount) +{ + register pointer ptr; + + if ((long)amount <= 0) { + return (unsigned long *)NULL; + } + /* aligned extra on long word boundary */ + amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1); +#ifdef MEMBUG + if (!Must_have_memory && Memory_fail && + ((random() % MEM_FAIL_SCALE) < Memory_fail)) + return (unsigned long *)NULL; +#endif + if ((ptr = (pointer)malloc(amount))) { + return (unsigned long *)ptr; + } + if (Must_have_memory) + FatalError("Out of memory"); + return (unsigned long *)NULL; +} + +/***************** + * XNFalloc + * "no failure" realloc, alternate interface to Xalloc w/o Must_have_memory + *****************/ + +void * +XNFalloc(unsigned long amount) +{ + register pointer ptr; + + if ((long)amount <= 0) + { + return (unsigned long *)NULL; + } + /* aligned extra on long word boundary */ + amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1); + ptr = (pointer)malloc(amount); + if (!ptr) + { + FatalError("Out of memory"); + } + return ((unsigned long *)ptr); +} + +/***************** + * Xcalloc + *****************/ + +void * +Xcalloc(unsigned long amount) +{ + unsigned long *ret; + + ret = Xalloc (amount); + if (ret) + bzero ((char *) ret, (int) amount); + return ret; +} + +/***************** + * XNFcalloc + *****************/ + +void * +XNFcalloc(unsigned long amount) +{ + unsigned long *ret; + + ret = Xalloc (amount); + if (ret) + bzero ((char *) ret, (int) amount); + else if ((long)amount > 0) + FatalError("Out of memory"); + return ret; +} + +/***************** + * Xrealloc + *****************/ + +void * +Xrealloc(pointer ptr, unsigned long amount) +{ +#ifdef MEMBUG + if (!Must_have_memory && Memory_fail && + ((random() % MEM_FAIL_SCALE) < Memory_fail)) + return (unsigned long *)NULL; +#endif + if ((long)amount <= 0) + { + if (ptr && !amount) + free(ptr); + return (unsigned long *)NULL; + } + amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1); + if (ptr) + ptr = (pointer)realloc((char *)ptr, amount); + else + ptr = (pointer)malloc(amount); + if (ptr) + return (unsigned long *)ptr; + if (Must_have_memory) + FatalError("Out of memory"); + return (unsigned long *)NULL; +} + +/***************** + * XNFrealloc + * "no failure" realloc, alternate interface to Xrealloc w/o Must_have_memory + *****************/ + +void * +XNFrealloc(pointer ptr, unsigned long amount) +{ + if (( ptr = (pointer)Xrealloc( ptr, amount ) ) == NULL) + { + if ((long)amount > 0) + FatalError( "Out of memory" ); + } + return ((unsigned long *)ptr); +} + +/***************** + * Xfree + * calls free + *****************/ + +void +Xfree(pointer ptr) +{ + if (ptr) + free((char *)ptr); +} + +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 +} +#endif /* !INTERNAL_MALLOC */ + + +char * +Xstrdup(const char *s) +{ + char *sd; + + if (s == NULL) + return NULL; + + sd = (char *)Xalloc(strlen(s) + 1); + if (sd != NULL) + strcpy(sd, s); + return sd; +} + + +char * +XNFstrdup(const char *s) +{ + char *sd; + + if (s == NULL) + return NULL; + + sd = (char *)XNFalloc(strlen(s) + 1); + strcpy(sd, s); + return sd; +} + +#ifdef SMART_SCHEDULE + +unsigned long SmartScheduleIdleCount; +Bool SmartScheduleIdle; +Bool SmartScheduleTimerStopped; + +#ifdef SIGVTALRM +#define SMART_SCHEDULE_POSSIBLE +#endif + +#ifdef SMART_SCHEDULE_POSSIBLE +#define SMART_SCHEDULE_SIGNAL SIGALRM +#define SMART_SCHEDULE_TIMER ITIMER_REAL +#endif + +#ifdef NX_TRANS_SOCKET +void +SmartScheduleStopTimer (void) +#else +static void +SmartScheduleStopTimer (void) +#endif +{ +#ifdef SMART_SCHEDULE_POSSIBLE + struct itimerval timer; + + #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); + SmartScheduleTimerStopped = TRUE; +#endif +} + +Bool +SmartScheduleStartTimer (void) +{ +#ifdef SMART_SCHEDULE_POSSIBLE + struct itimerval timer; + + #ifdef NX_TRANS_SOCKET + + if (SmartScheduleDisable) + { + return FALSE; + } + + #endif + + #ifdef NX_TRANS_TEST + fprintf(stderr, "SmartScheduleStartTimer: Starting timer with [%ld] ms.\n", + SmartScheduleInterval); + #endif + + SmartScheduleTimerStopped = FALSE; + 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; + return setitimer (ITIMER_REAL, &timer, 0) >= 0; +#endif + return FALSE; +} + +#ifdef SMART_SCHEDULE_POSSIBLE +static void +SmartScheduleTimer (int sig) +{ + int olderrno = errno; + + SmartScheduleTime += SmartScheduleInterval; + + #ifdef NX_TRANS_TEST + fprintf(stderr, "SmartScheduleTimer: Got timer with time [%ld] ms.\n", + SmartScheduleTime); + #endif + + if (SmartScheduleIdle) + { + SmartScheduleStopTimer (); + } + errno = olderrno; +} +#endif + +Bool +SmartScheduleInit (void) +{ +#ifdef SMART_SCHEDULE_POSSIBLE + struct sigaction act; + + if (SmartScheduleDisable) + return TRUE; + + #ifdef NX_TRANS_TEST + fprintf(stderr, "SmartScheduleInit: Initializing the smart scheduler.\n"); + #endif + + bzero ((char *) &act, sizeof(struct sigaction)); + + /* Set up the timer signal function */ + act.sa_handler = SmartScheduleTimer; + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SMART_SCHEDULE_SIGNAL); + if (sigaction (SMART_SCHEDULE_SIGNAL, &act, 0) < 0) + { + perror ("sigaction for smart scheduler"); + return FALSE; + } + /* Set up the virtual timer */ + if (!SmartScheduleStartTimer ()) + { + perror ("scheduling timer"); + return FALSE; + } + /* stop the timer and wait for WaitForSomething to start it */ + SmartScheduleStopTimer (); + return TRUE; +#else + return FALSE; +#endif +} +#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) && !defined(__UNIXOS2__) +/* + * "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; + + if (!command) + return(1); + +#ifdef SIGCHLD + csig = signal(SIGCHLD, SIG_DFL); +#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 */ + 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 + signal(SIGCHLD, csig); +#endif + + return p == -1 ? -1 : status; +} + +static struct pid { + struct pid *next; + FILE *fp; + int pid; +} *pidlist; + +pointer +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 *)xalloc(sizeof(struct pid))) == NULL) + return NULL; + + if (pipe(pdes) < 0) { + xfree(cur); + return NULL; + } + +#ifdef NX_TRANS_EXIT + if (OsVendorStartRedirectErrorFProc != NULL) { + OsVendorStartRedirectErrorFProc(); + } +#endif + switch (pid = fork()) { + case -1: /* error */ + close(pdes[0]); + close(pdes[1]); + xfree(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]); + } + + #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 + + execl("/bin/sh", "sh", "-c", command, (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; +} + +/* fopen that drops privileges */ +pointer +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 *)xalloc(sizeof(struct pid))) == NULL) + return NULL; + + if (pipe(pdes) < 0) { + xfree(cur); + return NULL; + } + + switch (pid = fork()) { + case -1: /* error */ + close(pdes[0]); + close(pdes[1]); + xfree(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(pointer 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; + xfree(cur); + + /* allow EINTR again */ + OsReleaseSignals (); + +#ifdef NX_TRANS_EXIT + if (OsVendorEndRedirectErrorFProc != NULL) { + OsVendorEndRedirectErrorFProc(); + } +#endif + return pid == -1 ? -1 : pstat; +} + +int +Fclose(pointer iop) +{ +#ifdef HAS_SAVED_IDS_AND_SETEUID + return fclose(iop); +#else + return Pclose(iop); +#endif +} + +#endif /* !WIN32 && !__UNIXOS2__ */ + + +/* + * 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 defined(__QNX__) && !defined(__QNXNTO__) + char cmd_name[64]; +#endif + +#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/utils.c.NX.original b/nx-X11/programs/Xserver/os/utils.c.NX.original new file mode 100644 index 000000000..c806621ff --- /dev/null +++ b/nx-X11/programs/Xserver/os/utils.c.NX.original @@ -0,0 +1,2427 @@ +/* $XdotOrg: xc/programs/Xserver/os/utils.c,v 1.21 2005/11/08 06:33:30 jkj Exp $ */ +/* $Xorg: utils.c,v 1.5 2001/02/09 02:05:24 xorgcvs Exp $ */ +/* + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1994 Quarterdeck Office Systems. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital and +Quarterdeck not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT +OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE +OR PERFORMANCE OF THIS SOFTWARE. + +*/ +/* $XFree86: xc/programs/Xserver/os/utils.c,v 3.96 2004/01/07 04:16:37 dawes Exp $ */ + +/**************************************************************************/ +/* */ +/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */ +/* */ +/* NX-X11, NX protocol compression and NX extensions to this software */ +/* are copyright of NoMachine. Redistribution and use of the present */ +/* software is allowed according to terms specified in the file LICENSE */ +/* which comes in the source distribution. */ +/* */ +/* Check http://www.nomachine.com/licensing.html for applicability. */ +/* */ +/* NX and NoMachine are trademarks of NoMachine S.r.l. */ +/* */ +/* All rights reserved. */ +/* */ +/**************************************************************************/ + +#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 <X11/Xwinsock.h> +#endif +#include <X11/Xos.h> +#include <stdio.h> +#include "misc.h" +#include <X11/X.h> +#include <X11/Xtrans/Xtrans.h> +#include "input.h" +#include "dixfont.h" +#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) && !defined(Lynx) && !defined(QNX4) +#include <sys/resource.h> +#endif +#include <time.h> +#include <sys/stat.h> +#include <ctype.h> /* for isspace */ +#include <stdarg.h> + +#if defined(DGUX) +#include <sys/resource.h> +#include <netdb.h> +#endif + +#include <stdlib.h> /* for malloc() */ + +#if defined(TCPCONN) || defined(STREAMSCONN) +# ifndef WIN32 +# include <netdb.h> +# endif +#endif + +#include "opaque.h" + +#ifdef SMART_SCHEDULE +#include "dixstruct.h" +#endif + +#ifdef XKB +#include <X11/extensions/XKBsrv.h> +#endif +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <X11/extensions/security.h> +#endif + +#ifdef RENDER +#include "picture.h" +#endif + +#ifdef XPRINT +#include "DiPrint.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 EVI +Bool noEVIExtension = FALSE; +#endif +#ifdef FONTCACHE +Bool noFontCacheExtension = FALSE; +#endif +#ifdef GLXEXT +Bool noGlxExtension = FALSE; +#endif +#ifdef LBX +Bool noLbxExtension = FALSE; +#endif +#ifdef SCREENSAVER +Bool noScreenSaverExtension = FALSE; +#endif +#ifdef MITSHM +Bool noMITShmExtension = FALSE; +#endif +#ifdef MITMISC +Bool noMITMiscExtension = FALSE; +#endif +#ifdef MULTIBUFFER +Bool noMultibufferExtension = FALSE; +#endif +#ifdef RANDR +Bool noRRExtension = 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 TOGCUP +Bool noXcupExtension = FALSE; +#endif +#ifdef RES +Bool noResExtension = FALSE; +#endif +#ifdef XAPPGROUP +Bool noXagExtension = FALSE; +#endif +#ifdef XCMISC +Bool noXCMiscExtension = FALSE; +#endif +#ifdef XEVIE +/* Xevie is disabled by default for now until the + * interface is stable */ +Bool noXevieExtension = TRUE; +#endif +#ifdef XF86BIGFONT +Bool noXFree86BigfontExtension = FALSE; +#endif +#ifdef XFreeXDGA +Bool noXFree86DGAExtension = FALSE; +#endif +#ifdef XF86DRI +Bool noXFree86DRIExtension = FALSE; +#endif +#ifdef XF86MISC +Bool noXFree86MiscExtension = FALSE; +#endif +#ifdef XF86VIDMODE +Bool noXFree86VidModeExtension = 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 <X11/Xos_r.h> + +#include <errno.h> + +#ifdef NX_TRANS_SOCKET + +#include "NX.h" +#include "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; + +#ifdef AIXV3 +int SyncOn = 0; +extern int SelectWaitTime; +#endif + +#ifdef DEBUG +#ifndef SPECIAL_MALLOC +#define MEMBUG +#endif +#endif + +#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 + +#ifdef sgi +int userdefinedfontpath = 0; +#endif /* sgi */ + +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; + sigaction(sig, &act, &oact); + 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. + */ +#ifndef __UNIXOS2__ +#define LOCK_DIR "/tmp" +#endif +#define LOCK_TMP_PREFIX "/.tX" +#define LOCK_PREFIX "/.X" +#define LOCK_SUFFIX "-lock" + +#if defined(DGUX) +#include <limits.h> +#include <sys/param.h> +#endif + +#ifdef __UNIXOS2__ +#define link rename +#endif + +#ifndef PATH_MAX +#ifndef Lynx +#include <sys/param.h> +#else +#include <param.h> +#endif +#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) return; + /* + * Path names + */ +#ifndef __UNIXOS2__ + tmppath = LOCK_DIR; +#else + /* OS/2 uses TMP directory, must also prepare for 8.3 names */ + tmppath = getenv("TMP"); + if (!tmppath) + FatalError("No TMP dir found\n"); +#endif + + 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()); + (void) write(lfd, pid_str, 11); +#ifndef __UNIXOS2__ +#ifndef USE_CHMOD + (void) fchmod(lfd, 0444); +#else + (void) chmod(tmp, 0444); +#endif +#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); + 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) return; + + if (!StillLocking){ + +#ifdef __UNIXOS2__ + (void) chmod(LockFile,S_IREAD|S_IWRITE); +#endif /* __UNIXOS2__ */ + (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 (pointer waitTime, unsigned long newdelay) +{ + static struct timeval delay_val; + struct timeval **wt = (struct timeval **) waitTime; + unsigned long olddelay; + + if (*wt == NULL) + { + delay_val.tv_sec = newdelay / 1000; + delay_val.tv_usec = 1000 * (newdelay % 1000); + *wt = &delay_val; + } + else + { + olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000; + if (newdelay < olddelay) + { + (*wt)->tv_sec = newdelay / 1000; + (*wt)->tv_usec = 1000 * (newdelay % 1000); + } + } +} + +void UseMsg(void) +{ +#if !defined(AIXrt) && !defined(AIX386) + ErrorF("use: X [:<display>] [option]\n"); + ErrorF("-a # mouse acceleration (pixels)\n"); + ErrorF("-ac disable access control restrictions\n"); +#ifdef MEMBUG + ErrorF("-alloc int chance alloc should fail\n"); +#endif + ErrorF("-audit int set audit trail level\n"); + ErrorF("-auth file select authorization file\n"); + ErrorF("bc enable bug compatibility\n"); + ErrorF("-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"); + ErrorF("-co file color database file\n"); +#ifdef COMMANDLINE_CHALLENGED_OPERATING_SYSTEMS + ErrorF("-config file read options from file\n"); +#endif + ErrorF("-core generate core dump on fatal error\n"); + ErrorF("-dpi int screen resolution in dots per inch\n"); +#ifdef DPMSExtension + ErrorF("dpms enables VESA DPMS monitor control\n"); + ErrorF("-dpms disables VESA DPMS monitor control\n"); +#endif + ErrorF("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n"); + ErrorF("-f # bell base (0-100)\n"); + ErrorF("-fc string cursor font\n"); + ErrorF("-fn string default font name\n"); + ErrorF("-fp string default font path\n"); + ErrorF("-help prints message with these options\n"); + ErrorF("-I ignore all remaining arguments\n"); +#ifdef RLIMIT_DATA + ErrorF("-ld int limit data space to N Kb\n"); +#endif +#ifdef RLIMIT_NOFILE + ErrorF("-lf int limit number of open files to N\n"); +#endif +#ifdef RLIMIT_STACK + ErrorF("-ls int limit stack space to N Kb\n"); +#endif +#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 +#ifdef XPRINT + PrinterUseMsg(); +#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("-x string loads named extension at init time \n"); + ErrorF("-maxbigreqsize set maximal bigrequest size \n"); +#ifdef PANORAMIX + ErrorF("+xinerama Enable XINERAMA extension\n"); + ErrorF("-xinerama Disable XINERAMA extension\n"); +#endif +#ifdef SMART_SCHEDULE + ErrorF("-dumbSched Disable smart scheduling, enable old behavior\n"); + ErrorF("-schedInterval int Set scheduler interval in msec\n"); +#endif + ErrorF("+extension name Enable extension\n"); + ErrorF("-extension name Disable extension\n"); +#ifdef XDMCP + XdmcpUseMsg(); +#endif +#endif /* !AIXrt && ! AIX386 */ +#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]; + 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], "-co") == 0) + { + if(++i < argc) + rgbPath = argv[i]; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-core") == 0) + CoreDump = TRUE; + else if ( strcmp( argv[i], "-dpi") == 0) + { + if(++i < argc) + monitorResolution = atoi(argv[i]); + else + UseMsg(); + } +#ifdef DPMSExtension + else if ( strcmp( argv[i], "dpms") == 0) + DPMSEnabledSwitch = TRUE; + else if ( strcmp( argv[i], "-dpms") == 0) + DPMSDisabledSwitch = TRUE; +#endif + else if ( strcmp( argv[i], "-deferglyphs") == 0) + { + if(++i >= argc || !ParseGlyphCachingMode(argv[i])) + UseMsg(); + } + else if ( strcmp( argv[i], "-f") == 0) + { + if(++i < argc) + defaultKeyboardControl.bell = atoi(argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-fc") == 0) + { + if(++i < argc) + defaultCursorFont = argv[i]; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-fn") == 0) + { + if(++i < argc) + defaultTextFont = argv[i]; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-fp") == 0) + { + if(++i < argc) + { +#ifdef sgi + userdefinedfontpath = 1; +#endif /* sgi */ + defaultFontPath = argv[i]; + } + else + UseMsg(); + } + else if ( strcmp( argv[i], "-help") == 0) + { + UseMsg(); + exit(0); + } +#ifdef XKB + else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) { + if (skip>0) + i+= skip-1; + else UseMsg(); + } +#endif +#ifdef RLIMIT_DATA + else if ( strcmp( argv[i], "-ld") == 0) + { + if(++i < argc) + { + limitDataSpace = atoi(argv[i]); + if (limitDataSpace > 0) + limitDataSpace *= 1024; + } + else + UseMsg(); + } +#endif +#ifdef RLIMIT_NOFILE + else if ( strcmp( argv[i], "-lf") == 0) + { + if(++i < argc) + limitNoFile = atoi(argv[i]); + else + UseMsg(); + } +#endif +#ifdef RLIMIT_STACK + else if ( strcmp( argv[i], "-ls") == 0) + { + if(++i < argc) + { + limitStackSpace = atoi(argv[i]); + if (limitStackSpace > 0) + limitStackSpace *= 1024; + } + else + UseMsg(); + } +#endif +#ifdef SERVER_LOCK + else if ( strcmp ( argv[i], "-nolock") == 0) + { +#if !defined(WIN32) && !defined(__UNIXOS2__) && !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) { + 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 + else if ( strcmp( argv[i], "-x") == 0) + { + if(++i >= argc) + UseMsg(); + /* For U**x, which doesn't support dynamic loading, there's nothing + * to do when we see a -x. Either the extension is linked in or + * it isn't */ + } + else if ( strcmp( argv[i], "-I") == 0) + { + /* ignore all remaining arguments */ + break; + } + else if (strncmp (argv[i], "tty", 3) == 0) + { + /* just in case any body is interested */ + dev_tty_from_init = argv[i]; + } +#ifdef XDMCP + else if ((skip = XdmcpOptions(argc, argv, i)) != i) + { + i = skip - 1; + } +#endif +#ifdef XPRINT + else if ((skip = PrinterOptions(argc, argv, i)) != i) + { + i = skip - 1; + } +#endif +#ifdef XCSECURITY + else if ((skip = XSecurityOptions(argc, argv, i)) != i) + { + i = skip - 1; + } +#endif +#ifdef AIXV3 + else if ( strcmp( argv[i], "-timeout") == 0) + { + if(++i < argc) + SelectWaitTime = atoi(argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-sync") == 0) + { + SyncOn++; + } +#endif +#ifdef SMART_SCHEDULE + else if ( strcmp( argv[i], "-dumbSched") == 0) + { + SmartScheduleDisable = TRUE; + } + 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(); + } +#endif +#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 *) xalloc((unsigned) st.st_size + 1); + if (!buf) + FatalError("Out of Memory\n"); + + len = fread(buf, 1, (unsigned) st.st_size, f); + + fclose(f); + + if (len < 0) + FatalError("Error reading option file %s\n", filename); + + buf[len] = '\0'; + + p = buf; + q = buf; + insert_argc = 0; + + while (*p) + { + while (isspace(*p)) + p++; + if (!*p) + break; + if (*p == '#') + { + while (*p && *p != '\n') + p++; + } else + { + while (*p && !isspace(*p)) + *q++ = *p++; + /* Since p and q might still be pointing at the same place, we */ + /* need to step p over the whitespace now before we add the null. */ + if (*p) + p++; + *q++ = '\0'; + insert_argc++; + } + } + + buf = (char *) xrealloc(buf, q - buf); + if (!buf) + FatalError("Out of memory reallocing option buf\n"); + + *resargc = prefix_argc + insert_argc + suffix_argc; + *resargv = (char **) xalloc((*resargc + 1) * sizeof(char *)); + if (!*resargv) + FatalError("Out of Memory\n"); + + memcpy(*resargv, prefix_argv, prefix_argc * sizeof(char *)); + + p = buf; + for (i = 0; i < insert_argc; i++) + { + (*resargv)[prefix_argc + i] = p; + p += strlen(p) + 1; + } + + memcpy(*resargv + prefix_argc + insert_argc, + suffix_argv, suffix_argc * sizeof(char *)); + + (*resargv)[*resargc] = NULL; +} /* end InsertFileIntoCommandLine */ + + +void +ExpandCommandLine(int *pargc, char ***pargv) +{ + int i; + +#if !defined(WIN32) && !defined(__UNIXOS2__) && !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, pointer client) +{ +#define AUTHORIZATION_NAME "hp-hostname-1" +#if defined(TCPCONN) || defined(STREAMSCONN) + 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 = xalloc(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 */ +} + +/* XALLOC -- X's internal memory allocator. Why does it return unsigned + * long * instead of the more common char *? Well, if you read K&R you'll + * see they say that alloc must return a pointer "suitable for conversion" + * to whatever type you really want. In a full-blown generic allocator + * there's no way to solve the alignment problems without potentially + * wasting lots of space. But we have a more limited problem. We know + * we're only ever returning pointers to structures which will have to + * be long word aligned. So we are making a stronger guarantee. It might + * have made sense to make Xalloc return char * to conform with people's + * expectations of malloc, but this makes lint happier. + */ + +#ifndef INTERNAL_MALLOC + +void * +Xalloc(unsigned long amount) +{ + register pointer ptr; + + if ((long)amount <= 0) { + return (unsigned long *)NULL; + } + /* aligned extra on long word boundary */ + amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1); +#ifdef MEMBUG + if (!Must_have_memory && Memory_fail && + ((random() % MEM_FAIL_SCALE) < Memory_fail)) + return (unsigned long *)NULL; +#endif + if ((ptr = (pointer)malloc(amount))) { + return (unsigned long *)ptr; + } + if (Must_have_memory) + FatalError("Out of memory"); + return (unsigned long *)NULL; +} + +/***************** + * XNFalloc + * "no failure" realloc, alternate interface to Xalloc w/o Must_have_memory + *****************/ + +void * +XNFalloc(unsigned long amount) +{ + register pointer ptr; + + if ((long)amount <= 0) + { + return (unsigned long *)NULL; + } + /* aligned extra on long word boundary */ + amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1); + ptr = (pointer)malloc(amount); + if (!ptr) + { + FatalError("Out of memory"); + } + return ((unsigned long *)ptr); +} + +/***************** + * Xcalloc + *****************/ + +void * +Xcalloc(unsigned long amount) +{ + unsigned long *ret; + + ret = Xalloc (amount); + if (ret) + bzero ((char *) ret, (int) amount); + return ret; +} + +/***************** + * XNFcalloc + *****************/ + +void * +XNFcalloc(unsigned long amount) +{ + unsigned long *ret; + + ret = Xalloc (amount); + if (ret) + bzero ((char *) ret, (int) amount); + else if ((long)amount > 0) + FatalError("Out of memory"); + return ret; +} + +/***************** + * Xrealloc + *****************/ + +void * +Xrealloc(pointer ptr, unsigned long amount) +{ +#ifdef MEMBUG + if (!Must_have_memory && Memory_fail && + ((random() % MEM_FAIL_SCALE) < Memory_fail)) + return (unsigned long *)NULL; +#endif + if ((long)amount <= 0) + { + if (ptr && !amount) + free(ptr); + return (unsigned long *)NULL; + } + amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1); + if (ptr) + ptr = (pointer)realloc((char *)ptr, amount); + else + ptr = (pointer)malloc(amount); + if (ptr) + return (unsigned long *)ptr; + if (Must_have_memory) + FatalError("Out of memory"); + return (unsigned long *)NULL; +} + +/***************** + * XNFrealloc + * "no failure" realloc, alternate interface to Xrealloc w/o Must_have_memory + *****************/ + +void * +XNFrealloc(pointer ptr, unsigned long amount) +{ + if (( ptr = (pointer)Xrealloc( ptr, amount ) ) == NULL) + { + if ((long)amount > 0) + FatalError( "Out of memory" ); + } + return ((unsigned long *)ptr); +} + +/***************** + * Xfree + * calls free + *****************/ + +void +Xfree(pointer ptr) +{ + if (ptr) + free((char *)ptr); +} + +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 +} +#endif /* !INTERNAL_MALLOC */ + + +char * +Xstrdup(const char *s) +{ + char *sd; + + if (s == NULL) + return NULL; + + sd = (char *)Xalloc(strlen(s) + 1); + if (sd != NULL) + strcpy(sd, s); + return sd; +} + + +char * +XNFstrdup(const char *s) +{ + char *sd; + + if (s == NULL) + return NULL; + + sd = (char *)XNFalloc(strlen(s) + 1); + strcpy(sd, s); + return sd; +} + +#ifdef SMART_SCHEDULE + +unsigned long SmartScheduleIdleCount; +Bool SmartScheduleIdle; +Bool SmartScheduleTimerStopped; + +#ifdef SIGVTALRM +#define SMART_SCHEDULE_POSSIBLE +#endif + +#ifdef SMART_SCHEDULE_POSSIBLE +#define SMART_SCHEDULE_SIGNAL SIGALRM +#define SMART_SCHEDULE_TIMER ITIMER_REAL +#endif + +#ifdef NX_TRANS_SOCKET +void +SmartScheduleStopTimer (void) +#else +static void +SmartScheduleStopTimer (void) +#endif +{ +#ifdef SMART_SCHEDULE_POSSIBLE + struct itimerval timer; + + #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); + SmartScheduleTimerStopped = TRUE; +#endif +} + +Bool +SmartScheduleStartTimer (void) +{ +#ifdef SMART_SCHEDULE_POSSIBLE + struct itimerval timer; + + #ifdef NX_TRANS_SOCKET + + if (SmartScheduleDisable) + { + return FALSE; + } + + #endif + + #ifdef NX_TRANS_TEST + fprintf(stderr, "SmartScheduleStartTimer: Starting timer with [%ld] ms.\n", + SmartScheduleInterval); + #endif + + SmartScheduleTimerStopped = FALSE; + 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; + return setitimer (ITIMER_REAL, &timer, 0) >= 0; +#endif + return FALSE; +} + +#ifdef SMART_SCHEDULE_POSSIBLE +static void +SmartScheduleTimer (int sig) +{ + int olderrno = errno; + + SmartScheduleTime += SmartScheduleInterval; + + #ifdef NX_TRANS_TEST + fprintf(stderr, "SmartScheduleTimer: Got timer with time [%ld] ms.\n", + SmartScheduleTime); + #endif + + if (SmartScheduleIdle) + { + SmartScheduleStopTimer (); + } + errno = olderrno; +} +#endif + +Bool +SmartScheduleInit (void) +{ +#ifdef SMART_SCHEDULE_POSSIBLE + struct sigaction act; + + if (SmartScheduleDisable) + return TRUE; + + #ifdef NX_TRANS_TEST + fprintf(stderr, "SmartScheduleInit: Initializing the smart scheduler.\n"); + #endif + + bzero ((char *) &act, sizeof(struct sigaction)); + + /* Set up the timer signal function */ + act.sa_handler = SmartScheduleTimer; + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SMART_SCHEDULE_SIGNAL); + if (sigaction (SMART_SCHEDULE_SIGNAL, &act, 0) < 0) + { + perror ("sigaction for smart scheduler"); + return FALSE; + } + /* Set up the virtual timer */ + if (!SmartScheduleStartTimer ()) + { + perror ("scheduling timer"); + return FALSE; + } + /* stop the timer and wait for WaitForSomething to start it */ + SmartScheduleStopTimer (); + return TRUE; +#else + return FALSE; +#endif +} +#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) && !defined(__UNIXOS2__) +/* + * "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; + + if (!command) + return(1); + +#ifdef SIGCHLD + csig = signal(SIGCHLD, SIG_DFL); +#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 */ + 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 + signal(SIGCHLD, csig); +#endif + + return p == -1 ? -1 : status; +} + +static struct pid { + struct pid *next; + FILE *fp; + int pid; +} *pidlist; + +pointer +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 *)xalloc(sizeof(struct pid))) == NULL) + return NULL; + + if (pipe(pdes) < 0) { + xfree(cur); + return NULL; + } + +#ifdef NX_TRANS_EXIT + if (OsVendorStartRedirectErrorFProc != NULL) { + OsVendorStartRedirectErrorFProc(); + } +#endif + switch (pid = fork()) { + case -1: /* error */ + close(pdes[0]); + close(pdes[1]); + xfree(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]); + } + + #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 + + execl("/bin/sh", "sh", "-c", command, (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; +} + +/* fopen that drops privileges */ +pointer +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 *)xalloc(sizeof(struct pid))) == NULL) + return NULL; + + if (pipe(pdes) < 0) { + xfree(cur); + return NULL; + } + + switch (pid = fork()) { + case -1: /* error */ + close(pdes[0]); + close(pdes[1]); + xfree(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(pointer 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; + xfree(cur); + + /* allow EINTR again */ + OsReleaseSignals (); + +#ifdef NX_TRANS_EXIT + if (OsVendorEndRedirectErrorFProc != NULL) { + OsVendorEndRedirectErrorFProc(); + } +#endif + return pid == -1 ? -1 : pstat; +} + +int +Fclose(pointer iop) +{ +#ifdef HAS_SAVED_IDS_AND_SETEUID + return fclose(iop); +#else + return Pclose(iop); +#endif +} + +#endif /* !WIN32 && !__UNIXOS2__ */ + + +/* + * 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 defined(__QNX__) && !defined(__QNXNTO__) + char cmd_name[64]; +#endif + +#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/utils.c.X.original b/nx-X11/programs/Xserver/os/utils.c.X.original new file mode 100644 index 000000000..b0a806fd7 --- /dev/null +++ b/nx-X11/programs/Xserver/os/utils.c.X.original @@ -0,0 +1,2296 @@ +/* $XdotOrg: xc/programs/Xserver/os/utils.c,v 1.21 2005/11/08 06:33:30 jkj Exp $ */ +/* $Xorg: utils.c,v 1.5 2001/02/09 02:05:24 xorgcvs Exp $ */ +/* + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1994 Quarterdeck Office Systems. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital and +Quarterdeck not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT +OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE +OR PERFORMANCE OF THIS SOFTWARE. + +*/ +/* $XFree86: xc/programs/Xserver/os/utils.c,v 3.96 2004/01/07 04:16:37 dawes Exp $ */ + +#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 <X11/Xwinsock.h> +#endif +#include <X11/Xos.h> +#include <stdio.h> +#include "misc.h" +#include <X11/X.h> +#include <X11/Xtrans/Xtrans.h> +#include "input.h" +#include "dixfont.h" +#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) && !defined(Lynx) && !defined(QNX4) +#include <sys/resource.h> +#endif +#include <time.h> +#include <sys/stat.h> +#include <ctype.h> /* for isspace */ +#include <stdarg.h> + +#if defined(DGUX) +#include <sys/resource.h> +#include <netdb.h> +#endif + +#include <stdlib.h> /* for malloc() */ + +#if defined(TCPCONN) || defined(STREAMSCONN) +# ifndef WIN32 +# include <netdb.h> +# endif +#endif + +#include "opaque.h" + +#ifdef SMART_SCHEDULE +#include "dixstruct.h" +#endif + +#ifdef XKB +#include <X11/extensions/XKBsrv.h> +#endif +#ifdef XCSECURITY +#define _SECURITY_SERVER +#include <X11/extensions/security.h> +#endif + +#ifdef RENDER +#include "picture.h" +#endif + +#ifdef XPRINT +#include "DiPrint.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 EVI +Bool noEVIExtension = FALSE; +#endif +#ifdef FONTCACHE +Bool noFontCacheExtension = FALSE; +#endif +#ifdef GLXEXT +Bool noGlxExtension = FALSE; +#endif +#ifdef LBX +Bool noLbxExtension = FALSE; +#endif +#ifdef SCREENSAVER +Bool noScreenSaverExtension = FALSE; +#endif +#ifdef MITSHM +Bool noMITShmExtension = FALSE; +#endif +#ifdef MITMISC +Bool noMITMiscExtension = FALSE; +#endif +#ifdef MULTIBUFFER +Bool noMultibufferExtension = FALSE; +#endif +#ifdef RANDR +Bool noRRExtension = 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 TOGCUP +Bool noXcupExtension = FALSE; +#endif +#ifdef RES +Bool noResExtension = FALSE; +#endif +#ifdef XAPPGROUP +Bool noXagExtension = FALSE; +#endif +#ifdef XCMISC +Bool noXCMiscExtension = FALSE; +#endif +#ifdef XEVIE +/* Xevie is disabled by default for now until the + * interface is stable */ +Bool noXevieExtension = TRUE; +#endif +#ifdef XF86BIGFONT +Bool noXFree86BigfontExtension = FALSE; +#endif +#ifdef XFreeXDGA +Bool noXFree86DGAExtension = FALSE; +#endif +#ifdef XF86DRI +Bool noXFree86DRIExtension = FALSE; +#endif +#ifdef XF86MISC +Bool noXFree86MiscExtension = FALSE; +#endif +#ifdef XF86VIDMODE +Bool noXFree86VidModeExtension = 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 <X11/Xos_r.h> + +#include <errno.h> + +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; + +#ifdef AIXV3 +int SyncOn = 0; +extern int SelectWaitTime; +#endif + +#ifdef DEBUG +#ifndef SPECIAL_MALLOC +#define MEMBUG +#endif +#endif + +#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 + +#ifdef sgi +int userdefinedfontpath = 0; +#endif /* sgi */ + +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; + sigaction(sig, &act, &oact); + 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. + */ +#ifndef __UNIXOS2__ +#define LOCK_DIR "/tmp" +#endif +#define LOCK_TMP_PREFIX "/.tX" +#define LOCK_PREFIX "/.X" +#define LOCK_SUFFIX "-lock" + +#if defined(DGUX) +#include <limits.h> +#include <sys/param.h> +#endif + +#ifdef __UNIXOS2__ +#define link rename +#endif + +#ifndef PATH_MAX +#ifndef Lynx +#include <sys/param.h> +#else +#include <param.h> +#endif +#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) return; + /* + * Path names + */ +#ifndef __UNIXOS2__ + tmppath = LOCK_DIR; +#else + /* OS/2 uses TMP directory, must also prepare for 8.3 names */ + tmppath = getenv("TMP"); + if (!tmppath) + FatalError("No TMP dir found\n"); +#endif + + 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()); + (void) write(lfd, pid_str, 11); +#ifndef __UNIXOS2__ +#ifndef USE_CHMOD + (void) fchmod(lfd, 0444); +#else + (void) chmod(tmp, 0444); +#endif +#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); + 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) return; + + if (!StillLocking){ + +#ifdef __UNIXOS2__ + (void) chmod(LockFile,S_IREAD|S_IWRITE); +#endif /* __UNIXOS2__ */ + (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; + + 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 (pointer waitTime, unsigned long newdelay) +{ + static struct timeval delay_val; + struct timeval **wt = (struct timeval **) waitTime; + unsigned long olddelay; + + if (*wt == NULL) + { + delay_val.tv_sec = newdelay / 1000; + delay_val.tv_usec = 1000 * (newdelay % 1000); + *wt = &delay_val; + } + else + { + olddelay = (*wt)->tv_sec * 1000 + (*wt)->tv_usec / 1000; + if (newdelay < olddelay) + { + (*wt)->tv_sec = newdelay / 1000; + (*wt)->tv_usec = 1000 * (newdelay % 1000); + } + } +} + +void UseMsg(void) +{ +#if !defined(AIXrt) && !defined(AIX386) + ErrorF("use: X [:<display>] [option]\n"); + ErrorF("-a # mouse acceleration (pixels)\n"); + ErrorF("-ac disable access control restrictions\n"); +#ifdef MEMBUG + ErrorF("-alloc int chance alloc should fail\n"); +#endif + ErrorF("-audit int set audit trail level\n"); + ErrorF("-auth file select authorization file\n"); + ErrorF("bc enable bug compatibility\n"); + ErrorF("-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"); + ErrorF("-co file color database file\n"); +#ifdef COMMANDLINE_CHALLENGED_OPERATING_SYSTEMS + ErrorF("-config file read options from file\n"); +#endif + ErrorF("-core generate core dump on fatal error\n"); + ErrorF("-dpi int screen resolution in dots per inch\n"); +#ifdef DPMSExtension + ErrorF("dpms enables VESA DPMS monitor control\n"); + ErrorF("-dpms disables VESA DPMS monitor control\n"); +#endif + ErrorF("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n"); + ErrorF("-f # bell base (0-100)\n"); + ErrorF("-fc string cursor font\n"); + ErrorF("-fn string default font name\n"); + ErrorF("-fp string default font path\n"); + ErrorF("-help prints message with these options\n"); + ErrorF("-I ignore all remaining arguments\n"); +#ifdef RLIMIT_DATA + ErrorF("-ld int limit data space to N Kb\n"); +#endif +#ifdef RLIMIT_NOFILE + ErrorF("-lf int limit number of open files to N\n"); +#endif +#ifdef RLIMIT_STACK + ErrorF("-ls int limit stack space to N Kb\n"); +#endif +#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 +#ifdef XPRINT + PrinterUseMsg(); +#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("-x string loads named extension at init time \n"); + ErrorF("-maxbigreqsize set maximal bigrequest size \n"); +#ifdef PANORAMIX + ErrorF("+xinerama Enable XINERAMA extension\n"); + ErrorF("-xinerama Disable XINERAMA extension\n"); +#endif +#ifdef SMART_SCHEDULE + ErrorF("-dumbSched Disable smart scheduling, enable old behavior\n"); + ErrorF("-schedInterval int Set scheduler interval in msec\n"); +#endif + ErrorF("+extension name Enable extension\n"); + ErrorF("-extension name Disable extension\n"); +#ifdef XDMCP + XdmcpUseMsg(); +#endif +#endif /* !AIXrt && ! AIX386 */ +#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]; + 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], "-co") == 0) + { + if(++i < argc) + rgbPath = argv[i]; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-core") == 0) + CoreDump = TRUE; + else if ( strcmp( argv[i], "-dpi") == 0) + { + if(++i < argc) + monitorResolution = atoi(argv[i]); + else + UseMsg(); + } +#ifdef DPMSExtension + else if ( strcmp( argv[i], "dpms") == 0) + DPMSEnabledSwitch = TRUE; + else if ( strcmp( argv[i], "-dpms") == 0) + DPMSDisabledSwitch = TRUE; +#endif + else if ( strcmp( argv[i], "-deferglyphs") == 0) + { + if(++i >= argc || !ParseGlyphCachingMode(argv[i])) + UseMsg(); + } + else if ( strcmp( argv[i], "-f") == 0) + { + if(++i < argc) + defaultKeyboardControl.bell = atoi(argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-fc") == 0) + { + if(++i < argc) + defaultCursorFont = argv[i]; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-fn") == 0) + { + if(++i < argc) + defaultTextFont = argv[i]; + else + UseMsg(); + } + else if ( strcmp( argv[i], "-fp") == 0) + { + if(++i < argc) + { +#ifdef sgi + userdefinedfontpath = 1; +#endif /* sgi */ + defaultFontPath = argv[i]; + } + else + UseMsg(); + } + else if ( strcmp( argv[i], "-help") == 0) + { + UseMsg(); + exit(0); + } +#ifdef XKB + else if ( (skip=XkbProcessArguments(argc,argv,i))!=0 ) { + if (skip>0) + i+= skip-1; + else UseMsg(); + } +#endif +#ifdef RLIMIT_DATA + else if ( strcmp( argv[i], "-ld") == 0) + { + if(++i < argc) + { + limitDataSpace = atoi(argv[i]); + if (limitDataSpace > 0) + limitDataSpace *= 1024; + } + else + UseMsg(); + } +#endif +#ifdef RLIMIT_NOFILE + else if ( strcmp( argv[i], "-lf") == 0) + { + if(++i < argc) + limitNoFile = atoi(argv[i]); + else + UseMsg(); + } +#endif +#ifdef RLIMIT_STACK + else if ( strcmp( argv[i], "-ls") == 0) + { + if(++i < argc) + { + limitStackSpace = atoi(argv[i]); + if (limitStackSpace > 0) + limitStackSpace *= 1024; + } + else + UseMsg(); + } +#endif +#ifdef SERVER_LOCK + else if ( strcmp ( argv[i], "-nolock") == 0) + { +#if !defined(WIN32) && !defined(__UNIXOS2__) && !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) { + 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 + else if ( strcmp( argv[i], "-x") == 0) + { + if(++i >= argc) + UseMsg(); + /* For U**x, which doesn't support dynamic loading, there's nothing + * to do when we see a -x. Either the extension is linked in or + * it isn't */ + } + else if ( strcmp( argv[i], "-I") == 0) + { + /* ignore all remaining arguments */ + break; + } + else if (strncmp (argv[i], "tty", 3) == 0) + { + /* just in case any body is interested */ + dev_tty_from_init = argv[i]; + } +#ifdef XDMCP + else if ((skip = XdmcpOptions(argc, argv, i)) != i) + { + i = skip - 1; + } +#endif +#ifdef XPRINT + else if ((skip = PrinterOptions(argc, argv, i)) != i) + { + i = skip - 1; + } +#endif +#ifdef XCSECURITY + else if ((skip = XSecurityOptions(argc, argv, i)) != i) + { + i = skip - 1; + } +#endif +#ifdef AIXV3 + else if ( strcmp( argv[i], "-timeout") == 0) + { + if(++i < argc) + SelectWaitTime = atoi(argv[i]); + else + UseMsg(); + } + else if ( strcmp( argv[i], "-sync") == 0) + { + SyncOn++; + } +#endif +#ifdef SMART_SCHEDULE + else if ( strcmp( argv[i], "-dumbSched") == 0) + { + SmartScheduleDisable = TRUE; + } + 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(); + } +#endif +#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 *) xalloc((unsigned) st.st_size + 1); + if (!buf) + FatalError("Out of Memory\n"); + + len = fread(buf, 1, (unsigned) st.st_size, f); + + fclose(f); + + if (len < 0) + FatalError("Error reading option file %s\n", filename); + + buf[len] = '\0'; + + p = buf; + q = buf; + insert_argc = 0; + + while (*p) + { + while (isspace(*p)) + p++; + if (!*p) + break; + if (*p == '#') + { + while (*p && *p != '\n') + p++; + } else + { + while (*p && !isspace(*p)) + *q++ = *p++; + /* Since p and q might still be pointing at the same place, we */ + /* need to step p over the whitespace now before we add the null. */ + if (*p) + p++; + *q++ = '\0'; + insert_argc++; + } + } + + buf = (char *) xrealloc(buf, q - buf); + if (!buf) + FatalError("Out of memory reallocing option buf\n"); + + *resargc = prefix_argc + insert_argc + suffix_argc; + *resargv = (char **) xalloc((*resargc + 1) * sizeof(char *)); + if (!*resargv) + FatalError("Out of Memory\n"); + + memcpy(*resargv, prefix_argv, prefix_argc * sizeof(char *)); + + p = buf; + for (i = 0; i < insert_argc; i++) + { + (*resargv)[prefix_argc + i] = p; + p += strlen(p) + 1; + } + + memcpy(*resargv + prefix_argc + insert_argc, + suffix_argv, suffix_argc * sizeof(char *)); + + (*resargv)[*resargc] = NULL; +} /* end InsertFileIntoCommandLine */ + + +void +ExpandCommandLine(int *pargc, char ***pargv) +{ + int i; + +#if !defined(WIN32) && !defined(__UNIXOS2__) && !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, pointer client) +{ +#define AUTHORIZATION_NAME "hp-hostname-1" +#if defined(TCPCONN) || defined(STREAMSCONN) + 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 = xalloc(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 */ +} + +/* XALLOC -- X's internal memory allocator. Why does it return unsigned + * long * instead of the more common char *? Well, if you read K&R you'll + * see they say that alloc must return a pointer "suitable for conversion" + * to whatever type you really want. In a full-blown generic allocator + * there's no way to solve the alignment problems without potentially + * wasting lots of space. But we have a more limited problem. We know + * we're only ever returning pointers to structures which will have to + * be long word aligned. So we are making a stronger guarantee. It might + * have made sense to make Xalloc return char * to conform with people's + * expectations of malloc, but this makes lint happier. + */ + +#ifndef INTERNAL_MALLOC + +void * +Xalloc(unsigned long amount) +{ + register pointer ptr; + + if ((long)amount <= 0) { + return (unsigned long *)NULL; + } + /* aligned extra on long word boundary */ + amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1); +#ifdef MEMBUG + if (!Must_have_memory && Memory_fail && + ((random() % MEM_FAIL_SCALE) < Memory_fail)) + return (unsigned long *)NULL; +#endif + if ((ptr = (pointer)malloc(amount))) { + return (unsigned long *)ptr; + } + if (Must_have_memory) + FatalError("Out of memory"); + return (unsigned long *)NULL; +} + +/***************** + * XNFalloc + * "no failure" realloc, alternate interface to Xalloc w/o Must_have_memory + *****************/ + +void * +XNFalloc(unsigned long amount) +{ + register pointer ptr; + + if ((long)amount <= 0) + { + return (unsigned long *)NULL; + } + /* aligned extra on long word boundary */ + amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1); + ptr = (pointer)malloc(amount); + if (!ptr) + { + FatalError("Out of memory"); + } + return ((unsigned long *)ptr); +} + +/***************** + * Xcalloc + *****************/ + +void * +Xcalloc(unsigned long amount) +{ + unsigned long *ret; + + ret = Xalloc (amount); + if (ret) + bzero ((char *) ret, (int) amount); + return ret; +} + +/***************** + * XNFcalloc + *****************/ + +void * +XNFcalloc(unsigned long amount) +{ + unsigned long *ret; + + ret = Xalloc (amount); + if (ret) + bzero ((char *) ret, (int) amount); + else if ((long)amount > 0) + FatalError("Out of memory"); + return ret; +} + +/***************** + * Xrealloc + *****************/ + +void * +Xrealloc(pointer ptr, unsigned long amount) +{ +#ifdef MEMBUG + if (!Must_have_memory && Memory_fail && + ((random() % MEM_FAIL_SCALE) < Memory_fail)) + return (unsigned long *)NULL; +#endif + if ((long)amount <= 0) + { + if (ptr && !amount) + free(ptr); + return (unsigned long *)NULL; + } + amount = (amount + (sizeof(long) - 1)) & ~(sizeof(long) - 1); + if (ptr) + ptr = (pointer)realloc((char *)ptr, amount); + else + ptr = (pointer)malloc(amount); + if (ptr) + return (unsigned long *)ptr; + if (Must_have_memory) + FatalError("Out of memory"); + return (unsigned long *)NULL; +} + +/***************** + * XNFrealloc + * "no failure" realloc, alternate interface to Xrealloc w/o Must_have_memory + *****************/ + +void * +XNFrealloc(pointer ptr, unsigned long amount) +{ + if (( ptr = (pointer)Xrealloc( ptr, amount ) ) == NULL) + { + if ((long)amount > 0) + FatalError( "Out of memory" ); + } + return ((unsigned long *)ptr); +} + +/***************** + * Xfree + * calls free + *****************/ + +void +Xfree(pointer ptr) +{ + if (ptr) + free((char *)ptr); +} + +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 +} +#endif /* !INTERNAL_MALLOC */ + + +char * +Xstrdup(const char *s) +{ + char *sd; + + if (s == NULL) + return NULL; + + sd = (char *)Xalloc(strlen(s) + 1); + if (sd != NULL) + strcpy(sd, s); + return sd; +} + + +char * +XNFstrdup(const char *s) +{ + char *sd; + + if (s == NULL) + return NULL; + + sd = (char *)XNFalloc(strlen(s) + 1); + strcpy(sd, s); + return sd; +} + +#ifdef SMART_SCHEDULE + +unsigned long SmartScheduleIdleCount; +Bool SmartScheduleIdle; +Bool SmartScheduleTimerStopped; + +#ifdef SIGVTALRM +#define SMART_SCHEDULE_POSSIBLE +#endif + +#ifdef SMART_SCHEDULE_POSSIBLE +#define SMART_SCHEDULE_SIGNAL SIGALRM +#define SMART_SCHEDULE_TIMER ITIMER_REAL +#endif + +static void +SmartScheduleStopTimer (void) +{ +#ifdef SMART_SCHEDULE_POSSIBLE + struct itimerval timer; + + 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); + SmartScheduleTimerStopped = TRUE; +#endif +} + +Bool +SmartScheduleStartTimer (void) +{ +#ifdef SMART_SCHEDULE_POSSIBLE + struct itimerval timer; + + SmartScheduleTimerStopped = FALSE; + 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; + return setitimer (ITIMER_REAL, &timer, 0) >= 0; +#endif + return FALSE; +} + +#ifdef SMART_SCHEDULE_POSSIBLE +static void +SmartScheduleTimer (int sig) +{ + int olderrno = errno; + + SmartScheduleTime += SmartScheduleInterval; + if (SmartScheduleIdle) + { + SmartScheduleStopTimer (); + } + errno = olderrno; +} +#endif + +Bool +SmartScheduleInit (void) +{ +#ifdef SMART_SCHEDULE_POSSIBLE + struct sigaction act; + + if (SmartScheduleDisable) + return TRUE; + + bzero ((char *) &act, sizeof(struct sigaction)); + + /* Set up the timer signal function */ + act.sa_handler = SmartScheduleTimer; + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SMART_SCHEDULE_SIGNAL); + if (sigaction (SMART_SCHEDULE_SIGNAL, &act, 0) < 0) + { + perror ("sigaction for smart scheduler"); + return FALSE; + } + /* Set up the virtual timer */ + if (!SmartScheduleStartTimer ()) + { + perror ("scheduling timer"); + return FALSE; + } + /* stop the timer and wait for WaitForSomething to start it */ + SmartScheduleStopTimer (); + return TRUE; +#else + return FALSE; +#endif +} +#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) && !defined(__UNIXOS2__) +/* + * "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; + + if (!command) + return(1); + +#ifdef SIGCHLD + csig = signal(SIGCHLD, SIG_DFL); +#endif + +#ifdef DEBUG + ErrorF("System: `%s'\n", command); +#endif + + switch (pid = fork()) { + case -1: /* error */ + p = -1; + case 0: /* child */ + 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 SIGCHLD + signal(SIGCHLD, csig); +#endif + + return p == -1 ? -1 : status; +} + +static struct pid { + struct pid *next; + FILE *fp; + int pid; +} *pidlist; + +pointer +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 *)xalloc(sizeof(struct pid))) == NULL) + return NULL; + + if (pipe(pdes) < 0) { + xfree(cur); + return NULL; + } + + switch (pid = fork()) { + case -1: /* error */ + close(pdes[0]); + close(pdes[1]); + xfree(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/sh", "sh", "-c", command, (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; +} + +/* fopen that drops privileges */ +pointer +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 *)xalloc(sizeof(struct pid))) == NULL) + return NULL; + + if (pipe(pdes) < 0) { + xfree(cur); + return NULL; + } + + switch (pid = fork()) { + case -1: /* error */ + close(pdes[0]); + close(pdes[1]); + xfree(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(pointer 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; + xfree(cur); + + /* allow EINTR again */ + OsReleaseSignals (); + + return pid == -1 ? -1 : pstat; +} + +int +Fclose(pointer iop) +{ +#ifdef HAS_SAVED_IDS_AND_SETEUID + return fclose(iop); +#else + return Pclose(iop); +#endif +} + +#endif /* !WIN32 && !__UNIXOS2__ */ + + +/* + * 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 defined(__QNX__) && !defined(__QNXNTO__) + char cmd_name[64]; +#endif + +#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/xalloc.c b/nx-X11/programs/Xserver/os/xalloc.c new file mode 100644 index 000000000..e1cdbfc5b --- /dev/null +++ b/nx-X11/programs/Xserver/os/xalloc.c @@ -0,0 +1,817 @@ +#define FATALERRORS 1 +/* +Copyright (C) 1995 Pascal Haible. 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 +PASCAL HAIBLE 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 Pascal Haible shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from +Pascal Haible. +*/ + +/* $XFree86: xc/programs/Xserver/os/xalloc.c,v 3.35tsi Exp $ */ + +/* Only used if INTERNAL_MALLOC is defined + * - otherwise xalloc() in utils.c is used + */ +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef INTERNAL_MALLOC + +#include <stdlib.h> /* for malloc() etc. */ + +#include <X11/Xos.h> +#include "misc.h" +#include <X11/X.h> + +#ifdef XALLOC_LOG +#include <stdio.h> +#endif + +extern Bool Must_have_memory; + +/* + ***** New malloc approach for the X server ***** + * Pascal Haible 1995 + * + * Some statistics about memory allocation of the X server + * The test session included several clients of different size, including + * xv, emacs and xpaint with a new canvas of 3000x2000, zoom 5. + * All clients were running together. + * A protocolling version of Xalloc recorded 318917 allocating actions + * (191573 Xalloc, 85942 XNFalloc, 41438 Xrealloc, 279727 Xfree). + * Results grouped by size, excluding the next lower size + * (i.e. size=32 means 16<size<=32): + * + * size nr of alloc max nr of blocks allocated together + * 8 1114 287 + * 16 17341 4104 + * 32 147352 2068 + * 64 59053 2518 + * 128 46882 1230 + * 256 20544 1217 + * 512 6808 117 + * 1024 8254 171 + * 2048 4841 287 + * 4096 2429 84 + * 8192 3364 85 + * 16384 573 22 + * 32768 49 7 + * 65536 45 5 + * 131072 48 2 + * 262144 209 2 + * 524288 7 4 + * 1048576 2 1 + * 8388608 2 2 + * + * The most used sizes: + * count size + * 24 136267 + * 40 37055 + * 72 17278 + * 56 13504 + * 80 9372 + * 16 8966 + * 32 8411 + * 136 8399 + * 104 7690 + * 12 7630 + * 120 5512 + * 88 4634 + * 152 3062 + * 52 2881 + * 48 2736 + * 156 1569 + * 168 1487 + * 160 1483 + * 28 1446 + * 1608 1379 + * 184 1305 + * 552 1270 + * 64 934 + * 320 891 + * 8 754 + * + * Conclusions: more than the half of all allocations are <= 32 bytes. + * But of these about 150,000 blocks, only a maximum of about 6,000 are + * allocated together (including memory leaks..). + * On the other side, only 935 of the 191573 or 0.5% were larger than 8kB + * (362 or 0.2% larger than 16k). + * + * What makes the server really grow is the fragmentation of the heap, + * and the fact that it can't shrink. + * To cure this, we do the following: + * - large blocks (>=11k) are mmapped on xalloc, and unmapped on xfree, + * so we don't need any free lists etc. + * As this needs 2 system calls, we only do this for the quite + * infrequent large (>=11k) blocks. + * - instead of reinventing the wheel, we use system malloc for medium + * sized blocks (>256, <11k). + * - for small blocks (<=256) we use an other approach: + * As we need many small blocks, and most ones for a short time, + * we don't go through the system malloc: + * for each fixed sizes a seperate list of free blocks is kept. + * to KISS (Keep it Small and Simple), we don't free them + * (not freeing a block of 32 bytes won't be worse than having fragmented + * a larger area on allocation). + * This way, we (almost) allways have a fitting free block right at hand, + * and don't have to walk any lists. + */ + +/* + * structure layout of a allocated block + * unsigned long size: + * rounded up netto size for small and medium blocks + * brutto size == mmap'ed area for large blocks + * unsigned long DEBUG ? MAGIC : unused + * .... data + * ( unsigned long MAGIC2 ) only if SIZE_TAIL defined + * + */ + +/* use otherwise unused long in the header to store a magic */ +/* shouldn't this be removed for production release ? */ +#define XALLOC_DEBUG + +#ifdef XALLOC_DEBUG +/* Xfree fills the memory with a certain pattern (currently 0xF0) */ +/* this should really be removed for production release! */ +#define XFREE_ERASES +#endif + +/* this must be a multiple of SIZE_STEPS below */ +#define MAX_SMALL 264 /* quite many blocks of 264 */ + +#define MIN_LARGE (11*1024) +/* worst case is 25% loss with a page size of 4k */ + +/* SIZE_STEPS defines the granularity of size of small blocks - + * this makes blocks align to that, too! */ +#define SIZE_STEPS (sizeof(double)) +#define SIZE_HEADER (2*sizeof(long)) /* = sizeof(double) for 32bit */ +#ifdef XALLOC_DEBUG +#if defined(__sparc__) +#define SIZE_TAIL (2*sizeof(long)) /* = sizeof(double) for 32bit */ +#else +#define SIZE_TAIL (sizeof(long)) +#endif +#endif + +#undef TAIL_SIZE +#ifdef SIZE_TAIL +#define TAIL_SIZE SIZE_TAIL +#else +#define TAIL_SIZE 0 +#endif + +#if defined (_LP64) || \ + defined(__alpha__) || defined(__alpha) || \ + defined(__ia64__) || defined(ia64) || \ + defined(__sparc64__) || \ + defined(__s390x__) || \ + defined(__amd64__) || defined(amd64) || \ + defined(__powerpc64__) || \ + (defined(sgi) && _MIPS_SZLONG == 64)) +#define MAGIC 0x1404196414071968 +#define MAGIC_FREE 0x1506196615061966 +#define MAGIC2 0x2515207525182079 +#else +#define MAGIC 0x14071968 +#define MAGIC_FREE 0x15061966 +#define MAGIC2 0x25182079 +#endif + +/* To get some statistics about memory allocation */ + +#ifdef XALLOC_LOG +#define XALLOC_LOG_FILE "/tmp/Xalloc.log" /* unsecure... */ +#define LOG_BODY(_body) \ + { FILE *f; \ + f = fopen(XALLOC_LOG_FILE, "a"); \ + if (NULL!=f) { \ + _body; \ + fclose(f); \ + } \ + } +#if defined(linux) && defined(i386) +#define LOG_ALLOC(_fun, _size, _ret) \ + { unsigned long *from; \ + __asm__("movl %%ebp,%0" : /*OUT*/ "=r" (from) : /*IN*/ ); \ + LOG_BODY(fprintf(f, "%s\t%i\t%p\t[%lu]\n", _fun, _size, _ret, *(from+1))) \ + } +#else +#define LOG_ALLOC(_fun, _size, _ret) \ + LOG_BODY(fprintf(f, "%s\t%i\t%p\n", _fun, _size, _ret)) +#endif +#define LOG_REALLOC(_fun, _ptr, _size, _ret) \ + LOG_BODY(fprintf(f, "%s\t%p\t%i\t%p\n", _fun, _ptr, _size, _ret)) +#define LOG_FREE(_fun, _ptr) \ + LOG_BODY(fprintf(f, "%s\t%p\n", _fun, _ptr)) +#else +#define LOG_ALLOC(_fun, _size, _ret) +#define LOG_REALLOC(_fun, _ptr, _size, _ret) +#define LOG_FREE(_fun, _ptr) +#endif /* XALLOC_LOG */ + +static unsigned long *free_lists[MAX_SMALL/SIZE_STEPS]; + +/* + * systems that support it should define HAS_MMAP_ANON or MMAP_DEV_ZERO + * and include the appropriate header files for + * mmap(), munmap(), PROT_READ, PROT_WRITE, MAP_PRIVATE, + * PAGE_SIZE or _SC_PAGESIZE (and MAP_ANON for HAS_MMAP_ANON). + * + * systems that don't support MAP_ANON fall through to the 2 fold behaviour + */ + +#if defined(linux) +#define HAS_MMAP_ANON +#include <sys/types.h> +#include <sys/mman.h> +#include <asm/page.h> /* PAGE_SIZE */ +#define HAS_SC_PAGESIZE /* _SC_PAGESIZE may be an enum for Linux */ +#define HAS_GETPAGESIZE +#endif /* linux */ + +#if defined(__GNU__) +#define HAS_MMAP_ANON +#include <sys/types.h> +#include <sys/mman.h> +#include <mach/vm_param.h> /* PAGE_SIZE */ +#define HAS_SC_PAGESIZE +#define HAS_GETPAGESIZE +#endif /* __GNU__ */ + +#if defined(CSRG_BASED) +#define HAS_MMAP_ANON +#define HAS_GETPAGESIZE +#include <sys/types.h> +#include <sys/mman.h> +#endif /* CSRG_BASED */ + +#if defined(DGUX) +#define HAS_GETPAGESIZE +#define MMAP_DEV_ZERO +#include <sys/types.h> +#include <sys/mman.h> +#include <unistd.h> +#endif /* DGUX */ + +#if defined(SVR4) && !defined(DGUX) +#define MMAP_DEV_ZERO +#include <sys/types.h> +#include <sys/mman.h> +#include <unistd.h> +#endif /* SVR4 && !DGUX */ + +#if defined(sun) && !defined(SVR4) /* SunOS */ +#define MMAP_DEV_ZERO /* doesn't SunOS have MAP_ANON ?? */ +#define HAS_GETPAGESIZE +#include <sys/types.h> +#include <sys/mman.h> +#endif /* sun && !SVR4 */ + +#ifdef XNO_SYSCONF +#undef _SC_PAGESIZE +#endif + +#if defined(HAS_MMAP_ANON) || defined (MMAP_DEV_ZERO) +static int pagesize; +#endif + +#ifdef MMAP_DEV_ZERO +static int devzerofd = -1; +#include <errno.h> +#endif + +/* + * empty trap function for gdb. Breakpoint here + * to find who tries to free a free area + */ +void XfreeTrap(void) +{ +} + +void * +Xalloc (unsigned long amount) +{ + register unsigned long *ptr; + int indx; + + /* sanity checks */ + + /* zero size requested */ + if (amount == 0) { + LOG_ALLOC("Xalloc=0", amount, 0); + return NULL; + } + /* negative size (or size > 2GB) - what do we do? */ + if ((long)amount < 0) { + /* Diagnostic */ +#ifdef FATALERRORS + FatalError("Xalloc: Xalloc(<0)\n"); +#else + ErrorF("Xalloc warning: Xalloc(<0) ignored..\n"); +#endif + LOG_ALLOC("Xalloc<0", amount, 0); + return NULL; + } + + /* alignment check */ +#if defined(__alpha__) || defined(__alpha) || \ + defined(__sparc__) || \ + defined(__mips__) || \ + defined(__powerpc__) || \ + defined(__arm32__) || \ + defined(__ia64__) || defined(ia64) || \ + defined(__s390x__) || defined(__s390__) + amount = (amount + (sizeof(long)-1)) & ~(sizeof(long)-1); +#endif + + if (amount <= MAX_SMALL) { + /* + * small block + */ + /* pick a ready to use small chunk */ + indx = (amount-1) / SIZE_STEPS; + ptr = free_lists[indx]; + if (NULL == ptr) { + /* list empty - get 20 or 40 more */ + /* amount = size rounded up */ + amount = (indx+1) * SIZE_STEPS; + ptr = (unsigned long *)calloc(1,(amount+SIZE_HEADER+TAIL_SIZE) + * (amount<100 ? 40 : 20)); + if (NULL!=ptr) { + int i; + unsigned long *p1, *p2; + p1 = 0; + p2 = (unsigned long *)((char *)ptr + SIZE_HEADER); + for (i=0; i<(amount<100 ? 40 : 20); i++) { + p1 = p2; + p1[-2] = amount; +#ifdef XALLOC_DEBUG + p1[-1] = MAGIC_FREE; +#endif /* XALLOC_DEBUG */ +#ifdef SIZE_TAIL + *(unsigned long *)((unsigned char *)p1 + amount) = MAGIC2; +#endif /* SIZE_TAIL */ + p2 = (unsigned long *)((char *)p1 + SIZE_HEADER + amount + TAIL_SIZE); + *(unsigned long **)p1 = p2; + } + /* last one has no next one */ + *(unsigned long **)p1 = NULL; + /* put the second in the list */ + free_lists[indx] = (unsigned long *)((char *)ptr + SIZE_HEADER + amount + TAIL_SIZE + SIZE_HEADER); + /* take the fist one */ + ptr = (unsigned long *)((char *)ptr + SIZE_HEADER); + LOG_ALLOC("Xalloc-S", amount, ptr); + ptr[-1] = MAGIC; + return (void *)ptr; + } /* else fall through to 'Out of memory' */ + } else { + /* take that piece of mem out of the list */ + free_lists[indx] = *((unsigned long **)ptr); + /* already has size (and evtl. magic) filled in */ +#ifdef XALLOC_DEBUG + ptr[-1] = MAGIC; +#endif /* XALLOC_DEBUG */ + LOG_ALLOC("Xalloc-S", amount, ptr); + return (void *)ptr; + } + +#if defined(HAS_MMAP_ANON) || defined(MMAP_DEV_ZERO) + } else if (amount >= MIN_LARGE) { + /* + * large block + */ + /* mmapped malloc */ + /* round up amount */ + amount += SIZE_HEADER + TAIL_SIZE; + /* round up brutto amount to a multiple of the page size */ + amount = (amount + pagesize-1) & ~(pagesize-1); +#ifdef MMAP_DEV_ZERO + ptr = (unsigned long *)mmap((caddr_t)0, + (size_t)amount, + PROT_READ | PROT_WRITE, + MAP_PRIVATE, + devzerofd, + (off_t)0); +#else + ptr = (unsigned long *)mmap((caddr_t)0, + (size_t)amount, + PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, + -1, + (off_t)0); +#endif + if (-1!=(long)ptr) { + ptr[0] = amount - SIZE_HEADER - TAIL_SIZE; +#ifdef XALLOC_DEBUG + ptr[1] = MAGIC; +#endif /* XALLOC_DEBUG */ +#ifdef SIZE_TAIL + ((unsigned long *)((char *)ptr + amount - TAIL_SIZE))[0] = MAGIC2; +#endif /* SIZE_TAIL */ + ptr = (unsigned long *)((char *)ptr + SIZE_HEADER); + LOG_ALLOC("Xalloc-L", amount, ptr); + return (void *)ptr; + } /* else fall through to 'Out of memory' */ +#endif /* HAS_MMAP_ANON || MMAP_DEV_ZERO */ + } else { + /* + * medium sized block + */ + /* 'normal' malloc() */ + ptr=(unsigned long *)calloc(1,amount+SIZE_HEADER+TAIL_SIZE); + if (ptr != (unsigned long *)NULL) { + ptr[0] = amount; +#ifdef XALLOC_DEBUG + ptr[1] = MAGIC; +#endif /* XALLOC_DEBUG */ +#ifdef SIZE_TAIL + *(unsigned long *)((char *)ptr + amount + SIZE_HEADER) = MAGIC2; +#endif /* SIZE_TAIL */ + ptr = (unsigned long *)((char *)ptr + SIZE_HEADER); + LOG_ALLOC("Xalloc-M", amount, ptr); + return (void *)ptr; + } + } + if (Must_have_memory) + FatalError("Out of memory"); + LOG_ALLOC("Xalloc-oom", amount, 0); + return NULL; +} + +/***************** + * XNFalloc + * "no failure" realloc, alternate interface to Xalloc w/o Must_have_memory + *****************/ + +pointer +XNFalloc (unsigned long amount) +{ + register pointer ptr; + + /* zero size requested */ + if (amount == 0) { + LOG_ALLOC("XNFalloc=0", amount, 0); + return NULL; + } + /* negative size (or size > 2GB) - what do we do? */ + if ((long)amount < 0) { + /* Diagnostic */ +#ifdef FATALERRORS + FatalError("Xalloc: XNFalloc(<0)\n"); +#else + ErrorF("Xalloc warning: XNFalloc(<0) ignored..\n"); +#endif + LOG_ALLOC("XNFalloc<0", amount, 0); + return (unsigned long *)NULL; + } + ptr = Xalloc(amount); + if (!ptr) + { + FatalError("Out of memory"); + } + return ptr; +} + +/***************** + * Xcalloc + *****************/ + +pointer +Xcalloc (unsigned long amount) +{ + pointer ret; + + ret = Xalloc (amount); + if (ret != 0 +#if defined(HAS_MMAP_ANON) || defined(MMAP_DEV_ZERO) + && (amount < MIN_LARGE) /* mmaped anonymous mem is already cleared */ +#endif + ) + bzero ((char *) ret, (int) amount); + return ret; +} + +/***************** + * XNFcalloc + *****************/ +void * +XNFcalloc (unsigned long amount) +{ + pointer ret; + + ret = XNFalloc (amount); + if (ret != 0 +#if defined(HAS_MMAP_ANON) || defined(MMAP_DEV_ZERO) + && (amount < MIN_LARGE) /* mmaped anonymous mem is already cleared */ +#endif + ) + bzero ((char *) ret, (int) amount); + return ret; +} + +/***************** + * Xrealloc + *****************/ + +void * +Xrealloc (pointer ptr, unsigned long amount) +{ + register unsigned long *new_ptr; + + /* zero size requested */ + if (amount == 0) { + if (ptr) + Xfree(ptr); + LOG_REALLOC("Xrealloc=0", ptr, amount, 0); + return NULL; + } + /* negative size (or size > 2GB) - what do we do? */ + if ((long)amount < 0) { + /* Diagnostic */ +#ifdef FATALERRORS + FatalError("Xalloc: Xrealloc(<0)\n"); +#else + ErrorF("Xalloc warning: Xrealloc(<0) ignored..\n"); +#endif + if (ptr) + Xfree(ptr); /* ?? */ + LOG_REALLOC("Xrealloc<0", ptr, amount, 0); + return NULL; + } + + new_ptr = Xalloc(amount); + if ( (new_ptr) && (ptr) ) { + unsigned long old_size; + old_size = ((unsigned long *)ptr)[-2]; +#ifdef XALLOC_DEBUG + if (MAGIC != ((unsigned long *)ptr)[-1]) { + if (MAGIC_FREE == ((unsigned long *)ptr)[-1]) { +#ifdef FATALERRORS + XfreeTrap(); + FatalError("Xalloc error: range already freed in Xrealloc() :-(\n"); +#else + ErrorF("Xalloc error: range already freed in Xrealloc() :-(\a\n"); + sleep(5); + XfreeTrap(); +#endif + LOG_REALLOC("Xalloc error: ranged already freed in Xrealloc() :-(", + ptr, amount, 0); + return NULL; + } +#ifdef FATALERRORS + XfreeTrap(); + FatalError("Xalloc error: header corrupt in Xrealloc() :-(\n"); +#else + ErrorF("Xalloc error: header corrupt in Xrealloc() :-(\n"); + XfreeTrap(); +#endif + LOG_REALLOC("Xalloc error: header corrupt in Xrealloc() :-(", + ptr, amount, 0); + return NULL; + } +#endif /* XALLOC_DEBUG */ + /* copy min(old size, new size) */ + memcpy((char *)new_ptr, (char *)ptr, (amount < old_size ? amount : old_size)); + } + if (ptr) + Xfree(ptr); + if (new_ptr) { + LOG_REALLOC("Xrealloc", ptr, amount, new_ptr); + return (void *)new_ptr; + } + if (Must_have_memory) + FatalError("Out of memory"); + LOG_REALLOC("Xrealloc", ptr, amount, 0); + return NULL; +} + +/***************** + * XNFrealloc + * "no failure" realloc, alternate interface to Xrealloc w/o Must_have_memory + *****************/ + +void * +XNFrealloc (pointer ptr, unsigned long amount) +{ + if (( ptr = (pointer)Xrealloc( ptr, amount ) ) == NULL) + { + FatalError( "Out of memory" ); + } + return ptr; +} + +/***************** + * Xfree + * calls free + *****************/ + +void +Xfree(pointer ptr) +{ + unsigned long size; + unsigned long *pheader; + + /* free(NULL) IS valid :-( - and widely used throughout the server.. */ + if (!ptr) + return; + + pheader = (unsigned long *)((char *)ptr - SIZE_HEADER); +#ifdef XALLOC_DEBUG + if (MAGIC != pheader[1]) { + /* Diagnostic */ + if (MAGIC_FREE == pheader[1]) { +#ifdef FATALERRORS + XfreeTrap(); + FatalError("Xalloc error: range already freed in Xrealloc() :-(\n"); +#else + ErrorF("Xalloc error: range already freed in Xrealloc() :-(\a\n"); + sleep(5); + XfreeTrap(); +#endif + LOG_FREE("Xalloc error: ranged already freed in Xrealloc() :-(", ptr); + return; + } +#ifdef FATALERRORS + XfreeTrap(); + FatalError("Xalloc error: Header corrupt in Xfree() :-(\n"); +#else + ErrorF("Xalloc error: Header corrupt in Xfree() :-(\n"); + XfreeTrap(); +#endif + LOG_FREE("Xalloc error: Header corrupt in Xfree() :-(", ptr); + return; + } +#endif /* XALLOC_DEBUG */ + + size = pheader[0]; + if (size <= MAX_SMALL) { + int indx; + /* + * small block + */ +#ifdef SIZE_TAIL + if (MAGIC2 != *(unsigned long *)((char *)ptr + size)) { + /* Diagnostic */ +#ifdef FATALERRORS + XfreeTrap(); + FatalError("Xalloc error: Tail corrupt in Xfree() for small block (adr=0x%x, val=0x%x)\n",(char *)ptr + size,*(unsigned long *)((char *)ptr + size)); +#else + ErrorF("Xalloc error: Tail corrupt in Xfree() for small block (adr=0x%x, val=0x%x)\n",(char *)ptr + size,*(unsigned long *)((char *)ptr + size)); + XfreeTrap(); +#endif + LOG_FREE("Xalloc error: Tail corrupt in Xfree() for small block", ptr); + return; + } +#endif /* SIZE_TAIL */ + +#ifdef XFREE_ERASES + memset(ptr,0xF0,size); +#endif /* XFREE_ERASES */ +#ifdef XALLOC_DEBUG + pheader[1] = MAGIC_FREE; +#endif + /* put this small block at the head of the list */ + indx = (size-1) / SIZE_STEPS; + *(unsigned long **)(ptr) = free_lists[indx]; + free_lists[indx] = (unsigned long *)ptr; + LOG_FREE("Xfree", ptr); + return; + +#if defined(HAS_MMAP_ANON) || defined(MMAP_DEV_ZERO) + } else if (size >= MIN_LARGE) { + /* + * large block + */ +#ifdef SIZE_TAIL + if (MAGIC2 != ((unsigned long *)((char *)ptr + size))[0]) { + /* Diagnostic */ +#ifdef FATALERRORS + XfreeTrap(); + FatalError("Xalloc error: Tail corrupt in Xfree() for big block (adr=0x%x, val=0x%x)\n",(char *)ptr+size,((unsigned long *)((char *)ptr + size))[0]); +#else + ErrorF("Xalloc error: Tail corrupt in Xfree() for big block (adr=0x%x, val=0x%x)\n",(char *)ptr+size,((unsigned long *)((char *)ptr + size))[0]); + XfreeTrap(); +#endif + LOG_FREE("Xalloc error: Tail corrupt in Xfree() for big block", ptr); + return; + } + size += SIZE_TAIL; +#endif /* SIZE_TAIL */ + + LOG_FREE("Xfree", ptr); + size += SIZE_HEADER; + munmap((caddr_t)pheader, (size_t)size); + /* no need to clear - mem is inaccessible after munmap.. */ +#endif /* HAS_MMAP_ANON */ + + } else { + /* + * medium sized block + */ +#ifdef SIZE_TAIL + if (MAGIC2 != *(unsigned long *)((char *)ptr + size)) { + /* Diagnostic */ +#ifdef FATALERRORS + XfreeTrap(); + FatalError("Xalloc error: Tail corrupt in Xfree() for medium block (adr=0x%x, val=0x%x)\n",(char *)ptr + size,*(unsigned long *)((char *)ptr + size)); +#else + ErrorF("Xalloc error: Tail corrupt in Xfree() for medium block (adr=0x%x, val=0x%x)\n",(char *)ptr + size,*(unsigned long *)((char *)ptr + size)); + XfreeTrap(); +#endif + LOG_FREE("Xalloc error: Tail corrupt in Xfree() for medium block", ptr); + return; + } +#endif /* SIZE_TAIL */ + +#ifdef XFREE_ERASES + memset(pheader,0xF0,size+SIZE_HEADER); +#endif /* XFREE_ERASES */ +#ifdef XALLOC_DEBUG + pheader[1] = MAGIC_FREE; +#endif + + LOG_FREE("Xfree", ptr); + free((char *)pheader); + } +} + +void +OsInitAllocator (void) +{ + static Bool beenhere = FALSE; + + if (beenhere) + return; + beenhere = TRUE; + +#if defined(HAS_MMAP_ANON) || defined (MMAP_DEV_ZERO) + pagesize = -1; +#if defined(_SC_PAGESIZE) || defined(HAS_SC_PAGESIZE) + pagesize = sysconf(_SC_PAGESIZE); +#endif +#ifdef _SC_PAGE_SIZE + if (pagesize == -1) + pagesize = sysconf(_SC_PAGE_SIZE); +#endif +#ifdef HAS_GETPAGESIZE + if (pagesize == -1) + pagesize = getpagesize(); +#endif +#ifdef PAGE_SIZE + if (pagesize == -1) + pagesize = PAGE_SIZE; +#endif + if (pagesize == -1) + FatalError("OsInitAllocator: Cannot determine page size\n"); +#endif + + /* set up linked lists of free blocks */ + bzero ((char *) free_lists, MAX_SMALL/SIZE_STEPS*sizeof(unsigned long *)); + +#ifdef MMAP_DEV_ZERO + /* open /dev/zero on systems that have mmap, but not MAP_ANON */ + if (devzerofd < 0) { + if ((devzerofd = open("/dev/zero", O_RDWR, 0)) < 0) + FatalError("OsInitAllocator: Cannot open /dev/zero (errno=%d)\n", + errno); + } +#endif + +#ifdef XALLOC_LOG + /* reset the log file to zero length */ + { + FILE *f; + f = fopen(XALLOC_LOG_FILE, "w"); + if (NULL!=f) + fclose(f); + } +#endif +} + +#else /* !INTERNAL_MALLOC */ +/* This is to avoid an empty .o */ +static int no_internal_xalloc; +#endif /* INTERNAL_MALLOC */ diff --git a/nx-X11/programs/Xserver/os/xdmauth.c b/nx-X11/programs/Xserver/os/xdmauth.c new file mode 100644 index 000000000..e02ca349c --- /dev/null +++ b/nx-X11/programs/Xserver/os/xdmauth.c @@ -0,0 +1,502 @@ +/* $Xorg: xdmauth.c,v 1.4 2001/02/09 02:05:24 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ +/* $XFree86: xdmauth.c,v 1.7 2002/11/05 05:50:34 keithp Exp $ */ + +/* + * 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 <X11/X.h> +#include <X11/Xtrans/Xtrans.h> +#include "os.h" +#include "osdep.h" +#include "dixstruct.h" + +#ifdef HASXDMAUTH + +static Bool authFromXDMCP; + +#ifdef XDMCP +#include <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, &privateKey, + incomingData->data,incomingData->length); + switch (packet_type) + { + case ACCEPT: + if (incomingData->length != 8) + return FALSE; + incoming = (XdmAuthKeyPtr) incomingData->data; + XdmcpDecrementKey (incoming); + return XdmcpCompareKeys (incoming, &rho); + } + return FALSE; +} + +static Bool +XdmAuthenticationGenerator (ARRAY8Ptr privateData, ARRAY8Ptr outgoingData, + xdmOpCode packet_type) +{ + outgoingData->length = 0; + outgoingData->data = 0; + switch (packet_type) + { + case REQUEST: + if (XdmcpAllocARRAY8 (outgoingData, 8)) + XdmcpWrap (&rho, &privateKey, outgoingData->data, 8); + } + return TRUE; +} + +static Bool +XdmAuthenticationAddAuth (int name_len, char *name, + int data_len, char *data) +{ + Bool ret; + XdmcpUnwrap (data, (unsigned char *)&privateKey, data, data_len); + authFromXDMCP = TRUE; + ret = AddAuthorization (name_len, name, data_len, data); + authFromXDMCP = FALSE; + return ret; +} + + +#define atox(c) ('0' <= c && c <= '9' ? c - '0' : \ + 'a' <= c && c <= 'f' ? c - 'a' + 10 : \ + 'A' <= c && c <= 'F' ? c - 'A' + 10 : -1) + +static int +HexToBinary (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, + (unsigned char *)&rho, + sizeof (rho), + XdmAuthenticationValidator, + XdmAuthenticationGenerator, + XdmAuthenticationAddAuth); +} + +#endif /* XDMCP */ + +/* XDM-AUTHORIZATION-1 */ +typedef struct _XdmAuthorization { + struct _XdmAuthorization *next; + XdmAuthKeyRec rho; + XdmAuthKeyRec key; + XID id; +} XdmAuthorizationRec, *XdmAuthorizationPtr; + +static XdmAuthorizationPtr xdmAuth; + +typedef struct _XdmClientAuth { + struct _XdmClientAuth *next; + XdmAuthKeyRec rho; + char client[6]; + long time; +} XdmClientAuthRec, *XdmClientAuthPtr; + +static XdmClientAuthPtr xdmClients; +static long clockOffset; +static Bool gotClock; + +#define TwentyMinutes (20 * 60) +#define TwentyFiveMinutes (25 * 60) + +static Bool +XdmClientAuthCompare (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; + xfree (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) xalloc (sizeof (XdmClientAuthRec)); + if (!client) + return NULL; + XdmClientAuthDecode (plain, client); + if (!XdmcpCompareKeys (&client->rho, rho)) + { + xfree (client); + if (reason) + *reason = "Invalid XDM-AUTHORIZATION-1 key (failed key comparison)"; + return NULL; + } + for (i = 18; i < 24; i++) + if (plain[i] != 0) { + xfree (client); + if (reason) + *reason = "Invalid XDM-AUTHORIZATION-1 key (failed NULL check)"; + return NULL; + } + if (xclient) { + int family, addr_len; + Xtransaddr *addr; + + if (_XSERVTransGetPeerAddr(((OsCommPtr)xclient->osPrivate)->trans_conn, + &family, &addr_len, &addr) == 0 + && _XSERVTransConvertAddress(&family, &addr_len, &addr) == 0) { +#if defined(TCPCONN) || defined(STREAMSCONN) + if (family == FamilyInternet && + memcmp((char *)addr, client->client, 4) != 0) { + xfree (client); + xfree (addr); + if (reason) + *reason = "Invalid XDM-AUTHORIZATION-1 key (failed address comparison)"; + return NULL; + + } +#endif + xfree (addr); + } + } + now = time(0); + if (!gotClock) + { + clockOffset = client->time - now; + gotClock = TRUE; + } + now += clockOffset; + XdmClientAuthTimeout (now); + if (abs (client->time - now) > TwentyMinutes) + { + xfree (client); + if (reason) + *reason = "Excessive XDM-AUTHORIZATION-1 time offset"; + return NULL; + } + for (existing = xdmClients; existing; existing=existing->next) + { + if (XdmClientAuthCompare (existing, client)) + { + xfree (client); + if (reason) + *reason = "XDM authorization key matches an existing client!"; + return NULL; + } + } + return client; +} + +int +XdmAddCookie (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) xalloc (sizeof (XdmAuthorizationRec)); + if (!new) + return 0; + new->next = xdmAuth; + xdmAuth = new; + memmove (new->key.data, key_bits, (int) 8); + memmove (new->rho.data, rho_bits, (int) 8); + new->id = id; + return 1; +} + +XID +XdmCheckCookie (unsigned short cookie_length, char *cookie, + ClientPtr xclient, char **reason) +{ + XdmAuthorizationPtr auth; + XdmClientAuthPtr client; + unsigned char *plain; + + /* Auth packets must be a multiple of 8 bytes long */ + if (cookie_length & 7) + return (XID) -1; + plain = (unsigned char *) xalloc (cookie_length); + if (!plain) + return (XID) -1; + for (auth = xdmAuth; auth; auth=auth->next) { + XdmcpUnwrap (cookie, (unsigned char *)&auth->key, plain, cookie_length); + if ((client = XdmAuthorizationValidate (plain, cookie_length, &auth->rho, xclient, reason)) != NULL) + { + client->next = xdmClients; + xdmClients = client; + xfree (plain); + return auth->id; + } + } + xfree (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; + xfree (auth); + } + xdmAuth = 0; + for (client = xdmClients; client; client=next_client) + { + next_client = client->next; + xfree (client); + } + xdmClients = (XdmClientAuthPtr) 0; + return 1; +} + +XID +XdmToID (unsigned short cookie_length, char *cookie) +{ + XdmAuthorizationPtr auth; + XdmClientAuthPtr client; + unsigned char *plain; + + plain = (unsigned char *) xalloc (cookie_length); + if (!plain) + return (XID) -1; + for (auth = xdmAuth; auth; auth=auth->next) { + XdmcpUnwrap (cookie, (unsigned char *)&auth->key, plain, cookie_length); + if ((client = XdmAuthorizationValidate (plain, cookie_length, &auth->rho, NULL, NULL)) != NULL) + { + xfree (client); + xfree (cookie); + return auth->id; + } + } + xfree (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; + xfree (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..032d58f15 --- /dev/null +++ b/nx-X11/programs/Xserver/os/xdmcp.c @@ -0,0 +1,1710 @@ +/* $XdotOrg: xc/programs/Xserver/os/xdmcp.c,v 1.10 2005/07/03 08:53:52 daniels Exp $ */ +/* $Xorg: xdmcp.c,v 1.4 2001/01/31 13:37:19 pookie Exp $ */ +/* + * Copyright 1989 Network Computing Devices, Inc., Mountain View, California. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of N.C.D. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. N.C.D. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + */ +/* $XFree86: xc/programs/Xserver/os/xdmcp.c,v 3.31 2003/12/30 21:24:32 herrb Exp $ */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif + +#include <X11/Xos.h> + +#if !defined(WIN32) +#ifndef Lynx +#include <sys/param.h> +#include <sys/socket.h> +#else +#include <socket.h> +#endif +#include <netinet/in.h> +#include <netdb.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <X11/X.h> +#include <X11/Xmd.h> +#include "misc.h" +#include <X11/Xpoll.h> +#include "osdep.h" +#include "input.h" +#include "dixstruct.h" +#include "opaque.h" + +#if defined(DGUX) +#include <net/net_ioctl.h> +#include <sys/ioctl.h> +#endif + +#ifdef STREAMSCONN +#include <tiuser.h> +#include <netconfig.h> +#include <netdir.h> +#endif + +#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 <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 CARD32 defaultKeepaliveDormancy = XDM_DEF_DORMANCY; +static CARD32 keepaliveDormancy = XDM_DEF_DORMANCY; +static CARD16 DisplayNumber; +static xdmcp_states XDM_INIT_STATE = XDM_OFF; +#ifdef HASXDMAUTH +static char *xdmAuthCookie; +#endif + +static XdmcpBuffer buffer; + +#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 restart(void); + +static void XdmcpBlockHandler( + pointer /*data*/, + struct timeval ** /*wt*/, + pointer /*LastSelectMask*/); + +static void XdmcpWakeupHandler( + pointer /*data*/, + int /*i*/, + pointer /*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) xalloc ( + (AuthenticationNames.length + 1) * sizeof (AuthenticationFuncsRec))))) + { + XdmcpDisposeARRAY8 (&AuthenticationName); + XdmcpDisposeARRAY8 (&AuthenticationData); + return; + } + for (i = 0; i < AuthenticationNames.length - 1; i++) + newFuncs[i] = AuthenticationFuncsList[i]; + newFuncs[AuthenticationNames.length-1].Validator = Validator; + newFuncs[AuthenticationNames.length-1].Generator = Generator; + newFuncs[AuthenticationNames.length-1].AddAuth = AddAuth; + xfree (AuthenticationFuncsList); + AuthenticationFuncsList = newFuncs; + AuthenticationNames.data[AuthenticationNames.length-1] = AuthenticationName; + AuthenticationDatas.data[AuthenticationDatas.length-1] = AuthenticationData; +} + +/* + * Select the authentication type to be used; this is + * set by the manager of the host to be connected to. + */ + +ARRAY8 noAuthenticationName = {(CARD16) 0, (CARD8Ptr) 0}; +ARRAY8 noAuthenticationData = {(CARD16) 0, (CARD8Ptr) 0}; +ARRAY8Ptr AuthenticationName = &noAuthenticationName; +ARRAY8Ptr AuthenticationData = &noAuthenticationData; +AuthenticationFuncsPtr AuthenticationFuncs; + +void +XdmcpSetAuthentication (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 *) xalloc (addrlen * sizeof (CARD8)); + if (!newAddress) + return; + if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1)) + { + xfree (newAddress); + return; + } + if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses, + ConnectionAddresses.length + 1)) + { + xfree (newAddress); + return; + } + ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type; + for (i = 0; i < addrlen; i++) + newAddress[i] = address[i]; + ConnectionAddresses.data[ConnectionAddresses.length-1].data = newAddress; + ConnectionAddresses.data[ConnectionAddresses.length-1].length = addrlen; +} + +/* + * Register an Authorization Name. XDMCP advertises this list + * to the manager. + */ + +static ARRAYofARRAY8 AuthorizationNames; + +void +XdmcpRegisterAuthorizations (void) +{ + XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames); + RegisterAuthorizations (); +} + +void +XdmcpRegisterAuthorization (char *name, int namelen) +{ + ARRAY8 authName; + int i; + + authName.data = (CARD8 *) xalloc (namelen * sizeof (CARD8)); + if (!authName.data) + return; + if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1)) + { + xfree (authName.data); + return; + } + for (i = 0; i < namelen; i++) + authName.data[i] = (CARD8) name[i]; + authName.length = namelen; + AuthorizationNames.data[AuthorizationNames.length-1] = authName; +} + +/* + * Register the DisplayClass string + */ + +ARRAY8 DisplayClass; + +void +XdmcpRegisterDisplayClass (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, + (pointer) 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, + (pointer) 0); + timeOutRtx = 0; + send_packet(); + } +} + +/* + * Called whenever a new connection is created; notices the + * first connection and saves it to terminate the session + * when it is closed + */ + +void +XdmcpOpenDisplay(int sock) +{ + if (state != XDM_AWAIT_MANAGE_RESPONSE) + return; + state = XDM_RUN_SESSION; + 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( + pointer data, /* unused */ + struct timeval **wt, + pointer 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( + pointer data, /* unused */ + int i, + pointer pReadmask) +{ + fd_set* LastSelectMask = (fd_set*)pReadmask; + fd_set devicesReadable; + +#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 + XFD_ANDSET(&devicesReadable, LastSelectMask, &EnabledDevices); + if (XFD_ANYSET(&devicesReadable)) + { + if (state == XDM_AWAIT_USER_INPUT) + restart(); + else if (state == XDM_RUN_SESSION) + keepaliveDormancy = defaultKeepaliveDormancy; + } + if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION) + timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000; + } + else if (timeOutTime && (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(); +} + +static void +restart(void) +{ + state = XDM_INIT_STATE; + timeOutRtx = 0; + 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) +{ +#ifdef STREAMSCONN + struct netconfig *nconf; + + if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) { + XdmcpWarning("t_open() of /dev/udp failed"); + return; + } + + if( t_bind(xdmcpSocket,NULL,NULL) < 0 ) { + XdmcpWarning("UDP socket creation failed"); + t_error("t_bind(xdmcpSocket) failed" ); + t_close(xdmcpSocket); + return; + } + + /* + * This part of the code looks contrived. It will actually fit in nicely + * when the CLTS part of Xtrans is implemented. + */ + + if( (nconf=getnetconfigent("udp")) == NULL ) { + XdmcpWarning("UDP socket creation failed: getnetconfigent()"); + t_unbind(xdmcpSocket); + t_close(xdmcpSocket); + return; + } + + if( netdir_options(nconf, ND_SET_BROADCAST, xdmcpSocket, NULL) ) { + XdmcpWarning("UDP set broadcast option failed: netdir_options()"); + freenetconfigent(nconf); + t_unbind(xdmcpSocket); + t_close(xdmcpSocket); + return; + } + + freenetconfigent(nconf); +#else + 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); + } + } +#endif /* STREAMSCONN */ +} + +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) + { + /* backoff dormancy period */ + state = XDM_RUN_SESSION; + if ((GetTimeInMillis() - lastDeviceEventTime.milliseconds) > + keepaliveDormancy * 1000) + { + keepaliveDormancy <<= 1; + if (keepaliveDormancy > XDM_MAX_DORMANCY) + keepaliveDormancy = XDM_MAX_DORMANCY; + } + timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000; + } + else + { + XdmcpDeadSession ("Alive 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) || defined(DNETCONN)) + _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/xdmcp.c.NX.original b/nx-X11/programs/Xserver/os/xdmcp.c.NX.original new file mode 100644 index 000000000..032d58f15 --- /dev/null +++ b/nx-X11/programs/Xserver/os/xdmcp.c.NX.original @@ -0,0 +1,1710 @@ +/* $XdotOrg: xc/programs/Xserver/os/xdmcp.c,v 1.10 2005/07/03 08:53:52 daniels Exp $ */ +/* $Xorg: xdmcp.c,v 1.4 2001/01/31 13:37:19 pookie Exp $ */ +/* + * Copyright 1989 Network Computing Devices, Inc., Mountain View, California. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of N.C.D. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. N.C.D. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + */ +/* $XFree86: xc/programs/Xserver/os/xdmcp.c,v 3.31 2003/12/30 21:24:32 herrb Exp $ */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif + +#include <X11/Xos.h> + +#if !defined(WIN32) +#ifndef Lynx +#include <sys/param.h> +#include <sys/socket.h> +#else +#include <socket.h> +#endif +#include <netinet/in.h> +#include <netdb.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <X11/X.h> +#include <X11/Xmd.h> +#include "misc.h" +#include <X11/Xpoll.h> +#include "osdep.h" +#include "input.h" +#include "dixstruct.h" +#include "opaque.h" + +#if defined(DGUX) +#include <net/net_ioctl.h> +#include <sys/ioctl.h> +#endif + +#ifdef STREAMSCONN +#include <tiuser.h> +#include <netconfig.h> +#include <netdir.h> +#endif + +#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 <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 CARD32 defaultKeepaliveDormancy = XDM_DEF_DORMANCY; +static CARD32 keepaliveDormancy = XDM_DEF_DORMANCY; +static CARD16 DisplayNumber; +static xdmcp_states XDM_INIT_STATE = XDM_OFF; +#ifdef HASXDMAUTH +static char *xdmAuthCookie; +#endif + +static XdmcpBuffer buffer; + +#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 restart(void); + +static void XdmcpBlockHandler( + pointer /*data*/, + struct timeval ** /*wt*/, + pointer /*LastSelectMask*/); + +static void XdmcpWakeupHandler( + pointer /*data*/, + int /*i*/, + pointer /*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) xalloc ( + (AuthenticationNames.length + 1) * sizeof (AuthenticationFuncsRec))))) + { + XdmcpDisposeARRAY8 (&AuthenticationName); + XdmcpDisposeARRAY8 (&AuthenticationData); + return; + } + for (i = 0; i < AuthenticationNames.length - 1; i++) + newFuncs[i] = AuthenticationFuncsList[i]; + newFuncs[AuthenticationNames.length-1].Validator = Validator; + newFuncs[AuthenticationNames.length-1].Generator = Generator; + newFuncs[AuthenticationNames.length-1].AddAuth = AddAuth; + xfree (AuthenticationFuncsList); + AuthenticationFuncsList = newFuncs; + AuthenticationNames.data[AuthenticationNames.length-1] = AuthenticationName; + AuthenticationDatas.data[AuthenticationDatas.length-1] = AuthenticationData; +} + +/* + * Select the authentication type to be used; this is + * set by the manager of the host to be connected to. + */ + +ARRAY8 noAuthenticationName = {(CARD16) 0, (CARD8Ptr) 0}; +ARRAY8 noAuthenticationData = {(CARD16) 0, (CARD8Ptr) 0}; +ARRAY8Ptr AuthenticationName = &noAuthenticationName; +ARRAY8Ptr AuthenticationData = &noAuthenticationData; +AuthenticationFuncsPtr AuthenticationFuncs; + +void +XdmcpSetAuthentication (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 *) xalloc (addrlen * sizeof (CARD8)); + if (!newAddress) + return; + if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1)) + { + xfree (newAddress); + return; + } + if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses, + ConnectionAddresses.length + 1)) + { + xfree (newAddress); + return; + } + ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type; + for (i = 0; i < addrlen; i++) + newAddress[i] = address[i]; + ConnectionAddresses.data[ConnectionAddresses.length-1].data = newAddress; + ConnectionAddresses.data[ConnectionAddresses.length-1].length = addrlen; +} + +/* + * Register an Authorization Name. XDMCP advertises this list + * to the manager. + */ + +static ARRAYofARRAY8 AuthorizationNames; + +void +XdmcpRegisterAuthorizations (void) +{ + XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames); + RegisterAuthorizations (); +} + +void +XdmcpRegisterAuthorization (char *name, int namelen) +{ + ARRAY8 authName; + int i; + + authName.data = (CARD8 *) xalloc (namelen * sizeof (CARD8)); + if (!authName.data) + return; + if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1)) + { + xfree (authName.data); + return; + } + for (i = 0; i < namelen; i++) + authName.data[i] = (CARD8) name[i]; + authName.length = namelen; + AuthorizationNames.data[AuthorizationNames.length-1] = authName; +} + +/* + * Register the DisplayClass string + */ + +ARRAY8 DisplayClass; + +void +XdmcpRegisterDisplayClass (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, + (pointer) 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, + (pointer) 0); + timeOutRtx = 0; + send_packet(); + } +} + +/* + * Called whenever a new connection is created; notices the + * first connection and saves it to terminate the session + * when it is closed + */ + +void +XdmcpOpenDisplay(int sock) +{ + if (state != XDM_AWAIT_MANAGE_RESPONSE) + return; + state = XDM_RUN_SESSION; + 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( + pointer data, /* unused */ + struct timeval **wt, + pointer 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( + pointer data, /* unused */ + int i, + pointer pReadmask) +{ + fd_set* LastSelectMask = (fd_set*)pReadmask; + fd_set devicesReadable; + +#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 + XFD_ANDSET(&devicesReadable, LastSelectMask, &EnabledDevices); + if (XFD_ANYSET(&devicesReadable)) + { + if (state == XDM_AWAIT_USER_INPUT) + restart(); + else if (state == XDM_RUN_SESSION) + keepaliveDormancy = defaultKeepaliveDormancy; + } + if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION) + timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000; + } + else if (timeOutTime && (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(); +} + +static void +restart(void) +{ + state = XDM_INIT_STATE; + timeOutRtx = 0; + 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) +{ +#ifdef STREAMSCONN + struct netconfig *nconf; + + if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) { + XdmcpWarning("t_open() of /dev/udp failed"); + return; + } + + if( t_bind(xdmcpSocket,NULL,NULL) < 0 ) { + XdmcpWarning("UDP socket creation failed"); + t_error("t_bind(xdmcpSocket) failed" ); + t_close(xdmcpSocket); + return; + } + + /* + * This part of the code looks contrived. It will actually fit in nicely + * when the CLTS part of Xtrans is implemented. + */ + + if( (nconf=getnetconfigent("udp")) == NULL ) { + XdmcpWarning("UDP socket creation failed: getnetconfigent()"); + t_unbind(xdmcpSocket); + t_close(xdmcpSocket); + return; + } + + if( netdir_options(nconf, ND_SET_BROADCAST, xdmcpSocket, NULL) ) { + XdmcpWarning("UDP set broadcast option failed: netdir_options()"); + freenetconfigent(nconf); + t_unbind(xdmcpSocket); + t_close(xdmcpSocket); + return; + } + + freenetconfigent(nconf); +#else + 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); + } + } +#endif /* STREAMSCONN */ +} + +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) + { + /* backoff dormancy period */ + state = XDM_RUN_SESSION; + if ((GetTimeInMillis() - lastDeviceEventTime.milliseconds) > + keepaliveDormancy * 1000) + { + keepaliveDormancy <<= 1; + if (keepaliveDormancy > XDM_MAX_DORMANCY) + keepaliveDormancy = XDM_MAX_DORMANCY; + } + timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000; + } + else + { + XdmcpDeadSession ("Alive 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) || defined(DNETCONN)) + _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/xdmcp.c.X.original b/nx-X11/programs/Xserver/os/xdmcp.c.X.original new file mode 100644 index 000000000..19a62a56b --- /dev/null +++ b/nx-X11/programs/Xserver/os/xdmcp.c.X.original @@ -0,0 +1,1681 @@ +/* $XdotOrg: xc/programs/Xserver/os/xdmcp.c,v 1.10 2005/07/03 08:53:52 daniels Exp $ */ +/* $Xorg: xdmcp.c,v 1.4 2001/01/31 13:37:19 pookie Exp $ */ +/* + * Copyright 1989 Network Computing Devices, Inc., Mountain View, California. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of N.C.D. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. N.C.D. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + */ +/* $XFree86: xc/programs/Xserver/os/xdmcp.c,v 3.31 2003/12/30 21:24:32 herrb Exp $ */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifdef WIN32 +#include <X11/Xwinsock.h> +#endif + +#include <X11/Xos.h> + +#if !defined(WIN32) +#ifndef Lynx +#include <sys/param.h> +#include <sys/socket.h> +#else +#include <socket.h> +#endif +#include <netinet/in.h> +#include <netdb.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <X11/X.h> +#include <X11/Xmd.h> +#include "misc.h" +#include <X11/Xpoll.h> +#include "osdep.h" +#include "input.h" +#include "dixstruct.h" +#include "opaque.h" + +#if defined(DGUX) +#include <net/net_ioctl.h> +#include <sys/ioctl.h> +#endif + +#ifdef STREAMSCONN +#include <tiuser.h> +#include <netconfig.h> +#include <netdir.h> +#endif + +#ifdef XDMCP +#undef REQUEST + +#ifdef XDMCP_NO_IPV6 +#undef IPv6 +#endif + +#include <X11/Xdmcp.h> + +#define X_INCLUDE_NETDB_H +#include <X11/Xos_r.h> + +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 CARD32 defaultKeepaliveDormancy = XDM_DEF_DORMANCY; +static CARD32 keepaliveDormancy = XDM_DEF_DORMANCY; +static CARD16 DisplayNumber; +static xdmcp_states XDM_INIT_STATE = XDM_OFF; +#ifdef HASXDMAUTH +static char *xdmAuthCookie; +#endif + +static XdmcpBuffer buffer; + +#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 restart(void); + +static void XdmcpBlockHandler( + pointer /*data*/, + struct timeval ** /*wt*/, + pointer /*LastSelectMask*/); + +static void XdmcpWakeupHandler( + pointer /*data*/, + int /*i*/, + pointer /*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) xalloc ( + (AuthenticationNames.length + 1) * sizeof (AuthenticationFuncsRec))))) + { + XdmcpDisposeARRAY8 (&AuthenticationName); + XdmcpDisposeARRAY8 (&AuthenticationData); + return; + } + for (i = 0; i < AuthenticationNames.length - 1; i++) + newFuncs[i] = AuthenticationFuncsList[i]; + newFuncs[AuthenticationNames.length-1].Validator = Validator; + newFuncs[AuthenticationNames.length-1].Generator = Generator; + newFuncs[AuthenticationNames.length-1].AddAuth = AddAuth; + xfree (AuthenticationFuncsList); + AuthenticationFuncsList = newFuncs; + AuthenticationNames.data[AuthenticationNames.length-1] = AuthenticationName; + AuthenticationDatas.data[AuthenticationDatas.length-1] = AuthenticationData; +} + +/* + * Select the authentication type to be used; this is + * set by the manager of the host to be connected to. + */ + +ARRAY8 noAuthenticationName = {(CARD16) 0, (CARD8Ptr) 0}; +ARRAY8 noAuthenticationData = {(CARD16) 0, (CARD8Ptr) 0}; +ARRAY8Ptr AuthenticationName = &noAuthenticationName; +ARRAY8Ptr AuthenticationData = &noAuthenticationData; +AuthenticationFuncsPtr AuthenticationFuncs; + +void +XdmcpSetAuthentication (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 *) xalloc (addrlen * sizeof (CARD8)); + if (!newAddress) + return; + if (!XdmcpReallocARRAY16 (&ConnectionTypes, ConnectionTypes.length + 1)) + { + xfree (newAddress); + return; + } + if (!XdmcpReallocARRAYofARRAY8 (&ConnectionAddresses, + ConnectionAddresses.length + 1)) + { + xfree (newAddress); + return; + } + ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type; + for (i = 0; i < addrlen; i++) + newAddress[i] = address[i]; + ConnectionAddresses.data[ConnectionAddresses.length-1].data = newAddress; + ConnectionAddresses.data[ConnectionAddresses.length-1].length = addrlen; +} + +/* + * Register an Authorization Name. XDMCP advertises this list + * to the manager. + */ + +static ARRAYofARRAY8 AuthorizationNames; + +void +XdmcpRegisterAuthorizations (void) +{ + XdmcpDisposeARRAYofARRAY8 (&AuthorizationNames); + RegisterAuthorizations (); +} + +void +XdmcpRegisterAuthorization (char *name, int namelen) +{ + ARRAY8 authName; + int i; + + authName.data = (CARD8 *) xalloc (namelen * sizeof (CARD8)); + if (!authName.data) + return; + if (!XdmcpReallocARRAYofARRAY8 (&AuthorizationNames, AuthorizationNames.length +1)) + { + xfree (authName.data); + return; + } + for (i = 0; i < namelen; i++) + authName.data[i] = (CARD8) name[i]; + authName.length = namelen; + AuthorizationNames.data[AuthorizationNames.length-1] = authName; +} + +/* + * Register the DisplayClass string + */ + +ARRAY8 DisplayClass; + +void +XdmcpRegisterDisplayClass (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) +{ + state = XDM_INIT_STATE; +#ifdef HASXDMAUTH + if (xdmAuthCookie) + XdmAuthenticationInit (xdmAuthCookie, strlen (xdmAuthCookie)); +#endif + if (state != XDM_OFF) + { + XdmcpRegisterAuthorizations(); + XdmcpRegisterDisplayClass (defaultDisplayClass, strlen (defaultDisplayClass)); + AccessUsingXdmcp(); + RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler, + (pointer) 0); + timeOutRtx = 0; + DisplayNumber = (CARD16) atoi(display); + get_xdmcp_sock(); + send_packet(); + } +} + +void +XdmcpReset (void) +{ + state = XDM_INIT_STATE; + if (state != XDM_OFF) + { + RegisterBlockAndWakeupHandlers (XdmcpBlockHandler, XdmcpWakeupHandler, + (pointer) 0); + timeOutRtx = 0; + send_packet(); + } +} + +/* + * Called whenever a new connection is created; notices the + * first connection and saves it to terminate the session + * when it is closed + */ + +void +XdmcpOpenDisplay(int sock) +{ + if (state != XDM_AWAIT_MANAGE_RESPONSE) + return; + state = XDM_RUN_SESSION; + 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( + pointer data, /* unused */ + struct timeval **wt, + pointer 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( + pointer data, /* unused */ + int i, + pointer pReadmask) +{ + fd_set* LastSelectMask = (fd_set*)pReadmask; + fd_set devicesReadable; + + if (state == XDM_OFF) + return; + if (i > 0) + { + if (FD_ISSET(xdmcpSocket, LastSelectMask)) + { + receive_packet(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 + XFD_ANDSET(&devicesReadable, LastSelectMask, &EnabledDevices); + if (XFD_ANYSET(&devicesReadable)) + { + if (state == XDM_AWAIT_USER_INPUT) + restart(); + else if (state == XDM_RUN_SESSION) + keepaliveDormancy = defaultKeepaliveDormancy; + } + if (XFD_ANYSET(&AllClients) && state == XDM_RUN_SESSION) + timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000; + } + else if (timeOutTime && (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(); +} + +static void +restart(void) +{ + state = XDM_INIT_STATE; + timeOutRtx = 0; + 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) +{ +#ifdef STREAMSCONN + struct netconfig *nconf; + + if ((xdmcpSocket = t_open("/dev/udp", O_RDWR, 0)) < 0) { + XdmcpWarning("t_open() of /dev/udp failed"); + return; + } + + if( t_bind(xdmcpSocket,NULL,NULL) < 0 ) { + XdmcpWarning("UDP socket creation failed"); + t_error("t_bind(xdmcpSocket) failed" ); + t_close(xdmcpSocket); + return; + } + + /* + * This part of the code looks contrived. It will actually fit in nicely + * when the CLTS part of Xtrans is implemented. + */ + + if( (nconf=getnetconfigent("udp")) == NULL ) { + XdmcpWarning("UDP socket creation failed: getnetconfigent()"); + t_unbind(xdmcpSocket); + t_close(xdmcpSocket); + return; + } + + if( netdir_options(nconf, ND_SET_BROADCAST, xdmcpSocket, NULL) ) { + XdmcpWarning("UDP set broadcast option failed: netdir_options()"); + freenetconfigent(nconf); + t_unbind(xdmcpSocket); + t_close(xdmcpSocket); + return; + } + + freenetconfigent(nconf); +#else + 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); + } + } +#endif /* STREAMSCONN */ +} + +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) + { + /* backoff dormancy period */ + state = XDM_RUN_SESSION; + if ((GetTimeInMillis() - lastDeviceEventTime.milliseconds) > + keepaliveDormancy * 1000) + { + keepaliveDormancy <<= 1; + if (keepaliveDormancy > XDM_MAX_DORMANCY) + keepaliveDormancy = XDM_MAX_DORMANCY; + } + timeOutTime = GetTimeInMillis() + keepaliveDormancy * 1000; + } + else + { + XdmcpDeadSession ("Alive 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) || defined(DNETCONN)) + _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..07eaa1f58 --- /dev/null +++ b/nx-X11/programs/Xserver/os/xprintf.c @@ -0,0 +1,104 @@ +/* + * printf routines which xalloc 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 <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 + +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 *)Xalloc(size + 1); + if (ret == NULL) + return NULL; + + vsnprintf(ret, size + 1, format, va); + ret[size] = 0; + return ret; +} + +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; +} |