diff --git a/.gitignore b/.gitignore index 27a84a4..a9c89fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/tigervnc-1.2.80-20130314svn5065.tar.bz2 +SOURCES/tigervnc-1.3.1.tar.gz diff --git a/.tigervnc.metadata b/.tigervnc.metadata index afeeeab..a4c986b 100644 --- a/.tigervnc.metadata +++ b/.tigervnc.metadata @@ -1 +1 @@ -581d9ec01dee4602c554ef1d2ae8434d9ea53774 SOURCES/tigervnc-1.2.80-20130314svn5065.tar.bz2 +2253b5460bd5a450b10b1c42eb97b4215c3efd99 SOURCES/tigervnc-1.3.1.tar.gz diff --git a/SOURCES/tigervnc-1.3.0-xserver-1.15.patch b/SOURCES/tigervnc-1.3.0-xserver-1.15.patch deleted file mode 100644 index d070a70..0000000 --- a/SOURCES/tigervnc-1.3.0-xserver-1.15.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff -up tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h.jx tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h ---- tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h.jx 2013-07-01 08:41:24.000000000 -0400 -+++ tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h 2013-11-07 11:39:49.749992669 -0500 -@@ -44,8 +44,10 @@ - #define XORG 113 - #elif XORG_VERSION_CURRENT < ((1 * 10000000) + (14 * 100000) + (99 * 1000)) - #define XORG 114 -+#elif XORG_VERSION_CURRENT < ((1 * 10000000) + (15 * 100000) + (99 * 1000)) -+#define XORG 115 - #else --#error "X.Org newer than 1.14 is not supported" -+#error "X.Org newer than 1.15 is not supported" - #endif - - #endif diff --git a/SOURCES/tigervnc-1.3.1-CVE-2014-8240.patch b/SOURCES/tigervnc-1.3.1-CVE-2014-8240.patch new file mode 100644 index 0000000..9267c8c --- /dev/null +++ b/SOURCES/tigervnc-1.3.1-CVE-2014-8240.patch @@ -0,0 +1,74 @@ +diff --git a/unix/x0vncserver/Image.cxx b/unix/x0vncserver/Image.cxx +index f998c6a..d113f17 100644 +--- a/unix/x0vncserver/Image.cxx ++++ b/unix/x0vncserver/Image.cxx +@@ -80,6 +80,14 @@ void Image::Init(int width, int height) + xim = XCreateImage(dpy, vis, DefaultDepth(dpy, DefaultScreen(dpy)), + ZPixmap, 0, 0, width, height, BitmapPad(dpy), 0); + ++ if (xim->bytes_per_line <= 0 || ++ xim->height <= 0 || ++ xim->height >= INT_MAX / xim->bytes_per_line) { ++ vlog.error("Invalid display size"); ++ XDestroyImage(xim); ++ exit(1); ++ } ++ + xim->data = (char *)malloc(xim->bytes_per_line * xim->height); + if (xim->data == NULL) { + vlog.error("malloc() failed"); +@@ -256,6 +264,17 @@ void ShmImage::Init(int width, int height, const XVisualInfo *vinfo) + return; + } + ++ if (xim->bytes_per_line <= 0 || ++ xim->height <= 0 || ++ xim->height >= INT_MAX / xim->bytes_per_line) { ++ vlog.error("Invalid display size"); ++ XDestroyImage(xim); ++ xim = NULL; ++ delete shminfo; ++ shminfo = NULL; ++ return; ++ } ++ + shminfo->shmid = shmget(IPC_PRIVATE, + xim->bytes_per_line * xim->height, + IPC_CREAT|0777); +diff --git a/vncviewer/X11PixelBuffer.cxx b/vncviewer/X11PixelBuffer.cxx +index bd0610c..2c493c9 100644 +--- a/vncviewer/X11PixelBuffer.cxx ++++ b/vncviewer/X11PixelBuffer.cxx +@@ -105,6 +105,15 @@ PlatformPixelBuffer::PlatformPixelBuffer(int width, int height) : + ZPixmap, 0, 0, width, height, BitmapPad(fl_display), 0); + assert(xim); + ++ if (xim->bytes_per_line <= 0 || ++ xim->height <= 0 || ++ xim->height >= INT_MAX / xim->bytes_per_line) { ++ if (xim) ++ XDestroyImage(xim); ++ xim = NULL; ++ throw rfb::Exception("Invalid display size"); ++ } ++ + xim->data = (char*)malloc(xim->bytes_per_line * xim->height); + assert(xim->data); + } +@@ -169,6 +178,16 @@ int PlatformPixelBuffer::setupShm() + if (!xim) + goto free_shminfo; + ++ if (xim->bytes_per_line <= 0 || ++ xim->height <= 0 || ++ xim->height >= INT_MAX / xim->bytes_per_line) { ++ XDestroyImage(xim); ++ xim = NULL; ++ delete shminfo; ++ shminfo = NULL; ++ throw rfb::Exception("Invalid display size"); ++ } ++ + shminfo->shmid = shmget(IPC_PRIVATE, + xim->bytes_per_line * xim->height, + IPC_CREAT|0777); diff --git a/SOURCES/tigervnc-1.3.1-xserver-1.16.patch b/SOURCES/tigervnc-1.3.1-xserver-1.16.patch new file mode 100644 index 0000000..eb6a9c8 --- /dev/null +++ b/SOURCES/tigervnc-1.3.1-xserver-1.16.patch @@ -0,0 +1,286 @@ +diff -up tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h.jx tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h +--- tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h.jx 2013-07-01 08:41:24.000000000 -0400 ++++ tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h 2013-11-07 11:39:49.749992669 -0500 +@@ -44,8 +44,12 @@ + #define XORG 113 + #elif XORG_VERSION_CURRENT < ((1 * 10000000) + (14 * 100000) + (99 * 1000)) + #define XORG 114 ++#elif XORG_VERSION_CURRENT < ((1 * 10000000) + (15 * 100000) + (99 * 1000)) ++#define XORG 115 ++#elif XORG_VERSION_CURRENT < ((1 * 10000000) + (16 * 100000) + (99 * 1000)) ++#define XORG 116 + #else +-#error "X.Org newer than 1.14 is not supported" ++#error "X.Org newer than 1.16 is not supported" + #endif + + #endif + +diff -up tigervnc-1.3.1/unix/xserver/hw/vnc/Input.cc.116 tigervnc-1.3.1/unix/xserver/hw/vnc/Input.cc +--- tigervnc-1.3.1/unix/xserver/hw/vnc/Input.cc.116 2013-05-30 16:53:40.000000000 +0200 ++++ tigervnc-1.3.1/unix/xserver/hw/vnc/Input.cc 2014-04-28 16:55:02.591440218 +0200 +@@ -262,7 +262,7 @@ static int pointerProc(DeviceIntPtr pDev + return Success; + } + +-static void keyboardBell(int percent, DeviceIntPtr device, pointer ctrl, ++static void keyboardBell(int percent, DeviceIntPtr device, void * ctrl, + int class_) + { + if (percent > 0) +diff -up tigervnc-1.3.1/unix/xserver/hw/vnc/XserverDesktop.cc.116 tigervnc-1.3.1/unix/xserver/hw/vnc/XserverDesktop.cc +--- tigervnc-1.3.1/unix/xserver/hw/vnc/XserverDesktop.cc.116 2014-04-28 16:55:02.530441812 +0200 ++++ tigervnc-1.3.1/unix/xserver/hw/vnc/XserverDesktop.cc 2014-04-28 16:55:02.592440192 +0200 +@@ -48,7 +48,7 @@ extern "C" { + #define public c_public + #define class c_class + +-extern char *display; ++extern const char *display; + + #include "colormapst.h" + #ifdef RANDR +@@ -174,7 +174,7 @@ void XserverDesktop::serverReset(ScreenP + { + pScreen = pScreen_; + int i; +- pointer retval; ++ void * retval; + + #if XORG >= 17 + #define dixLookupResource dixLookupResourceByType +diff -up tigervnc-1.3.1/unix/xserver/hw/vnc/vncExtInit.cc.116 tigervnc-1.3.1/unix/xserver/hw/vnc/vncExtInit.cc +--- tigervnc-1.3.1/unix/xserver/hw/vnc/vncExtInit.cc.116 2014-04-28 16:55:02.524441969 +0200 ++++ tigervnc-1.3.1/unix/xserver/hw/vnc/vncExtInit.cc 2014-04-28 16:55:02.592440192 +0200 +@@ -65,18 +65,18 @@ extern "C" { + + extern void vncExtensionInit(); + static void vncResetProc(ExtensionEntry* extEntry); +- static void vncBlockHandler(pointer data, OSTimePtr t, pointer readmask); +- static void vncWakeupHandler(pointer data, int nfds, pointer readmask); ++ static void vncBlockHandler(void * data, OSTimePtr t, void * readmask); ++ static void vncWakeupHandler(void * data, int nfds, void * readmask); + void vncWriteBlockHandler(fd_set *fds); + void vncWriteWakeupHandler(int nfds, fd_set *fds); +- static void vncClientStateChange(CallbackListPtr*, pointer, pointer); ++ static void vncClientStateChange(CallbackListPtr*, void *, void *); + static void SendSelectionChangeEvent(Atom selection); + static int ProcVncExtDispatch(ClientPtr client); + static int SProcVncExtDispatch(ClientPtr client); +- static void vncSelectionCallback(CallbackListPtr *callbacks, pointer data, +- pointer args); ++ static void vncSelectionCallback(CallbackListPtr *callbacks, void * data, ++ void * args); + +- extern char *display; ++ extern const char *display; + extern char *listenaddr; + } + +@@ -284,7 +284,7 @@ static void vncResetProc(ExtensionEntry* + { + } + +-static void vncSelectionCallback(CallbackListPtr *callbacks, pointer data, pointer args) ++static void vncSelectionCallback(CallbackListPtr *callbacks, void * data, void * args) + { + SelectionInfoRec *info = (SelectionInfoRec *) args; + Selection *selection = info->selection; +@@ -301,7 +301,7 @@ static void vncWriteWakeupHandlerFallbac + // selections have changed, and if so, notify any interested X clients. + // + +-static void vncBlockHandler(pointer data, OSTimePtr timeout, pointer readmask) ++static void vncBlockHandler(void * data, OSTimePtr timeout, void * readmask) + { + fd_set* fds = (fd_set*)readmask; + +@@ -312,7 +312,7 @@ static void vncBlockHandler(pointer data + desktop[scr]->blockHandler(fds, timeout); + } + +-static void vncWakeupHandler(pointer data, int nfds, pointer readmask) ++static void vncWakeupHandler(void * data, int nfds, void * readmask) + { + fd_set* fds = (fd_set*)readmask; + +@@ -402,7 +402,7 @@ static void vncWriteWakeupHandlerFallbac + vncWriteWakeupHandler(ret, &fallbackFds); + } + +-static void vncClientStateChange(CallbackListPtr*, pointer, pointer p) ++static void vncClientStateChange(CallbackListPtr*, void *, void * p) + { + ClientPtr client = ((NewClientInfoRec*)p)->client; + if (client->clientState == ClientStateGone) { +@@ -468,7 +468,7 @@ void vncClientCutText(const char* str, i + + + static CARD32 queryConnectTimerCallback(OsTimerPtr timer, +- CARD32 now, pointer arg) ++ CARD32 now, void * arg) + { + if (queryConnectTimeout) + queryConnectDesktop->approveConnection(queryConnectId, false, "The attempt to prompt the user to accept the connection failed"); +diff -up tigervnc-1.3.1/unix/xserver/hw/vnc/vncHooks.cc.116 tigervnc-1.3.1/unix/xserver/hw/vnc/vncHooks.cc +--- tigervnc-1.3.1/unix/xserver/hw/vnc/vncHooks.cc.116 2013-05-22 14:57:16.000000000 +0200 ++++ tigervnc-1.3.1/unix/xserver/hw/vnc/vncHooks.cc 2014-04-28 16:55:02.593440166 +0200 +@@ -91,8 +91,8 @@ typedef struct { + } vncHooksScreenRec, *vncHooksScreenPtr; + + typedef struct { +- GCFuncs *wrappedFuncs; +- GCOps *wrappedOps; ++ const GCFuncs *wrappedFuncs; ++ const GCOps *wrappedOps; + } vncHooksGCRec, *vncHooksGCPtr; + + #if XORG == 15 +@@ -141,11 +141,11 @@ static Bool vncHooksDisplayCursor( + #endif + ScreenPtr pScreen, CursorPtr cursor); + #if XORG < 112 +-static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout, +- pointer pReadmask); ++static void vncHooksBlockHandler(int i, void * blockData, void * pTimeout, ++ void * pReadmask); + #else +-static void vncHooksBlockHandler(ScreenPtr pScreen, pointer pTimeout, +- pointer pReadmask); ++static void vncHooksBlockHandler(ScreenPtr pScreen, void * pTimeout, ++ void * pReadmask); + #endif + #ifdef RENDER + static void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, +@@ -174,7 +174,7 @@ static void vncHooksValidateGC(GCPtr pGC + static void vncHooksChangeGC(GCPtr pGC, unsigned long mask); + static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst); + static void vncHooksDestroyGC(GCPtr pGC); +-static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue,int nrects); ++static void vncHooksChangeClip(GCPtr pGC, int type, void * pValue,int nrects); + static void vncHooksDestroyClip(GCPtr pGC); + static void vncHooksCopyClip(GCPtr dst, GCPtr src); + +@@ -226,10 +226,10 @@ static void vncHooksImageText16(Drawable + int count, unsigned short *chars); + static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, unsigned int nglyph, +- CharInfoPtr *ppci, pointer pglyphBase); ++ CharInfoPtr *ppci, void * pglyphBase); + static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, unsigned int nglyph, +- CharInfoPtr *ppci, pointer pglyphBase); ++ CharInfoPtr *ppci, void * pglyphBase); + static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap, + DrawablePtr pDrawable, int w, int h, int x, + int y); +@@ -575,11 +575,11 @@ static Bool vncHooksDisplayCursor( + // these are just drawing the cursor. + + #if XORG < 112 +-static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout, +- pointer pReadmask) ++static void vncHooksBlockHandler(int i, void * blockData, void * pTimeout, ++ void * pReadmask) + #else +-static void vncHooksBlockHandler(ScreenPtr pScreen_, pointer pTimeout, +- pointer pReadmask) ++static void vncHooksBlockHandler(ScreenPtr pScreen_, void * pTimeout, ++ void * pReadmask) + #endif + { + #if XORG < 112 +@@ -914,7 +914,7 @@ static void vncHooksDestroyGC(GCPtr pGC) + GCFuncUnwrapper u(pGC); + (*pGC->funcs->DestroyGC) (pGC); + } +-static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue, int nrects) ++static void vncHooksChangeClip(GCPtr pGC, int type, void * pValue, int nrects) + { + GCFuncUnwrapper u(pGC); + (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects); +@@ -954,7 +954,7 @@ public: + } + GCPtr pGC; + vncHooksGCPtr vncHooksGC; +- GCFuncs* oldFuncs; ++ const GCFuncs* oldFuncs; + ScreenPtr pScreen; + }; + +@@ -1793,7 +1793,7 @@ static void vncHooksImageText16(Drawable + + static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, unsigned int nglyph, +- CharInfoPtr *ppci, pointer pglyphBase) ++ CharInfoPtr *ppci, void * pglyphBase) + { + GC_OP_UNWRAPPER(pDrawable, pGC, ImageGlyphBlt); + +@@ -1819,7 +1819,7 @@ static void vncHooksImageGlyphBlt(Drawab + + static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, + int y, unsigned int nglyph, +- CharInfoPtr *ppci, pointer pglyphBase) ++ CharInfoPtr *ppci, void * pglyphBase) + { + GC_OP_UNWRAPPER(pDrawable, pGC, PolyGlyphBlt); + +diff -up tigervnc-1.3.1/unix/xserver/hw/vnc/xf86vncModule.cc.116 tigervnc-1.3.1/unix/xserver/hw/vnc/xf86vncModule.cc +--- tigervnc-1.3.1/unix/xserver/hw/vnc/xf86vncModule.cc.116 2013-03-14 18:52:53.000000000 +0100 ++++ tigervnc-1.3.1/unix/xserver/hw/vnc/xf86vncModule.cc 2014-04-28 16:55:02.593440166 +0200 +@@ -81,11 +81,11 @@ static XF86ModuleVersionInfo vncVersRec + + _X_EXPORT XF86ModuleData vncModuleData = { &vncVersRec, vncSetup, NULL }; + +-static pointer +-vncSetup(pointer module, pointer opts, int *errmaj, int *errmin) { +- LoadExtension(&vncExt, FALSE); ++static void * ++vncSetup(void * module, void * opts, int *errmaj, int *errmin) { ++ LoadExtensionList(&vncExt, 1, FALSE); + /* Need a non-NULL return value to indicate success */ +- return (pointer)1; ++ return (void *)1; + } + + static void vncExtensionInitWithParams(INITARGS) +diff -up tigervnc-1.3.1/unix/xserver/hw/vnc/xvnc.cc.116 tigervnc-1.3.1/unix/xserver/hw/vnc/xvnc.cc +--- tigervnc-1.3.1/unix/xserver/hw/vnc/xvnc.cc.116 2014-03-19 13:11:09.000000000 +0100 ++++ tigervnc-1.3.1/unix/xserver/hw/vnc/xvnc.cc 2014-04-28 16:53:12.580314921 +0200 +@@ -103,7 +103,7 @@ extern "C" { + "See http://www.tigervnc.org for information on TigerVNC.\n") + + +-extern char *display; ++extern const char *display; + extern int monitorResolution; + + #define VFB_DEFAULT_WIDTH 1024 +@@ -762,7 +762,7 @@ vfbUninstallColormap(ColormapPtr pmap) + curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap, + RT_COLORMAP); + #else +- dixLookupResourceByType((pointer *) &curpmap, pmap->pScreen->defColormap, ++ dixLookupResourceByType((void * *) &curpmap, pmap->pScreen->defColormap, + RT_COLORMAP, serverClient, DixUnknownAccess); + #endif + (*pmap->pScreen->InstallColormap)(curpmap); +@@ -1597,7 +1597,7 @@ vfbScreenInit(ScreenPtr pScreen, int arg + } /* end vfbScreenInit */ + + +-static void vfbClientStateChange(CallbackListPtr*, pointer, pointer) { ++static void vfbClientStateChange(CallbackListPtr*, void *, void *) { + dispatchException &= ~DE_RESET; + } + +@@ -1625,7 +1625,7 @@ InitOutput(ScreenInfo *screenInfo, int a + #if XORG >= 113 + #ifdef GLXEXT + if (serverGeneration == 1) +- LoadExtension(&glxExt, TRUE); ++ LoadExtensionList(&glxExt, 1, TRUE); + #endif + #endif + diff --git a/SOURCES/tigervnc-1.3.1-xserver-1.17.patch b/SOURCES/tigervnc-1.3.1-xserver-1.17.patch new file mode 100644 index 0000000..77f813b --- /dev/null +++ b/SOURCES/tigervnc-1.3.1-xserver-1.17.patch @@ -0,0 +1,44 @@ +diff -up tigervnc-1.4.2/unix/xserver/hw/vnc/xorg-version.h.xserver117 tigervnc-1.4.2/unix/xserver/hw/vnc/xorg-version.h +--- tigervnc-1.4.2/unix/xserver/hw/vnc/xorg-version.h.xserver117 2015-01-23 23:37:23.000000000 +0000 ++++ tigervnc-1.4.2/unix/xserver/hw/vnc/xorg-version.h 2015-02-13 17:35:29.847294663 +0000 +@@ -48,8 +48,10 @@ + #define XORG 115 + #elif XORG_VERSION_CURRENT < ((1 * 10000000) + (16 * 100000) + (99 * 1000)) + #define XORG 116 ++#elif XORG_VERSION_CURRENT < ((1 * 10000000) + (17 * 100000) + (99 * 1000)) ++#define XORG 117 + #else +-#error "X.Org newer than 1.16 is not supported" ++#error "X.Org newer than 1.17 is not supported" + #endif + + #endif +diff -up tigervnc-1.4.2/unix/xserver/hw/vnc/xvnc.cc.xserver117 tigervnc-1.4.2/unix/xserver/hw/vnc/xvnc.cc +--- tigervnc-1.4.2/unix/xserver/hw/vnc/xvnc.cc.xserver117 2015-01-23 23:37:23.000000000 +0000 ++++ tigervnc-1.4.2/unix/xserver/hw/vnc/xvnc.cc 2015-02-13 17:35:27.963265774 +0000 +@@ -717,9 +717,9 @@ vfbInstallColormap(ColormapPtr pmap) + entries = pmap->pVisual->ColormapEntries; + pVisual = pmap->pVisual; + +- ppix = (Pixel *)xalloc(entries * sizeof(Pixel)); +- prgb = (xrgb *)xalloc(entries * sizeof(xrgb)); +- defs = (xColorItem *)xalloc(entries * sizeof(xColorItem)); ++ ppix = (Pixel *)calloc(entries, sizeof(Pixel)); ++ prgb = (xrgb *)calloc(entries, sizeof(xrgb)); ++ defs = (xColorItem *)calloc(entries, sizeof(xColorItem)); + + for (i = 0; i < entries; i++) ppix[i] = i; + /* XXX truecolor */ +@@ -738,9 +738,9 @@ vfbInstallColormap(ColormapPtr pmap) + } + (*pmap->pScreen->StoreColors)(pmap, entries, defs); + +- xfree(ppix); +- xfree(prgb); +- xfree(defs); ++ free(ppix); ++ free(prgb); ++ free(defs); + } + } + diff --git a/SOURCES/tigervnc-CVE-2014-0011.patch b/SOURCES/tigervnc-CVE-2014-0011.patch deleted file mode 100644 index 0075720..0000000 --- a/SOURCES/tigervnc-CVE-2014-0011.patch +++ /dev/null @@ -1,49 +0,0 @@ -diff -up tigervnc-1.3.0/common/CMakeLists.txt.CVE-2014-0011 tigervnc-1.3.0/common/CMakeLists.txt ---- tigervnc-1.3.0/common/CMakeLists.txt.CVE-2014-0011 2013-07-01 13:42:01.000000000 +0100 -+++ tigervnc-1.3.0/common/CMakeLists.txt 2014-02-04 16:59:10.840037314 +0000 -@@ -23,3 +23,6 @@ if(CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_S - set_target_properties(zlib PROPERTIES COMPILE_FLAGS -fPIC) - endif() - endif() -+ -+# Turn asserts on. -+set_target_properties(rdr rfb PROPERTIES COMPILE_FLAGS -UNDEBUG) -diff -up tigervnc-1.3.0/common/rfb/zrleDecode.h.CVE-2014-0011 tigervnc-1.3.0/common/rfb/zrleDecode.h ---- tigervnc-1.3.0/common/rfb/zrleDecode.h.CVE-2014-0011 2013-07-01 13:41:59.000000000 +0100 -+++ tigervnc-1.3.0/common/rfb/zrleDecode.h 2014-02-04 16:17:00.881565540 +0000 -@@ -25,9 +25,10 @@ - // FILL_RECT - fill a rectangle with a single colour - // IMAGE_RECT - draw a rectangle of pixel data from a buffer - -+#include - #include - #include --#include -+#include - - namespace rfb { - -@@ -143,7 +144,10 @@ void ZRLE_DECODE (const Rect& r, rdr::In - len += b; - } while (b == 255); - -- assert(len <= end - ptr); -+ if (end - ptr < len) { -+ fprintf (stderr, "ZRLE decode error\n"); -+ throw Exception ("ZRLE decode error"); -+ } - - #ifdef FAVOUR_FILL_RECT - int i = ptr - buf; -@@ -193,7 +197,10 @@ void ZRLE_DECODE (const Rect& r, rdr::In - len += b; - } while (b == 255); - -- assert(len <= end - ptr); -+ if (end - ptr < len) { -+ fprintf (stderr, "ZRLE decode error\n"); -+ throw Exception ("ZRLE decode error"); -+ } - } - - index &= 127; diff --git a/SOURCES/tigervnc-CVE-2014-8241.patch b/SOURCES/tigervnc-CVE-2014-8241.patch new file mode 100644 index 0000000..56216cc --- /dev/null +++ b/SOURCES/tigervnc-CVE-2014-8241.patch @@ -0,0 +1,101 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 0e325e2..1d4e1bf 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -67,6 +67,14 @@ add_definitions(-D__BUILD__="${BUILD}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -UNDEBUG") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -UNDEBUG") + ++# We want to keep our asserts even in release builds so remove NDEBUG ++set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -UNDEBUG") ++set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -UNDEBUG") ++set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -UNDEBUG") ++set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -UNDEBUG") ++set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -UNDEBUG") ++set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -UNDEBUG") ++ + if(NOT DEFINED BUILD_WINVNC) + set(BUILD_WINVNC 1) + endif() +diff --git a/common/Xregion/Region.c b/common/Xregion/Region.c +index 604ecde..4bb52ea 100644 +--- a/common/Xregion/Region.c ++++ b/common/Xregion/Region.c +@@ -1083,6 +1083,8 @@ miRegionOp(newReg, reg1, reg2, overlapFunc, nonOverlap1Func, nonOverlap2Func) + newReg->size = 1; + Xfree((char *) newReg->rects); + newReg->rects = (BoxPtr) Xmalloc(sizeof(BoxRec)); ++ if (! newReg->rects) ++ newReg->size = 0; + } + } + Xfree ((char *) oldRects); +diff --git a/unix/vncconfig/vncExt.c b/unix/vncconfig/vncExt.c +index ff5532b..c2e6d3c 100644 +--- a/unix/vncconfig/vncExt.c ++++ b/unix/vncconfig/vncExt.c +@@ -109,6 +109,10 @@ Bool XVncExtGetParam(Display* dpy, const char* param, char** value, int* len) + if (rep.success) { + *len = rep.valueLen; + *value = (char*) Xmalloc (*len+1); ++ if (!*value) { ++ _XEatData(dpy, (*len+1)&~1); ++ return False; ++ } + _XReadPad(dpy, *value, *len); + (*value)[*len] = 0; + } +@@ -141,6 +145,10 @@ char* XVncExtGetParamDesc(Display* dpy, const char* param) + } + if (rep.success) { + desc = (char*)Xmalloc(rep.descLen+1); ++ if (!*desc) { ++ _XEatData(dpy, (rep.descLen+1)&~1); ++ return False; ++ } + _XReadPad(dpy, desc, rep.descLen); + desc[rep.descLen] = 0; + } +@@ -243,6 +251,10 @@ Bool XVncExtGetClientCutText(Display* dpy, char** str, int* len) + SyncHandle(); + *len = rep.textLen; + *str = (char*) Xmalloc (*len+1); ++ if (!*str) { ++ _XEatData(dpy, (*len+1)&~1); ++ return False; ++ } + _XReadPad(dpy, *str, *len); + (*str)[*len] = 0; + return True; +@@ -312,9 +324,15 @@ Bool XVncExtGetQueryConnect(Display* dpy, char** addr, char** user, + SyncHandle(); + + *addr = Xmalloc(rep.addrLen+1); ++ *user = Xmalloc(rep.userLen+1); ++ if (!*addr || !*user) { ++ Xfree(*addr); ++ Xfree(*user); ++ _XEatData(dpy, (rep.addrLen+1)&~1 + (rep.userLen+1)&~1); ++ return False; ++ } + _XReadPad(dpy, *addr, rep.addrLen); + (*addr)[rep.addrLen] = 0; +- *user = Xmalloc(rep.userLen+1); + _XReadPad(dpy, *user, rep.userLen); + (*user)[rep.userLen] = 0; + *timeout = rep.timeout; +diff --git a/unix/vncconfig/vncconfig.cxx b/unix/vncconfig/vncconfig.cxx +index f70cc71..bffdfbe 100644 +--- a/unix/vncconfig/vncconfig.cxx ++++ b/unix/vncconfig/vncconfig.cxx +@@ -215,6 +215,10 @@ public: + if (cutText) + XFree(cutText); + cutText = (char*)malloc(nitems); // assuming XFree() same as free() ++ if (!cutText) { ++ vlog.error("unable to allocate selection buffer"); ++ return; ++ } + memcpy(cutText, data, nitems); + cutTextLen = nitems; + vlog.debug("sending %s selection as server cut text: '%.*s%s'", diff --git a/SOURCES/tigervnc-check-return-value-from-xshmattach.patch b/SOURCES/tigervnc-check-return-value-from-xshmattach.patch new file mode 100644 index 0000000..a3b011a --- /dev/null +++ b/SOURCES/tigervnc-check-return-value-from-xshmattach.patch @@ -0,0 +1,17 @@ +diff --git a/vncviewer/X11PixelBuffer.cxx b/vncviewer/X11PixelBuffer.cxx +index 548591e..bd0610c 100644 +--- a/vncviewer/X11PixelBuffer.cxx ++++ b/vncviewer/X11PixelBuffer.cxx +@@ -186,7 +186,11 @@ int PlatformPixelBuffer::setupShm() + caughtError = false; + old_handler = XSetErrorHandler(XShmAttachErrorHandler); + +- XShmAttach(fl_display, shminfo); ++ if (!XShmAttach(fl_display, shminfo)) { ++ XSetErrorHandler(old_handler); ++ goto free_shmaddr; ++ } ++ + XSync(fl_display, False); + + XSetErrorHandler(old_handler); diff --git a/SOURCES/tigervnc-input.patch b/SOURCES/tigervnc-input.patch deleted file mode 100644 index e1e7b0b..0000000 --- a/SOURCES/tigervnc-input.patch +++ /dev/null @@ -1,2569 +0,0 @@ -diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.cc.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.cc ---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.cc.input 2012-08-29 09:56:37.000000000 +0100 -+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.cc 2014-01-17 16:01:13.140109450 +0000 -@@ -1,5 +1,6 @@ - /* Copyright (C) 2009 TightVNC Team - * Copyright (C) 2009 Red Hat, Inc. -+ * Copyright 2013 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -34,16 +35,6 @@ extern "C" { - #include "inpututils.h" - #endif - #include "mi.h" --#ifndef XKB_IN_SERVER --#define XKB_IN_SERVER --#endif --#ifdef XKB --/* -- * This include is needed to use XkbConvertCase instead of XConvertCase even if -- * we don't use XKB extension. -- */ --#include --#endif - #if XORG >= 16 - #include "exevents.h" - #endif -@@ -58,6 +49,7 @@ CopyKeyClass(DeviceIntPtr device, Device - extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey; - #endif - #include -+#include - #include - #undef public - #undef class -@@ -72,12 +64,9 @@ using namespace rfb; - - static LogWriter vlog("Input"); - --#define BUTTONS 7 --static int pointerProc(DeviceIntPtr pDevice, int onoff); -+rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock", "Avoid fake Shift presses for keys affected by NumLock.", true); - --static int keyboardProc(DeviceIntPtr pDevice, int onoff); --static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col); --static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col); -+#define BUTTONS 7 - - /* Event queue is shared between all devices. */ - #if XORG == 15 -@@ -128,26 +117,16 @@ static void enqueueEvents(DeviceIntPtr d - #endif /* XORG < 111 */ - - InputDevice::InputDevice(rfb::VNCServerST *_server) -- : server(_server), oldButtonMask(0) -+ : server(_server), initialized(false), oldButtonMask(0) - { --#if XORG < 17 -- pointerDev = AddInputDevice( --#if XORG >= 16 -- serverClient, --#endif -- pointerProc, TRUE); -- RegisterPointerDevice(pointerDev); -+ int i; - -- keyboardDev = AddInputDevice( --#if XORG >= 16 -- serverClient, --#endif -- keyboardProc, TRUE); -- RegisterKeyboardDevice(keyboardDev); --#endif - #if XORG < 111 - initEventq(); - #endif -+ -+ for (i = 0;i < 256;i++) -+ pressedKeys[i] = NoSymbol; - } - - void InputDevice::PointerButtonAction(int buttonMask) -@@ -160,8 +139,6 @@ void InputDevice::PointerButtonAction(in - ValuatorMask mask; - #endif - -- initInputDevice(); -- - for (i = 0; i < BUTTONS; i++) { - if ((buttonMask ^ oldButtonMask) & (1 << i)) { - int action = (buttonMask & (1< 0) -+ vncBell(); -+} -+ -+extern void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap); -+ -+static int keyboardProc(DeviceIntPtr pDevice, int onoff) -+{ -+#if XORG < 17 -+ KeySymsRec keySyms; -+ CARD8 modMap[MAP_LENGTH]; -+#endif -+ DevicePtr pDev = (DevicePtr)pDevice; -+ -+ switch (onoff) { -+ case DEVICE_INIT: -+#if XORG < 17 -+ GetInitKeyboardMap(&keySyms, modMap); -+#endif -+ InitKeyboardDeviceStruct( - #if XORG >= 17 -- int ret; -- static int initialized = 0; -+ pDevice, NULL, -+#else -+ pDev, &keySyms, modMap, -+#endif -+ keyboardBell, (KbdCtrlProcPtr)NoopDDA); -+ break; -+ case DEVICE_ON: -+ pDev->on = TRUE; -+ break; -+ case DEVICE_OFF: -+ pDev->on = FALSE; -+ break; -+ } - -- if (initialized != 0) -+ return Success; -+} -+ -+void InputDevice::InitInputDevice(void) -+{ -+ if (initialized) - return; - -- initialized = 1; -+ initialized = true; -+ -+#if XORG < 17 -+ pointerDev = AddInputDevice( -+#if XORG >= 16 -+ serverClient, -+#endif -+ pointerProc, TRUE); -+ RegisterPointerDevice(pointerDev); -+ -+ keyboardDev = AddInputDevice( -+#if XORG >= 16 -+ serverClient, -+#endif -+ keyboardProc, TRUE); -+ RegisterKeyboardDevice(keyboardDev); -+ -+ if (ActivateDevice(pointerDev) != Success || -+ ActivateDevice(keyboardDev) != Success) -+ FatalError("Failed to activate TigerVNC devices\n"); -+ -+ if (!EnableDevice(pointerDev) || -+ !EnableDevice(keyboardDev)) -+ FatalError("Failed to enable TigerVNC devices\n"); -+#else /* < 17 */ -+ int ret; - - ret = AllocDevicePair(serverClient, "TigerVNC", &pointerDev, - &keyboardDev, pointerProc, keyboardProc, -@@ -312,7 +349,9 @@ void InputDevice::initInputDevice(void) - if (!EnableDevice(pointerDev, TRUE) || - !EnableDevice(keyboardDev, TRUE)) - FatalError("Failed to activate TigerVNC devices\n"); --#endif -+#endif /* 17 */ -+ -+ PrepareInputDevices(); - } - - static inline void pressKey(DeviceIntPtr dev, int kc, bool down, const char *msg) -@@ -334,143 +373,6 @@ static inline void pressKey(DeviceIntPtr - #endif - } - --#define IS_PRESSED(keyc, keycode) \ -- ((keyc)->down[(keycode) >> 3] & (1 << ((keycode) & 7))) -- --/* -- * ModifierState is a class which helps simplify generating a "fake" press or -- * release of shift, ctrl, alt, etc. An instance of the class is created for -- * every modifier which may need to be pressed or released. Then either -- * press() or release() may be called to make sure that the corresponding keys -- * are in the right state. The destructor of the class automatically reverts -- * to the previous state. Each modifier may have multiple keys associated with -- * it, so in the case of a fake release, this may involve releasing more than -- * one key. -- */ -- --class ModifierState { --public: -- ModifierState(DeviceIntPtr _dev, int _modIndex) -- : modIndex(_modIndex), nKeys(0), keys(0), pressed(false), -- dev(_dev) {} -- -- ~ModifierState() -- { -- for (int i = 0; i < nKeys; i++) -- pressKey(dev, keys[i], !pressed, "fake keycode"); -- delete [] keys; -- } -- -- void press() -- { -- int state, maxKeysPerMod, keycode; --#if XORG >= 17 -- KeyCode *modmap = NULL; --#if XORG >= 111 -- state = XkbStateFieldFromRec(&dev->master->key->xkbInfo->state); --#else /* XORG >= 111 */ -- state = XkbStateFieldFromRec(&dev->u.master->key->xkbInfo->state); --#endif /* XORG >= 111 */ --#else -- KeyClassPtr keyc = dev->key; -- state = keyc->state; --#endif -- if ((state & (1 << modIndex)) != 0) -- return; -- --#if XORG >= 17 -- if (generate_modkeymap(serverClient, dev, &modmap, -- &maxKeysPerMod) != Success) { -- vlog.error("generate_modkeymap failed"); -- return; -- } -- -- if (maxKeysPerMod == 0) { -- vlog.debug("Keyboard has no modifiers"); -- xfree(modmap); -- return; -- } -- -- keycode = modmap[modIndex * maxKeysPerMod]; -- xfree(modmap); --#else -- maxKeysPerMod = keyc->maxKeysPerModifier; -- keycode = keyc->modifierKeyMap[modIndex * maxKeysPerMod]; --#endif -- tempKeyEvent(keycode, true, maxKeysPerMod); -- pressed = true; -- } -- -- void release() -- { -- int state, maxKeysPerMod; -- KeyClassPtr keyc; --#if XORG >= 17 -- KeyCode *modmap = NULL; -- --#if XORG >= 111 -- keyc = dev->master->key; --#else /* XORG >= 111 */ -- keyc = dev->u.master->key; --#endif /* XORG >= 111 */ -- state = XkbStateFieldFromRec(&keyc->xkbInfo->state); --#else -- keyc = dev->key; -- state = keyc->state; --#endif -- if ((state & (1 << modIndex)) == 0) -- return; -- --#if XORG >= 17 -- if (generate_modkeymap(serverClient, dev, &modmap, -- &maxKeysPerMod) != Success) { -- vlog.error("generate_modkeymap failed"); -- return; -- } -- -- if (maxKeysPerMod == 0) { -- vlog.debug("Keyboard has no modifiers"); -- xfree(modmap); -- return; -- } --#else -- maxKeysPerMod = keyc->maxKeysPerModifier; --#endif -- -- for (int k = 0; k < maxKeysPerMod; k++) { -- int keycode; -- int index = modIndex * maxKeysPerMod + k; --#if XORG >= 17 -- keycode = modmap[index]; --#else -- keycode = keyc->modifierKeyMap[index]; --#endif -- if (keycode && IS_PRESSED(keyc, keycode)) -- tempKeyEvent(keycode, false, maxKeysPerMod); -- } --#if XORG >= 17 -- xfree(modmap); --#endif -- } -- --private: -- void tempKeyEvent(int keycode, bool down, int maxKeysPerMod) -- { -- if (keycode) { -- if (!keys) keys = new int[maxKeysPerMod]; -- keys[nKeys++] = keycode; -- pressKey(dev, keycode, down, "fake keycode"); -- } -- } -- -- int modIndex; -- int nKeys; -- int *keys; -- bool pressed; -- DeviceIntPtr dev; --}; -- -- - /* altKeysym is a table of alternative keysyms which have the same meaning. */ - - static struct altKeysym_t { -@@ -517,102 +419,48 @@ static struct altKeysym_t { - { XK_KP_7, XK_7 }, - { XK_KP_8, XK_8 }, - { XK_KP_9, XK_9 }, -+ { XK_ISO_Level3_Shift, XK_Mode_switch }, - }; - - /* - * keyEvent() - work out the best keycode corresponding to the keysym sent by -- * the viewer. This is non-trivial because we can't assume much about the -- * local keyboard layout. We must also find out which column of the keyboard -- * mapping the keysym is in, and alter the shift state appropriately. Column 0 -- * means both shift and "mode_switch" (AltGr) must be released, column 1 means -- * shift must be pressed and mode_switch released, column 2 means shift must be -- * released and mode_switch pressed, and column 3 means both shift and -- * mode_switch must be pressed. -- * -- * Magic, which dynamically adds keysym<->keycode mapping depends on X.Org -- * version. Quick explanation of that "magic": -- * -- * 1.5 -- * - has only one core keyboard so we have to keep core keyboard mapping -- * synchronized with vncKeyboardDevice. Do it via SwitchCoreKeyboard() -- * -- * 1.6 (aka MPX - Multi pointer X) -- * - multiple master devices (= core devices) exists, keep vncKeyboardDevice -- * synchronized with proper master device -- */ -- --#if XORG >= 17 --#define FREE_MAPS \ -- do { \ -- xfree(modmap); \ -- xfree(keymap->map); \ -- xfree(keymap); \ -- } while (0); --#else --#define FREE_MAPS --#endif -- --#if XORG >= 17 --/* -- * Modifier keysyms must be handled differently. Instead of finding -- * the right row and collumn in the keymap, directly press/release -- * the keycode which is mapped as modifier with the same keysym. -- * -- * This will avoid issues when there are multiple modifier keysyms -- * in the keymap but only some of them are mapped as modifiers in -- * the modmap. -- * -- * Returns keycode of the modifier key. -+ * the viewer. This is basically impossible in the general case, but we make -+ * a best effort by assuming that all useful keysyms can be reached using -+ * just the Shift and Level 3 (AltGr) modifiers. For core keyboards this is -+ * basically always true, and should be true for most sane, western XKB -+ * layouts. - */ -- --static inline int isModifier(KeySymsPtr keymap, KeyCode *modmap, -- int maxKeysPerMod, rdr::U32 keysym) -+void InputDevice::keyEvent(rdr::U32 keysym, bool down) - { -- KeySym *map = keymap->map; -- KeyCode minKeyCode = keymap->minKeyCode; -- int mapWidth = keymap->mapWidth; -- int i, j, k; -- -- /* Find modifier index in the modmap */ -- for (i = 0; i < 8; i++) { -- for (k = 0; k < maxKeysPerMod; k++) { -- int index = i * maxKeysPerMod + k; -- int keycode = modmap[index]; -+ int i; -+ unsigned state, new_state; -+ KeyCode keycode; - -- if (keycode == 0) -- continue; -+ unsigned level_three_mask; -+ KeyCode shift_press, level_three_press; -+ std::list shift_release, level_three_release; - -- for (j = 0; j < mapWidth; j++) { -- if (map[(keycode - minKeyCode) * mapWidth + j] -- == keysym) { -- return keycode; -- } -+ /* -+ * Release events must match the press event, so look up what -+ * keycode we sent for the press. -+ */ -+ if (!down) { -+ for (i = 0;i < 256;i++) { -+ if (pressedKeys[i] == keysym) { -+ pressedKeys[i] = NoSymbol; -+ pressKey(keyboardDev, i, false, "keycode"); -+ mieqProcessInputEvents(); -+ return; - } - } -- } -- -- return -1; /* Not a modifier */ --} --#endif - --void InputDevice::keyEvent(rdr::U32 keysym, bool down) --{ --#if XORG < 17 -- DeviceIntPtr master; --#endif -- KeyClassPtr keyc; -- KeySymsPtr keymap = NULL; -- KeySym *map = NULL; -- KeyCode minKeyCode, maxKeyCode; -- KeyCode *modmap = NULL; -- int mapWidth; -- unsigned int i; -- int j, k, state, maxKeysPerMod; --#if XORG >= 17 -- KeybdCtrl ctrl; --#endif -- -- initInputDevice(); -+ /* -+ * This can happen quite often as we ignore some -+ * key presses. -+ */ -+ vlog.debug("Unexpected release of keysym 0x%x", keysym); -+ return; -+ } - - /* - * Since we are checking the current state to determine if we need -@@ -622,543 +470,214 @@ void InputDevice::keyEvent(rdr::U32 keys - */ - mieqProcessInputEvents(); - -- if (keysym == XK_Caps_Lock) { -- vlog.debug("Ignoring caps lock"); -- return; -- } -+ state = getKeyboardState(); - --#if XORG >= 17 --#if XORG >= 111 -- keyc = keyboardDev->master->key; --#else /* XORG >= 111 */ -- keyc = keyboardDev->u.master->key; --#endif /* XORG >= 111 */ -- -- keymap = XkbGetCoreMap(keyboardDev); -- if (!keymap) { -- vlog.error("VNC keyboard device has no map"); -- return; -- } -+ keycode = keysymToKeycode(keysym, state, &new_state); - -- if (generate_modkeymap(serverClient, keyboardDev, &modmap, -- &maxKeysPerMod) != Success) { -- vlog.error("generate_modkeymap failed"); -- xfree(keymap->map); -- xfree(keymap); -- return; -- } -- -- if (maxKeysPerMod == 0) -- vlog.debug("Keyboard has no modifiers"); -- -- state = XkbStateFieldFromRec(&keyc->xkbInfo->state); --#else -- keyc = keyboardDev->key; -- state = keyc->state; -- maxKeysPerMod = keyc->maxKeysPerModifier; -- keymap = &keyc->curKeySyms; -- modmap = keyc->modifierKeyMap; --#endif -- map = keymap->map; -- minKeyCode = keymap->minKeyCode; -- maxKeyCode = keymap->maxKeyCode; -- mapWidth = keymap->mapWidth; -- --#if XORG >= 17 -- /* -- * No server-side key repeating, please. Some clients won't work well, -- * check https://bugzilla.redhat.com/show_bug.cgi?id=607866. -- */ -- ctrl = keyboardDev->kbdfeed->ctrl; -- if (ctrl.autoRepeat != FALSE) { -- ctrl.autoRepeat = FALSE; -- XkbSetRepeatKeys(keyboardDev, -1, ctrl.autoRepeat); -- } --#endif -- -- /* find which modifier Mode_switch is on. */ -- int modeSwitchMapIndex = 0; -- for (i = 3; i < 8; i++) { -- for (k = 0; k < maxKeysPerMod; k++) { -- int index = i * maxKeysPerMod + k; -- int keycode = modmap[index]; -- -- if (keycode == 0) -+ /* Try some equivalent keysyms if we couldn't find a perfect match */ -+ if (keycode == 0) { -+ for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) { -+ KeySym altsym; -+ -+ if (altKeysym[i].a == keysym) -+ altsym = altKeysym[i].b; -+ else if (altKeysym[i].b == keysym) -+ altsym = altKeysym[i].a; -+ else - continue; - -- for (j = 0; j < mapWidth; j++) { -- if (map[(keycode - minKeyCode) * mapWidth + j] -- == XK_Mode_switch) { -- modeSwitchMapIndex = i; -- goto ModeSwitchFound; -- } -- } -+ keycode = keysymToKeycode(altsym, state, &new_state); -+ if (keycode != 0) -+ break; - } - } --ModeSwitchFound: - -- int kc; -- int col = 0; -+ /* We don't have lock synchronisation... */ -+ if (isLockModifier(keycode, new_state)) { -+ vlog.debug("Ignoring lock key (e.g. caps lock)"); -+ return; -+ } - --#if XORG >= 17 -- if ((kc = isModifier(keymap, modmap, maxKeysPerMod, keysym)) != -1) { -- /* -- * It is a modifier key event. -- * -- * Don't do any auto-repeat because the X server will translate -- * each press into a release followed by a press. -- */ -- if (IS_PRESSED(keyc, kc) && down) { -- FREE_MAPS; -+ /* No matches. Will have to add a new entry... */ -+ if (keycode == 0) { -+ keycode = addKeysym(keysym, state); -+ if (keycode == 0) { -+ vlog.error("Failure adding new keysym 0x%x", keysym); - return; - } - -- goto press; -- } --#endif -- -- if (maxKeysPerMod != 0) { -- if ((state & (1 << ShiftMapIndex)) != 0) -- col |= 1; -- if (modeSwitchMapIndex != 0 && -- ((state & (1 << modeSwitchMapIndex))) != 0) -- col |= 2; -- } -- -- kc = KeysymToKeycode(keymap, keysym, &col); -+ vlog.info("Added unknown keysym 0x%x to keycode %d", -+ keysym, keycode); - -- /* -- * Sort out the "shifted Tab" mess. If we are sent a shifted Tab, -- * generate a local shifted Tab regardless of what the "shifted Tab" -- * keysym is on the local keyboard (it might be Tab, ISO_Left_Tab or -- * HP's private BackTab keysym, and quite possibly some others too). -- * We never get ISO_Left_Tab here because it's already been translated -- * in VNCSConnectionST. -- */ -- if (maxKeysPerMod != 0 && keysym == XK_Tab && -- ((state & (1 << ShiftMapIndex))) != 0) -- col |= 1; -- -- if (kc == 0) { - /* -- * Not a direct match in the local keyboard mapping. Check for -- * alternative keysyms with the same meaning. -+ * The state given to addKeysym() is just a hint and -+ * the actual result might still require some state -+ * changes. - */ -- for (i = 0; i < sizeof(altKeysym) / sizeof(altKeysym_t); i++) { -- if (keysym == altKeysym[i].a) -- kc = KeysymToKeycode(keymap, altKeysym[i].b, -- &col); -- else if (keysym == altKeysym[i].b) -- kc = KeysymToKeycode(keymap, altKeysym[i].a, -- &col); -- if (kc) -- break; -+ keycode = keysymToKeycode(keysym, state, &new_state); -+ if (keycode == 0) { -+ vlog.error("Newly added keysym 0x%x cannot be generated", keysym); -+ return; - } - } - -- if (kc == 0) { -- /* Dynamically add a new key to the keyboard mapping. */ -- for (kc = maxKeyCode; kc >= minKeyCode; kc--) { -- if (map[(kc - minKeyCode) * mapWidth] != 0) -+ /* -+ * X11 generally lets shift toggle the keys on the numeric pad -+ * the same way NumLock does. This is however not the case on -+ * other systems like Windows. As a result, some applications -+ * get confused when we do a fake shift to get the same effect -+ * that having NumLock active would produce. -+ * -+ * Until we have proper NumLock synchronisation (so we can -+ * avoid faking shift), we try to avoid the fake shifts if we -+ * can use an alternative keysym. -+ */ -+ if (((state & ShiftMask) != (new_state & ShiftMask)) && -+ avoidShiftNumLock && isAffectedByNumLock(keycode)) { -+ KeyCode keycode2; -+ unsigned new_state2; -+ -+ vlog.debug("Finding alternative to keysym 0x%x to avoid fake shift for numpad", keysym); -+ -+ for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) { -+ KeySym altsym; -+ -+ if (altKeysym[i].a == keysym) -+ altsym = altKeysym[i].b; -+ else if (altKeysym[i].b == keysym) -+ altsym = altKeysym[i].a; -+ else - continue; - -- map[(kc - minKeyCode) * mapWidth] = keysym; -- col = 0; -+ keycode2 = keysymToKeycode(altsym, state, &new_state2); -+ if (keycode2 == 0) -+ continue; - -- vlog.info("Added unknown keysym 0x%x to keycode %d", -- keysym, kc); -+ if (((state & ShiftMask) != (new_state2 & ShiftMask)) && -+ isAffectedByNumLock(keycode2)) -+ continue; - --#if XORG < 17 --#if XORG == 15 -- master = inputInfo.keyboard; --#else -- master = keyboardDev->u.master; --#endif -- void *slave = dixLookupPrivate(&master->devPrivates, -- CoreDevicePrivateKey); -- if (keyboardDev == slave) { -- dixSetPrivate(&master->devPrivates, -- CoreDevicePrivateKey, NULL); --#if XORG == 15 -- SwitchCoreKeyboard(keyboardDev); --#else -- CopyKeyClass(keyboardDev, master); --#endif -- } --#else /* XORG < 17 */ -- XkbApplyMappingChange(keyboardDev, keymap, minKeyCode, -- maxKeyCode - minKeyCode + 1, -- NULL, serverClient); --#if XORG >= 111 -- XkbCopyDeviceKeymap(keyboardDev->master, keyboardDev); --#else -- XkbCopyDeviceKeymap(keyboardDev->u.master, keyboardDev); --#endif --#endif /* XORG < 17 */ - break; - } -- } - -- if (kc < minKeyCode) { -- vlog.info("Keyboard mapping full - ignoring unknown keysym " -- "0x%x",keysym); -- FREE_MAPS; -- return; -- } -- --#if XORG < 17 -- /* -- * See if it's a modifier key. If so, then don't do any auto-repeat, -- * because the X server will translate each press into a release -- * followed by a press. -- */ -- for (i = 0; i < 8; i++) { -- for (k = 0; k < maxKeysPerMod; k++) { -- int index = i * maxKeysPerMod + k; -- if (kc == modmap[index] && IS_PRESSED(keyc,kc) && down) { -- FREE_MAPS; -- return; -- } -+ if (i == sizeof(altKeysym)/sizeof(altKeysym[0])) -+ vlog.debug("No alternative keysym found"); -+ else { -+ keycode = keycode2; -+ new_state = new_state2; - } - } --#else -+ - /* -- * If you would like to press a key which is already pressed then -- * viewer didn't send the "release" event. In this case release it -- * before the press. -+ * "Shifted Tab" is a bit of a mess. Some systems have varying, -+ * special keysyms for this symbol. VNC mandates that clients -+ * should always send the plain XK_Tab keysym and the server -+ * should deduce the meaning based on current Shift state. -+ * To comply with this, we will find the keycode that sends -+ * XK_Tab, and make sure that Shift isn't cleared. This can -+ * possibly result in a different keysym than XK_Tab, but that -+ * is the desired behaviour. -+ * -+ * Note: We never get ISO_Left_Tab here because it's already -+ * been translated in VNCSConnectionST. - */ -- if (IS_PRESSED(keyc, kc) && down) { -- vlog.debug("KeyRelease for %d wasn't sent, releasing", kc); -- pressKey(keyboardDev, kc, false, "fixing keycode"); -- } --#endif -+ if (keysym == XK_Tab && (state & ShiftMask)) -+ new_state |= ShiftMask; - -- if (maxKeysPerMod != 0) { -- ModifierState shift(keyboardDev, ShiftMapIndex); -- ModifierState modeSwitch(keyboardDev, modeSwitchMapIndex); -- if (down) { -- if (col & 1) -- shift.press(); -- else -- shift.release(); -- if (modeSwitchMapIndex) { -- if (col & 2) -- modeSwitch.press(); -- else -- modeSwitch.release(); -- } -- } -- /* -- * Ensure ModifierState objects are not destroyed before -- * pressKey call, otherwise fake modifier keypress can be lost. -- */ -- pressKey(keyboardDev, kc, down, "keycode"); -- } else { --press: -- pressKey(keyboardDev, kc, down, "keycode"); -- } -- -- -- FREE_MAPS; -- - /* -- * When faking a modifier we are putting a keycode (which can -- * currently activate the desired modifier) on the input -- * queue. A future modmap change can change the mapping so -- * that this keycode means something else entirely. Guard -- * against this by processing the queue now. -+ * We need a bigger state change than just shift, -+ * so we need to know what the mask is for level 3 shifts. - */ -- mieqProcessInputEvents(); --} -- --static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col) --{ -- int per = keymap->mapWidth; -- KeySym *syms; -- KeySym lsym, usym; -- -- if ((col < 0) || ((col >= per) && (col > 3)) || -- (keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode)) -- return NoSymbol; -- -- syms = &keymap->map[(keycode - keymap->minKeyCode) * per]; -- if (col >= 4) -- return syms[col]; -- -- if (col > 1) { -- while ((per > 2) && (syms[per - 1] == NoSymbol)) -- per--; -- if (per < 3) -- col -= 2; -- } -- -- if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) { -- XkbConvertCase -- (syms[col&~1], &lsym, &usym); -- if (!(col & 1)) -- return lsym; -- /* -- * I'm commenting out this logic because it's incorrect even -- * though it was copied from the Xlib sources. The X protocol -- * book quite clearly states that where a group consists of -- * element 1 being a non-alphabetic keysym and element 2 being -- * NoSymbol that you treat the second element as being the -- * same as the first. This also tallies with the behaviour -- * produced by the installed Xlib on my linux box (I believe -- * this is because it uses some XKB code rather than the -- * original Xlib code - compare XKBBind.c with KeyBind.c in -- * lib/X11). -- */ --#if 0 -- else if (usym == lsym) -- return NoSymbol; --#endif -- else -- return usym; -- } -- -- return syms[col]; --} -+ if ((new_state & ~ShiftMask) != (state & ~ShiftMask)) -+ level_three_mask = getLevelThreeMask(); -+ else -+ level_three_mask = 0; -+ -+ shift_press = level_three_press = 0; -+ -+ /* Need a fake press or release of shift? */ -+ if (!(state & ShiftMask) && (new_state & ShiftMask)) { -+ shift_press = pressShift(); -+ if (shift_press == 0) { -+ vlog.error("Unable to find a modifier key for Shift"); -+ return; -+ } - --/* -- * KeysymToKeycode() - find the keycode and column corresponding to the given -- * keysym. The value of col passed in should be the column determined from the -- * current shift state. If the keysym can be found in that column we prefer -- * that to finding it in a different column (which would require fake events to -- * alter the shift state). -- */ --static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col) --{ -- int i, j; -+ pressKey(keyboardDev, shift_press, true, "temp shift"); -+ } else if ((state & ShiftMask) && !(new_state & ShiftMask)) { -+ std::list::const_iterator iter; -+ -+ shift_release = releaseShift(); -+ if (shift_release.empty()) { -+ vlog.error("Unable to find the modifier key(s) for releasing Shift"); -+ return; -+ } - -- j = *col; -- for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { -- if (KeyCodetoKeySym(keymap, i, j) == ks) -- return i; -+ for (iter = shift_release.begin();iter != shift_release.end();++iter) -+ pressKey(keyboardDev, *iter, false, "temp shift"); - } - -- for (j = 0; j < keymap->mapWidth; j++) { -- for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { -- if (KeyCodetoKeySym(keymap, i, j) == ks) { -- *col = j; -- return i; -- } -+ /* Need a fake press or release of level three shift? */ -+ if (!(state & level_three_mask) && (new_state & level_three_mask)) { -+ level_three_press = pressLevelThree(); -+ if (level_three_press == 0) { -+ vlog.error("Unable to find a modifier key for ISO_Level3_Shift/Mode_Switch"); -+ return; - } -- } - -- return 0; --} -- --#if XORG < 17 --/* Fairly standard US PC Keyboard */ -- --#define MIN_KEY 8 --#define MAX_KEY 255 --#define MAP_LEN (MAX_KEY - MIN_KEY + 1) --#define KEYSYMS_PER_KEY 2 --KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = { -- NoSymbol, NoSymbol, -- XK_Escape, NoSymbol, -- XK_1, XK_exclam, -- XK_2, XK_at, -- XK_3, XK_numbersign, -- XK_4, XK_dollar, -- XK_5, XK_percent, -- XK_6, XK_asciicircum, -- XK_7, XK_ampersand, -- XK_8, XK_asterisk, -- XK_9, XK_parenleft, -- XK_0, XK_parenright, -- XK_minus, XK_underscore, -- XK_equal, XK_plus, -- XK_BackSpace, NoSymbol, -- XK_Tab, NoSymbol, -- XK_q, XK_Q, -- XK_w, XK_W, -- XK_e, XK_E, -- XK_r, XK_R, -- XK_t, XK_T, -- XK_y, XK_Y, -- XK_u, XK_U, -- XK_i, XK_I, -- XK_o, XK_O, -- XK_p, XK_P, -- XK_bracketleft, XK_braceleft, -- XK_bracketright, XK_braceright, -- XK_Return, NoSymbol, -- XK_Control_L, NoSymbol, -- XK_a, XK_A, -- XK_s, XK_S, -- XK_d, XK_D, -- XK_f, XK_F, -- XK_g, XK_G, -- XK_h, XK_H, -- XK_j, XK_J, -- XK_k, XK_K, -- XK_l, XK_L, -- XK_semicolon, XK_colon, -- XK_apostrophe, XK_quotedbl, -- XK_grave, XK_asciitilde, -- XK_Shift_L, NoSymbol, -- XK_backslash, XK_bar, -- XK_z, XK_Z, -- XK_x, XK_X, -- XK_c, XK_C, -- XK_v, XK_V, -- XK_b, XK_B, -- XK_n, XK_N, -- XK_m, XK_M, -- XK_comma, XK_less, -- XK_period, XK_greater, -- XK_slash, XK_question, -- XK_Shift_R, NoSymbol, -- XK_KP_Multiply, NoSymbol, -- XK_Alt_L, XK_Meta_L, -- XK_space, NoSymbol, -- XK_Caps_Lock, NoSymbol, -- XK_F1, NoSymbol, -- XK_F2, NoSymbol, -- XK_F3, NoSymbol, -- XK_F4, NoSymbol, -- XK_F5, NoSymbol, -- XK_F6, NoSymbol, -- XK_F7, NoSymbol, -- XK_F8, NoSymbol, -- XK_F9, NoSymbol, -- XK_F10, NoSymbol, -- XK_Num_Lock, XK_Pointer_EnableKeys, -- XK_Scroll_Lock, NoSymbol, -- XK_KP_Home, XK_KP_7, -- XK_KP_Up, XK_KP_8, -- XK_KP_Prior, XK_KP_9, -- XK_KP_Subtract, NoSymbol, -- XK_KP_Left, XK_KP_4, -- XK_KP_Begin, XK_KP_5, -- XK_KP_Right, XK_KP_6, -- XK_KP_Add, NoSymbol, -- XK_KP_End, XK_KP_1, -- XK_KP_Down, XK_KP_2, -- XK_KP_Next, XK_KP_3, -- XK_KP_Insert, XK_KP_0, -- XK_KP_Delete, XK_KP_Decimal, -- NoSymbol, NoSymbol, -- NoSymbol, NoSymbol, -- NoSymbol, NoSymbol, -- XK_F11, NoSymbol, -- XK_F12, NoSymbol, -- XK_Home, NoSymbol, -- XK_Up, NoSymbol, -- XK_Prior, NoSymbol, -- XK_Left, NoSymbol, -- NoSymbol, NoSymbol, -- XK_Right, NoSymbol, -- XK_End, NoSymbol, -- XK_Down, NoSymbol, -- XK_Next, NoSymbol, -- XK_Insert, NoSymbol, -- XK_Delete, NoSymbol, -- XK_KP_Enter, NoSymbol, -- XK_Control_R, NoSymbol, -- XK_Pause, XK_Break, -- XK_Print, XK_Execute, -- XK_KP_Divide, NoSymbol, -- XK_Alt_R, XK_Meta_R, -- NoSymbol, NoSymbol, -- XK_Super_L, NoSymbol, -- XK_Super_R, NoSymbol, -- XK_Menu, NoSymbol, --}; -+ pressKey(keyboardDev, level_three_press, true, "temp level 3 shift"); -+ } else if ((state & level_three_mask) && !(new_state & level_three_mask)) { -+ std::list::const_iterator iter; -+ -+ level_three_release = releaseLevelThree(); -+ if (level_three_release.empty()) { -+ vlog.error("Unable to find the modifier key(s) for releasing ISO_Level3_Shift/Mode_Switch"); -+ return; -+ } - --static Bool GetMappings(KeySymsPtr pKeySyms, CARD8 *pModMap) --{ -- int i; -+ for (iter = level_three_release.begin();iter != level_three_release.end();++iter) -+ pressKey(keyboardDev, *iter, false, "temp level 3 shift"); -+ } - -- for (i = 0; i < MAP_LENGTH; i++) -- pModMap[i] = NoSymbol; -+ /* Now press the actual key */ -+ pressKey(keyboardDev, keycode, true, "keycode"); - -- for (i = 0; i < MAP_LEN; i++) { -- switch (keyboardMap[i * KEYSYMS_PER_KEY]) { -- case XK_Shift_L: -- case XK_Shift_R: -- pModMap[i + MIN_KEY] = ShiftMask; -- break; -- case XK_Caps_Lock: -- pModMap[i + MIN_KEY] = LockMask; -- break; -- case XK_Control_L: -- case XK_Control_R: -- pModMap[i + MIN_KEY] = ControlMask; -- break; -- case XK_Alt_L: -- case XK_Alt_R: -- pModMap[i + MIN_KEY] = Mod1Mask; -- break; -- case XK_Num_Lock: -- pModMap[i + MIN_KEY] = Mod2Mask; -- break; -- /* No defaults for Mod3Mask yet */ -- case XK_Super_L: -- case XK_Super_R: -- case XK_Hyper_L: -- case XK_Hyper_R: -- pModMap[i + MIN_KEY] = Mod4Mask; -- break; -- case XK_ISO_Level3_Shift: -- case XK_Mode_switch: -- pModMap[i + MIN_KEY] = Mod5Mask; -- break; -+ /* And store the mapping so that we can do a proper release later */ -+ for (i = 0;i < 256;i++) { -+ if (i == keycode) -+ continue; -+ if (pressedKeys[i] == keysym) { -+ vlog.error("Keysym 0x%x generated by both keys %d and %d", keysym, i, keycode); -+ pressedKeys[i] = NoSymbol; - } - } - -- pKeySyms->minKeyCode = MIN_KEY; -- pKeySyms->maxKeyCode = MAX_KEY; -- pKeySyms->mapWidth = KEYSYMS_PER_KEY; -- pKeySyms->map = keyboardMap; -+ pressedKeys[keycode] = keysym; - -- return TRUE; --} --#endif -- --static void keyboardBell(int percent, DeviceIntPtr device, pointer ctrl, -- int class_) --{ -- if (percent > 0) -- vncBell(); --} -- --static int keyboardProc(DeviceIntPtr pDevice, int onoff) --{ --#if XORG < 17 -- KeySymsRec keySyms; -- CARD8 modMap[MAP_LENGTH]; --#endif -- DevicePtr pDev = (DevicePtr)pDevice; -+ /* Undo any fake level three shift */ -+ if (level_three_press != 0) -+ pressKey(keyboardDev, level_three_press, false, "temp level 3 shift"); -+ else if (!level_three_release.empty()) { -+ std::list::const_iterator iter; -+ for (iter = level_three_release.begin();iter != level_three_release.end();++iter) -+ pressKey(keyboardDev, *iter, true, "temp level 3 shift"); -+ } - -- switch (onoff) { -- case DEVICE_INIT: --#if XORG < 17 -- GetMappings(&keySyms, modMap); --#endif -- InitKeyboardDeviceStruct( --#if XORG >= 17 -- pDevice, NULL, --#else -- pDev, &keySyms, modMap, --#endif -- keyboardBell, (KbdCtrlProcPtr)NoopDDA); -- break; -- case DEVICE_ON: -- pDev->on = TRUE; -- break; -- case DEVICE_OFF: -- pDev->on = FALSE; -- break; --#if 0 -- case DEVICE_CLOSE: -- break; --#endif -+ /* Undo any fake shift */ -+ if (shift_press != 0) -+ pressKey(keyboardDev, shift_press, false, "temp shift"); -+ else if (!shift_release.empty()) { -+ std::list::const_iterator iter; -+ for (iter = shift_release.begin();iter != shift_release.end();++iter) -+ pressKey(keyboardDev, *iter, true, "temp shift"); - } - -- return Success; -+ /* -+ * When faking a modifier we are putting a keycode (which can -+ * currently activate the desired modifier) on the input -+ * queue. A future modmap change can change the mapping so -+ * that this keycode means something else entirely. Guard -+ * against this by processing the queue now. -+ */ -+ mieqProcessInputEvents(); - } -- -diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputCore.cc.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputCore.cc ---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputCore.cc.input 2014-01-17 16:01:13.141109454 +0000 -+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputCore.cc 2014-01-17 16:01:13.141109454 +0000 -@@ -0,0 +1,594 @@ -+/* Copyright (C) 2009 TightVNC Team -+ * Copyright (C) 2009 Red Hat, Inc. -+ * Copyright 2013 Pierre Ossman for Cendio AB -+ * -+ * This is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This software is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this software; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -+ * USA. -+ */ -+ -+#ifdef HAVE_DIX_CONFIG_H -+#include -+#endif -+ -+#include "Input.h" -+#include "xorg-version.h" -+ -+extern "C" { -+#define public c_public -+#define class c_class -+#include "inputstr.h" -+#ifndef XKB_IN_SERVER -+#define XKB_IN_SERVER -+#endif -+#ifdef XKB -+/* -+ * This include is needed to use XkbConvertCase instead of XConvertCase even if -+ * we don't use XKB extension. -+ */ -+#include -+#endif -+/* These defines give us access to all keysyms we need */ -+#define XK_PUBLISHING -+#define XK_TECHNICAL -+#include -+#include -+#include -+#include -+#undef public -+#undef class -+} -+ -+#if XORG < 17 -+ -+#define IS_PRESSED(dev, keycode) \ -+ ((dev)->key->down[(keycode) >> 3] & (1 << ((keycode) & 7))) -+ -+/* Fairly standard US PC Keyboard */ -+ -+#define MIN_KEY 8 -+#define MAX_KEY 255 -+#define MAP_LEN (MAX_KEY - MIN_KEY + 1) -+#define KEYSYMS_PER_KEY 2 -+KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = { -+ NoSymbol, NoSymbol, -+ XK_Escape, NoSymbol, -+ XK_1, XK_exclam, -+ XK_2, XK_at, -+ XK_3, XK_numbersign, -+ XK_4, XK_dollar, -+ XK_5, XK_percent, -+ XK_6, XK_asciicircum, -+ XK_7, XK_ampersand, -+ XK_8, XK_asterisk, -+ XK_9, XK_parenleft, -+ XK_0, XK_parenright, -+ XK_minus, XK_underscore, -+ XK_equal, XK_plus, -+ XK_BackSpace, NoSymbol, -+ XK_Tab, NoSymbol, -+ XK_q, XK_Q, -+ XK_w, XK_W, -+ XK_e, XK_E, -+ XK_r, XK_R, -+ XK_t, XK_T, -+ XK_y, XK_Y, -+ XK_u, XK_U, -+ XK_i, XK_I, -+ XK_o, XK_O, -+ XK_p, XK_P, -+ XK_bracketleft, XK_braceleft, -+ XK_bracketright, XK_braceright, -+ XK_Return, NoSymbol, -+ XK_Control_L, NoSymbol, -+ XK_a, XK_A, -+ XK_s, XK_S, -+ XK_d, XK_D, -+ XK_f, XK_F, -+ XK_g, XK_G, -+ XK_h, XK_H, -+ XK_j, XK_J, -+ XK_k, XK_K, -+ XK_l, XK_L, -+ XK_semicolon, XK_colon, -+ XK_apostrophe, XK_quotedbl, -+ XK_grave, XK_asciitilde, -+ XK_Shift_L, NoSymbol, -+ XK_backslash, XK_bar, -+ XK_z, XK_Z, -+ XK_x, XK_X, -+ XK_c, XK_C, -+ XK_v, XK_V, -+ XK_b, XK_B, -+ XK_n, XK_N, -+ XK_m, XK_M, -+ XK_comma, XK_less, -+ XK_period, XK_greater, -+ XK_slash, XK_question, -+ XK_Shift_R, NoSymbol, -+ XK_KP_Multiply, NoSymbol, -+ XK_Alt_L, XK_Meta_L, -+ XK_space, NoSymbol, -+ XK_Caps_Lock, NoSymbol, -+ XK_F1, NoSymbol, -+ XK_F2, NoSymbol, -+ XK_F3, NoSymbol, -+ XK_F4, NoSymbol, -+ XK_F5, NoSymbol, -+ XK_F6, NoSymbol, -+ XK_F7, NoSymbol, -+ XK_F8, NoSymbol, -+ XK_F9, NoSymbol, -+ XK_F10, NoSymbol, -+ XK_Num_Lock, XK_Pointer_EnableKeys, -+ XK_Scroll_Lock, NoSymbol, -+ XK_KP_Home, XK_KP_7, -+ XK_KP_Up, XK_KP_8, -+ XK_KP_Prior, XK_KP_9, -+ XK_KP_Subtract, NoSymbol, -+ XK_KP_Left, XK_KP_4, -+ XK_KP_Begin, XK_KP_5, -+ XK_KP_Right, XK_KP_6, -+ XK_KP_Add, NoSymbol, -+ XK_KP_End, XK_KP_1, -+ XK_KP_Down, XK_KP_2, -+ XK_KP_Next, XK_KP_3, -+ XK_KP_Insert, XK_KP_0, -+ XK_KP_Delete, XK_KP_Decimal, -+ NoSymbol, NoSymbol, -+ NoSymbol, NoSymbol, -+ NoSymbol, NoSymbol, -+ XK_F11, NoSymbol, -+ XK_F12, NoSymbol, -+ XK_Home, NoSymbol, -+ XK_Up, NoSymbol, -+ XK_Prior, NoSymbol, -+ XK_Left, NoSymbol, -+ NoSymbol, NoSymbol, -+ XK_Right, NoSymbol, -+ XK_End, NoSymbol, -+ XK_Down, NoSymbol, -+ XK_Next, NoSymbol, -+ XK_Insert, NoSymbol, -+ XK_Delete, NoSymbol, -+ XK_KP_Enter, NoSymbol, -+ XK_Control_R, NoSymbol, -+ XK_Pause, XK_Break, -+ XK_Print, XK_Execute, -+ XK_KP_Divide, NoSymbol, -+ XK_Alt_R, XK_Meta_R, -+ NoSymbol, NoSymbol, -+ XK_Super_L, NoSymbol, -+ XK_Super_R, NoSymbol, -+ XK_Menu, NoSymbol, -+}; -+ -+void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap) -+{ -+ int i; -+ -+ for (i = 0; i < MAP_LENGTH; i++) -+ modmap[i] = NoSymbol; -+ -+ for (i = 0; i < MAP_LEN; i++) { -+ switch (keyboardMap[i * KEYSYMS_PER_KEY]) { -+ case XK_Shift_L: -+ case XK_Shift_R: -+ modmap[i + MIN_KEY] = ShiftMask; -+ break; -+ case XK_Caps_Lock: -+ modmap[i + MIN_KEY] = LockMask; -+ break; -+ case XK_Control_L: -+ case XK_Control_R: -+ modmap[i + MIN_KEY] = ControlMask; -+ break; -+ case XK_Alt_L: -+ case XK_Alt_R: -+ modmap[i + MIN_KEY] = Mod1Mask; -+ break; -+ case XK_Num_Lock: -+ modmap[i + MIN_KEY] = Mod2Mask; -+ break; -+ /* No defaults for Mod3Mask yet */ -+ case XK_Super_L: -+ case XK_Super_R: -+ case XK_Hyper_L: -+ case XK_Hyper_R: -+ modmap[i + MIN_KEY] = Mod4Mask; -+ break; -+ case XK_ISO_Level3_Shift: -+ case XK_Mode_switch: -+ modmap[i + MIN_KEY] = Mod5Mask; -+ break; -+ } -+ } -+ -+ keysyms->minKeyCode = MIN_KEY; -+ keysyms->maxKeyCode = MAX_KEY; -+ keysyms->mapWidth = KEYSYMS_PER_KEY; -+ keysyms->map = keyboardMap; -+} -+ -+void InputDevice::PrepareInputDevices(void) -+{ -+ /* Don't need to do anything here */ -+} -+ -+unsigned InputDevice::getKeyboardState(void) -+{ -+ return keyboardDev->key->state; -+} -+ -+unsigned InputDevice::getLevelThreeMask(void) -+{ -+ int i, j, k; -+ -+ int minKeyCode, mapWidth; -+ KeySym *map; -+ -+ int maxKeysPerMod; -+ CARD8 *modmap; -+ -+ minKeyCode = keyboardDev->key->curKeySyms.minKeyCode; -+ mapWidth = keyboardDev->key->curKeySyms.mapWidth; -+ map = keyboardDev->key->curKeySyms.map; -+ -+ maxKeysPerMod = keyboardDev->key->maxKeysPerModifier; -+ modmap = keyboardDev->key->modifierKeyMap; -+ -+ for (i = 3; i < 8; i++) { -+ for (k = 0; k < maxKeysPerMod; k++) { -+ int index = i * maxKeysPerMod + k; -+ int keycode = modmap[index]; -+ -+ if (keycode == 0) -+ continue; -+ -+ for (j = 0; j < mapWidth; j++) { -+ KeySym keysym; -+ keysym = map[(keycode - minKeyCode) * mapWidth + j]; -+ if (keysym == XK_Mode_switch) -+ return 1 << i; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+KeyCode InputDevice::pressShift(void) -+{ -+ int maxKeysPerMod; -+ -+ maxKeysPerMod = keyboardDev->key->maxKeysPerModifier; -+ return keyboardDev->key->modifierKeyMap[ShiftMapIndex * maxKeysPerMod]; -+} -+ -+std::list InputDevice::releaseShift(void) -+{ -+ std::list keys; -+ -+ int maxKeysPerMod; -+ -+ maxKeysPerMod = keyboardDev->key->maxKeysPerModifier; -+ for (int k = 0; k < maxKeysPerMod; k++) { -+ int keycode; -+ int index; -+ -+ index = ShiftMapIndex * maxKeysPerMod + k; -+ -+ keycode = keyboardDev->key->modifierKeyMap[index]; -+ if (keycode == 0) -+ continue; -+ -+ if (!IS_PRESSED(keyboardDev, keycode)) -+ continue; -+ -+ keys.push_back(keycode); -+ } -+ -+ return keys; -+} -+ -+KeyCode InputDevice::pressLevelThree(void) -+{ -+ unsigned mask, index; -+ int maxKeysPerMod; -+ -+ mask = getLevelThreeMask(); -+ if (mask == 0) -+ return 0; -+ -+ index = ffs(mask) - 1; -+ maxKeysPerMod = keyboardDev->key->maxKeysPerModifier; -+ return keyboardDev->key->modifierKeyMap[index * maxKeysPerMod]; -+} -+ -+std::list InputDevice::releaseLevelThree(void) -+{ -+ std::list keys; -+ -+ unsigned mask, msindex; -+ int maxKeysPerMod; -+ -+ mask = getLevelThreeMask(); -+ if (mask == 0) -+ return keys; -+ -+ msindex = ffs(mask) - 1; -+ -+ maxKeysPerMod = keyboardDev->key->maxKeysPerModifier; -+ for (int k = 0; k < maxKeysPerMod; k++) { -+ int keycode; -+ int index; -+ -+ index = msindex * maxKeysPerMod + k; -+ -+ keycode = keyboardDev->key->modifierKeyMap[index]; -+ if (keycode == 0) -+ continue; -+ -+ if (!IS_PRESSED(keyboardDev, keycode)) -+ continue; -+ -+ keys.push_back(keycode); -+ } -+ -+ return keys; -+} -+ -+static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col) -+{ -+ int per = keymap->mapWidth; -+ KeySym *syms; -+ KeySym lsym, usym; -+ -+ if ((col < 0) || ((col >= per) && (col > 3)) || -+ (keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode)) -+ return NoSymbol; -+ -+ syms = &keymap->map[(keycode - keymap->minKeyCode) * per]; -+ if (col >= 4) -+ return syms[col]; -+ -+ if (col > 1) { -+ while ((per > 2) && (syms[per - 1] == NoSymbol)) -+ per--; -+ if (per < 3) -+ col -= 2; -+ } -+ -+ if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) { -+ XkbConvertCase(syms[col&~1], &lsym, &usym); -+ if (!(col & 1)) -+ return lsym; -+ /* -+ * I'm commenting out this logic because it's incorrect even -+ * though it was copied from the Xlib sources. The X protocol -+ * book quite clearly states that where a group consists of -+ * element 1 being a non-alphabetic keysym and element 2 being -+ * NoSymbol that you treat the second element as being the -+ * same as the first. This also tallies with the behaviour -+ * produced by the installed Xlib on my linux box (I believe -+ * this is because it uses some XKB code rather than the -+ * original Xlib code - compare XKBBind.c with KeyBind.c in -+ * lib/X11). -+ */ -+#if 0 -+ else if (usym == lsym) -+ return NoSymbol; -+#endif -+ else -+ return usym; -+ } -+ -+ return syms[col]; -+} -+ -+KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state) -+{ -+ int i, j; -+ unsigned mask; -+ -+ KeySymsPtr keymap; -+ int mapWidth; -+ -+ mask = getLevelThreeMask(); -+ -+ keymap = &keyboardDev->key->curKeySyms; -+ -+ /* -+ * Column 0 means both shift and "mode_switch" (AltGr) must be released, -+ * column 1 means shift must be pressed and mode_switch released, -+ * column 2 means shift must be released and mode_switch pressed, and -+ * column 3 means both shift and mode_switch must be pressed. -+ */ -+ j = 0; -+ if (state & ShiftMask) -+ j |= 0x1; -+ if (state & mask) -+ j |= 0x2; -+ -+ *new_state = state; -+ for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { -+ if (KeyCodetoKeySym(keymap, i, j) == keysym) -+ return i; -+ } -+ -+ /* Only the first four columns have well-defined meaning */ -+ mapWidth = keymap->mapWidth; -+ if (mapWidth > 4) -+ mapWidth = 4; -+ -+ for (j = 0; j < mapWidth; j++) { -+ for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { -+ if (KeyCodetoKeySym(keymap, i, j) == keysym) { -+ *new_state = state & ~(ShiftMask|mask); -+ if (j & 0x1) -+ *new_state |= ShiftMask; -+ if (j & 0x2) -+ *new_state |= mask; -+ -+ return i; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+bool InputDevice::isLockModifier(KeyCode keycode, unsigned state) -+{ -+ int i, j, k; -+ -+ int minKeyCode, mapWidth; -+ KeySym *map; -+ -+ int maxKeysPerMod; -+ CARD8 *modmap; -+ -+ int num_lock_index; -+ -+ minKeyCode = keyboardDev->key->curKeySyms.minKeyCode; -+ mapWidth = keyboardDev->key->curKeySyms.mapWidth; -+ map = keyboardDev->key->curKeySyms.map; -+ -+ maxKeysPerMod = keyboardDev->key->maxKeysPerModifier; -+ modmap = keyboardDev->key->modifierKeyMap; -+ -+ /* Caps Lock is fairly easy as it has a dedicated modmap entry */ -+ for (k = 0; k < maxKeysPerMod; k++) { -+ int index; -+ -+ index = LockMapIndex * maxKeysPerMod + k; -+ if (keycode == modmap[index]) -+ return true; -+ } -+ -+ /* For Num Lock we need to find the correct modmap entry */ -+ num_lock_index = i; -+ for (i = 3; i < 8; i++) { -+ for (k = 0; k < maxKeysPerMod; k++) { -+ int index = i * maxKeysPerMod + k; -+ int keycode = modmap[index]; -+ -+ if (keycode == 0) -+ continue; -+ -+ for (j = 0; j < mapWidth; j++) { -+ KeySym keysym; -+ keysym = map[(keycode - minKeyCode) * mapWidth + j]; -+ if (keysym == XK_Num_Lock) { -+ num_lock_index = i; -+ goto done; -+ } -+ } -+ } -+ } -+done: -+ -+ if (num_lock_index == 0) -+ return false; -+ -+ /* Now we can look in the modmap */ -+ for (k = 0; k < maxKeysPerMod; k++) { -+ int index; -+ -+ index = num_lock_index * maxKeysPerMod + k; -+ if (keycode == modmap[index]) -+ return true; -+ } -+ -+ return false; -+} -+ -+bool InputDevice::isAffectedByNumLock(KeyCode keycode) -+{ -+ KeySymsPtr keymap; -+ int i, per; -+ KeySym *syms; -+ -+ keymap = &keyboardDev->key->curKeySyms; -+ per = keymap->mapWidth; -+ syms = &keymap->map[(keycode - keymap->minKeyCode) * per]; -+ -+ for (i = 0;i < per;i++) { -+ if (IsKeypadKey(syms[i])) -+ return true; -+ if (IsPrivateKeypadKey(syms[i])) -+ return true; -+ } -+ -+ return false; -+} -+ -+KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state) -+{ -+ KeyCode kc; -+ -+ int minKeyCode, maxKeyCode, mapWidth; -+ KeySym *map; -+ -+ minKeyCode = keyboardDev->key->curKeySyms.minKeyCode; -+ maxKeyCode = keyboardDev->key->curKeySyms.maxKeyCode; -+ mapWidth = keyboardDev->key->curKeySyms.mapWidth; -+ map = keyboardDev->key->curKeySyms.map; -+ -+ /* -+ * Magic, which dynamically adds keysym<->keycode mapping -+ * depends on X.Org version. Quick explanation of that "magic": -+ * -+ * 1.5 -+ * - has only one core keyboard so we have to keep core -+ * keyboard mapping synchronized with vncKeyboardDevice. Do -+ * it via SwitchCoreKeyboard() -+ * -+ * 1.6 (aka MPX - Multi pointer X) -+ * - multiple master devices (= core devices) exists, keep -+ * vncKeyboardDevice synchronized with proper master device -+ */ -+ for (kc = maxKeyCode; kc >= minKeyCode; kc--) { -+ DeviceIntPtr master; -+ -+ if (map[(kc - minKeyCode) * mapWidth] != 0) -+ continue; -+ -+ map[(kc - minKeyCode) * mapWidth] = keysym; -+ -+#if XORG == 15 -+ master = inputInfo.keyboard; -+#else -+ master = keyboardDev->u.master; -+#endif -+ void *slave = dixLookupPrivate(&master->devPrivates, -+ CoreDevicePrivateKey); -+ if (keyboardDev == slave) { -+ dixSetPrivate(&master->devPrivates, -+ CoreDevicePrivateKey, NULL); -+#if XORG == 15 -+ SwitchCoreKeyboard(keyboardDev); -+#else -+ CopyKeyClass(keyboardDev, master); -+#endif -+ } -+ -+ return kc; -+ } -+ -+ return 0; -+} -+ -+#endif -+ -diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.h.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.h ---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.h.input 2010-04-14 10:24:06.000000000 +0100 -+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.h 2014-01-17 16:01:13.141109454 +0000 -@@ -1,6 +1,7 @@ - /* Copyright (C) 2009 TightVNC Team - * Copyright (C) 2009, 2010 Red Hat, Inc. - * Copyright (C) 2009, 2010 TigerVNC Team -+ * Copyright 2013 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -26,12 +27,16 @@ - #include - #endif - -+#include -+ - #include - - extern "C" { - #include "input.h" - }; - -+#include "xorg-version.h" -+ - /* Represents input device (keyboard + pointer) */ - class InputDevice { - public: -@@ -55,24 +60,58 @@ public: - - void KeyboardPress(rdr::U32 keysym) { keyEvent(keysym, true); } - void KeyboardRelease(rdr::U32 keysym) { keyEvent(keysym, false); } --private: -+ - /* - * Init input device. This cannot be done in the constructor - * because constructor is called during X server extensions - * initialization. Devices must be initialized after core - * pointer/keyboard initialization which is actually after extesions - * initialization. Check InitExtensions(), InitCoreDevices() and -- * InitInput() calls in dix/main.c -+ * InitInput() calls in dix/main.c. Instead it is called from -+ * XserverDesktop at an appropriate time. - */ -- void initInputDevice(void); -+ void InitInputDevice(void); - -+private: - void keyEvent(rdr::U32 keysym, bool down); - -+ /* Backend dependent functions below here */ -+ void PrepareInputDevices(void); -+ -+ unsigned getKeyboardState(void); -+ unsigned getLevelThreeMask(void); -+ -+ KeyCode pressShift(void); -+ std::list releaseShift(void); -+ -+ KeyCode pressLevelThree(void); -+ std::list releaseLevelThree(void); -+ -+ KeyCode keysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state); -+ -+ bool isLockModifier(KeyCode keycode, unsigned state); -+ -+ bool isAffectedByNumLock(KeyCode keycode); -+ -+ KeyCode addKeysym(KeySym keysym, unsigned state); -+ -+private: -+#if XORG >= 17 -+ static void vncXkbProcessDeviceEvent(int screenNum, -+ InternalEvent *event, -+ DeviceIntPtr dev); -+#endif -+ -+private: - rfb::VNCServerST *server; -+ bool initialized; - DeviceIntPtr keyboardDev; - DeviceIntPtr pointerDev; -+ - int oldButtonMask; - rfb::Point cursorPos, oldCursorPos; -+ -+ KeySym pressedKeys[256]; - }; - - #endif -diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputXKB.cc.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputXKB.cc ---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputXKB.cc.input 2014-01-17 16:01:13.141109454 +0000 -+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputXKB.cc 2014-01-17 16:01:13.141109454 +0000 -@@ -0,0 +1,669 @@ -+/* Copyright (C) 2009 TightVNC Team -+ * Copyright (C) 2009 Red Hat, Inc. -+ * Copyright 2013 Pierre Ossman for Cendio AB -+ * -+ * This is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This software is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this software; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -+ * USA. -+ */ -+ -+#ifdef HAVE_DIX_CONFIG_H -+#include -+#endif -+ -+#include "Input.h" -+#include "xorg-version.h" -+ -+#if XORG >= 17 -+ -+extern "C" { -+#define public c_public -+#define class c_class -+#include "xkbsrv.h" -+#include "xkbstr.h" -+#include "eventstr.h" -+#include "scrnintstr.h" -+#include "mi.h" -+#include -+#include -+#include -+#undef public -+#undef class -+} -+ -+#if XORG < 19 -+static int vncXkbScreenPrivateKeyIndex; -+static DevPrivateKey vncXkbScreenPrivateKey = &vncXkbScreenPrivateKeyIndex; -+#else -+static DevPrivateKeyRec vncXkbPrivateKeyRec; -+#define vncXkbScreenPrivateKey (&vncXkbPrivateKeyRec) -+#endif -+ -+#define vncXkbScreenPrivate(pScreen) \ -+ (*(InputDevice**) dixLookupPrivate(&(pScreen)->devPrivates, \ -+ vncXkbScreenPrivateKey)) -+ -+#ifndef KEYBOARD_OR_FLOAT -+#define KEYBOARD_OR_FLOAT MASTER_KEYBOARD -+#endif -+ -+/* Stolen from libX11 */ -+static Bool -+XkbTranslateKeyCode(register XkbDescPtr xkb, KeyCode key, -+ register unsigned int mods, unsigned int *mods_rtrn, -+ KeySym *keysym_rtrn) -+{ -+ XkbKeyTypeRec *type; -+ int col,nKeyGroups; -+ unsigned preserve,effectiveGroup; -+ KeySym *syms; -+ -+ if (mods_rtrn!=NULL) -+ *mods_rtrn = 0; -+ -+ nKeyGroups= XkbKeyNumGroups(xkb,key); -+ if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) { -+ if (keysym_rtrn!=NULL) -+ *keysym_rtrn = NoSymbol; -+ return False; -+ } -+ -+ syms = XkbKeySymsPtr(xkb,key); -+ -+ /* find the offset of the effective group */ -+ col = 0; -+ effectiveGroup= XkbGroupForCoreState(mods); -+ if ( effectiveGroup>=nKeyGroups ) { -+ unsigned groupInfo= XkbKeyGroupInfo(xkb,key); -+ switch (XkbOutOfRangeGroupAction(groupInfo)) { -+ default: -+ effectiveGroup %= nKeyGroups; -+ break; -+ case XkbClampIntoRange: -+ effectiveGroup = nKeyGroups-1; -+ break; -+ case XkbRedirectIntoRange: -+ effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo); -+ if (effectiveGroup>=nKeyGroups) -+ effectiveGroup= 0; -+ break; -+ } -+ } -+ col= effectiveGroup*XkbKeyGroupsWidth(xkb,key); -+ type = XkbKeyKeyType(xkb,key,effectiveGroup); -+ -+ preserve= 0; -+ if (type->map) { /* find the column (shift level) within the group */ -+ register int i; -+ register XkbKTMapEntryPtr entry; -+ for (i=0,entry=type->map;imap_count;i++,entry++) { -+ if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) { -+ col+= entry->level; -+ if (type->preserve) -+ preserve= type->preserve[i].mask; -+ break; -+ } -+ } -+ } -+ -+ if (keysym_rtrn!=NULL) -+ *keysym_rtrn= syms[col]; -+ if (mods_rtrn) -+ *mods_rtrn= type->mods.mask&(~preserve); -+ -+ return (syms[col]!=NoSymbol); -+} -+ -+static XkbAction *XkbKeyActionPtr(XkbDescPtr xkb, KeyCode key, unsigned int mods) -+{ -+ XkbKeyTypeRec *type; -+ int col,nKeyGroups; -+ unsigned effectiveGroup; -+ XkbAction *acts; -+ -+ if (!XkbKeyHasActions(xkb, key)) -+ return NULL; -+ -+ nKeyGroups= XkbKeyNumGroups(xkb,key); -+ if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) -+ return NULL; -+ -+ acts = XkbKeyActionsPtr(xkb,key); -+ -+ /* find the offset of the effective group */ -+ col = 0; -+ effectiveGroup= XkbGroupForCoreState(mods); -+ if ( effectiveGroup>=nKeyGroups ) { -+ unsigned groupInfo= XkbKeyGroupInfo(xkb,key); -+ switch (XkbOutOfRangeGroupAction(groupInfo)) { -+ default: -+ effectiveGroup %= nKeyGroups; -+ break; -+ case XkbClampIntoRange: -+ effectiveGroup = nKeyGroups-1; -+ break; -+ case XkbRedirectIntoRange: -+ effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo); -+ if (effectiveGroup>=nKeyGroups) -+ effectiveGroup= 0; -+ break; -+ } -+ } -+ col= effectiveGroup*XkbKeyGroupsWidth(xkb,key); -+ type = XkbKeyKeyType(xkb,key,effectiveGroup); -+ -+ if (type->map) { /* find the column (shift level) within the group */ -+ register int i; -+ register XkbKTMapEntryPtr entry; -+ for (i=0,entry=type->map;imap_count;i++,entry++) { -+ if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) { -+ col+= entry->level; -+ break; -+ } -+ } -+ } -+ -+ return &acts[col]; -+} -+ -+static unsigned XkbKeyEffectiveGroup(XkbDescPtr xkb, KeyCode key, unsigned int mods) -+{ -+ int nKeyGroups; -+ unsigned effectiveGroup; -+ -+ nKeyGroups= XkbKeyNumGroups(xkb,key); -+ if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) -+ return 0; -+ -+ effectiveGroup= XkbGroupForCoreState(mods); -+ if ( effectiveGroup>=nKeyGroups ) { -+ unsigned groupInfo= XkbKeyGroupInfo(xkb,key); -+ switch (XkbOutOfRangeGroupAction(groupInfo)) { -+ default: -+ effectiveGroup %= nKeyGroups; -+ break; -+ case XkbClampIntoRange: -+ effectiveGroup = nKeyGroups-1; -+ break; -+ case XkbRedirectIntoRange: -+ effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo); -+ if (effectiveGroup>=nKeyGroups) -+ effectiveGroup= 0; -+ break; -+ } -+ } -+ -+ return effectiveGroup; -+} -+ -+void InputDevice::PrepareInputDevices(void) -+{ -+#if XORG < 19 -+ if (!dixRequestPrivate(vncXkbScreenPrivateKey, sizeof(InputDevice*))) -+ FatalError("Failed to register TigerVNC XKB screen key\n"); -+#else -+ if (!dixRegisterPrivateKey(vncXkbScreenPrivateKey, PRIVATE_SCREEN, -+ sizeof(InputDevice*))) -+ FatalError("Failed to register TigerVNC XKB screen key\n"); -+#endif -+ -+ for (int scr = 0; scr < screenInfo.numScreens; scr++) -+ vncXkbScreenPrivate(screenInfo.screens[scr]) = this; -+ -+ /* -+ * Not ideal since these callbacks do not stack, but it's the only -+ * decent way we can reliably catch events for both the slave and -+ * master device. -+ */ -+ mieqSetHandler(ET_KeyPress, vncXkbProcessDeviceEvent); -+ mieqSetHandler(ET_KeyRelease, vncXkbProcessDeviceEvent); -+} -+ -+unsigned InputDevice::getKeyboardState(void) -+{ -+ return XkbStateFieldFromRec(&keyboardDev->master->key->xkbInfo->state); -+} -+ -+unsigned InputDevice::getLevelThreeMask(void) -+{ -+ unsigned state; -+ KeyCode keycode; -+ XkbDescPtr xkb; -+ XkbAction *act; -+ -+ /* Group state is still important */ -+ state = getKeyboardState(); -+ state &= ~0xff; -+ -+ keycode = keysymToKeycode(XK_ISO_Level3_Shift, state, NULL); -+ if (keycode == 0) { -+ keycode = keysymToKeycode(XK_Mode_switch, state, NULL); -+ if (keycode == 0) -+ return 0; -+ } -+ -+ xkb = keyboardDev->master->key->xkbInfo->desc; -+ -+ act = XkbKeyActionPtr(xkb, keycode, state); -+ if (act == NULL) -+ return 0; -+ if (act->type != XkbSA_SetMods) -+ return 0; -+ -+ if (act->mods.flags & XkbSA_UseModMapMods) -+ return xkb->map->modmap[keycode]; -+ else -+ return act->mods.mask; -+} -+ -+KeyCode InputDevice::pressShift(void) -+{ -+ unsigned state; -+ -+ XkbDescPtr xkb; -+ unsigned int key; -+ -+ state = getKeyboardState(); -+ if (state & ShiftMask) -+ return 0; -+ -+ xkb = keyboardDev->master->key->xkbInfo->desc; -+ for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) { -+ XkbAction *act; -+ unsigned char mask; -+ -+ act = XkbKeyActionPtr(xkb, key, state); -+ if (act == NULL) -+ continue; -+ -+ if (act->type != XkbSA_SetMods) -+ continue; -+ -+ if (act->mods.flags & XkbSA_UseModMapMods) -+ mask = xkb->map->modmap[key]; -+ else -+ mask = act->mods.mask; -+ -+ if ((mask & ShiftMask) == ShiftMask) -+ return key; -+ } -+ -+ return 0; -+} -+ -+std::list InputDevice::releaseShift(void) -+{ -+ unsigned state; -+ std::list keys; -+ -+ DeviceIntPtr master; -+ XkbDescPtr xkb; -+ unsigned int key; -+ -+ state = getKeyboardState(); -+ if (!(state & ShiftMask)) -+ return keys; -+ -+ master = keyboardDev->master; -+ xkb = master->key->xkbInfo->desc; -+ for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) { -+ XkbAction *act; -+ unsigned char mask; -+ -+ if (!key_is_down(master, key, KEY_PROCESSED)) -+ continue; -+ -+ act = XkbKeyActionPtr(xkb, key, state); -+ if (act == NULL) -+ continue; -+ -+ if (act->type != XkbSA_SetMods) -+ continue; -+ -+ if (act->mods.flags & XkbSA_UseModMapMods) -+ mask = xkb->map->modmap[key]; -+ else -+ mask = act->mods.mask; -+ -+ if (!(mask & ShiftMask)) -+ continue; -+ -+ keys.push_back(key); -+ } -+ -+ return keys; -+} -+ -+KeyCode InputDevice::pressLevelThree(void) -+{ -+ unsigned state, mask; -+ -+ KeyCode keycode; -+ XkbDescPtr xkb; -+ XkbAction *act; -+ -+ mask = getLevelThreeMask(); -+ if (mask == 0) -+ return 0; -+ -+ state = getKeyboardState(); -+ if (state & mask) -+ return 0; -+ -+ keycode = keysymToKeycode(XK_ISO_Level3_Shift, state, NULL); -+ if (keycode == 0) { -+ keycode = keysymToKeycode(XK_Mode_switch, state, NULL); -+ if (keycode == 0) -+ return 0; -+ } -+ -+ xkb = keyboardDev->master->key->xkbInfo->desc; -+ -+ act = XkbKeyActionPtr(xkb, keycode, state); -+ if (act == NULL) -+ return 0; -+ if (act->type != XkbSA_SetMods) -+ return 0; -+ -+ return keycode; -+} -+ -+std::list InputDevice::releaseLevelThree(void) -+{ -+ unsigned state, mask; -+ std::list keys; -+ -+ DeviceIntPtr master; -+ XkbDescPtr xkb; -+ unsigned int key; -+ -+ mask = getLevelThreeMask(); -+ if (mask == 0) -+ return keys; -+ -+ state = getKeyboardState(); -+ if (!(state & mask)) -+ return keys; -+ -+ master = keyboardDev->master; -+ xkb = master->key->xkbInfo->desc; -+ for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) { -+ XkbAction *act; -+ unsigned char key_mask; -+ -+ if (!key_is_down(master, key, KEY_PROCESSED)) -+ continue; -+ -+ act = XkbKeyActionPtr(xkb, key, state); -+ if (act == NULL) -+ continue; -+ -+ if (act->type != XkbSA_SetMods) -+ continue; -+ -+ if (act->mods.flags & XkbSA_UseModMapMods) -+ key_mask = xkb->map->modmap[key]; -+ else -+ key_mask = act->mods.mask; -+ -+ if (!(key_mask & mask)) -+ continue; -+ -+ keys.push_back(key); -+ } -+ -+ return keys; -+} -+ -+KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state, -+ unsigned *new_state) -+{ -+ XkbDescPtr xkb; -+ unsigned int key; -+ KeySym ks; -+ unsigned level_three_mask; -+ -+ if (new_state != NULL) -+ *new_state = state; -+ -+ xkb = keyboardDev->master->key->xkbInfo->desc; -+ for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) { -+ unsigned int state_out; -+ KeySym dummy; -+ -+ XkbTranslateKeyCode(xkb, key, state, &state_out, &ks); -+ if (ks == NoSymbol) -+ continue; -+ -+ /* -+ * Despite every known piece of documentation on -+ * XkbTranslateKeyCode() stating that mods_rtrn returns -+ * the unconsumed modifiers, in reality it always -+ * returns the _potentially consumed_ modifiers. -+ */ -+ state_out = state & ~state_out; -+ if (state_out & LockMask) -+ XkbConvertCase(ks, &dummy, &ks); -+ -+ if (ks == keysym) -+ return key; -+ } -+ -+ if (new_state == NULL) -+ return 0; -+ -+ *new_state = (state & ~ShiftMask) | -+ ((state & ShiftMask) ? 0 : ShiftMask); -+ key = keysymToKeycode(keysym, *new_state, NULL); -+ if (key != 0) -+ return key; -+ -+ level_three_mask = getLevelThreeMask(); -+ if (level_three_mask == 0) -+ return 0; -+ -+ *new_state = (state & ~level_three_mask) | -+ ((state & level_three_mask) ? 0 : level_three_mask); -+ key = keysymToKeycode(keysym, *new_state, NULL); -+ if (key != 0) -+ return key; -+ -+ *new_state = (state & ~(ShiftMask | level_three_mask)) | -+ ((state & ShiftMask) ? 0 : ShiftMask) | -+ ((state & level_three_mask) ? 0 : level_three_mask); -+ key = keysymToKeycode(keysym, *new_state, NULL); -+ if (key != 0) -+ return key; -+ -+ return 0; -+} -+ -+bool InputDevice::isLockModifier(KeyCode keycode, unsigned state) -+{ -+ XkbDescPtr xkb; -+ XkbAction *act; -+ -+ xkb = keyboardDev->master->key->xkbInfo->desc; -+ -+ act = XkbKeyActionPtr(xkb, keycode, state); -+ if (act == NULL) -+ return false; -+ -+ if (act->type != XkbSA_LockMods) -+ return false; -+ -+ return true; -+} -+ -+bool InputDevice::isAffectedByNumLock(KeyCode keycode) -+{ -+ unsigned state; -+ -+ KeyCode numlock_keycode; -+ unsigned numlock_mask; -+ -+ XkbDescPtr xkb; -+ XkbAction *act; -+ -+ unsigned group; -+ XkbKeyTypeRec *type; -+ -+ /* Group state is still important */ -+ state = getKeyboardState(); -+ state &= ~0xff; -+ -+ /* -+ * Not sure if hunting for a virtual modifier called "NumLock", -+ * or following the keysym Num_Lock is the best approach. We -+ * try the latter. -+ */ -+ numlock_keycode = keysymToKeycode(XK_Num_Lock, state, NULL); -+ if (numlock_keycode == 0) -+ return false; -+ -+ xkb = keyboardDev->master->key->xkbInfo->desc; -+ -+ act = XkbKeyActionPtr(xkb, numlock_keycode, state); -+ if (act == NULL) -+ return false; -+ if (act->type != XkbSA_LockMods) -+ return false; -+ -+ if (act->mods.flags & XkbSA_UseModMapMods) -+ numlock_mask = xkb->map->modmap[keycode]; -+ else -+ numlock_mask = act->mods.mask; -+ -+ group = XkbKeyEffectiveGroup(xkb, keycode, state); -+ type = XkbKeyKeyType(xkb, keycode, group); -+ if ((type->mods.mask & numlock_mask) == 0) -+ return false; -+ -+ return true; -+} -+ -+KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state) -+{ -+ DeviceIntPtr master; -+ XkbDescPtr xkb; -+ unsigned int key; -+ -+ XkbEventCauseRec cause; -+ XkbChangesRec changes; -+ -+ int types[1]; -+ KeySym *syms; -+ KeySym upper, lower; -+ -+ master = keyboardDev->master; -+ xkb = master->key->xkbInfo->desc; -+ for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) { -+ if (XkbKeyNumGroups(xkb, key) == 0) -+ break; -+ } -+ -+ if (key < xkb->min_key_code) -+ return 0; -+ -+ memset(&changes, 0, sizeof(changes)); -+ memset(&cause, 0, sizeof(cause)); -+ -+ XkbSetCauseUnknown(&cause); -+ -+ /* -+ * Tools like xkbcomp get confused if there isn't a name -+ * assigned to the keycode we're trying to use. -+ */ -+ if (xkb->names && xkb->names->keys && -+ (xkb->names->keys[key].name[0] == '\0')) { -+ xkb->names->keys[key].name[0] = 'I'; -+ xkb->names->keys[key].name[1] = '0' + (key / 100) % 10; -+ xkb->names->keys[key].name[2] = '0' + (key / 10) % 10; -+ xkb->names->keys[key].name[3] = '0' + (key / 1) % 10; -+ -+ changes.names.changed |= XkbKeyNamesMask; -+ changes.names.first_key = key; -+ changes.names.num_keys = 1; -+ } -+ -+ /* FIXME: Verify that ONE_LEVEL/ALPHABETIC isn't screwed up */ -+ -+ /* -+ * For keysyms that are affected by Lock, we are better off -+ * using ALPHABETIC rather than ONE_LEVEL as the latter -+ * generally cannot produce lower case when Lock is active. -+ */ -+ XkbConvertCase(keysym, &lower, &upper); -+ if (upper == lower) -+ types[XkbGroup1Index] = XkbOneLevelIndex; -+ else -+ types[XkbGroup1Index] = XkbAlphabeticIndex; -+ -+ XkbChangeTypesOfKey(xkb, key, 1, XkbGroup1Mask, types, &changes.map); -+ -+ syms = XkbKeySymsPtr(xkb,key); -+ if (upper == lower) -+ syms[0] = keysym; -+ else { -+ syms[0] = lower; -+ syms[1] = upper; -+ } -+ -+ changes.map.changed |= XkbKeySymsMask; -+ changes.map.first_key_sym = key; -+ changes.map.num_key_syms = 1; -+ -+ XkbSendNotification(master, &changes, &cause); -+ -+ return key; -+} -+ -+void InputDevice::vncXkbProcessDeviceEvent(int screenNum, -+ InternalEvent *event, -+ DeviceIntPtr dev) -+{ -+ InputDevice *self = vncXkbScreenPrivate(screenInfo.screens[screenNum]); -+ unsigned int backupctrls; -+ -+ if (event->device_event.sourceid == self->keyboardDev->id) { -+ XkbControlsPtr ctrls; -+ -+ /* -+ * We need to bypass AccessX since it is timing sensitive and -+ * the network can cause fake event delays. -+ */ -+ ctrls = dev->key->xkbInfo->desc->ctrls; -+ backupctrls = ctrls->enabled_ctrls; -+ ctrls->enabled_ctrls &= ~XkbAllFilteredEventsMask; -+ -+ /* -+ * This flag needs to be set for key repeats to be properly -+ * respected. -+ */ -+ if ((event->device_event.type == ET_KeyPress) && -+ key_is_down(dev, event->device_event.detail.key, KEY_PROCESSED)) -+ event->device_event.key_repeat = TRUE; -+ } -+ -+ dev->c_public.processInputProc(event, dev); -+ -+ if (event->device_event.sourceid == self->keyboardDev->id) { -+ XkbControlsPtr ctrls; -+ -+ ctrls = dev->key->xkbInfo->desc->ctrls; -+ ctrls->enabled_ctrls = backupctrls; -+ } -+} -+ -+#endif /* XORG >= 117 */ -diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Makefile.am.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Makefile.am ---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Makefile.am.input 2014-01-17 16:01:04.154064515 +0000 -+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Makefile.am 2014-01-17 16:01:13.142109459 +0000 -@@ -14,7 +14,7 @@ HDRS = RegionHelper.h vncExtInit.h vncHo - Input.h - - libvnccommon_la_SOURCES = $(HDRS) vncExtInit.cc vncHooks.cc XserverDesktop.cc \ -- Input.cc -+ Input.cc InputCore.cc InputXKB.cc - - libvnccommon_la_CPPFLAGS = -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \ - -DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(TIGERVNC_SRCDIR)/common -UHAVE_CONFIG_H \ -diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc ---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc.input 2014-01-17 16:01:32.532206349 +0000 -+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc 2014-01-17 16:02:13.775412129 +0000 -@@ -579,6 +579,12 @@ static struct timeval XserverDesktopTime - - void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout) - { -+ // We don't have a good callback for when we can init input devices[1], -+ // so we abuse the fact that this routine will be called first thing -+ // once the dix is done initialising. -+ // [1] Technically Xvnc has InitInput(), but libvnc.so has nothing. -+ inputDevice->InitInputDevice(); -+ - try { - int nextTimeout; - diff --git a/SOURCES/tigervnc-inputreset.patch b/SOURCES/tigervnc-inputreset.patch new file mode 100644 index 0000000..90f8663 --- /dev/null +++ b/SOURCES/tigervnc-inputreset.patch @@ -0,0 +1,385 @@ +diff --git a/unix/xserver/hw/vnc/Input.cc b/unix/xserver/hw/vnc/Input.cc +index 43c3ac3..4112fee 100644 +--- a/unix/xserver/hw/vnc/Input.cc ++++ b/unix/xserver/hw/vnc/Input.cc +@@ -68,6 +68,9 @@ rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock", "Avoid fake Shift pres + + #define BUTTONS 7 + ++class InputDevice *vncInputDevice; ++InputDevice InputDevice::singleton; ++ + /* Event queue is shared between all devices. */ + #if XORG == 15 + static xEvent *eventq = NULL; +@@ -116,11 +119,12 @@ static void enqueueEvents(DeviceIntPtr dev, int n) + } + #endif /* XORG < 111 */ + +-InputDevice::InputDevice(rfb::VNCServerST *_server) +- : server(_server), initialized(false), oldButtonMask(0) ++InputDevice::InputDevice() ++ : oldButtonMask(0) + { + int i; + ++ vncInputDevice = this; + #if XORG < 111 + initEventq(); + #endif +@@ -195,7 +199,7 @@ void InputDevice::PointerMove(const rfb::Point &pos) + cursorPos = pos; + } + +-void InputDevice::PointerSync(void) ++const rfb::Point &InputDevice::getPointerPos(void) + { + if (pointerDev) { + int x, y; +@@ -205,14 +209,10 @@ void InputDevice::PointerSync(void) + cursorPos.y = y; + } + +- if (cursorPos.equals(oldCursorPos)) +- return; +- +- oldCursorPos = cursorPos; +- server->setCursorPos(cursorPos); ++ return cursorPos; + } + +-static int pointerProc(DeviceIntPtr pDevice, int onoff) ++int InputDevice::pointerProc(DeviceIntPtr pDevice, int onoff) + { + BYTE map[BUTTONS + 1]; + DevicePtr pDev = (DevicePtr)pDevice; +@@ -237,6 +237,8 @@ static int pointerProc(DeviceIntPtr pDevice, int onoff) + btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); + btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); + btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); ++ btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); ++ btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); + + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); +@@ -261,10 +263,9 @@ static int pointerProc(DeviceIntPtr pDevice, int onoff) + case DEVICE_OFF: + pDev->on = FALSE; + break; +-#if 0 + case DEVICE_CLOSE: ++ singleton.pointerDev = NULL; + break; +-#endif + } + + return Success; +@@ -277,9 +278,7 @@ static void keyboardBell(int percent, DeviceIntPtr device, void * ctrl, + vncBell(); + } + +-extern void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap); +- +-static int keyboardProc(DeviceIntPtr pDevice, int onoff) ++int InputDevice::keyboardProc(DeviceIntPtr pDevice, int onoff) + { + #if XORG < 17 + KeySymsRec keySyms; +@@ -306,6 +305,9 @@ static int keyboardProc(DeviceIntPtr pDevice, int onoff) + case DEVICE_OFF: + pDev->on = FALSE; + break; ++ case DEVICE_CLOSE: ++ singleton.keyboardDev = NULL; ++ break; + } + + return Success; +@@ -313,11 +315,9 @@ static int keyboardProc(DeviceIntPtr pDevice, int onoff) + + void InputDevice::InitInputDevice(void) + { +- if (initialized) ++ if ((pointerDev != NULL) || (keyboardDev != NULL)) + return; + +- initialized = true; +- + #if XORG < 17 + pointerDev = AddInputDevice( + #if XORG >= 16 +diff --git a/unix/xserver/hw/vnc/Input.h b/unix/xserver/hw/vnc/Input.h +index e893049..f58242d 100644 +--- a/unix/xserver/hw/vnc/Input.h ++++ b/unix/xserver/hw/vnc/Input.h +@@ -29,20 +29,26 @@ + + #include + +-#include ++#include ++#include + + extern "C" { + #include "input.h" ++/* The Xorg headers define macros that wreak havoc with STL */ ++#undef max + }; + + #include "xorg-version.h" + +-/* Represents input device (keyboard + pointer) */ ++/* ++ * Represents input device (keyboard + pointer) ++ * ++ * Is a singleton as input devices are global in the X server so ++ * we do not have one per desktop (i.e. per screen). ++ */ ++extern class InputDevice *vncInputDevice; + class InputDevice { + public: +- /* Create new InputDevice instance */ +- InputDevice(rfb::VNCServerST *_server); +- + /* + * Press or release buttons. Relationship between buttonMask and + * buttons is specified in RFB protocol. +@@ -52,27 +58,28 @@ public: + /* Move pointer to target location (point coords are absolute). */ + void PointerMove(const rfb::Point &point); + +- /* +- * Send pointer position to clients. If not called then Move() calls +- * won't be visible to VNC clients. +- */ +- void PointerSync(void); ++ /* Get current known location of the pointer */ ++ const rfb::Point &getPointerPos(void); + ++ /* Press or release one or more keys to get the given symbol */ + void KeyboardPress(rdr::U32 keysym) { keyEvent(keysym, true); } + void KeyboardRelease(rdr::U32 keysym) { keyEvent(keysym, false); } + + /* +- * Init input device. This cannot be done in the constructor +- * because constructor is called during X server extensions +- * initialization. Devices must be initialized after core +- * pointer/keyboard initialization which is actually after extesions +- * initialization. Check InitExtensions(), InitCoreDevices() and +- * InitInput() calls in dix/main.c. Instead it is called from +- * XserverDesktop at an appropriate time. ++ * Init input device. ++ * This has to be called after core pointer/keyboard ++ * initialization which unfortunately is after extesions ++ * initialization (which means we cannot call it in ++ * vncExtensionInit(). Check InitExtensions(), ++ * InitCoreDevices() and InitInput() calls in dix/main.c. ++ * Instead we call it from XserverDesktop at an appropriate ++ * time. + */ + void InitInputDevice(void); + + private: ++ InputDevice(); ++ + void keyEvent(rdr::U32 keysym, bool down); + + /* Backend dependent functions below here */ +@@ -96,22 +103,26 @@ private: + KeyCode addKeysym(KeySym keysym, unsigned state); + + private: ++ static int pointerProc(DeviceIntPtr pDevice, int onoff); ++ static int keyboardProc(DeviceIntPtr pDevice, int onoff); ++ + #if XORG >= 17 + static void vncXkbProcessDeviceEvent(int screenNum, + InternalEvent *event, + DeviceIntPtr dev); ++#else ++ static void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap); + #endif + + private: +- rfb::VNCServerST *server; +- bool initialized; + DeviceIntPtr keyboardDev; + DeviceIntPtr pointerDev; + + int oldButtonMask; +- rfb::Point cursorPos, oldCursorPos; +- ++ rfb::Point cursorPos; + KeySym pressedKeys[256]; ++private: ++ static InputDevice singleton; + }; + + #endif +diff --git a/unix/xserver/hw/vnc/InputCore.cc b/unix/xserver/hw/vnc/InputCore.cc +index a880ca0..b565c73 100644 +--- a/unix/xserver/hw/vnc/InputCore.cc ++++ b/unix/xserver/hw/vnc/InputCore.cc +@@ -174,7 +174,7 @@ KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = { + XK_Menu, NoSymbol, + }; + +-void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap) ++void InputDevice::GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap) + { + int i; + +diff --git a/unix/xserver/hw/vnc/InputXKB.cc b/unix/xserver/hw/vnc/InputXKB.cc +index ed93afc..92288aa 100644 +--- a/unix/xserver/hw/vnc/InputXKB.cc ++++ b/unix/xserver/hw/vnc/InputXKB.cc +@@ -42,18 +42,6 @@ extern "C" { + #undef class + } + +-#if XORG < 19 +-static int vncXkbScreenPrivateKeyIndex; +-static DevPrivateKey vncXkbScreenPrivateKey = &vncXkbScreenPrivateKeyIndex; +-#else +-static DevPrivateKeyRec vncXkbPrivateKeyRec; +-#define vncXkbScreenPrivateKey (&vncXkbPrivateKeyRec) +-#endif +- +-#define vncXkbScreenPrivate(pScreen) \ +- (*(InputDevice**) dixLookupPrivate(&(pScreen)->devPrivates, \ +- vncXkbScreenPrivateKey)) +- + #ifndef KEYBOARD_OR_FLOAT + #define KEYBOARD_OR_FLOAT MASTER_KEYBOARD + #endif +@@ -209,18 +197,6 @@ static unsigned XkbKeyEffectiveGroup(XkbDescPtr xkb, KeyCode key, unsigned int m + + void InputDevice::PrepareInputDevices(void) + { +-#if XORG < 19 +- if (!dixRequestPrivate(vncXkbScreenPrivateKey, sizeof(InputDevice*))) +- FatalError("Failed to register TigerVNC XKB screen key\n"); +-#else +- if (!dixRegisterPrivateKey(vncXkbScreenPrivateKey, PRIVATE_SCREEN, +- sizeof(InputDevice*))) +- FatalError("Failed to register TigerVNC XKB screen key\n"); +-#endif +- +- for (int scr = 0; scr < screenInfo.numScreens; scr++) +- vncXkbScreenPrivate(screenInfo.screens[scr]) = this; +- + /* + * Not ideal since these callbacks do not stack, but it's the only + * decent way we can reliably catch events for both the slave and +@@ -636,10 +612,9 @@ void InputDevice::vncXkbProcessDeviceEvent(int screenNum, + InternalEvent *event, + DeviceIntPtr dev) + { +- InputDevice *self = vncXkbScreenPrivate(screenInfo.screens[screenNum]); + unsigned int backupctrls; + +- if (event->device_event.sourceid == self->keyboardDev->id) { ++ if (event->device_event.sourceid == singleton.keyboardDev->id) { + XkbControlsPtr ctrls; + + /* +@@ -661,7 +636,7 @@ void InputDevice::vncXkbProcessDeviceEvent(int screenNum, + + dev->c_public.processInputProc(event, dev); + +- if (event->device_event.sourceid == self->keyboardDev->id) { ++ if (event->device_event.sourceid == singleton.keyboardDev->id) { + XkbControlsPtr ctrls; + + ctrls = dev->key->xkbInfo->desc->ctrls; +diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc +index fc0646d..05169b0 100644 +--- a/unix/xserver/hw/vnc/XserverDesktop.cc ++++ b/unix/xserver/hw/vnc/XserverDesktop.cc +@@ -157,15 +157,12 @@ XserverDesktop::XserverDesktop(ScreenPtr pScreen_, + + if (httpListener) + httpServer = new FileHTTPServer(this); +- +- inputDevice = new InputDevice(server); + } + + XserverDesktop::~XserverDesktop() + { + if (!directFbptr) + delete [] data; +- delete inputDevice; + delete httpServer; + delete server; + } +@@ -583,7 +580,7 @@ void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout) + // so we abuse the fact that this routine will be called first thing + // once the dix is done initialising. + // [1] Technically Xvnc has InitInput(), but libvnc.so has nothing. +- inputDevice->InitInputDevice(); ++ vncInputDevice->InitInputDevice(); + + try { + int nextTimeout; +@@ -691,7 +688,11 @@ void XserverDesktop::wakeupHandler(fd_set* fds, int nfds) + } + } + +- inputDevice->PointerSync(); ++ // We are responsible for propagating mouse movement between clients ++ if (!oldCursorPos.equals(vncInputDevice->getPointerPos())) { ++ oldCursorPos = vncInputDevice->getPointerPos(); ++ server->setCursorPos(oldCursorPos); ++ } + } + + // Then let the timers do some processing. Rescheduling is done in +@@ -818,8 +819,8 @@ void XserverDesktop::approveConnection(void* opaqueId, bool accept, + + void XserverDesktop::pointerEvent(const Point& pos, int buttonMask) + { +- inputDevice->PointerMove(pos); +- inputDevice->PointerButtonAction(buttonMask); ++ vncInputDevice->PointerMove(pos); ++ vncInputDevice->PointerButtonAction(buttonMask); + } + + void XserverDesktop::clientCutText(const char* str, int len) +@@ -1136,7 +1137,7 @@ void XserverDesktop::lookup(int index, int* r, int* g, int* b) + void XserverDesktop::keyEvent(rdr::U32 keysym, bool down) + { + if (down) +- inputDevice->KeyboardPress(keysym); ++ vncInputDevice->KeyboardPress(keysym); + else +- inputDevice->KeyboardRelease(keysym); ++ vncInputDevice->KeyboardRelease(keysym); + } +diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h +index fb247b0..ca6e8af 100644 +--- a/unix/xserver/hw/vnc/XserverDesktop.h ++++ b/unix/xserver/hw/vnc/XserverDesktop.h +@@ -153,5 +153,7 @@ private: + typedef std::map OutputIdMap; + OutputIdMap outputIdMap; + #endif ++ ++ rfb::Point oldCursorPos; + }; + #endif +diff --git a/unix/xserver/hw/vnc/xf86vncModule.cc b/unix/xserver/hw/vnc/xf86vncModule.cc +index 3187bba..596d399 100644 +--- a/unix/xserver/hw/vnc/xf86vncModule.cc ++++ b/unix/xserver/hw/vnc/xf86vncModule.cc +@@ -112,9 +112,9 @@ static void vncExtensionInitWithParams(INITARGS) + i.param->setParam(val); + } + } +- +- vncExtensionInit(); + } ++ ++ vncExtensionInit(); + } + } + diff --git a/SOURCES/tigervnc-ipv6-support.patch b/SOURCES/tigervnc-ipv6-support.patch new file mode 100644 index 0000000..083cc7c --- /dev/null +++ b/SOURCES/tigervnc-ipv6-support.patch @@ -0,0 +1,1708 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index f2656d1..0e325e2 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -71,16 +71,9 @@ if(NOT DEFINED BUILD_WINVNC) + set(BUILD_WINVNC 1) + endif() + +-# Minimum version is Windows 2000 (5.0) ++# Minimum version is Windows XP SP2 (5.2) + if(WIN32) +- if(NOT CMAKE_SIZEOF_VOID_P MATCHES 8) +- add_definitions(-D_WIN32_IE=0x0500 -D_WIN32_WINNT=0x0500) +- else() +- set(WIN64 1) +- # Win64 doesn't like us requesting a Windows version that didn't have +- # 64-bit support. Request XP (5.1) instead. +- add_definitions(-D_WIN32_IE=0x0501 -D_WIN32_WINNT=0x0501) +- endif() ++ add_definitions(-D_WIN32_IE=0x0502 -D_WIN32_WINNT=0x0502) + endif() + + if(CMAKE_SIZEOF_VOID_P MATCHES 8) +@@ -366,20 +359,6 @@ if(ENABLE_PAM) + endif() + set(HAVE_PAM ${ENABLE_PAM}) + +-# Check for socket functions +-if(WIN32) +- set(CMAKE_EXTRA_INCLUDE_FILES winsock2.h ws2tcpip.h) +- set(CMAKE_REQUIRED_LIBRARIES ws2_32) +-else() +- set(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h) +-endif() +-check_function_exists(inet_aton HAVE_INET_ATON) +-check_function_exists(inet_ntop HAVE_INET_NTOP) +-check_function_exists(getaddrinfo HAVE_GETADDRINFO) +-check_type_size(socklen_t SOCKLEN_T) +-set(CMAKE_EXTRA_INCLUDE_FILES) +-set(CMAKE_REQUIRED_LIBRARIES) +- + # Check for the newer standard string functions + check_function_exists(snprintf HAVE_SNPRINTF) + check_function_exists(strcasecmp HAVE_STRCASECMP) +diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx +index afd66f9..83387ab 100644 +--- a/common/network/TcpSocket.cxx ++++ b/common/network/TcpSocket.cxx +@@ -31,10 +31,8 @@ + #include + #include + #include +-#include + #include + #include +-#include + #include + #include + #include +@@ -42,10 +40,15 @@ + #endif + + #include ++#include + #include +-#include + #include + #include ++#include ++ ++#ifdef WIN32 ++#include ++#endif + + #ifndef INADDR_NONE + #define INADDR_NONE ((unsigned long)-1) +@@ -54,26 +57,24 @@ + #define INADDR_LOOPBACK ((unsigned long)0x7F000001) + #endif + +-#if defined(HAVE_GETADDRINFO) && !defined(IN6_ARE_ADDR_EQUAL) ++#ifndef IN6_ARE_ADDR_EQUAL + #define IN6_ARE_ADDR_EQUAL(a,b) \ + (memcmp ((const void*)(a), (const void*)(b), sizeof (struct in6_addr)) == 0) + #endif + ++// Missing on older Windows and OS X ++#ifndef AI_NUMERICSERV ++#define AI_NUMERICSERV 0 ++#endif ++ + using namespace network; + using namespace rdr; + +-typedef struct vnc_sockaddr { +- union { +- sockaddr sa; +- sockaddr_in sin; +-#ifdef HAVE_GETADDRINFO +- sockaddr_in6 sin6; +-#endif +- } u; +-} vnc_sockaddr_t; +- + static rfb::LogWriter vlog("TcpSocket"); + ++static rfb::BoolParameter UseIPv4("UseIPv4", "Use IPv4 for incoming and outgoing connections.", true); ++static rfb::BoolParameter UseIPv6("UseIPv6", "Use IPv6 for incoming and outgoing connections.", true); ++ + /* Tunnelling support. */ + int network::findFreeTcpPort (void) + { +@@ -117,6 +118,23 @@ static void initSockets() { + } + + ++// -=- Socket duplication help for Windows ++static int dupsocket(int fd) ++{ ++#ifdef WIN32 ++ int ret; ++ WSAPROTOCOL_INFO info; ++ ret = WSADuplicateSocket(fd, GetCurrentProcessId(), &info); ++ if (ret != 0) ++ throw SocketException("unable to duplicate socket", errorNumber); ++ return WSASocket(info.iAddressFamily, info.iSocketType, info.iProtocol, ++ &info, 0, 0); ++#else ++ return dup(fd); ++#endif ++} ++ ++ + // -=- TcpSocket + + TcpSocket::TcpSocket(int sock, bool close) +@@ -130,14 +148,11 @@ TcpSocket::TcpSocket(const char *host, int port) + int sock, err, result, family; + vnc_sockaddr_t sa; + socklen_t salen; +-#ifdef HAVE_GETADDRINFO + struct addrinfo *ai, *current, hints; +-#endif + + // - Create a socket + initSockets(); + +-#ifdef HAVE_GETADDRINFO + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; +@@ -147,13 +162,28 @@ TcpSocket::TcpSocket(const char *host, int port) + + if ((result = getaddrinfo(host, NULL, &hints, &ai)) != 0) { + throw Exception("unable to resolve host by name: %s", +- gai_strerror(result)); ++ gai_strerror(result)); + } + ++ // This logic is too complex for the compiler to determine if ++ // sock is properly assigned or not. ++ sock = -1; ++ + for (current = ai; current != NULL; current = current->ai_next) { + family = current->ai_family; +- if (family != AF_INET && family != AF_INET6) ++ ++ switch (family) { ++ case AF_INET: ++ if (!UseIPv4) ++ continue; ++ break; ++ case AF_INET6: ++ if (!UseIPv6) ++ continue; ++ break; ++ default: + continue; ++ } + + salen = current->ai_addrlen; + memcpy(&sa, current->ai_addr, salen); +@@ -163,34 +193,10 @@ TcpSocket::TcpSocket(const char *host, int port) + else + sa.u.sin6.sin6_port = htons(port); + +-#else /* HAVE_GETADDRINFO */ +- family = AF_INET; +- salen = sizeof(struct sockaddr_in); +- +- /* Try processing the host as an IP address */ +- memset(&sa, 0, sizeof(sa)); +- sa.u.sin.sin_family = AF_INET; +- sa.u.sin.sin_addr.s_addr = inet_addr((char *)host); +- sa.u.sin.sin_port = htons(port); +- if ((int)sa.u.sin.sin_addr.s_addr == -1) { +- /* Host was not an IP address - try resolving as DNS name */ +- struct hostent *hostinfo; +- hostinfo = gethostbyname((char *)host); +- if (hostinfo && hostinfo->h_addr) { +- sa.u.sin.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr; +- } else { +- err = errorNumber; +- throw SocketException("unable to resolve host by name", err); +- } +- } +-#endif /* HAVE_GETADDRINFO */ +- + sock = socket (family, SOCK_STREAM, 0); + if (sock == -1) { + err = errorNumber; +-#ifdef HAVE_GETADDRINFO + freeaddrinfo(ai); +-#endif /* HAVE_GETADDRINFO */ + throw SocketException("unable to create socket", err); + } + +@@ -199,19 +205,20 @@ TcpSocket::TcpSocket(const char *host, int port) + err = errorNumber; + #ifndef WIN32 + if (err == EINTR) +- continue; ++ continue; + #endif + closesocket(sock); + break; + } + +-#ifdef HAVE_GETADDRINFO + if (result == 0) + break; + } + + freeaddrinfo(ai); +-#endif /* HAVE_GETADDRINFO */ ++ ++ if (current == NULL) ++ throw Exception("No useful address for host"); + + if (result == -1) + throw SocketException("unable connect to socket", err); +@@ -240,27 +247,63 @@ int TcpSocket::getMyPort() { + } + + char* TcpSocket::getPeerAddress() { +- struct sockaddr_in info; +- struct in_addr addr; +- socklen_t info_size = sizeof(info); ++ vnc_sockaddr_t sa; ++ socklen_t sa_size = sizeof(sa); + +- getpeername(getFd(), (struct sockaddr *)&info, &info_size); +- memcpy(&addr, &info.sin_addr, sizeof(addr)); ++ if (getpeername(getFd(), &sa.u.sa, &sa_size) != 0) { ++ vlog.error("unable to get peer name for socket"); ++ return rfb::strDup(""); ++ } ++ ++ if (sa.u.sa.sa_family == AF_INET6) { ++ char buffer[INET6_ADDRSTRLEN + 2]; ++ int ret; ++ ++ buffer[0] = '['; ++ ++ ret = getnameinfo(&sa.u.sa, sizeof(sa.u.sin6), ++ buffer + 1, sizeof(buffer) - 2, NULL, 0, ++ NI_NUMERICHOST); ++ if (ret != 0) { ++ vlog.error("unable to convert peer name to a string"); ++ return rfb::strDup(""); ++ } ++ ++ strcat(buffer, "]"); ++ ++ return rfb::strDup(buffer); ++ } ++ ++ if (sa.u.sa.sa_family == AF_INET) { ++ char *name; ++ ++ name = inet_ntoa(sa.u.sin.sin_addr); ++ if (name == NULL) { ++ vlog.error("unable to convert peer name to a string"); ++ return rfb::strDup(""); ++ } + +- char* name = inet_ntoa(addr); +- if (name) { + return rfb::strDup(name); +- } else { +- return rfb::strDup(""); + } ++ ++ vlog.error("unknown address family for socket"); ++ return rfb::strDup(""); + } + + int TcpSocket::getPeerPort() { +- struct sockaddr_in info; +- socklen_t info_size = sizeof(info); ++ vnc_sockaddr_t sa; ++ socklen_t sa_size = sizeof(sa); ++ ++ getpeername(getFd(), &sa.u.sa, &sa_size); + +- getpeername(getFd(), (struct sockaddr *)&info, &info_size); +- return ntohs(info.sin_port); ++ switch (sa.u.sa.sa_family) { ++ case AF_INET6: ++ return ntohs(sa.u.sin6.sin6_port); ++ case AF_INET: ++ return ntohs(sa.u.sin.sin_port); ++ default: ++ return 0; ++ } + } + + char* TcpSocket::getPeerEndpoint() { +@@ -288,13 +331,14 @@ bool TcpSocket::sameMachine() { + if (peeraddr.u.sa.sa_family != myaddr.u.sa.sa_family) + return false; + +-#ifdef HAVE_GETADDRINFO + if (peeraddr.u.sa.sa_family == AF_INET6) + return IN6_ARE_ADDR_EQUAL(&peeraddr.u.sin6.sin6_addr, +- &myaddr.u.sin6.sin6_addr); +-#endif ++ &myaddr.u.sin6.sin6_addr); ++ if (peeraddr.u.sa.sa_family == AF_INET) ++ return (peeraddr.u.sin.sin_addr.s_addr == myaddr.u.sin.sin_addr.s_addr); + +- return (peeraddr.u.sin.sin_addr.s_addr == myaddr.u.sin.sin_addr.s_addr); ++ // No idea what this is. Assume we're on different machines. ++ return false; + } + + void TcpSocket::shutdown() +@@ -306,7 +350,7 @@ void TcpSocket::shutdown() + bool TcpSocket::enableNagles(int sock, bool enable) { + int one = enable ? 0 : 1; + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, +- (char *)&one, sizeof(one)) < 0) { ++ (char *)&one, sizeof(one)) < 0) { + int e = errorNumber; + vlog.error("unable to setsockopt TCP_NODELAY: %d", e); + return false; +@@ -335,77 +379,89 @@ bool TcpSocket::isListening(int sock) + + int TcpSocket::getSockPort(int sock) + { +- struct sockaddr_in info; +- socklen_t info_size = sizeof(info); +- if (getsockname(sock, (struct sockaddr *)&info, &info_size) < 0) +- return 0; +- return ntohs(info.sin_port); ++ vnc_sockaddr_t sa; ++ socklen_t sa_size = sizeof(sa); ++ if (getsockname(sock, &sa.u.sa, &sa_size) < 0) ++ return 0; ++ ++ switch (sa.u.sa.sa_family) { ++ case AF_INET6: ++ return ntohs(sa.u.sin6.sin6_port); ++ default: ++ return ntohs(sa.u.sin.sin_port); ++ } + } + ++TcpListener::TcpListener(int sock) ++{ ++ fd = sock; ++} + +-TcpListener::TcpListener(const char *listenaddr, int port, bool localhostOnly, +- int sock, bool close_) : closeFd(close_) ++TcpListener::TcpListener(const TcpListener& other) + { +- if (sock != -1) { +- fd = sock; +- return; ++ fd = dupsocket (other.fd); ++ // Hope TcpListener::shutdown(other) doesn't get called... ++} ++ ++TcpListener& TcpListener::operator= (const TcpListener& other) ++{ ++ if (this != &other) ++ { ++ closesocket (fd); ++ fd = dupsocket (other.fd); ++ // Hope TcpListener::shutdown(other) doesn't get called... + } ++ return *this; ++} ++ ++TcpListener::TcpListener(const struct sockaddr *listenaddr, ++ socklen_t listenaddrlen) ++{ ++ int one = 1; ++ vnc_sockaddr_t sa; ++ int sock; + + initSockets(); +- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) +- throw SocketException("unable to create listening socket", errorNumber); + ++ if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0) ++ throw SocketException("unable to create listening socket", errorNumber); ++ ++ memcpy (&sa, listenaddr, listenaddrlen); ++#ifdef IPV6_V6ONLY ++ if (listenaddr->sa_family == AF_INET6) { ++ if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&one, sizeof(one))) ++ throw SocketException("unable to set IPV6_V6ONLY", errorNumber); ++ } ++#endif /* defined(IPV6_V6ONLY) */ ++ ++ if (bind(sock, &sa.u.sa, listenaddrlen) == -1) { ++ closesocket(sock); ++ throw SocketException("failed to bind socket", errorNumber); ++ } + #ifndef WIN32 + // - By default, close the socket on exec() +- fcntl(fd, F_SETFD, FD_CLOEXEC); ++ fcntl(sock, F_SETFD, FD_CLOEXEC); + +- int one = 1; +- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, +- (char *)&one, sizeof(one)) < 0) { ++ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, ++ (char *)&one, sizeof(one)) < 0) { + int e = errorNumber; +- closesocket(fd); ++ closesocket(sock); + throw SocketException("unable to create listening socket", e); + } +-#endif +- +- // - Bind it to the desired port +- struct sockaddr_in addr; +- memset(&addr, 0, sizeof(addr)); +- addr.sin_family = AF_INET; + +- if (localhostOnly) { +- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); +- } else if (listenaddr != NULL) { +-#ifdef HAVE_INET_ATON +- if (inet_aton(listenaddr, &addr.sin_addr) == 0) +-#else +- /* Some systems (e.g. Windows) do not have inet_aton, sigh */ +- if ((addr.sin_addr.s_addr = inet_addr(listenaddr)) == INADDR_NONE) ++ fd = sock; + #endif +- { +- closesocket(fd); +- throw Exception("invalid network interface address: %s", listenaddr); +- } +- } else +- addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Bind to 0.0.0.0 by default. */ +- +- addr.sin_port = htons(port); +- if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { +- int e = errorNumber; +- closesocket(fd); +- throw SocketException("unable to bind listening socket", e); +- } + + // - Set it to be a listening socket +- if (listen(fd, 5) < 0) { ++ if (listen(sock, 5) < 0) { + int e = errorNumber; +- closesocket(fd); ++ closesocket(sock); + throw SocketException("unable to set socket to listening mode", e); + } + } + + TcpListener::~TcpListener() { +- if (closeFd) closesocket(fd); ++ closesocket(fd); + } + + void TcpListener::shutdown() +@@ -444,17 +500,45 @@ TcpListener::accept() { + } + + void TcpListener::getMyAddresses(std::list* result) { +- const hostent* addrs = gethostbyname(0); +- if (addrs == 0) +- throw rdr::SystemException("gethostbyname", errorNumber); +- if (addrs->h_addrtype != AF_INET) +- throw rdr::Exception("getMyAddresses: bad family"); +- for (int i=0; addrs->h_addr_list[i] != 0; i++) { +- const char* addrC = inet_ntoa(*((struct in_addr*)addrs->h_addr_list[i])); +- char* addr = new char[strlen(addrC)+1]; +- strcpy(addr, addrC); ++ struct addrinfo *ai, *current, hints; ++ ++ initSockets(); ++ ++ memset(&hints, 0, sizeof(struct addrinfo)); ++ hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; ++ hints.ai_family = AF_UNSPEC; ++ hints.ai_socktype = SOCK_STREAM; ++ hints.ai_canonname = NULL; ++ hints.ai_addr = NULL; ++ hints.ai_next = NULL; ++ ++ // Windows doesn't like NULL for service, so specify something ++ if ((getaddrinfo(NULL, "1", &hints, &ai)) != 0) ++ return; ++ ++ for (current= ai; current != NULL; current = current->ai_next) { ++ switch (current->ai_family) { ++ case AF_INET: ++ if (!UseIPv4) ++ continue; ++ break; ++ case AF_INET6: ++ if (!UseIPv6) ++ continue; ++ break; ++ default: ++ continue; ++ } ++ ++ char *addr = new char[INET6_ADDRSTRLEN]; ++ ++ getnameinfo(current->ai_addr, current->ai_addrlen, addr, INET6_ADDRSTRLEN, ++ NULL, 0, NI_NUMERICHOST); ++ + result->push_back(addr); + } ++ ++ freeaddrinfo(ai); + } + + int TcpListener::getMyPort() { +@@ -462,6 +546,115 @@ int TcpListener::getMyPort() { + } + + ++void network::createLocalTcpListeners(std::list *listeners, ++ int port) ++{ ++ std::list new_listeners; ++ vnc_sockaddr_t sa; ++ ++ initSockets(); ++ ++ if (UseIPv6) { ++ sa.u.sin6.sin6_family = AF_INET6; ++ sa.u.sin6.sin6_port = htons (port); ++ sa.u.sin6.sin6_addr = in6addr_loopback; ++ try { ++ new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin6))); ++ } catch (SocketException& e) { ++ // Ignore this if it is due to lack of address family support on ++ // the interface or on the system ++ if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) ++ // Otherwise, report the error ++ throw; ++ } ++ } ++ if (UseIPv4) { ++ sa.u.sin.sin_family = AF_INET; ++ sa.u.sin.sin_port = htons (port); ++ sa.u.sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); ++ try { ++ new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin))); ++ } catch (SocketException& e) { ++ // Ignore this if it is due to lack of address family support on ++ // the interface or on the system ++ if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) ++ // Otherwise, report the error ++ throw; ++ } ++ } ++ ++ if (new_listeners.empty ()) ++ throw SocketException("createLocalTcpListeners: no addresses available", ++ EADDRNOTAVAIL); ++ ++ listeners->splice (listeners->end(), new_listeners); ++} ++ ++void network::createTcpListeners(std::list *listeners, ++ const char *addr, ++ int port) ++{ ++ std::list new_listeners; ++ ++ struct addrinfo *ai, *current, hints; ++ char service[16]; ++ int result; ++ ++ initSockets(); ++ ++ memset(&hints, 0, sizeof(struct addrinfo)); ++ hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; ++ hints.ai_family = AF_UNSPEC; ++ hints.ai_socktype = SOCK_STREAM; ++ hints.ai_canonname = NULL; ++ hints.ai_addr = NULL; ++ hints.ai_next = NULL; ++ ++ snprintf (service, sizeof (service) - 1, "%d", port); ++ service[sizeof (service) - 1] = '\0'; ++ if ((result = getaddrinfo(addr, service, &hints, &ai)) != 0) ++ throw rdr::Exception("unable to resolve listening address: %s", ++ gai_strerror(result)); ++ ++ for (current = ai; current != NULL; current = current->ai_next) { ++ switch (current->ai_family) { ++ case AF_INET: ++ if (!UseIPv4) ++ continue; ++ break; ++ ++ case AF_INET6: ++ if (!UseIPv6) ++ continue; ++ break; ++ ++ default: ++ continue; ++ } ++ ++ try { ++ new_listeners.push_back(TcpListener (current->ai_addr, ++ current->ai_addrlen)); ++ } catch (SocketException& e) { ++ // Ignore this if it is due to lack of address family support on ++ // the interface or on the system ++ if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) { ++ // Otherwise, report the error ++ freeaddrinfo(ai); ++ throw; ++ } ++ } ++ } ++ freeaddrinfo(ai); ++ ++ if (new_listeners.empty ()) ++ throw SocketException("createTcpListeners: no addresses available", ++ EADDRNOTAVAIL); ++ ++ listeners->splice (listeners->end(), new_listeners); ++} ++ ++ + TcpFilter::TcpFilter(const char* spec) { + rfb::CharArray tmp; + tmp.buf = rfb::strDup(spec); +@@ -478,20 +671,69 @@ TcpFilter::~TcpFilter() { + + + static bool +-patternMatchIP(const TcpFilter::Pattern& pattern, const char* value) { +- unsigned long address = inet_addr((char *)value); +- if (address == INADDR_NONE) return false; +- return ((pattern.address & pattern.mask) == (address & pattern.mask)); ++patternMatchIP(const TcpFilter::Pattern& pattern, vnc_sockaddr_t *sa) { ++ switch (pattern.address.u.sa.sa_family) { ++ unsigned long address; ++ ++ case AF_INET: ++ if (sa->u.sa.sa_family != AF_INET) ++ return false; ++ ++ address = sa->u.sin.sin_addr.s_addr; ++ if (address == htonl (INADDR_NONE)) return false; ++ return ((pattern.address.u.sin.sin_addr.s_addr & ++ pattern.mask.u.sin.sin_addr.s_addr) == ++ (address & pattern.mask.u.sin.sin_addr.s_addr)); ++ ++ case AF_INET6: ++ if (sa->u.sa.sa_family != AF_INET6) ++ return false; ++ ++ for (unsigned int n = 0; n < 16; n++) { ++ unsigned int bits = (n + 1) * 8; ++ unsigned int mask; ++ if (pattern.prefixlen > bits) ++ mask = 0xff; ++ else { ++ unsigned int lastbits = 0xff; ++ lastbits <<= bits - pattern.prefixlen; ++ mask = lastbits & 0xff; ++ } ++ ++ if ((pattern.address.u.sin6.sin6_addr.s6_addr[n] & mask) != ++ (sa->u.sin6.sin6_addr.s6_addr[n] & mask)) ++ return false; ++ ++ if (mask < 0xff) ++ break; ++ } ++ ++ return true; ++ ++ case AF_UNSPEC: ++ // Any address matches ++ return true; ++ ++ default: ++ break; ++ } ++ ++ return false; + } + + bool + TcpFilter::verifyConnection(Socket* s) { + rfb::CharArray name; ++ vnc_sockaddr_t sa; ++ socklen_t sa_size = sizeof(sa); ++ ++ if (getpeername(s->getFd(), &sa.u.sa, &sa_size) != 0) ++ return false; + + name.buf = s->getPeerAddress(); + std::list::iterator i; + for (i=filter.begin(); i!=filter.end(); i++) { +- if (patternMatchIP(*i, name.buf)) { ++ if (patternMatchIP(*i, &sa)) { + switch ((*i).action) { + case Accept: + vlog.debug("ACCEPT %s", name.buf); +@@ -515,31 +757,102 @@ TcpFilter::verifyConnection(Socket* s) { + TcpFilter::Pattern TcpFilter::parsePattern(const char* p) { + TcpFilter::Pattern pattern; + +- bool expandMask = false; +- rfb::CharArray addr, mask; ++ rfb::CharArray addr, pref; ++ bool prefix_specified; ++ int family; ++ ++ prefix_specified = rfb::strSplit(&p[1], '/', &addr.buf, &pref.buf); ++ if (addr.buf[0] == '\0') { ++ // Match any address ++ memset (&pattern.address, 0, sizeof (pattern.address)); ++ pattern.address.u.sa.sa_family = AF_UNSPEC; ++ pattern.prefixlen = 0; ++ } else { ++ struct addrinfo hints; ++ struct addrinfo *ai; ++ char *p = addr.buf; ++ int result; ++ memset (&hints, 0, sizeof (hints)); ++ hints.ai_family = AF_UNSPEC; ++ hints.ai_flags = AI_NUMERICHOST; ++ ++ // Take out brackets, if present ++ if (*p == '[') { ++ size_t len; ++ p++; ++ len = strlen (p); ++ if (len > 0 && p[len - 1] == ']') ++ p[len - 1] = '\0'; ++ } ++ ++ if ((result = getaddrinfo (p, NULL, &hints, &ai)) != 0) { ++ throw Exception("unable to resolve host by name: %s", ++ gai_strerror(result)); ++ } + +- if (rfb::strSplit(&p[1], '/', &addr.buf, &mask.buf)) { +- if (rfb::strContains(mask.buf, '.')) { +- pattern.mask = inet_addr(mask.buf); ++ memcpy (&pattern.address.u.sa, ai->ai_addr, ai->ai_addrlen); ++ freeaddrinfo (ai); ++ ++ family = pattern.address.u.sa.sa_family; ++ ++ if (prefix_specified) { ++ if (family == AF_INET && ++ rfb::strContains(pref.buf, '.')) { ++ throw Exception("mask no longer supported for filter, " ++ "use prefix instead"); ++ } ++ ++ pattern.prefixlen = (unsigned int) atoi(pref.buf); + } else { +- pattern.mask = atoi(mask.buf); +- expandMask = true; ++ switch (family) { ++ case AF_INET: ++ pattern.prefixlen = 32; ++ break; ++ case AF_INET6: ++ pattern.prefixlen = 128; ++ break; ++ default: ++ throw Exception("unknown address family"); ++ } + } +- } else { +- pattern.mask = 32; +- expandMask = true; +- } +- if (expandMask) { +- unsigned long expanded = 0; +- // *** check endianness! +- for (int i=0; i<(int)pattern.mask; i++) +- expanded |= 1<<(31-i); +- pattern.mask = htonl(expanded); + } + +- pattern.address = inet_addr(addr.buf) & pattern.mask; +- if ((pattern.address == INADDR_NONE) || +- (pattern.address == 0)) pattern.mask = 0; ++ family = pattern.address.u.sa.sa_family; ++ ++ if (pattern.prefixlen > (family == AF_INET ? 32: 128)) ++ throw Exception("invalid prefix length for filter address: %u", ++ pattern.prefixlen); ++ ++ // Compute mask from address and prefix length ++ memset (&pattern.mask, 0, sizeof (pattern.mask)); ++ switch (family) { ++ unsigned long mask; ++ case AF_INET: ++ mask = 0; ++ for (unsigned int i=0; i bits) ++ pattern.mask.u.sin6.sin6_addr.s6_addr[n] = 0xff; ++ else { ++ unsigned int lastbits = 0xff; ++ lastbits <<= bits - pattern.prefixlen; ++ pattern.mask.u.sin6.sin6_addr.s6_addr[n] = lastbits & 0xff; ++ break; ++ } ++ } ++ break; ++ case AF_UNSPEC: ++ // No mask to compute ++ break; ++ default: ++ ; /* not reached */ ++ } + + switch(p[0]) { + case '+': pattern.action = TcpFilter::Accept; break; +@@ -551,21 +864,39 @@ TcpFilter::Pattern TcpFilter::parsePattern(const char* p) { + } + + char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) { +- in_addr tmp; +- rfb::CharArray addr, mask; +- tmp.s_addr = p.address; +- addr.buf = rfb::strDup(inet_ntoa(tmp)); +- tmp.s_addr = p.mask; +- mask.buf = rfb::strDup(inet_ntoa(tmp)); +- char* result = new char[strlen(addr.buf)+1+strlen(mask.buf)+1+1]; ++ rfb::CharArray addr; ++ char buffer[INET6_ADDRSTRLEN + 2]; ++ ++ if (p.address.u.sa.sa_family == AF_INET) { ++ getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin), ++ buffer, sizeof (buffer), NULL, 0, NI_NUMERICHOST); ++ addr.buf = rfb::strDup(buffer); ++ } else if (p.address.u.sa.sa_family == AF_INET6) { ++ buffer[0] = '['; ++ getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin6), ++ buffer + 1, sizeof (buffer) - 2, NULL, 0, NI_NUMERICHOST); ++ strcat(buffer, "]"); ++ addr.buf = rfb::strDup(buffer); ++ } else if (p.address.u.sa.sa_family == AF_UNSPEC) ++ addr.buf = rfb::strDup(""); ++ ++ char action; + switch (p.action) { +- case Accept: result[0] = '+'; break; +- case Reject: result[0] = '-'; break; +- case Query: result[0] = '?'; break; ++ case Accept: action = '+'; break; ++ case Reject: action = '-'; break; ++ default: ++ case Query: action = '?'; break; + }; +- result[1] = 0; +- strcat(result, addr.buf); +- strcat(result, "/"); +- strcat(result, mask.buf); ++ size_t resultlen = (1 // action ++ + strlen (addr.buf) // address ++ + 1 // slash ++ + 3 // prefix length, max 128 ++ + 1); // terminating nul ++ char* result = new char[resultlen]; ++ if (addr.buf[0] == '\0') ++ snprintf(result, resultlen, "%c", action); ++ else ++ snprintf(result, resultlen, "%c%s/%u", action, addr.buf, p.prefixlen); ++ + return result; + } +diff --git a/common/network/TcpSocket.h b/common/network/TcpSocket.h +index cd4393e..3f72c85 100644 +--- a/common/network/TcpSocket.h ++++ b/common/network/TcpSocket.h +@@ -30,6 +30,14 @@ + + #include + ++#ifdef WIN32 ++#include ++#include ++#else ++#include /* for socklen_t */ ++#include /* for struct sockaddr_in */ ++#endif ++ + #include + + /* Tunnelling support. */ +@@ -65,20 +73,33 @@ namespace network { + + class TcpListener : public SocketListener { + public: +- TcpListener(const char *listenaddr, int port, bool localhostOnly=false, +- int sock=-1, bool close=true); ++ TcpListener(const struct sockaddr *listenaddr, socklen_t listenaddrlen); ++ TcpListener(int sock); ++ TcpListener(const TcpListener& other); ++ TcpListener& operator= (const TcpListener& other); + virtual ~TcpListener(); + + virtual void shutdown(); + virtual Socket* accept(); + +- void getMyAddresses(std::list* addrs); ++ static void getMyAddresses(std::list* result); + int getMyPort(); +- +- private: +- bool closeFd; + }; + ++ void createLocalTcpListeners(std::list *listeners, ++ int port); ++ void createTcpListeners(std::list *listeners, ++ const char *addr, ++ int port); ++ ++ typedef struct vnc_sockaddr { ++ union { ++ sockaddr sa; ++ sockaddr_in sin; ++ sockaddr_in6 sin6; ++ } u; ++ } vnc_sockaddr_t; ++ + class TcpFilter : public ConnectionFilter { + public: + TcpFilter(const char* filter); +@@ -89,8 +110,10 @@ namespace network { + typedef enum {Accept, Reject, Query} Action; + struct Pattern { + Action action; +- unsigned long address; +- unsigned long mask; ++ vnc_sockaddr_t address; ++ unsigned int prefixlen; ++ ++ vnc_sockaddr_t mask; // computed from address and prefix + }; + static Pattern parsePattern(const char* s); + static char* patternToStr(const Pattern& p); +diff --git a/common/os/CMakeLists.txt b/common/os/CMakeLists.txt +index 39d5c10..cd066f8 100644 +--- a/common/os/CMakeLists.txt ++++ b/common/os/CMakeLists.txt +@@ -2,7 +2,6 @@ include_directories(${CMAKE_SOURCE_DIR}/common) + + add_library(os STATIC + print.c +- net.c + w32tiger.c + os.cxx + tls.cxx) +diff --git a/common/os/net.c b/common/os/net.c +deleted file mode 100644 +index 7bad36c..0000000 +--- a/common/os/net.c ++++ /dev/null +@@ -1,53 +0,0 @@ +-/* Copyright (C) 2008 TightVNC Team. All Rights Reserved. +- * +- * This is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This software is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this software; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +- * USA. +- */ +- +-#ifdef HAVE_CONFIG_H +-#include +-#endif +- +-#include +-#include +- +-#ifdef WIN32 +-#include +-#include +-#else +-#include +-#include +-#include +-#endif +- +-#include +- +- +-#ifndef HAVE_INET_NTOP +-const char *tight_inet_ntop(int af, const void *src, char *dst, +- socklen_t size) { +- char *tempstr; +- +- /* Catch bugs - we should not use IPv6 if we don't have inet_ntop */ +- if (af != AF_INET) +- abort(); +- +- /* inet_ntoa never fails */ +- tempstr = inet_ntoa(*(struct in_addr *)(src)); +- memcpy(dst, tempstr, strlen(tempstr) + 1); +- +- return dst; +-} +-#endif +diff --git a/common/os/net.h b/common/os/net.h +deleted file mode 100644 +index bd8b21c..0000000 +--- a/common/os/net.h ++++ /dev/null +@@ -1,50 +0,0 @@ +-/* Copyright (C) 2008 TightVNC Team. All Rights Reserved. +- * +- * This is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This software is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this software; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +- * USA. +- */ +- +-#ifndef OS_NET_H +-#define OS_NET_H +- +-#ifdef HAVE_CONFIG_H +-#include +-#endif +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-#ifndef HAVE_SOCKLEN_T +-typedef int socklen_t; +-#endif +- +-/* IPv6 support on server side - we have to have all those functions */ +-#if defined(HAVE_INET_NTOP) +-#define HAVE_IPV6 +-#endif +- +-/* IPv4-only stub implementation */ +-#ifndef HAVE_INET_NTOP +-const char *tight_inet_ntop(int af, const void *src, +- char *dst, socklen_t size); +-#define inet_ntop tight_inet_ntop +-#endif +- +-#ifdef __cplusplus +-}; +-#endif +- +-#endif /* OS_NET_H */ +diff --git a/config.h.in b/config.h.in +index ec2aed9..c6d27ee 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -2,9 +2,6 @@ + #define PACKAGE_VERSION "@VERSION@" + + #cmakedefine HAVE_SOCKLEN_T +-#cmakedefine HAVE_INET_ATON +-#cmakedefine HAVE_INET_NTOP +-#cmakedefine HAVE_GETADDRINFO + #cmakedefine HAVE_SNPRINTF + #cmakedefine HAVE_STRCASECMP + #cmakedefine HAVE_STRNCASECMP +diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx +index b5498e1..400af75 100644 +--- a/unix/x0vncserver/x0vncserver.cxx ++++ b/unix/x0vncserver/x0vncserver.cxx +@@ -434,6 +434,8 @@ int main(int argc, char** argv) + signal(SIGINT, CleanupSignalHandler); + signal(SIGTERM, CleanupSignalHandler); + ++ std::list listeners; ++ + try { + TXWindow::init(dpy,"x0vncserver"); + Geometry geo(DisplayWidth(dpy, DefaultScreen(dpy)), +@@ -448,13 +450,16 @@ int main(int argc, char** argv) + QueryConnHandler qcHandler(dpy, &server); + server.setQueryConnectionHandler(&qcHandler); + +- TcpListener listener(NULL, (int)rfbport); ++ createTcpListeners(&listeners, 0, (int)rfbport); + vlog.info("Listening on port %d", (int)rfbport); + + const char *hostsData = hostsFile.getData(); + FileTcpFilter fileTcpFilter(hostsData); + if (strlen(hostsData) != 0) +- listener.setFilter(&fileTcpFilter); ++ for (std::list::iterator i = listeners.begin(); ++ i != listeners.end(); ++ i++) ++ (*i).setFilter(&fileTcpFilter); + delete[] hostsData; + + PollingScheduler sched((int)pollingCycle, (int)maxProcessorUsage); +@@ -469,7 +474,11 @@ int main(int argc, char** argv) + TXWindow::handleXEvents(dpy); + + FD_ZERO(&rfds); +- FD_SET(listener.getFd(), &rfds); ++ for (std::list::iterator i = listeners.begin(); ++ i != listeners.end(); ++ i++) ++ FD_SET((*i).getFd(), &rfds); ++ + server.getSockets(&sockets); + int clients_connected = 0; + for (i = sockets.begin(); i != sockets.end(); i++) { +@@ -514,12 +523,16 @@ int main(int argc, char** argv) + } + + // Accept new VNC connections +- if (FD_ISSET(listener.getFd(), &rfds)) { +- Socket* sock = listener.accept(); +- if (sock) { +- server.addSocket(sock); +- } else { +- vlog.status("Client connection rejected"); ++ for (std::list::iterator i = listeners.begin(); ++ i != listeners.end(); ++ i++) { ++ if (FD_ISSET((*i).getFd(), &rfds)) { ++ Socket* sock = (*i).accept(); ++ if (sock) { ++ server.addSocket(sock); ++ } else { ++ vlog.status("Client connection rejected"); ++ } + } + } + +diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc +index 05169b0..d0a9953 100644 +--- a/unix/xserver/hw/vnc/XserverDesktop.cc ++++ b/unix/xserver/hw/vnc/XserverDesktop.cc +@@ -135,13 +135,13 @@ public: + + + XserverDesktop::XserverDesktop(ScreenPtr pScreen_, +- network::TcpListener* listener_, +- network::TcpListener* httpListener_, ++ std::list listeners_, ++ std::list httpListeners_, + const char* name, const rfb::PixelFormat &pf, + void* fbptr, int stride) + : pScreen(pScreen_), + server(0), httpServer(0), +- listener(listener_), httpListener(httpListener_), ++ listeners(listeners_), httpListeners(httpListeners_), + cmap(0), deferredUpdateTimerSet(false), + grabbing(false), ignoreHooks_(false), directFbptr(true), + queryConnectId(0) +@@ -155,7 +155,7 @@ XserverDesktop::XserverDesktop(ScreenPtr pScreen_, + setFramebuffer(pScreen->width, pScreen->height, fbptr, stride); + server->setQueryConnectionHandler(this); + +- if (httpListener) ++ if (!httpListeners.empty ()) + httpServer = new FileHTTPServer(this); + } + +@@ -315,7 +315,7 @@ char* XserverDesktop::substitute(const char* varName) + } + if (strcmp(varName, "$PORT") == 0) { + char* str = new char[10]; +- sprintf(str, "%d", listener ? listener->getMyPort() : 0); ++ sprintf(str, "%d", listeners.empty () ? 0 : (*listeners.begin ()).getMyPort()); + return str; + } + if (strcmp(varName, "$WIDTH") == 0) { +@@ -587,14 +587,18 @@ void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout) + + // Add all sockets we want read events for, after purging + // any closed sockets. +- if (listener) +- FD_SET(listener->getFd(), fds); +- if (httpListener) +- FD_SET(httpListener->getFd(), fds); ++ for (std::list::iterator i = listeners.begin(); ++ i != listeners.end(); ++ i++) ++ FD_SET((*i).getFd(), fds); ++ for (std::list::iterator i = httpListeners.begin(); ++ i != httpListeners.end(); ++ i++) ++ FD_SET((*i).getFd(), fds); + + std::list sockets; +- server->getSockets(&sockets); + std::list::iterator i; ++ server->getSockets(&sockets); + for (i = sockets.begin(); i != sockets.end(); i++) { + int fd = (*i)->getFd(); + if ((*i)->isShutdown()) { +@@ -646,20 +650,24 @@ void XserverDesktop::wakeupHandler(fd_set* fds, int nfds) + // First check for file descriptors with something to do + if (nfds >= 1) { + +- if (listener) { +- if (FD_ISSET(listener->getFd(), fds)) { +- FD_CLR(listener->getFd(), fds); +- Socket* sock = listener->accept(); ++ for (std::list::iterator i = listeners.begin(); ++ i != listeners.end(); ++ i++) { ++ if (FD_ISSET((*i).getFd(), fds)) { ++ FD_CLR((*i).getFd(), fds); ++ Socket* sock = (*i).accept(); + sock->outStream().setBlocking(false); + server->addSocket(sock); + vlog.debug("new client, sock %d",sock->getFd()); + } + } + +- if (httpListener) { +- if (FD_ISSET(httpListener->getFd(), fds)) { +- FD_CLR(httpListener->getFd(), fds); +- Socket* sock = httpListener->accept(); ++ for (std::list::iterator i = httpListeners.begin(); ++ i != httpListeners.end(); ++ i++) { ++ if (FD_ISSET((*i).getFd(), fds)) { ++ FD_CLR((*i).getFd(), fds); ++ Socket* sock = (*i).accept(); + sock->outStream().setBlocking(false); + httpServer->addSocket(sock); + vlog.debug("new http client, sock %d",sock->getFd()); +diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h +index ca6e8af..23cdc83 100644 +--- a/unix/xserver/hw/vnc/XserverDesktop.h ++++ b/unix/xserver/hw/vnc/XserverDesktop.h +@@ -58,8 +58,9 @@ class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer, + public rfb::VNCServerST::QueryConnectionHandler { + public: + +- XserverDesktop(ScreenPtr pScreen, network::TcpListener* listener, +- network::TcpListener* httpListener_, ++ XserverDesktop(ScreenPtr pScreen, ++ std::list listeners_, ++ std::list httpListeners_, + const char* name, const rfb::PixelFormat &pf, + void* fbptr, int stride); + virtual ~XserverDesktop(); +@@ -136,8 +137,8 @@ private: + InputDevice *inputDevice; + rfb::VNCServerST* server; + rfb::HTTPServer* httpServer; +- network::TcpListener* listener; +- network::TcpListener* httpListener; ++ std::list listeners; ++ std::list httpListeners; + ColormapPtr cmap; + int stride_; + bool deferredUpdateTimerSet; +diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc +index 1abf7d5..1cfaf51 100644 +--- a/unix/xserver/hw/vnc/vncExtInit.cc ++++ b/unix/xserver/hw/vnc/vncExtInit.cc +@@ -127,6 +127,9 @@ rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11"); + rfb::BoolParameter localhostOnly("localhost", + "Only allow connections from localhost", + false); ++rfb::StringParameter interface("interface", ++ "listen on the specified network address", ++ "all"); + + static PixelFormat vncGetPixelFormat(ScreenPtr pScreen) + { +@@ -222,29 +225,43 @@ void vncExtensionInit() + for (int scr = 0; scr < screenInfo.numScreens; scr++) { + + if (!desktop[scr]) { +- network::TcpListener* listener = 0; +- network::TcpListener* httpListener = 0; ++ std::list listeners; ++ std::list httpListeners; + if (scr == 0 && vncInetdSock != -1) { + if (network::TcpSocket::isListening(vncInetdSock)) + { +- listener = new network::TcpListener(NULL, 0, 0, vncInetdSock, true); ++ listeners.push_back (network::TcpListener(vncInetdSock)); + vlog.info("inetd wait"); + } + } else { ++ const char *addr = interface; + int port = rfbport; + if (port == 0) port = 5900 + atoi(display); + port += 1000 * scr; +- listener = new network::TcpListener(listenaddr, port, localhostOnly); ++ if (strcasecmp(addr, "all") == 0) ++ addr = 0; ++ if (localhostOnly) ++ network::createLocalTcpListeners(&listeners, port); ++ else ++ network::createTcpListeners(&listeners, addr, port); ++ + vlog.info("Listening for VNC connections on %s interface(s), port %d", +- listenaddr == NULL ? "all" : listenaddr, port); ++ localhostOnly ? "local" : (const char*)interface, ++ port); ++ + CharArray httpDirStr(httpDir.getData()); + if (httpDirStr.buf[0]) { + port = httpPort; + if (port == 0) port = 5800 + atoi(display); + port += 1000 * scr; +- httpListener = new network::TcpListener(listenaddr, port, localhostOnly); ++ if (localhostOnly) ++ network::createLocalTcpListeners(&httpListeners, port); ++ else ++ network::createTcpListeners(&httpListeners, addr, port); ++ + vlog.info("Listening for HTTP connections on %s interface(s), port %d", +- listenaddr == NULL ? "all" : listenaddr, port); ++ localhostOnly ? "local" : (const char*)interface, ++ port); + } + } + +@@ -252,15 +269,15 @@ void vncExtensionInit() + PixelFormat pf = vncGetPixelFormat(screenInfo.screens[scr]); + + desktop[scr] = new XserverDesktop(screenInfo.screens[scr], +- listener, +- httpListener, ++ listeners, ++ httpListeners, + desktopNameStr.buf, + pf, + vncFbptr[scr], + vncFbstride[scr]); + vlog.info("created VNC server for screen %d", scr); + +- if (scr == 0 && vncInetdSock != -1 && !listener) { ++ if (scr == 0 && vncInetdSock != -1 && listeners.empty()) { + network::Socket* sock = new network::TcpSocket(vncInetdSock); + desktop[scr]->addClient(sock, false); + vlog.info("added inetd sock"); +diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx +index 2d7685f..81bf849 100644 +--- a/vncviewer/vncviewer.cxx ++++ b/vncviewer/vncviewer.cxx +@@ -459,15 +459,45 @@ int main(int argc, char** argv) + #endif + + if (listenMode) { ++ std::list listeners; + try { + int port = 5500; + if (isdigit(vncServerName[0])) + port = atoi(vncServerName); + +- TcpListener listener(NULL, port); ++ createTcpListeners(&listeners, 0, port); + + vlog.info("Listening on port %d\n", port); +- sock = listener.accept(); ++ ++ /* Wait for a connection */ ++ while (sock == NULL) { ++ fd_set rfds; ++ FD_ZERO(&rfds); ++ for (std::list::iterator i = listeners.begin(); ++ i != listeners.end(); ++ i++) ++ FD_SET((*i).getFd(), &rfds); ++ ++ int n = select(FD_SETSIZE, &rfds, 0, 0, 0); ++ if (n < 0) { ++ if (errno == EINTR) { ++ vlog.debug("Interrupted select() system call"); ++ continue; ++ } else { ++ throw rdr::SystemException("select", errno); ++ } ++ } ++ ++ for (std::list::iterator i = listeners.begin (); ++ i != listeners.end(); ++ i++) ++ if (FD_ISSET((*i).getFd(), &rfds)) { ++ sock = (*i).accept(); ++ if (sock) ++ /* Got a connection */ ++ break; ++ } ++ } + } catch (rdr::Exception& e) { + vlog.error("%s", e.str()); + fl_alert("%s", e.str()); +diff --git a/win/rfb_win32/Dialog.cxx b/win/rfb_win32/Dialog.cxx +index 70a5fb5..24e0d9f 100644 +--- a/win/rfb_win32/Dialog.cxx ++++ b/win/rfb_win32/Dialog.cxx +@@ -86,21 +86,17 @@ TCHAR* Dialog::getItemString(int id) { + } + + void Dialog::setItemChecked(int id, bool state) { +- dlog.debug("bool[%d]=%d", id, (int)state); + SendMessage(GetDlgItem(handle, id), BM_SETCHECK, state ? BST_CHECKED : BST_UNCHECKED, 0); + } + void Dialog::setItemInt(int id, int value) { +- dlog.debug("int[%d]=%d", id, value); + SetDlgItemInt(handle, id, value, TRUE); + } + void Dialog::setItemString(int id, const TCHAR* s) { +- dlog.debug("string[%d]=%s", id, (const char*)CStr(s)); + SetDlgItemText(handle, id, s); + } + + + void Dialog::enableItem(int id, bool state) { +- dlog.debug("enable[%d]=%d", id, (int)state); + EnableWindow(GetDlgItem(handle, id), state); + } + +@@ -361,7 +357,6 @@ bool PropSheet::showPropSheet(HWND owner, bool showApply, bool showCtxtHelp, boo + } + + void PropSheet::reInitPages() { +- plog.debug("reInitPages %lx", handle); + std::list::iterator pspi; + for (pspi=pages.begin(); pspi!=pages.end(); pspi++) { + if ((*pspi)->handle) +@@ -370,7 +365,6 @@ void PropSheet::reInitPages() { + } + + bool PropSheet::commitPages() { +- plog.debug("commitPages %lx", handle); + bool result = true; + std::list::iterator pspi; + for (pspi=pages.begin(); pspi!=pages.end(); pspi++) { +@@ -383,7 +377,6 @@ bool PropSheet::commitPages() { + + void PropSheetPage::setChanged(bool changed) { + if (propSheet) { +- plog.debug("setChanged[%lx(%lx)]=%d", handle, propSheet->handle, (int)changed); + if (changed) + PropSheet_Changed(propSheet->handle, handle); + else +diff --git a/win/rfb_win32/SocketManager.cxx b/win/rfb_win32/SocketManager.cxx +index d4f1965..b073b8f 100644 +--- a/win/rfb_win32/SocketManager.cxx ++++ b/win/rfb_win32/SocketManager.cxx +@@ -174,7 +174,7 @@ void SocketManager::processEvent(HANDLE event) { + vlog.info("deleting listening socket"); + remListener(li.sock); + } else if (network_events.lNetworkEvents & FD_ADDRESS_LIST_CHANGE) { +- li.notifier->processAddressChange(li.sock); ++ li.notifier->processAddressChange(); + requestAddressChangeEvents(li.sock); + } else { + vlog.error("unknown listener event: %lx", network_events.lNetworkEvents); +diff --git a/win/rfb_win32/SocketManager.h b/win/rfb_win32/SocketManager.h +index ef35974..c3c8faf 100644 +--- a/win/rfb_win32/SocketManager.h ++++ b/win/rfb_win32/SocketManager.h +@@ -48,7 +48,7 @@ namespace rfb { + class AddressChangeNotifier { + public: + virtual ~AddressChangeNotifier() {} +- virtual void processAddressChange(network::SocketListener* sl) = 0; ++ virtual void processAddressChange() = 0; + }; + + // Add a listening socket. Incoming connections will be added to the supplied +diff --git a/win/vncconfig/vncconfig.cxx b/win/vncconfig/vncconfig.cxx +index 535febb..74d5e66 100644 +--- a/win/vncconfig/vncconfig.cxx ++++ b/win/vncconfig/vncconfig.cxx +@@ -16,6 +16,7 @@ + * USA. + */ + ++#include + #include + #include + #include +diff --git a/win/winvnc/ManagedListener.cxx b/win/winvnc/ManagedListener.cxx +index f2933bb..ac408e7 100644 +--- a/win/winvnc/ManagedListener.cxx ++++ b/win/winvnc/ManagedListener.cxx +@@ -26,12 +26,16 @@ static LogWriter vlog("ManagedListener"); + + + ManagedListener::ManagedListener(SocketManager* mgr) +-: sock(0), filter(0), manager(mgr), addrChangeNotifier(0), server(0), port(0), localOnly(false) { ++: filter(0), manager(mgr), addrChangeNotifier(0), server(0), port(0), localOnly(false) { + } + + ManagedListener::~ManagedListener() { +- if (sock) +- manager->remListener(sock); ++ if (!sockets.empty()) { ++ std::list::iterator iter; ++ for (iter = sockets.begin(); iter != sockets.end(); ++iter) ++ manager->remListener(&*iter); ++ sockets.clear(); ++ } + delete filter; + } + +@@ -57,8 +61,11 @@ void ManagedListener::setFilter(const char* filterStr) { + vlog.info("set filter to %s", filterStr); + delete filter; + filter = new network::TcpFilter(filterStr); +- if (sock && !localOnly) +- sock->setFilter(filter); ++ if (!sockets.empty() && !localOnly) { ++ std::list::iterator iter; ++ for (iter = sockets.begin(); iter != sockets.end(); ++iter) ++ iter->setFilter(filter); ++ } + } + + void ManagedListener::setAddressChangeNotifier(SocketManager::AddressChangeNotifier* acn) { +@@ -68,26 +75,39 @@ void ManagedListener::setAddressChangeNotifier(SocketManager::AddressChangeNotif + refresh(); + } + ++bool ManagedListener::isListening() { ++ return !sockets.empty(); ++} + + void ManagedListener::refresh() { +- if (sock) +- manager->remListener(sock); +- sock = 0; ++ std::list::iterator iter; ++ if (!sockets.empty()) { ++ for (iter = sockets.begin(); iter != sockets.end(); ++iter) ++ manager->remListener(&*iter); ++ sockets.clear(); ++ } + if (!server) + return; + try { +- if (port) +- sock = new network::TcpListener(NULL, port, localOnly); ++ if (port) { ++ if (localOnly) ++ network::createLocalTcpListeners(&sockets, port); ++ else ++ network::createTcpListeners(&sockets, NULL, port); ++ } + } catch (rdr::Exception& e) { + vlog.error(e.str()); + } +- if (sock) { +- if (!localOnly) +- sock->setFilter(filter); ++ if (!sockets.empty()) { ++ if (!localOnly) { ++ for (iter = sockets.begin(); iter != sockets.end(); ++iter) ++ iter->setFilter(filter); ++ } + try { +- manager->addListener(sock, server, addrChangeNotifier); +- } catch (...) { +- sock = 0; ++ for (iter = sockets.begin(); iter != sockets.end(); ++iter) ++ manager->addListener(&*iter, server, addrChangeNotifier); } catch (...) { ++ // FIXME: Should unwind what we've added ++ sockets.clear(); + throw; + } + } +diff --git a/win/winvnc/ManagedListener.h b/win/winvnc/ManagedListener.h +index e83aa0b..1c7099f 100644 +--- a/win/winvnc/ManagedListener.h ++++ b/win/winvnc/ManagedListener.h +@@ -40,10 +40,12 @@ namespace winvnc { + void setPort(int port, bool localOnly=false); + void setFilter(const char* filter); + void setAddressChangeNotifier(rfb::win32::SocketManager::AddressChangeNotifier* acn); +- +- network::TcpListener* sock; ++ ++ bool isListening(); ++ + protected: + void refresh(); ++ std::list sockets; + network::TcpFilter* filter; + rfb::win32::SocketManager* manager; + rfb::win32::SocketManager::AddressChangeNotifier* addrChangeNotifier; +diff --git a/win/winvnc/VNCServerWin32.cxx b/win/winvnc/VNCServerWin32.cxx +index 4d89a0e..467ff70 100644 +--- a/win/winvnc/VNCServerWin32.cxx ++++ b/win/winvnc/VNCServerWin32.cxx +@@ -43,7 +43,7 @@ static IntParameter http_port("HTTPPortNumber", + static IntParameter port_number("PortNumber", + "TCP/IP port on which the server will accept connections", 5900); + static StringParameter hosts("Hosts", +- "Filter describing which hosts are allowed access to this server", "+0.0.0.0/0.0.0.0"); ++ "Filter describing which hosts are allowed access to this server", "+"); + static BoolParameter localHost("LocalHost", + "Only accept connections from via the local loop-back network interface", false); + static BoolParameter queryOnlyIfLoggedOn("QueryOnlyIfLoggedOn", +@@ -86,8 +86,8 @@ VNCServerWin32::~VNCServerWin32() { + } + + +-void VNCServerWin32::processAddressChange(network::SocketListener* sock_) { +- if (!trayIcon || (sock_ != rfbSock.sock)) ++void VNCServerWin32::processAddressChange() { ++ if (!trayIcon) + return; + + // Tool-tip prefix depends on server mode +@@ -97,8 +97,8 @@ void VNCServerWin32::processAddressChange(network::SocketListener* sock_) { + + // Fetch the list of addresses + std::list addrs; +- if (rfbSock.sock) +- rfbSock.sock->getMyAddresses(&addrs); ++ if (rfbSock.isListening()) ++ TcpListener::getMyAddresses(&addrs); + else + addrs.push_front(strDup("Not accepting connections")); + +@@ -132,7 +132,7 @@ void VNCServerWin32::regConfigChanged() { + httpSock.setPort(http_port, localHost); + + // -=- Update the Java viewer's web page port number. +- httpServer.setRFBport(rfbSock.sock ? port_number : 0); ++ httpServer.setRFBport(rfbSock.isListening() ? port_number : 0); + + // -=- Update the TCP address filter for both ports, if open. + CharArray pattern(hosts.getData()); +@@ -140,7 +140,7 @@ void VNCServerWin32::regConfigChanged() { + httpSock.setFilter(pattern.buf); + + // -=- Update the tray icon tooltip text with IP addresses +- processAddressChange(rfbSock.sock); ++ processAddressChange(); + } + + +diff --git a/win/winvnc/VNCServerWin32.h b/win/winvnc/VNCServerWin32.h +index 5b40a5a..27305d0 100644 +--- a/win/winvnc/VNCServerWin32.h ++++ b/win/winvnc/VNCServerWin32.h +@@ -82,7 +82,7 @@ namespace winvnc { + + // SocketManager::AddressChangeNotifier interface + // Used to keep tray icon up to date +- virtual void processAddressChange(network::SocketListener* sl); ++ virtual void processAddressChange(); + + // RegConfig::Callback interface + // Called via the EventManager whenver RegConfig sees the registry change diff --git a/SOURCES/tigervnc-no-warning-with-wformat-security.patch b/SOURCES/tigervnc-no-warning-with-wformat-security.patch new file mode 100644 index 0000000..f588be0 --- /dev/null +++ b/SOURCES/tigervnc-no-warning-with-wformat-security.patch @@ -0,0 +1,12 @@ +diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx +index c15c951..2d7685f 100644 +--- a/vncviewer/vncviewer.cxx ++++ b/vncviewer/vncviewer.cxx +@@ -309,7 +309,6 @@ interpretViaParam(char *remoteHost, int *remotePort, int localPort) + + snprintf(vncServerName, VNCSERVERNAMELEN, "localhost::%d", localPort); + vncServerName[VNCSERVERNAMELEN - 1] = '\0'; +- vlog.error(vncServerName); + + return 0; + } diff --git a/SOURCES/tigervnc-pointersync.patch b/SOURCES/tigervnc-pointersync.patch new file mode 100644 index 0000000..3870f2e --- /dev/null +++ b/SOURCES/tigervnc-pointersync.patch @@ -0,0 +1,19 @@ +diff --git a/unix/xserver/hw/vnc/Input.cc b/unix/xserver/hw/vnc/Input.cc +index d093f89..43c3ac3 100644 +--- a/unix/xserver/hw/vnc/Input.cc ++++ b/unix/xserver/hw/vnc/Input.cc +@@ -197,6 +197,14 @@ void InputDevice::PointerMove(const rfb::Point &pos) + + void InputDevice::PointerSync(void) + { ++ if (pointerDev) { ++ int x, y; ++ ++ GetSpritePosition (pointerDev, &x, &y); ++ cursorPos.x = x; ++ cursorPos.y = y; ++ } ++ + if (cursorPos.equals(oldCursorPos)) + return; + diff --git a/SOURCES/tigervnc-set-initial-mode-as-prefered.patch b/SOURCES/tigervnc-set-initial-mode-as-prefered.patch new file mode 100644 index 0000000..773981f --- /dev/null +++ b/SOURCES/tigervnc-set-initial-mode-as-prefered.patch @@ -0,0 +1,41 @@ +diff --git a/unix/xserver/hw/vnc/xvnc.cc b/unix/xserver/hw/vnc/xvnc.cc +index f2656d1..0e325e2 100644 +--- a/unix/xserver/hw/vnc/xvnc.cc ++++ b/unix/xserver/hw/vnc/xvnc.cc +@@ -1318,12 +1318,22 @@ static RRCrtcPtr vncRandRCrtcCreate(ScreenPtr pScreen) + /* Make sure the CRTC has this output set */ + vncRandRCrtcSet(pScreen, crtc, NULL, 0, 0, RR_Rotate_0, 1, &output); + +- /* Populate a list of default modes */ +- RRModePtr modes[sizeof(vncRandRWidths)/sizeof(*vncRandRWidths)]; +- int num_modes; ++ /* Populate a list of modes */ ++ RRModePtr modes[sizeof(vncRandRWidths)/sizeof(*vncRandRWidths) + 1]; ++ int num_modes = 0; + +- num_modes = 0; ++ /* Start with requested mode */ ++ mode = vncRandRModeGet(pScreen->width, pScreen->height); ++ if(mode != NULL) { ++ modes[num_modes] = mode; ++ num_modes++; ++ } ++ ++ /* Add default modes */ + for (int i = 0;i < sizeof(vncRandRWidths)/sizeof(*vncRandRWidths);i++) { ++ if (vncRandRWidths[i] == pScreen->width && vncRandRHeights[i] == pScreen->height) ++ continue; ++ + mode = vncRandRModeGet(vncRandRWidths[i], vncRandRHeights[i]); + if (mode != NULL) { + modes[num_modes] = mode; + @@ -1331,7 +1341,7 @@ static RRCrtcPtr vncRandRCrtcCreate(ScreenPtr pScreen) + } + } + +- RROutputSetModes(output, modes, num_modes, 0); ++ RROutputSetModes(output, modes, num_modes, 1); + + return crtc; + } + diff --git a/SOURCES/tigervnc-xserver117.patch b/SOURCES/tigervnc-xserver117.patch new file mode 100644 index 0000000..5f5a73c --- /dev/null +++ b/SOURCES/tigervnc-xserver117.patch @@ -0,0 +1,137 @@ +diff -up xorg-server-1.17.1/configure.ac.xserver116-rebased xorg-server-1.17.1/configure.ac +--- xorg-server-1.17.1/configure.ac.xserver116-rebased 2015-02-10 22:43:52.000000000 +0000 ++++ xorg-server-1.17.1/configure.ac 2015-02-13 16:14:05.074515927 +0000 +@@ -74,6 +74,7 @@ dnl forcing an entire recompile.x + AC_CONFIG_HEADERS(include/version-config.h) + + AM_PROG_AS ++AC_PROG_CXX + AC_PROG_LN_S + LT_PREREQ([2.2]) + LT_INIT([disable-static win32-dll]) +@@ -1795,6 +1796,10 @@ if test "x$XVFB" = xyes; then + AC_SUBST([XVFB_SYS_LIBS]) + fi + ++dnl Xvnc DDX ++AC_SUBST([XVNC_CPPFLAGS], ["-DHAVE_DIX_CONFIG_H $XSERVER_CFLAGS"]) ++AC_SUBST([XVNC_LIBS], ["$FB_LIB $FIXES_LIB $XEXT_LIB $CONFIG_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $MAIN_LIB"]) ++AC_SUBST([XVNC_SYS_LIBS], ["$GLX_SYS_LIBS"]) + + dnl Xnest DDX + +@@ -1830,6 +1835,8 @@ if test "x$XORG" = xauto; then + fi + AC_MSG_RESULT([$XORG]) + ++AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) ++ + if test "x$XORG" = xyes; then + XORG_DDXINCS='-I$(top_srcdir)/hw/xfree86 -I$(top_srcdir)/hw/xfree86/include -I$(top_srcdir)/hw/xfree86/common' + XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os' +@@ -2059,7 +2066,6 @@ if test "x$XORG" = xyes; then + AC_DEFINE(XORG_SERVER, 1, [Building Xorg server]) + AC_DEFINE(XORGSERVER, 1, [Building Xorg server]) + AC_DEFINE(XFree86Server, 1, [Building XFree86 server]) +- AC_DEFINE_UNQUOTED(XORG_VERSION_CURRENT, [$VENDOR_RELEASE], [Current Xorg version]) + AC_DEFINE(NEED_XF86_TYPES, 1, [Need XFree86 typedefs]) + AC_DEFINE(NEED_XF86_PROTOTYPES, 1, [Need XFree86 helper functions]) + AC_DEFINE(__XSERVERNAME__, "Xorg", [Name of X server]) +@@ -2599,6 +2605,7 @@ hw/dmx/Makefile + hw/dmx/man/Makefile + hw/vfb/Makefile + hw/vfb/man/Makefile ++hw/vnc/Makefile + hw/xnest/Makefile + hw/xnest/man/Makefile + hw/xwin/Makefile +diff -up xorg-server-1.17.1/hw/Makefile.am.xserver116-rebased xorg-server-1.17.1/hw/Makefile.am +--- xorg-server-1.17.1/hw/Makefile.am.xserver116-rebased 2014-04-16 21:24:00.000000000 +0100 ++++ xorg-server-1.17.1/hw/Makefile.am 2015-02-13 16:14:05.131516821 +0000 +@@ -38,7 +38,8 @@ SUBDIRS = \ + $(DMX_SUBDIRS) \ + $(KDRIVE_SUBDIRS) \ + $(XQUARTZ_SUBDIRS) \ +- $(XWAYLAND_SUBDIRS) ++ $(XWAYLAND_SUBDIRS) \ ++ vnc + + DIST_SUBDIRS = dmx xfree86 vfb xnest xwin xquartz kdrive xwayland + +diff -up xorg-server-1.17.1/mi/miinitext.c.xserver116-rebased xorg-server-1.17.1/mi/miinitext.c +--- xorg-server-1.17.1/mi/miinitext.c.xserver116-rebased 2015-01-17 23:42:52.000000000 +0000 ++++ xorg-server-1.17.1/mi/miinitext.c 2015-02-13 16:14:05.131516821 +0000 +@@ -111,6 +111,10 @@ SOFTWARE. + #include "micmap.h" + #include "globals.h" + ++#ifdef TIGERVNC ++extern void vncExtensionInit(INITARGS); ++#endif ++ + /* The following is only a small first step towards run-time + * configurable extensions. + */ +@@ -235,6 +239,9 @@ EnableDisableExtensionError(const char * + + /* List of built-in (statically linked) extensions */ + static const ExtensionModule staticExtensions[] = { ++#ifdef TIGERVNC ++ {vncExtensionInit, "VNC-EXTENSION", NULL}, ++#endif + {GEExtensionInit, "Generic Event Extension", &noGEExtension}, + {ShapeExtensionInit, "SHAPE", NULL}, + #ifdef MITSHM +diff -up xorg-server-1.17.1/os/WaitFor.c.xserver116-rebased xorg-server-1.17.1/os/WaitFor.c +--- xorg-server-1.17.1/os/WaitFor.c.xserver116-rebased 2015-01-26 18:40:30.000000000 +0000 ++++ xorg-server-1.17.1/os/WaitFor.c 2015-02-13 16:14:05.132516837 +0000 +@@ -125,6 +125,9 @@ static void DoTimer(OsTimerPtr timer, CA + static void CheckAllTimers(void); + static volatile OsTimerPtr timers = NULL; + ++extern void vncWriteBlockHandler(fd_set *fds); ++extern void vncWriteWakeupHandler(int nfds, fd_set *fds); ++ + /***************** + * WaitForSomething: + * Make the server suspend until there is +@@ -150,6 +153,7 @@ WaitForSomething(int *pClientsReady) + INT32 timeout = 0; + fd_set clientsReadable; + fd_set clientsWritable; ++ fd_set socketsWritable; + int curclient; + int selecterr; + static int nready; +@@ -212,6 +216,9 @@ WaitForSomething(int *pClientsReady) + XFD_COPYSET(&AllSockets, &LastSelectMask); + } + ++ FD_ZERO(&socketsWritable); ++ vncWriteBlockHandler(&socketsWritable); ++ + BlockHandler((void *) &wt, (void *) &LastSelectMask); + if (NewOutputPending) + FlushAllOutput(); +@@ -223,10 +230,20 @@ WaitForSomething(int *pClientsReady) + i = Select(MaxClients, &LastSelectMask, &clientsWritable, NULL, wt); + } + else { +- i = Select(MaxClients, &LastSelectMask, NULL, NULL, wt); ++ if (AnyClientsWriteBlocked) ++ XFD_ORSET(&socketsWritable, &ClientsWriteBlocked, &socketsWritable); ++ ++ if (XFD_ANYSET(&socketsWritable)) { ++ i = Select(MaxClients, &LastSelectMask, &socketsWritable, NULL, wt); ++ if (AnyClientsWriteBlocked) ++ XFD_ANDSET(&clientsWritable, &socketsWritable, &ClientsWriteBlocked); ++ } else { ++ i = Select(MaxClients, &LastSelectMask, NULL, NULL, wt); ++ } + } + selecterr = GetErrno(); + WakeupHandler(i, (void *) &LastSelectMask); ++ vncWriteWakeupHandler(i, &socketsWritable); + if (i <= 0) { /* An error or timeout occurred */ + if (dispatchException) + return 0; diff --git a/SOURCES/tigervnc12-xorg113-glx.patch b/SOURCES/tigervnc12-xorg113-glx.patch deleted file mode 100644 index c5a5621..0000000 --- a/SOURCES/tigervnc12-xorg113-glx.patch +++ /dev/null @@ -1,36 +0,0 @@ -diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/xvnc.cc.glx tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/xvnc.cc ---- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/xvnc.cc.glx 2013-02-19 13:51:29.000000000 +0000 -+++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/xvnc.cc 2013-12-09 17:03:52.147179079 +0000 -@@ -1564,6 +1564,18 @@ static void vfbClientStateChange(Callbac - dispatchException &= ~DE_RESET; - } - -+#if XORG >= 113 -+#ifdef GLXEXT -+extern "C" void GlxExtensionInit(void); -+ -+static ExtensionModule glxExt = { -+ GlxExtensionInit, -+ "GLX", -+ &noGlxExtension -+}; -+#endif -+#endif -+ - void - InitOutput(ScreenInfo *screenInfo, int argc, char **argv) - { -@@ -1573,6 +1585,13 @@ InitOutput(ScreenInfo *screenInfo, int a - int i; - int NumFormats = 0; - -+#if XORG >= 113 -+#ifdef GLXEXT -+ if (serverGeneration == 1) -+ LoadExtension(&glxExt, TRUE); -+#endif -+#endif -+ - /* initialize pixmap formats */ - - /* must have a pixmap depth to match every screen depth */ diff --git a/SOURCES/vncserver.service b/SOURCES/vncserver.service index 4d55de2..4cec744 100644 --- a/SOURCES/vncserver.service +++ b/SOURCES/vncserver.service @@ -1,7 +1,7 @@ # The vncserver service unit file # # Quick HowTo: -# 1. Copy this file to /etc/systemd/system/vncserver@:.service +# 1. Copy this file to /etc/systemd/system/vncserver@.service # 2. Edit and vncserver parameters appropriately # ("runuser -l -c /usr/bin/vncserver %i -arg1 -arg2") # 3. Run `systemctl daemon-reload` @@ -37,7 +37,7 @@ After=syslog.target network.target Type=forking # Clean any existing files in /tmp/.X11-unix environment ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :' -ExecStart=/sbin/runuser -l -c "/usr/bin/vncserver %i" +ExecStart=/usr/sbin/runuser -l -c "/usr/bin/vncserver %i" PIDFile=/home//.vnc/%H%i.pid ExecStop=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :' diff --git a/SPECS/tigervnc.spec b/SPECS/tigervnc.spec index 659aa18..b9bdcfc 100644 --- a/SPECS/tigervnc.spec +++ b/SPECS/tigervnc.spec @@ -1,59 +1,66 @@ -%global snap 20130314svn5065 - -Name: tigervnc -Version: 1.2.80 -Release: 0.30.%{snap}%{?dist} -Summary: A TigerVNC remote display system - -Group: User Interface/Desktops -License: GPLv2+ -URL: http://www.tigervnc.com - -Source0: %{name}-%{version}-%{snap}.tar.bz2 -Source1: vncserver.service -Source2: vncserver.sysconfig -Source3: 10-libvnc.conf -Source6: vncviewer.desktop -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -BuildRequires: libX11-devel, automake, autoconf, libtool, gettext, gettext-autopoint -BuildRequires: libXext-devel, xorg-x11-server-source, libXi-devel -BuildRequires: xorg-x11-xtrans-devel, xorg-x11-util-macros, libXtst-devel -BuildRequires: libdrm-devel, libXt-devel, pixman-devel libXfont-devel -BuildRequires: libxkbfile-devel, openssl-devel, libpciaccess-devel -BuildRequires: mesa-libGL-devel, libXinerama-devel, ImageMagick +Name: tigervnc +Version: 1.3.1 +Release: 3%{?dist} +Summary: A TigerVNC remote display system + +Group: User Interface/Desktops +License: GPLv2+ +URL: http://www.tigervnc.com + +Source0: %{name}-%{version}.tar.gz +Source1: vncserver.service +Source2: vncserver.sysconfig +Source3: 10-libvnc.conf +Source6: vncviewer.desktop +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +BuildRequires: libX11-devel, automake, autoconf, libtool, gettext, gettext-autopoint +BuildRequires: libXext-devel, xorg-x11-server-source, libXi-devel +BuildRequires: xorg-x11-xtrans-devel, xorg-x11-util-macros, libXtst-devel +BuildRequires: libdrm-devel, libXt-devel, pixman-devel libXfont-devel +BuildRequires: libxkbfile-devel, openssl-devel, libpciaccess-devel +BuildRequires: mesa-libGL-devel, libXinerama-devel, ImageMagick BuildRequires: freetype-devel, libXdmcp-devel -BuildRequires: desktop-file-utils, java-devel, jpackage-utils -BuildRequires: libjpeg-turbo-devel, gnutls-devel, pam-devel -BuildRequires: systemd, cmake, fltk-devel - -Requires(post): coreutils -Requires(postun):coreutils - -Requires: hicolor-icon-theme -Requires: tigervnc-license -Requires: tigervnc-icons - -Provides: vnc = 4.1.3-2, vnc-libs = 4.1.3-2 -Obsoletes: vnc < 4.1.3-2, vnc-libs < 4.1.3-2 -Provides: tightvnc = 1.5.0-0.15.20090204svn3586 -Obsoletes: tightvnc < 1.5.0-0.15.20090204svn3586 - -Patch4: tigervnc-cookie.patch -Patch10: tigervnc11-ldnow.patch -Patch11: tigervnc11-gethomedir.patch -Patch13: tigervnc11-rh692048.patch -Patch14: tigervnc12-xorg113-glx.patch -Patch15: tigervnc-inetd-nowait.patch -Patch16: tigervnc-setcursor-crash.patch -Patch17: tigervnc-manpages.patch -Patch18: tigervnc-shebang.patch -Patch19: tigervnc-1.3.0-xserver-1.15.patch -Patch20: tigervnc-zrle-crash.patch -Patch21: tigervnc-cursor.patch -Patch22: tigervnc-input.patch -Patch23: tigervnc-xstartup.patch -Patch24: tigervnc-CVE-2014-0011.patch +BuildRequires: desktop-file-utils, java-devel, jpackage-utils +BuildRequires: libjpeg-turbo-devel, gnutls-devel, pam-devel +BuildRequires: systemd, cmake, fltk-devel + +Requires(post): coreutils +Requires(postun): coreutils + +Requires: hicolor-icon-theme +Requires: tigervnc-license +Requires: tigervnc-icons + +Provides: vnc = 4.1.3-2, vnc-libs = 4.1.3-2 +Obsoletes: vnc < 4.1.3-2, vnc-libs < 4.1.3-2 +Provides: tightvnc = 1.5.0-0.15.20090204svn3586 +Obsoletes: tightvnc < 1.5.0-0.15.20090204svn3586 + +Patch4: tigervnc-cookie.patch +Patch10: tigervnc11-ldnow.patch +Patch11: tigervnc11-gethomedir.patch +Patch13: tigervnc11-rh692048.patch +Patch14: tigervnc-inetd-nowait.patch +Patch15: tigervnc-setcursor-crash.patch +Patch16: tigervnc-manpages.patch +Patch17: tigervnc-shebang.patch +Patch18: tigervnc-1.3.1-xserver-1.16.patch +Patch19: tigervnc-1.3.1-xserver-1.17.patch +Patch20: tigervnc-zrle-crash.patch +Patch21: tigervnc-cursor.patch +Patch22: tigervnc-xstartup.patch +Patch23: tigervnc-no-warning-with-wformat-security.patch +Patch24: tigervnc-check-return-value-from-xshmattach.patch +Patch25: tigervnc-pointersync.patch +Patch26: tigervnc-inputreset.patch +Patch27: tigervnc-ipv6-support.patch +Patch28: tigervnc-set-initial-mode-as-prefered.patch +Patch29: tigervnc-CVE-2014-8241.patch +Patch30: tigervnc-1.3.1-CVE-2014-8240.patch + +# This is tigervnc-%{version}/unix/xserver116.patch rebased on the latest xorg +Patch100: tigervnc-xserver117.patch %description Virtual Network Computing (VNC) is a remote display system which @@ -64,20 +71,20 @@ client which will allow you to connect to other desktops running a VNC server. %package server -Summary: A TigerVNC server -Group: User Interface/X -Provides: vnc-server = 4.1.3-2, vnc-libs = 4.1.3-2 -Obsoletes: vnc-server < 4.1.3-2, vnc-libs < 4.1.3-2 -Provides: tightvnc-server = 1.5.0-0.15.20090204svn3586 -Obsoletes: tightvnc-server < 1.5.0-0.15.20090204svn3586 -Requires: perl -Requires: tigervnc-server-minimal -Requires: xorg-x11-xauth -Requires: xorg-x11-xinit -Requires(post): systemd -Requires(preun): systemd +Summary: A TigerVNC server +Group: User Interface/X +Provides: vnc-server = 4.1.3-2, vnc-libs = 4.1.3-2 +Obsoletes: vnc-server < 4.1.3-2, vnc-libs < 4.1.3-2 +Provides: tightvnc-server = 1.5.0-0.15.20090204svn3586 +Obsoletes: tightvnc-server < 1.5.0-0.15.20090204svn3586 +Requires: perl +Requires: tigervnc-server-minimal +Requires: xorg-x11-xauth +Requires: xorg-x11-xinit +Requires(post): systemd +Requires(preun): systemd Requires(postun): systemd -Requires(post): systemd-sysv chkconfig +Requires(post): systemd-sysv chkconfig %description server The VNC system allows you to access the same desktop from a wide @@ -87,15 +94,15 @@ contains x0vncserver program which can export your active X session. %package server-minimal -Summary: A minimal installation of TigerVNC server -Group: User Interface/X -Requires(post): chkconfig -Requires(preun):chkconfig -Requires(preun):initscripts -Requires(postun):initscripts +Summary: A minimal installation of TigerVNC server +Group: User Interface/X +Requires(post): chkconfig +Requires(preun): chkconfig +Requires(preun): initscripts +Requires(postun): initscripts -Requires: mesa-dri-drivers, xkeyboard-config, xorg-x11-xkb-utils -Requires: tigervnc-license +Requires: mesa-dri-drivers, xkeyboard-config, xorg-x11-xkb-utils +Requires: tigervnc-license %description server-minimal The VNC system allows you to access the same desktop from a wide @@ -105,14 +112,14 @@ machine. %ifnarch s390 s390x %package server-module -Summary: TigerVNC module to Xorg -Group: User Interface/X -Provides: vnc-server = 4.1.3-2, vnc-libs = 4.1.3-2 -Obsoletes: vnc-server < 4.1.3-2, vnc-libs < 4.1.3-2 -Provides: tightvnc-server-module = 1.5.0-0.15.20090204svn3586 -Obsoletes: tightvnc-server-module < 1.5.0-0.15.20090204svn3586 -Requires: xorg-x11-server-Xorg -Requires: tigervnc-license +Summary: TigerVNC module to Xorg +Group: User Interface/X +Provides: vnc-server = 4.1.3-2, vnc-libs = 4.1.3-2 +Obsoletes: vnc-server < 4.1.3-2, vnc-libs < 4.1.3-2 +Provides: tightvnc-server-module = 1.5.0-0.15.20090204svn3586 +Obsoletes: tightvnc-server-module < 1.5.0-0.15.20090204svn3586 +Requires: xorg-x11-server-Xorg +Requires: tigervnc-license %description server-module This package contains libvnc.so module to X server, allowing others @@ -120,33 +127,33 @@ to access the desktop on your machine. %endif %package server-applet -Summary: Java TigerVNC viewer applet for TigerVNC server -Group: User Interface/X -Requires: tigervnc-server, java, jpackage-utils -BuildArch: noarch +Summary: Java TigerVNC viewer applet for TigerVNC server +Group: User Interface/X +Requires: tigervnc-server, java, jpackage-utils +BuildArch: noarch %description server-applet The Java TigerVNC viewer applet for web browsers. Install this package to allow clients to use web browser when connect to the TigerVNC server. %package license -Summary: License of TigerVNC suite -Group: User Interface/X -BuildArch: noarch +Summary: License of TigerVNC suite +Group: User Interface/X +BuildArch: noarch %description license This package contains license of the TigerVNC suite %package icons -Summary: Icons for TigerVNC viewer -Group: User Interface/X -BuildArch: noarch +Summary: Icons for TigerVNC viewer +Group: User Interface/X +BuildArch: noarch %description icons This package contains icons for TigerVNC viewer %prep -%setup -q -n %{name}-%{version}-%{snap} +%setup -q -n %{name}-%{version} %patch4 -p1 -b .cookie %patch10 -p1 -b .ldnow @@ -156,27 +163,26 @@ This package contains icons for TigerVNC viewer cp -r /usr/share/xorg-x11-server-source/* unix/xserver pushd unix/xserver for all in `find . -type f -perm -001`; do - chmod -x "$all" + chmod -x "$all" done -patch -p1 -b --suffix .vnc < ../xserver114.patch +%patch100 -p1 -b .xserver117 popd -%patch14 -p1 -b .glx - # Applied Debian patch to fix busy loop when run from inetd in nowait # mode (bug #920373). -%patch15 -p1 -b .inetd-nowait +%patch14 -p1 -b .inetd-nowait -%patch16 -p1 -b .setcursor-crash +%patch15 -p1 -b .setcursor-crash # Synchronise manpages and --help output (bug #980870). -%patch17 -p1 -b .manpages +%patch16 -p1 -b .manpages # Don't use shebang in vncserver script. -%patch18 -p1 -b .shebang +%patch17 -p1 -b .shebang -# source compatibility with xserver 1.15 -%patch19 -p1 -b .115 +# source compatibility with xserver 1.16 and 1.17 +%patch18 -p1 -b .xserver-1.16 +%patch19 -p1 -b .xserver-1.17 # Avoid invalid read when ZRLE connection closed (upstream bug #133). %patch20 -p1 -b .zrle-crash @@ -184,14 +190,33 @@ popd # Fixed viewer crash when cursor has not been set (bug #1051333). %patch21 -p1 -b .cursor -# Use keyboard input code from tigervnc-1.3.0 (bug #1053536). -%patch22 -p1 -b .input - # Clearer xstartup file (bug #923655). -%patch23 -p1 -b .xstartup +%patch22 -p1 -b .xstartup + +# No warning when compiling with gcc's -Wformat-security option +%patch23 -p1 -b .no-warning-with-wformat-security + +# Check the return value from XShmAttach +%patch24 -p1 -b .check-return-value-from-xshmattach + +# Keep pointer in sync +%patch25 -p1 -b .pointersync -# Fixed heap-based buffer overflow (CVE-2014-0011, bug #1050928). -%patch24 -p1 -b .CVE-2014-0011 +# Input reset fixes from upstream +%patch26 -p1 -b .inputreset + +# Add IPv6 support +%patch27 -p1 -b .ipv6-support + +# Set initial mode as prefered +%patch28 -p1 -b .set-initial-mode-as-prefered + +# CVE-2014-8241 tigervnc: NULL pointer dereference flaw in XRegion +%patch29 -p1 -b .tigervnc-CVE-2014-8241 + +# CVE-2014-8240 tigervnc: integer overflow flaw, leading to a heap-based +# buffer overflow in screen size handling +%patch30 -p1 -b .tigervnc-1.3.1-CVE-2014-8240 %build %ifarch sparcv9 sparc64 s390 s390x @@ -207,24 +232,24 @@ make %{?_smp_mflags} pushd unix/xserver autoreconf -fiv %configure \ - --disable-xorg --disable-xnest --disable-xvfb --disable-dmx \ - --disable-xwin --disable-xephyr --disable-kdrive --with-pic \ - --disable-static --disable-xinerama \ - --with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \ - --with-fontdir=%{_datadir}/X11/fonts \ - --with-xkb-output=%{_localstatedir}/lib/xkb \ - --enable-install-libxf86config \ - --enable-glx --disable-dri --enable-dri2 \ - --disable-wayland \ - --disable-present \ - --disable-config-dbus \ - --disable-config-hal \ - --disable-config-udev \ - --with-dri-driver-path=%{_libdir}/dri \ - --without-dtrace \ - --disable-unit-tests \ - --disable-devel-docs \ - --disable-selective-werror + --disable-xorg --disable-xnest --disable-xvfb --disable-dmx \ + --disable-xwin --disable-xephyr --disable-kdrive --with-pic \ + --disable-static --disable-xwayland \ + --with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \ + --with-fontdir=%{_datadir}/X11/fonts \ + --with-xkb-output=%{_localstatedir}/lib/xkb \ + --enable-install-libxf86config \ + --enable-glx --disable-dri --enable-dri2 \ + --disable-wayland \ + --disable-present \ + --disable-config-dbus \ + --disable-config-hal \ + --disable-config-udev \ + --with-dri-driver-path=%{_libdir}/dri \ + --without-dtrace \ + --disable-unit-tests \ + --disable-devel-docs \ + --disable-selective-werror make %{?_smp_mflags} popd @@ -267,8 +292,8 @@ popd mkdir $RPM_BUILD_ROOT%{_datadir}/applications desktop-file-install \ - --dir $RPM_BUILD_ROOT%{_datadir}/applications \ - %{SOURCE6} + --dir $RPM_BUILD_ROOT%{_datadir}/applications \ + %{SOURCE6} # Install Java applet pushd java @@ -295,13 +320,13 @@ rm -rf $RPM_BUILD_ROOT %post touch -c %{_datadir}/icons/hicolor if [ -x %{_bindir}/gtk-update-icon-cache ]; then - %{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor || : + %{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor || : fi %postun touch -c %{_datadir}/icons/hicolor if [ -x %{_bindir}/gtk-update-icon-cache ]; then - %{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor || : + %{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor || : fi %post server @@ -319,7 +344,7 @@ fi %files -f %{name}.lang %defattr(-,root,root,-) -%doc README.txt +%doc %{_docdir}/%{name}-%{version}/README.txt %{_bindir}/vncviewer %{_datadir}/applications/* %{_mandir}/man1/vncviewer.1* @@ -355,13 +380,38 @@ fi %{_datadir}/vnc/classes/* %files license -%doc LICENCE.TXT +%doc %{_docdir}/%{name}-%{version}/LICENCE.TXT %files icons %defattr(-,root,root,-) %{_datadir}/icons/hicolor/*/apps/* %changelog +* Wed Sep 02 2015 Jan Grulich - 1.3.1-3 +- Do not mention that display number is required in the file name + Resolves: bz#1195266 + +* Thu Jul 30 2015 Jan Grulich - 1.3.1-2 +- Resolves: bz#1248422 + CVE-2014-8240 CVE-2014-8241 tigervnc: various flaws + +* Wed Apr 15 2015 Jan Grulich - 1.3.1-1 +- Drop unecessary patches +- Re-base to 1.3.1 (bug #1199453) +- Re-build against re-based xserver (bug #1194898) +- Check the return value from XShmAttach (bug #1072733) +- Add missing part of xserver114.patch (bug #1140603) +- Keep pointer in sync (bug #1100661) +- Make input device class global (bug #1119640) +- Add IPv6 support (bug #1162722) +- Set initial mode as prefered (bug #1181287) +- Do not mention that display number is required in the file name (bug #1195266) +- Enable Xinerama extension (bug #1199437) +- Specify full path for runuser command (bug #1208817) + +* Tue Sep 23 2014 Tim Waugh - 1.2.80-0.31.20130314svn5065 +- Rebuilt against xorg-x11-server to pick up ppc64le fix (bug #1140424). + * Mon Mar 10 2014 Tim Waugh - 1.2.80-0.30.20130314svn5065 - Fixed heap-based buffer overflow (CVE-2014-0011, bug #1050928).