From 16cf35b2bf7b38784b384f1982c7f65bd3fc0142 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Fri, 30 Dec 2016 17:54:25 +0100 Subject: Use unprefixed b64_* functions in websockets code. --- libvncserver/websockets.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index bdec8f3..c9ee1e9 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -194,7 +194,7 @@ static void webSocketsGenSha1Key(char *target, int size, char *key) iov[1].iov_base = GUID; iov[1].iov_len = sizeof(GUID) - 1; digestsha1(iov, 2, hash); - if (-1 == __b64_ntop(hash, sizeof(hash), target, size)) + if (-1 == b64_ntop(hash, sizeof(hash), target, size)) rfbErr("b64_ntop failed\n"); } @@ -501,7 +501,7 @@ webSocketsEncodeHixie(rfbClientPtr cl, const char *src, int len, char **dst) ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; wsctx->codeBufEncode[sz++] = '\x00'; - len = __b64_ntop((unsigned char *)src, len, wsctx->codeBufEncode+sz, sizeof(wsctx->codeBufEncode) - (sz + 1)); + len = b64_ntop((unsigned char *)src, len, wsctx->codeBufEncode+sz, sizeof(wsctx->codeBufEncode) - (sz + 1)); if (len < 0) { return len; } @@ -612,7 +612,7 @@ webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len) /* Decode the rest of what we need */ buf[needlen] = '\x00'; /* Replace end marker with end of string */ /* rfbLog("buf: %s\n", buf); */ - n = __b64_pton(buf, (unsigned char *)dst+retlen, 2+len); + n = b64_pton(buf, (unsigned char *)dst+retlen, 2+len); if (n < len) { rfbErr("Base64 decode error\n"); errno = EIO; @@ -752,7 +752,7 @@ webSocketsDecodeHybi(rfbClientPtr cl, char *dst, int len) errno = ECONNRESET; break; case WS_OPCODE_TEXT_FRAME: - if (-1 == (flength = __b64_pton(payload, (unsigned char *)wsctx->codeBufDecode, sizeof(wsctx->codeBufDecode)))) { + if (-1 == (flength = b64_pton(payload, (unsigned char *)wsctx->codeBufDecode, sizeof(wsctx->codeBufDecode)))) { rfbErr("%s: Base64 decode error; %m\n", __func__); break; } @@ -826,7 +826,7 @@ webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst) } if (wsctx->base64) { - if (-1 == (ret = __b64_ntop((unsigned char *)src, len, wsctx->codeBufEncode + sz, sizeof(wsctx->codeBufEncode) - sz))) { + if (-1 == (ret = b64_ntop((unsigned char *)src, len, wsctx->codeBufEncode + sz, sizeof(wsctx->codeBufEncode) - sz))) { rfbErr("%s: Base 64 encode failed\n", __func__); } else { if (ret != blen) -- cgit v1.2.3 From 1d1d2090b77bb732ec8390856b3b8b2a37d09b24 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Fri, 30 Dec 2016 18:20:12 +0100 Subject: Make websockets code build on OSX without SSL. --- libvncserver/websockets.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'libvncserver') diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index c9ee1e9..f596ab1 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -54,12 +54,25 @@ #include "rfbssl.h" #include "rfbcrypto.h" +#if defined(__APPLE__) + +#include +#define WS_NTOH64(n) OSSwapBigToHostInt64(n) +#define WS_NTOH32(n) OSSwapBigToHostInt32(n) +#define WS_NTOH16(n) OSSwapBigToHostInt16(n) +#define WS_HTON64(n) OSSwapHostToBigInt64(n) +#define WS_HTON16(n) OSSwapHostToBigInt16(n) + +#else + #define WS_NTOH64(n) htobe64(n) #define WS_NTOH32(n) htobe32(n) #define WS_NTOH16(n) htobe16(n) #define WS_HTON64(n) htobe64(n) #define WS_HTON16(n) htobe16(n) +#endif + #define B64LEN(__x) (((__x + 2) / 3) * 12 / 3) #define WSHLENMAX 14 /* 2 + sizeof(uint64_t) + sizeof(uint32_t) */ -- cgit v1.2.3 From 73684172397d63c4274d7fbdf940f428cf31744c Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sat, 28 Jan 2017 21:02:11 +0100 Subject: Various #ifdef fixes to allow building with MSVC2014 --- common/md5.h | 6 +++++- libvncserver/httpd.c | 1 + libvncserver/rfbcrypto.h | 2 ++ libvncserver/rfbserver.c | 3 +++ libvncserver/tightvnc-filetransfer/filetransfermsg.c | 2 ++ .../handlefiletransferrequest.c | 2 ++ libvncserver/websockets.c | 20 +++++++++++++++++--- rfb/rfb.h | 1 + 8 files changed, 33 insertions(+), 4 deletions(-) (limited to 'libvncserver') diff --git a/common/md5.h b/common/md5.h index 0fb0a4a..b0daab1 100644 --- a/common/md5.h +++ b/common/md5.h @@ -88,7 +88,11 @@ struct md5_ctx md5_uint32 total[2]; md5_uint32 buflen; - char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32)))); + char buffer[128] +#if __GNUC__ + __attribute__ ((__aligned__ (__alignof__ (md5_uint32)))) +#endif + ; }; /* diff --git a/libvncserver/httpd.c b/libvncserver/httpd.c index 8634b15..26d49af 100644 --- a/libvncserver/httpd.c +++ b/libvncserver/httpd.c @@ -47,6 +47,7 @@ #include #include #define close closesocket +#define strcasecmp _stricmp #if defined(_MSC_VER) #include /* For the missing ssize_t */ #define ssize_t SSIZE_T diff --git a/libvncserver/rfbcrypto.h b/libvncserver/rfbcrypto.h index 9dc3e63..7853154 100644 --- a/libvncserver/rfbcrypto.h +++ b/libvncserver/rfbcrypto.h @@ -1,6 +1,7 @@ #ifndef _RFB_CRYPTO_H #define _RFB_CRYPTO_H 1 +#ifdef LIBVNCSERVER_HAVE_UIO_H #include #define SHA1_HASH_SIZE 20 @@ -8,5 +9,6 @@ void digestmd5(const struct iovec *iov, int iovcnt, void *dest); void digestsha1(const struct iovec *iov, int iovcnt, void *dest); +#endif #endif diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index bc9cc11..040238d 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -37,6 +37,7 @@ #include #include #include "private.h" +#include "rfb/rfbconfig.h" #ifdef LIBVNCSERVER_HAVE_FCNTL_H #include @@ -74,7 +75,9 @@ /* stst() */ #include #include +#if LIBVNCSERVER_HAVE_UNISTD_H #include +#endif #ifndef WIN32 /* readdir() */ diff --git a/libvncserver/tightvnc-filetransfer/filetransfermsg.c b/libvncserver/tightvnc-filetransfer/filetransfermsg.c index 153f123..5f84e7f 100644 --- a/libvncserver/tightvnc-filetransfer/filetransfermsg.c +++ b/libvncserver/tightvnc-filetransfer/filetransfermsg.c @@ -56,7 +56,9 @@ #endif #include +#if LIBVNCSERVER_HAVE_UNISTD_H #include +#endif #include #include diff --git a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c index b235fa0..c511eed 100644 --- a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c +++ b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c @@ -29,7 +29,9 @@ #include #include #include +#if LIBVNCSERVER_HAVE_UNISTD_H #include +#endif #ifndef _MSC_VER #include #include diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index f596ab1..72396c2 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -49,7 +49,9 @@ #endif #include +#if LIBVNCSERVER_UNISTD_H #include +#endif #include "rfb/rfbconfig.h" #include "rfbssl.h" #include "rfbcrypto.h" @@ -116,15 +118,27 @@ typedef union ws_mask_s { * it from recognizing anonymous structs and unions. * See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=4784 */ -typedef struct __attribute__ ((__packed__)) ws_header_s { +typedef struct +#if __GNUC__ +__attribute__ ((__packed__)) +#endif +ws_header_s { unsigned char b0; unsigned char b1; union { - struct __attribute__ ((__packed__)) { + struct +#if __GNUC__ + __attribute__ ((__packed__)) +#endif + { uint16_t l16; ws_mask_t m16; } s16; - struct __attribute__ ((__packed__)) { + struct +#if __GNUC__ +__attribute__ ((__packed__)) +#endif + { uint64_t l64; ws_mask_t m64; } s64; diff --git a/rfb/rfb.h b/rfb/rfb.h index c6edc11..f982b40 100644 --- a/rfb/rfb.h +++ b/rfb/rfb.h @@ -54,6 +54,7 @@ extern "C" #ifdef WIN32 #undef SOCKET +typedef UINT32 in_addr_t; #include #ifdef LIBVNCSERVER_HAVE_WS2TCPIP_H #undef socklen_t -- cgit v1.2.3 From c36147390e637bbe01079df4d079f2e2fa62a8ab Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sat, 28 Jan 2017 21:10:20 +0100 Subject: Fix websockets building --- libvncserver/rfbcrypto.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libvncserver') diff --git a/libvncserver/rfbcrypto.h b/libvncserver/rfbcrypto.h index 7853154..4483ad6 100644 --- a/libvncserver/rfbcrypto.h +++ b/libvncserver/rfbcrypto.h @@ -1,6 +1,8 @@ #ifndef _RFB_CRYPTO_H #define _RFB_CRYPTO_H 1 +#include "rfb/rfbconfig.h" + #ifdef LIBVNCSERVER_HAVE_UIO_H #include -- cgit v1.2.3 From 2300efd39629df1d5be9d7b2ffc03027ed5c7e17 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sat, 28 Jan 2017 21:17:02 +0100 Subject: Fix typo --- libvncserver/rfbcrypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libvncserver') diff --git a/libvncserver/rfbcrypto.h b/libvncserver/rfbcrypto.h index 4483ad6..9c9e4e0 100644 --- a/libvncserver/rfbcrypto.h +++ b/libvncserver/rfbcrypto.h @@ -3,7 +3,7 @@ #include "rfb/rfbconfig.h" -#ifdef LIBVNCSERVER_HAVE_UIO_H +#ifdef LIBVNCSERVER_HAVE_SYS_UIO_H #include #define SHA1_HASH_SIZE 20 -- cgit v1.2.3 From c5297bd47d5307a36eaf3f059fcb36c20c8a43b3 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sat, 28 Jan 2017 21:51:04 +0100 Subject: Fix building websockets with GnuTLS. --- libvncserver/rfbcrypto.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/rfbcrypto.h b/libvncserver/rfbcrypto.h index 9c9e4e0..fec095e 100644 --- a/libvncserver/rfbcrypto.h +++ b/libvncserver/rfbcrypto.h @@ -3,12 +3,12 @@ #include "rfb/rfbconfig.h" -#ifdef LIBVNCSERVER_HAVE_SYS_UIO_H -#include - #define SHA1_HASH_SIZE 20 #define MD5_HASH_SIZE 16 +#ifdef LIBVNCSERVER_HAVE_SYS_UIO_H +#include + void digestmd5(const struct iovec *iov, int iovcnt, void *dest); void digestsha1(const struct iovec *iov, int iovcnt, void *dest); #endif -- cgit v1.2.3 From fe943395873c6cbfdfa0eadb8a5d13f2c95e8614 Mon Sep 17 00:00:00 2001 From: Bert van Hall Date: Wed, 8 Feb 2017 17:53:58 +0100 Subject: drop autotools Since autotools officially is no longer supported (see various github issues), drop the related infrastructure to stop tempting people to use it for building. Signed-off-by: Bert van Hall --- LibVNCServer.spec.in | 97 ------ Makefile.am | 28 -- autogen.sh | 4 - client_examples/Makefile.am | 38 --- configure.ac | 599 --------------------------------- examples/Makefile.am | 27 -- examples/android/Makefile.am | 7 - libvncclient.pc.in | 14 - libvncclient/Makefile.am | 29 -- libvncserver-config.in | 78 ----- libvncserver.pc.in | 14 - libvncserver/Makefile.am | 80 ----- m4/.gitignore | 1 - m4/ax_prefix_config_h.m4 | 203 ----------- m4/ax_type_socklen_t.m4 | 61 ---- m4/libgcrypt.m4 | 123 ------- test/Makefile.am | 28 -- webclients/Makefile.am | 4 - webclients/java-applet/Makefile.am | 5 - webclients/java-applet/ssl/Makefile.am | 2 - 20 files changed, 1442 deletions(-) delete mode 100755 LibVNCServer.spec.in delete mode 100644 Makefile.am delete mode 100755 autogen.sh delete mode 100644 client_examples/Makefile.am delete mode 100644 configure.ac delete mode 100644 examples/Makefile.am delete mode 100644 examples/android/Makefile.am delete mode 100644 libvncclient.pc.in delete mode 100644 libvncclient/Makefile.am delete mode 100644 libvncserver-config.in delete mode 100644 libvncserver.pc.in delete mode 100644 libvncserver/Makefile.am delete mode 100644 m4/.gitignore delete mode 100644 m4/ax_prefix_config_h.m4 delete mode 100644 m4/ax_type_socklen_t.m4 delete mode 100644 m4/libgcrypt.m4 delete mode 100644 test/Makefile.am delete mode 100644 webclients/Makefile.am delete mode 100644 webclients/java-applet/Makefile.am delete mode 100644 webclients/java-applet/ssl/Makefile.am (limited to 'libvncserver') diff --git a/LibVNCServer.spec.in b/LibVNCServer.spec.in deleted file mode 100755 index 13fe351..0000000 --- a/LibVNCServer.spec.in +++ /dev/null @@ -1,97 +0,0 @@ -# Note that this is NOT a relocatable package -Name: @PACKAGE@ -Version: @VERSION@ -Release: 2 -Summary: a library to make writing a vnc server easy -Copyright: GPL -Group: Libraries/Network -Packager: Johannes.Schindelin -Source: %{name}-%{version}.tar.gz -BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot - -%description -LibVNCServer makes writing a VNC server (or more correctly, a program -exporting a framebuffer via the Remote Frame Buffer protocol) easy. - -It is based on OSXvnc, which in turn is based on the original Xvnc by -ORL, later AT&T research labs in UK. - -It hides the programmer from the tedious task of managing clients and -compression schemata. - -LibVNCServer was put together and is (actively ;-) maintained by -Johannes Schindelin - -%package devel -Requires: %{name} = %{version} -Summary: Static Libraries and Header Files for LibVNCServer -Group: Libraries/Network -Requires: %{name} = %{version} - -%description devel -Static Libraries and Header Files for LibVNCServer. - -%package x11vnc -Requires: %{name} = %{version} -Summary: VNC server for the current X11 session -Group: User Interface/X -Requires: %{name} = %{version} - -%description x11vnc -x11vnc is to X Window System what WinVNC is to Windows, i.e. a server -which serves the current X Window System desktop via RFB (VNC) -protocol to the user. - -Based on the ideas of x0rfbserver and on LibVNCServer, it has evolved -into a versatile and performant while still easy to use program. - -%prep -%setup -n %{name}-%{version} - -%build -# CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{_prefix} -%configure -make - -%install -[ -n "%{buildroot}" -a "%{buildroot}" != / ] && rm -rf %{buildroot} -# make install prefix=%{buildroot}%{_prefix} -%makeinstall includedir="%{buildroot}%{_includedir}/rfb" - -%{__install} -d -m0755 %{buildroot}%{_datadir}/x11vnc/classes -%{__install} webclients/VncViewer.jar webclients/index.vnc \ - %{buildroot}%{_datadir}/x11vnc/classes - -%clean -[ -n "%{buildroot}" -a "%{buildroot}" != / ] && rm -rf %{buildroot} - -%pre -%post -%preun -%postun - -%files -%defattr(-,root,root) -%doc README INSTALL AUTHORS ChangeLog NEWS TODO -%{_bindir}/LinuxVNC -%{_bindir}/libvncserver-config -%{_libdir}/libvncclient.* -%{_libdir}/libvncserver.* - -%files devel -%defattr(-,root,root) -%{_includedir}/rfb/* - -%files x11vnc -%defattr(-,root,root) -%{_bindir}/x11vnc -%{_mandir}/man1/x11vnc.1* -%{_datadir}/x11vnc/classes - -%changelog -* Fri Aug 19 2005 Alberto Lusiani release 2 -- create separate package for x11vnc to prevent conflicts with x11vnc rpm -- create devel package, needed to compile but not needed for running -* Sun Feb 9 2003 Johannes Schindelin -- created libvncserver.spec.in - diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index a7bc64d..0000000 --- a/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 - -SUBDIRS=libvncserver examples libvncclient webclients client_examples test -DIST_SUBDIRS=libvncserver examples libvncclient webclients client_examples test -EXTRA_DIST = CMakeLists.txt rfb/rfbconfig.h.cmake - -bin_SCRIPTS = libvncserver-config - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libvncserver.pc libvncclient.pc - -includedir=$(prefix)/include/rfb - -include_HEADERS=rfb/rfb.h rfb/rfbconfig.h rfb/rfbproto.h \ - rfb/keysym.h rfb/rfbregion.h rfb/rfbclient.h - -$(PACKAGE)-$(VERSION).tar.gz: dist - -if HAVE_RPM -# Rule to build RPM distribution package -rpm: $(PACKAGE)-$(VERSION).tar.gz $(PACKAGE).spec - cp $(PACKAGE)-$(VERSION).tar.gz @RPMSOURCEDIR@ - rpmbuild -ba $(PACKAGE).spec -endif - -t: - $(MAKE) -C test test - diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index 2437158..0000000 --- a/autogen.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -autoreconf -fiv && -./configure "$@" diff --git a/client_examples/Makefile.am b/client_examples/Makefile.am deleted file mode 100644 index 9cb2c32..0000000 --- a/client_examples/Makefile.am +++ /dev/null @@ -1,38 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir) -LDADD = ../libvncclient/libvncclient.la @WSOCKLIB@ - -if WITH_FFMPEG -FFMPEG_HOME=@with_ffmpeg@ - -if HAVE_MP3LAME -MP3LAME_LIB=-lmp3lame -endif - -vnc2mpg_CFLAGS=-I$(FFMPEG_HOME)/libavformat -I$(FFMPEG_HOME)/libavcodec -I$(FFMPEG_HOME)/libavutil -vnc2mpg_LDADD=$(LDADD) $(FFMPEG_HOME)/libavformat/libavformat.a $(FFMPEG_HOME)/libavcodec/libavcodec.a $(MP3LAME_LIB) -lm - -FFMPEG_CLIENT=vnc2mpg -endif - -if HAVE_LIBSDL -SDLVIEWER=SDLvncviewer - -SDLvncviewer_CFLAGS=$(SDL_CFLAGS) -SDLvncviewer_SOURCES=SDLvncviewer.c scrap.c scrap.h - -# thanks to autoconf, this looks ugly -SDLvncviewer_LDADD=$(LDADD) $(SDL_LIBS) -endif - -if HAVE_LIBGTK -GTKVIEWER=gtkvncviewer -gtkvncviewer_SOURCES=gtkvncviewer.c -gtkvncviewer_CFLAGS=$(GTK_CFLAGS) -gtkvncviewer_LDADD=$(LDADD) $(GTK_LIBS) -endif - - -noinst_PROGRAMS=ppmtest $(SDLVIEWER) $(GTKVIEWER) $(FFMPEG_CLIENT) backchannel - - - diff --git a/configure.ac b/configure.ac deleted file mode 100644 index f13edb4..0000000 --- a/configure.ac +++ /dev/null @@ -1,599 +0,0 @@ -# Process this file with autoconf to produce a configure script. -AC_INIT(LibVNCServer, 0.9.11, https://github.com/LibVNC/libvncserver) -AM_INIT_AUTOMAKE([subdir-objects]) -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -AM_CONFIG_HEADER(rfbconfig.h) -AX_PREFIX_CONFIG_H([rfb/rfbconfig.h]) -AC_CONFIG_MACRO_DIR([m4]) - - -# set detailed version info -AC_DEFINE(VERSION_MAJOR, 0, LibVNCServer major version) -AC_DEFINE(VERSION_MINOR, 9, LibVNCServer minor version) -AC_DEFINE(VERSION_PATCHLEVEL, 11, LibVNCServer patchlevel) - -# Checks for programs. -AC_PROG_CC -AM_PROG_CC_C_O -if test -z "$CC"; then - CCLD="\$(CC)" -else - CCLD="$CC" -fi -test "x$GCC" = "xyes" && CFLAGS="$CFLAGS -Wall" -AC_PROG_MAKE_SET -AC_LIBTOOL_WIN32_DLL -AC_PROG_LIBTOOL -AC_CHECK_TOOL([AR], [ar], [/usr/bin/ar], - [$PATH:/usr/ccs/bin]) - -# Options -AH_TEMPLATE(WITH_TIGHTVNC_FILETRANSFER, [Disable TightVNCFileTransfer protocol]) -AC_ARG_WITH(tightvnc-filetransfer, - [ --without-tightvnc-filetransfer disable TightVNC file transfer protocol], - , [ with_tightvnc_filetransfer=yes ]) -# AC_DEFINE moved to after libpthread check. - -# WebSockets support -AC_CHECK_FUNC(__b64_ntop, HAVE_B64_IN_LIBC="true", HAVE_B64_IN_LIBC="false") -if test "x$HAVE_B64_IN_LIBC" != "xtrue"; then - AC_CHECK_LIB(resolv, __b64_ntop, HAVE_B64_IN_LIBRESOLV="true", HAVE_B64_IN_LIBRESOLV="false") - if test "x$HAVE_B64_IN_LIBRESOLV" = "xtrue"; then - RESOLV_LIB="-lresolv" - HAVE_B64="true" - fi -else - HAVE_B64="true" -fi -AH_TEMPLATE(WITH_WEBSOCKETS, [Disable WebSockets support]) -AC_ARG_WITH(websockets, - [ --without-websockets disable WebSockets support], - , [ with_websockets=yes ]) -# AC_DEFINE moved to after libresolve check. - -AH_TEMPLATE(ALLOW24BPP, [Enable 24 bit per pixel in native framebuffer]) -AC_ARG_WITH(24bpp, - [ --without-24bpp disable 24 bpp framebuffers], - , [ with_24bpp=yes ]) -if test "x$with_24bpp" = "xyes"; then - AC_DEFINE(ALLOW24BPP) -fi -AH_TEMPLATE(FFMPEG, [Use ffmpeg (for vnc2mpg)]) -AC_ARG_WITH(ffmpeg, - [ --with-ffmpeg=dir set ffmpeg home directory],,) -AC_SUBST(with_ffmpeg) -AM_CONDITIONAL(WITH_FFMPEG, test ! -z "$with_ffmpeg") -if test ! -z "$with_ffmpeg"; then - AC_CHECK_LIB(mp3lame, lame_init, HAVE_MP3LAME="true", HAVE_MP3LAME="false" ) -fi -AM_CONDITIONAL(HAVE_MP3LAME, test "$HAVE_MP3LAME" = "true") - -PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd], [with_systemd=1], [with_systemd=0]) -AM_CONDITIONAL([WITH_SYSTEMD], [test $with_systemd -eq 1]) - -# Seem to need this dummy here to induce the 'checking for egrep... grep -E', etc. -# before it seemed to be inside the with_jpeg conditional. -AC_CHECK_HEADER(thenonexistentheader.h, HAVE_THENONEXISTENTHEADER_H="true") - -# set some ld -R nonsense -# -uname_s=`(uname -s) 2>/dev/null` -ld_minus_R="yes" -if test "x$uname_s" = "xHP-UX"; then - ld_minus_R="no" -elif test "x$uname_s" = "xOSF1"; then - ld_minus_R="no" -elif test "x$uname_s" = "xDarwin"; then - ld_minus_R="no" -fi - -# Check for OpenSSL -AH_TEMPLATE(HAVE_LIBCRYPT, [libcrypt library present]) -AC_ARG_WITH(crypt, -[ --without-crypt disable support for libcrypt],,) -if test "x$with_crypt" != "xno"; then - AC_CHECK_FUNCS([crypt], HAVE_LIBC_CRYPT="true") - if test -z "$HAVE_LIBC_CRYPT"; then - AC_CHECK_LIB(crypt, crypt, - CRYPT_LIBS="-lcrypt" - [AC_DEFINE(HAVE_LIBCRYPT)], ,) - fi -fi -AC_SUBST(CRYPT_LIBS) - -# some OS's need both -lssl and -lcrypto on link line: -AH_TEMPLATE(HAVE_LIBCRYPTO, [openssl libcrypto library present]) -AC_ARG_WITH(crypto, -[ --without-crypto disable support for openssl libcrypto],,) - -AH_TEMPLATE(HAVE_LIBSSL, [openssl libssl library present]) -AC_ARG_WITH(ssl, -[ --without-ssl disable support for openssl libssl] -[ --with-ssl=DIR use openssl include/library files in DIR],,) - -if test "x$with_crypto" != "xno" -a "x$with_ssl" != "xno"; then - if test ! -z "$with_ssl" -a "x$with_ssl" != "xyes"; then - saved_CPPFLAGS="$CPPFLAGS" - saved_LDFLAGS="$LDFLAGS" - CPPFLAGS="$CPPFLAGS -I$with_ssl/include" - LDFLAGS="$LDFLAGS -L$with_ssl/lib" - if test "x$ld_minus_R" = "xno"; then - : - elif test "x$GCC" = "xyes"; then - LDFLAGS="$LDFLAGS -Xlinker -R$with_ssl/lib" - else - LDFLAGS="$LDFLAGS -R$with_ssl/lib" - fi - fi - AC_CHECK_LIB(crypto, RAND_file_name, - [AC_DEFINE(HAVE_LIBCRYPTO) HAVE_LIBCRYPTO="true"], ,) - if test ! -z "$with_ssl" -a "x$with_ssl" != "xyes"; then - if test "x$HAVE_LIBCRYPTO" != "xtrue"; then - CPPFLAGS="$saved_CPPFLAGS" - LDFLAGS="$saved_LDFLAGS" - fi - fi -fi - -AH_TEMPLATE(HAVE_X509_PRINT_EX_FP, [open ssl X509_print_ex_fp available]) -if test "x$with_ssl" != "xno"; then - if test "x$HAVE_LIBCRYPTO" = "xtrue"; then - AC_CHECK_LIB(ssl, SSL_library_init, - SSL_LIBS="-lssl -lcrypto" - [AC_DEFINE(HAVE_LIBSSL) HAVE_LIBSSL="true"], , - -lcrypto) - else - AC_CHECK_LIB(ssl, SSL_library_init, - SSL_LIBS="-lssl" - [AC_DEFINE(HAVE_LIBSSL) HAVE_LIBSSL="true"], ,) - fi -fi -AC_SUBST(SSL_LIBS) -AM_CONDITIONAL(HAVE_LIBSSL, test ! -z "$SSL_LIBS") - - - - -AC_ARG_WITH(jpeg, -[ --without-jpeg disable support for jpeg] -[ --with-jpeg=DIR use jpeg include/library files in DIR],,) - -# At this point: -# no jpeg on command line with_jpeg="" -# -with-jpeg with_jpeg="yes" -# -without-jpeg with_jpeg="no" -# -with-jpeg=/foo/dir with_jpeg="/foo/dir" - -HAVE_LIBJPEG_TURBO="false" - -if test "x$with_jpeg" != "xno"; then - AC_ARG_VAR(JPEG_LDFLAGS, - [Linker flags to use when linking with libjpeg, e.g. -L/foo/dir/lib -Wl,-static -ljpeg -Wl,-shared. This overrides the linker flags set by --with-jpeg.]) - saved_CPPFLAGS="$CPPFLAGS" - saved_LDFLAGS="$LDFLAGS" - saved_LIBS="$LIBS" - if test ! -z "$with_jpeg" -a "x$with_jpeg" != "xyes"; then - # add user supplied directory to flags: - CPPFLAGS="$CPPFLAGS -I$with_jpeg/include" - LDFLAGS="$LDFLAGS -L$with_jpeg/lib" - if test "x$ld_minus_R" = "xno"; then - : - elif test "x$GCC" = "xyes"; then - # this is not complete... in general a rat's nest. - LDFLAGS="$LDFLAGS -Xlinker -R$with_jpeg/lib" - else - LDFLAGS="$LDFLAGS -R$with_jpeg/lib" - fi - fi - if test "x$JPEG_LDFLAGS" != "x"; then - LDFLAGS="$saved_LDFLAGS" - LIBS="$LIBS $JPEG_LDFLAGS" - else - LIBS="-ljpeg" - fi - AC_CHECK_HEADER(jpeglib.h, HAVE_JPEGLIB_H="true") - AC_MSG_CHECKING(for jpeg_CreateCompress in libjpeg) - if test "x$HAVE_JPEGLIB_H" = "xtrue"; then - AC_LINK_IFELSE([AC_LANG_CALL([], [jpeg_CreateCompress])], - [AC_MSG_RESULT(yes); - AC_DEFINE(HAVE_LIBJPEG, 1, libjpeg support enabled)], - [AC_MSG_RESULT(no); HAVE_JPEGLIB_H=""]) - fi - if test "x$HAVE_JPEGLIB_H" != "xtrue"; then - # restore old flags on failure: - CPPFLAGS="$saved_CPPFLAGS" - LDFLAGS="$saved_LDFLAGS" - LIBS="$saved_LIBS" - AC_MSG_WARN([ -========================================================================== -*** The libjpeg compression library was not found. *** -This may lead to reduced performance, especially over slow links. -If libjpeg is in a non-standard location use --with-jpeg=DIR to -indicate the header file is in DIR/include/jpeglib.h and the library -in DIR/lib/libjpeg.a. You can also set the JPEG_LDFLAGS variable to -specify more detailed linker flags. A copy of libjpeg-turbo may be -obtained from: https://sourceforge.net/projects/libjpeg-turbo/files/ -A copy of libjpeg may be obtained from: http://ijg.org/files/ -========================================================================== -]) - sleep 5 - fi - - if test "x$HAVE_JPEGLIB_H" = "xtrue"; then - AC_MSG_CHECKING(whether JPEG library is libjpeg-turbo) - m4_define([LJT_TEST], - [AC_LANG_PROGRAM([#include - #include ], - [struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - cinfo.err=jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - cinfo.input_components = 3; - jpeg_set_defaults(&cinfo); - cinfo.in_color_space = JCS_EXT_RGB; - jpeg_default_colorspace(&cinfo); - return 0;])] - ) - if test "x$cross_compiling" != "xyes"; then - AC_RUN_IFELSE([LJT_TEST], - [HAVE_LIBJPEG_TURBO="true"; AC_MSG_RESULT(yes)], - [AC_MSG_RESULT(no)]) - else - AC_LINK_IFELSE([LJT_TEST], - [HAVE_LIBJPEG_TURBO="true"; AC_MSG_RESULT(yes)], - [AC_MSG_RESULT(no)]) - fi - fi - - if test "x$HAVE_JPEGLIB_H" = "xtrue" -a "x$HAVE_LIBJPEG_TURBO" != "xtrue"; then - AC_MSG_WARN([ -========================================================================== -*** The libjpeg library you are building against is not libjpeg-turbo. -Performance will be reduced. You can obtain libjpeg-turbo from: -https://sourceforge.net/projects/libjpeg-turbo/files/ *** -========================================================================== -]) - fi - -fi - -AC_ARG_WITH(png, -[ --without-png disable support for png] -[ --with-png=DIR use png include/library files in DIR],,) - -# At this point: -# no png on command line with_png="" -# -with-png with_png="yes" -# -without-png with_png="no" -# -with-png=/foo/dir with_png="/foo/dir" - -if test "x$with_png" != "xno"; then - if test ! -z "$with_png" -a "x$with_png" != "xyes"; then - # add user supplied directory to flags: - saved_CPPFLAGS="$CPPFLAGS" - saved_LDFLAGS="$LDFLAGS" - CPPFLAGS="$CPPFLAGS -I$with_png/include" - LDFLAGS="$LDFLAGS -L$with_png/lib" - if test "x$ld_minus_R" = "xno"; then - : - elif test "x$GCC" = "xyes"; then - # this is not complete... in general a rat's nest. - LDFLAGS="$LDFLAGS -Xlinker -R$with_png/lib" - else - LDFLAGS="$LDFLAGS -R$with_png/lib" - fi - fi - AC_CHECK_HEADER(png.h, HAVE_PNGLIB_H="true") - if test "x$HAVE_PNGLIB_H" = "xtrue"; then - AC_CHECK_LIB(png, png_create_write_struct, , HAVE_PNGLIB_H="") - fi - if test ! -z "$with_png" -a "x$with_png" != "xyes"; then - if test "x$HAVE_PNGLIB_H" != "xtrue"; then - # restore old flags on failure: - CPPFLAGS="$saved_CPPFLAGS" - LDFLAGS="$saved_LDFLAGS" - fi - fi - if test "x$HAVE_PNGLIB_H" != "xtrue"; then - AC_MSG_WARN([ -========================================================================== -*** The libpng compression library was not found. *** -This may lead to reduced performance, especially over slow links. -If libpng is in a non-standard location use --with-png=DIR to -indicate the header file is in DIR/include/png.h and the library -in DIR/lib/libpng.a. A copy of libpng may be obtained from: -http://www.libpng.org/pub/png/libpng.html -========================================================================== -]) - sleep 5 - fi -fi - -AC_ARG_WITH(libz, -[ --without-libz disable support for deflate],,) -AC_ARG_WITH(zlib, -[ --without-zlib disable support for deflate] -[ --with-zlib=DIR use zlib include/library files in DIR],,) - -if test "x$with_zlib" != "xno" -a "x$with_libz" != "xno"; then - if test ! -z "$with_zlib" -a "x$with_zlib" != "xyes"; then - saved_CPPFLAGS="$CPPFLAGS" - saved_LDFLAGS="$LDFLAGS" - CPPFLAGS="$CPPFLAGS -I$with_zlib/include" - LDFLAGS="$LDFLAGS -L$with_zlib/lib" - if test "x$ld_minus_R" = "xno"; then - : - elif test "x$GCC" = "xyes"; then - LDFLAGS="$LDFLAGS -Xlinker -R$with_zlib/lib" - else - LDFLAGS="$LDFLAGS -R$with_zlib/lib" - fi - fi - AC_CHECK_HEADER(zlib.h, HAVE_ZLIB_H="true") - if test "x$HAVE_ZLIB_H" = "xtrue"; then - AC_CHECK_LIB(z, deflate, , HAVE_ZLIB_H="") - fi - if test ! -z "$with_zlib" -a "x$with_zlib" != "xyes"; then - if test "x$HAVE_ZLIB_H" != "xtrue"; then - CPPFLAGS="$saved_CPPFLAGS" - LDFLAGS="$saved_LDFLAGS" - fi - fi - if test "x$HAVE_ZLIB_H" != "xtrue"; then - AC_MSG_WARN([ -========================================================================== -*** The libz compression library was not found. *** -This may lead to reduced performance, especially over slow links. -If libz is in a non-standard location use --with-zlib=DIR to indicate the -header file is in DIR/include/zlib.h and the library in DIR/lib/libz.a. -A copy of libz may be obtained from: http://www.gzip.org/zlib/ -========================================================================== -]) - sleep 5 - fi -fi - -AC_ARG_WITH(pthread, -[ --without-pthread disable support for libpthread],,) - -if test "x$with_pthread" != "xno"; then - AC_CHECK_HEADER(pthread.h, HAVE_PTHREAD_H="true") - if test ! -z "$HAVE_PTHREAD_H"; then - AC_CHECK_LIB(pthread, pthread_mutex_lock) - AC_CHECK_LIB(pthread, pthread_mutex_lock, HAVE_LIBPTHREAD="true") - fi -fi -AM_CONDITIONAL(HAVE_LIBPTHREAD, test ! -z "$HAVE_LIBPTHREAD") - -AC_MSG_CHECKING([for __thread]) -AC_LINK_IFELSE([AC_LANG_PROGRAM(, [static __thread int p = 0])], - [AC_DEFINE(HAVE_TLS, 1, - Define to 1 if compiler supports __thread) - AC_MSG_RESULT([yes])], - [AC_MSG_RESULT([no])]) - -# tightvnc-filetransfer implemented using threads: -if test -z "$HAVE_LIBPTHREAD"; then - with_tightvnc_filetransfer="" -fi -if test "x$with_tightvnc_filetransfer" = "xyes"; then - AC_DEFINE(WITH_TIGHTVNC_FILETRANSFER) -fi -AM_CONDITIONAL(WITH_TIGHTVNC_FILETRANSFER, test "$with_tightvnc_filetransfer" = "yes") - -# websockets implemented using base64 from resolve -if test "x$HAVE_B64" != "xtrue"; then - with_websockets="" -fi -if test "x$with_websockets" = "xyes"; then - LIBS="$LIBS $RESOLV_LIB $SSL_LIBS" - AC_DEFINE(WITH_WEBSOCKETS) -fi -AM_CONDITIONAL(WITH_WEBSOCKETS, test "$with_websockets" = "yes") - -AM_CONDITIONAL(HAVE_LIBZ, test ! -z "$HAVE_ZLIB_H") -AM_CONDITIONAL(HAVE_LIBJPEG, test ! -z "$HAVE_JPEGLIB_H") -AM_CONDITIONAL(HAVE_LIBPNG, test ! -z "$HAVE_PNGLIB_H") - - -SDLCONFIG="sdl-config" -AC_ARG_WITH(sdl-config, -[[ --with-sdl-config=FILE - Use the given path to sdl-config when determining - SDL configuration; defaults to "sdl-config"]], -[ - if test "$withval" != "yes" -a "$withval" != ""; then - SDLCONFIG=$withval - fi -]) - -if test -z "$with_sdl"; then - if $SDLCONFIG --version >/dev/null 2>&1; then - with_sdl=yes - SDL_CFLAGS=`$SDLCONFIG --cflags` - SDL_LIBS=`$SDLCONFIG --libs` - else - with_sdl=no - fi -fi -AM_CONDITIONAL(HAVE_LIBSDL, test "x$with_sdl" = "xyes") -AC_SUBST(SDL_CFLAGS) -AC_SUBST(SDL_LIBS) - - -# Check for GTK+. if present, build the GTK+ vnc viewer example -PKG_CHECK_MODULES([GTK], [gtk+-2.0],,:) -AM_CONDITIONAL(HAVE_LIBGTK, test ! -z "$GTK_LIBS") - -AC_CANONICAL_HOST -MINGW=`echo $host_os | grep mingw32 2>/dev/null` -AM_CONDITIONAL(MINGW, test ! -z "$MINGW" ) -if test ! -z "$MINGW"; then - WSOCKLIB="-lws2_32" -fi -AC_SUBST(WSOCKLIB) - -# Check for libgcrypt -AH_TEMPLATE(WITH_CLIENT_GCRYPT, [Enable support for libgcrypt in libvncclient]) -AC_ARG_WITH(gcrypt, -[ --without-gcrypt disable support for gcrypt],,) -AC_ARG_WITH(client-gcrypt, -[ --without-client-gcrypt disable support for gcrypt in libvncclient],,) - -if test "x$with_gcrypt" != "xno"; then - AM_PATH_LIBGCRYPT(1.4.0, , with_client_gcrypt=no) - CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS" - LIBS="$LIBS $LIBGCRYPT_LIBS" - if test "x$with_client_gcrypt" != "xno"; then - AC_DEFINE(WITH_CLIENT_GCRYPT) - fi -fi - -# Checks for GnuTLS -AH_TEMPLATE(HAVE_GNUTLS, [GnuTLS library present]) -AC_ARG_WITH(gnutls, -[ --without-gnutls disable support for gnutls] -[ --with-gnutls=DIR use gnutls include/library files in DIR],,) - -if test "x$with_gnutls" != "xno"; then - PKG_CHECK_MODULES(GNUTLS, gnutls >= 2.4.0,,:) - CFLAGS="$CFLAGS $GNUTLS_CFLAGS" - LIBS="$LIBS $GNUTLS_LIBS" -fi -AM_CONDITIONAL(HAVE_GNUTLS, test ! -z "$GNUTLS_LIBS") -if test ! -z "$GNUTLS_LIBS" ; then - AC_DEFINE(HAVE_GNUTLS) -fi - - -# warn if neither GnuTLS nor OpenSSL are available -if test -z "$SSL_LIBS" -a -z "$GNUTLS_LIBS"; then - AC_MSG_WARN([ -========================================================================== -*** No encryption library could be found. *** -A libvncserver/libvncclient built this way will not support SSL encryption. -To enable SSL install the necessary development packages (perhaps it is named -something like libssl-dev or gnutls-dev) and run configure again. -========================================================================== -]) - sleep 5 -fi - - -# IPv6 -AH_TEMPLATE(IPv6, [Enable IPv6 support]) -AC_ARG_WITH(ipv6, -[ --without-ipv6 disable IPv6 support],,) -if test "x$with_ipv6" != "xno"; then - AC_CHECK_FUNC(getaddrinfo, AC_DEFINE(IPv6,1), - AC_CHECK_LIB(socket, getaddrinfo, AC_DEFINE(IPv6,1), [ - AC_MSG_CHECKING([for getaddrinfo in -lws2_32]) - LIBS="$LIBS -lws2_32" - AC_TRY_LINK([#include ], [getaddrinfo(0, 0, 0, 0);], [ - AC_DEFINE(IPv6,1) - AC_MSG_RESULT([yes]) - ], - AC_MSG_RESULT([no])) - ])) -fi - - - -# Checks for header files. -AC_HEADER_STDC -AC_CHECK_HEADERS([arpa/inet.h endian.h fcntl.h netdb.h netinet/in.h stdlib.h stdint.h string.h sys/endian.h sys/socket.h sys/time.h sys/timeb.h syslog.h unistd.h ws2tcpip.h]) - -# Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_C_INLINE -AC_TYPE_SIZE_T -AC_HEADER_TIME -AC_HEADER_SYS_WAIT -AX_TYPE_SOCKLEN_T -AC_CACHE_CHECK([for in_addr_t], - vnc_cv_inaddrt, [ - AC_TRY_COMPILE([#include -#include ], - [in_addr_t foo; return 0;], - [inaddrt=yes], - [inaddrt=no]), - ]) -AH_TEMPLATE(NEED_INADDR_T, [Need a typedef for in_addr_t]) -if test $inaddrt = no ; then - AC_DEFINE(NEED_INADDR_T) -fi -# Checks for library functions. -AC_FUNC_MEMCMP -AC_FUNC_STAT -AC_FUNC_STRFTIME -AC_FUNC_VPRINTF -AC_FUNC_FORK -AC_CHECK_LIB(nsl,gethostbyname) -AC_CHECK_LIB(socket,socket) - -uname_s=`(uname -s) 2>/dev/null` -if test "x$uname_s" = "xHP-UX"; then - # need -lsec for getspnam() - LDFLAGS="$LDFLAGS -lsec" -fi - -AC_CHECK_FUNCS([ftime gethostbyname gethostname gettimeofday inet_ntoa memmove memset mmap mkfifo select socket strchr strcspn strdup strerror strstr]) - -# check, if shmget is in cygipc.a -AC_CHECK_LIB(cygipc,shmget) -AM_CONDITIONAL(CYGIPC, test "$HAVE_CYGIPC" = "true") - -# Check if /usr/include/linux exists, if so, define LINUX -AM_CONDITIONAL(LINUX, test -d /usr/include/linux) - -# Check for OS X specific header -AC_CHECK_HEADER(ApplicationServices/ApplicationServices.h, HAVE_OSX="true") -AM_CONDITIONAL(OSX, test "$HAVE_OSX" = "true") - -# Check for Android specific header -AC_CHECK_HEADER(android/api-level.h, HAVE_ANDROID="true") -AM_CONDITIONAL(ANDROID, test "$HAVE_ANDROID" = "true") -if test "$HAVE_ANDROID" = "true"; then - AC_DEFINE(HAVE_ANDROID, 1, [Android host system detected]) -fi - -# On Solaris 2.7, write() returns ENOENT when it really means EAGAIN -AH_TEMPLATE(ENOENT_WORKAROUND, [work around when write() returns ENOENT but does not mean it]) -case `(uname -sr) 2>/dev/null` in - "SunOS 5.7") - AC_DEFINE(ENOENT_WORKAROUND) - ;; -esac - -# Check for rpm SOURCES path -printf "checking for rpm sources path... " -RPMSOURCEDIR="NOT-FOUND" -for directory in packages OpenLinux redhat RedHat rpm RPM "" ; do - if test -d /usr/src/${directory}/SOURCES; then - RPMSOURCEDIR="/usr/src/${directory}/SOURCES/" - fi -done -echo "$RPMSOURCEDIR" -AM_CONDITIONAL(HAVE_RPM, test "$RPMSOURCEDIR" != "NOT-FOUND") -AC_SUBST(RPMSOURCEDIR) - -AC_CONFIG_FILES([Makefile - libvncserver.pc - libvncclient.pc - libvncserver/Makefile - examples/Makefile - examples/android/Makefile - webclients/Makefile - webclients/java-applet/Makefile - webclients/java-applet/ssl/Makefile - libvncclient/Makefile - client_examples/Makefile - test/Makefile - libvncserver-config - LibVNCServer.spec]) - - -AC_CONFIG_COMMANDS([chmod-libvncserver-config],[chmod a+x libvncserver-config]) -AC_OUTPUT -chmod a+x ./libvncserver-config - diff --git a/examples/Makefile.am b/examples/Makefile.am deleted file mode 100644 index 829f735..0000000 --- a/examples/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir) -LDADD = ../libvncserver/libvncserver.la @WSOCKLIB@ - -if OSX -MAC=mac -mac_LDFLAGS=-framework ApplicationServices -framework Carbon -framework IOKit -endif - -if ANDROID -SUBDIRS=android -endif - -if WITH_TIGHTVNC_FILETRANSFER -FILETRANSFER=filetransfer -endif - -if HAVE_LIBPTHREAD -BLOOPTEST=blooptest -endif - -noinst_HEADERS=radon.h rotatetemplate.c - -noinst_PROGRAMS=example pnmshow regiontest pnmshow24 fontsel \ - vncev storepasswd colourmaptest simple simple15 $(MAC) \ - $(FILETRANSFER) backchannel $(BLOOPTEST) camera rotate \ - zippy repeater - diff --git a/examples/android/Makefile.am b/examples/android/Makefile.am deleted file mode 100644 index 9cb5c02..0000000 --- a/examples/android/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir) -LDADD = $(top_srcdir)/libvncserver/libvncserver.la @WSOCKLIB@ - -noinst_PROGRAMS=androidvncserver -androidvncserver_SOURCES=jni/fbvncserver.c - -EXTRA_DIST=jni/Android.mk diff --git a/libvncclient.pc.in b/libvncclient.pc.in deleted file mode 100644 index 37495e7..0000000 --- a/libvncclient.pc.in +++ /dev/null @@ -1,14 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: LibVNCClient -Description: A library for easy implementation of a VNC client. -Version: @VERSION@ -Requires: -Requires.private: zlib -Libs: -L${libdir} -lvncclient -Libs.private: @LIBS@ @WSOCKLIB@ -Cflags: -I${includedir} - diff --git a/libvncclient/Makefile.am b/libvncclient/Makefile.am deleted file mode 100644 index bc2420b..0000000 --- a/libvncclient/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/common - -if HAVE_GNUTLS -TLSSRCS = tls_gnutls.c -TLSLIBS = @GNUTLS_LIBS@ -else -if HAVE_LIBSSL -TLSSRCS = tls_openssl.c -TLSLIBS = @SSL_LIBS@ @CRYPT_LIBS@ -else -TLSSRCS = tls_none.c -endif -endif - - -libvncclient_la_SOURCES=cursor.c listen.c rfbproto.c sockets.c vncviewer.c ../common/minilzo.c $(TLSSRCS) -libvncclient_la_LIBADD=$(TLSLIBS) - -noinst_HEADERS=../common/lzodefs.h ../common/lzoconf.h ../common/minilzo.h tls.h - -rfbproto.o: rfbproto.c corre.c hextile.c rre.c tight.c zlib.c zrle.c ultra.c - -EXTRA_DIST=corre.c hextile.c rre.c tight.c zlib.c zrle.c ultra.c tls_gnutls.c tls_openssl.c tls_none.c - -$(libvncclient_la_OBJECTS): ../rfb/rfbclient.h - -lib_LTLIBRARIES=libvncclient.la -libvncclient_la_LDFLAGS = -version-info 1:0:0 - diff --git a/libvncserver-config.in b/libvncserver-config.in deleted file mode 100644 index ea0bef8..0000000 --- a/libvncserver-config.in +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/sh - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -exec_prefix_set=no -includedir=@includedir@ -libdir=@libdir@ - -# if this script is in the same directory as libvncserver-config.in, assume not installed -if [ -f "`dirname "$0"`/libvncserver-config.in" ]; then - dir="`dirname "$0"`" - prefix="`cd "$dir"; pwd`" - includedir="$prefix" - libdir="$prefix/libvncserver/.libs $prefix/libvncclient/.libs" -fi - -usage="\ -Usage: @PACKAGE@-config [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] [--link] [--libs] [--cflags]" - -if test $# -eq 0; then - echo "${usage}" 1>&2 - exit 1 -fi - -while test $# -gt 0; do - case "$1" in - -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; - *) optarg= ;; - esac - - case $1 in - --prefix=*) - prefix=$optarg - if test $exec_prefix_set = no ; then - exec_prefix=$optarg - fi - ;; - --prefix) - echo $prefix - ;; - --exec-prefix=*) - exec_prefix=$optarg - exec_prefix_set=yes - ;; - --exec-prefix) - echo $exec_prefix - ;; - --version) - echo @VERSION@ - ;; - --cflags) - if [ "$includedir" != /usr/include ]; then - includes=-I"$includedir" - fi - echo "$includes" - ;; - --libs) - libs="" - for dir in $libdir; do - libs="$libs -L$dir" - if [ "`uname`" = "SunOS" ]; then - # why only Solaris?? - libs="$libs -R$dir" - fi - done - echo "$libs" -lvncserver -lvncclient @LIBS@ @WSOCKLIB@ - ;; - --link) - echo @CC@ - ;; - *) - echo "${usage}" 1>&2 - exit 1 - ;; - esac - shift -done - diff --git a/libvncserver.pc.in b/libvncserver.pc.in deleted file mode 100644 index d246052..0000000 --- a/libvncserver.pc.in +++ /dev/null @@ -1,14 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: LibVNCServer -Description: A library for easy implementation of a VNC server. -Version: @VERSION@ -Requires: -Requires.private: zlib -Libs: -L${libdir} -lvncserver -Libs.private: @LIBS@ @WSOCKLIB@ -Cflags: -I${includedir} - diff --git a/libvncserver/Makefile.am b/libvncserver/Makefile.am deleted file mode 100644 index e25784b..0000000 --- a/libvncserver/Makefile.am +++ /dev/null @@ -1,80 +0,0 @@ -AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/common - -if WITH_TIGHTVNC_FILETRANSFER -TIGHTVNCFILETRANSFERHDRS=tightvnc-filetransfer/filelistinfo.h \ - tightvnc-filetransfer/filetransfermsg.h \ - tightvnc-filetransfer/handlefiletransferrequest.h \ - tightvnc-filetransfer/rfbtightproto.h - -TIGHTVNCFILETRANSFERSRCS = tightvnc-filetransfer/rfbtightserver.c \ - tightvnc-filetransfer/handlefiletransferrequest.c \ - tightvnc-filetransfer/filetransfermsg.c \ - tightvnc-filetransfer/filelistinfo.c -endif - -if WITH_WEBSOCKETS - -if HAVE_GNUTLS -WEBSOCKETSSSLSRCS = rfbssl_gnutls.c rfbcrypto_gnutls.c -WEBSOCKETSSSLLIBS = @GNUTLS_LIBS@ -else -if HAVE_LIBSSL -WEBSOCKETSSSLSRCS = rfbssl_openssl.c rfbcrypto_openssl.c -WEBSOCKETSSSLLIBS = @SSL_LIBS@ @CRYPT_LIBS@ -else -WEBSOCKETSSSLSRCS = rfbssl_none.c rfbcrypto_included.c ../common/md5.c ../common/sha1.c -endif -endif - -WEBSOCKETSSRCS = websockets.c $(WEBSOCKETSSSLSRCS) -endif - -includedir=$(prefix)/include/rfb - -include_HEADERS=../rfb/rfb.h ../rfb/rfbconfig.h \ - ../rfb/rfbproto.h ../rfb/keysym.h ../rfb/rfbregion.h ../rfb/rfbclient.h - -noinst_HEADERS=../common/d3des.h ../rfb/default8x16.h zrleoutstream.h \ - zrlepalettehelper.h zrletypes.h private.h scale.h rfbssl.h rfbcrypto.h \ - ../common/minilzo.h ../common/lzoconf.h ../common/lzodefs.h ../common/md5.h ../common/sha.h ../common/sha-private.h \ - $(TIGHTVNCFILETRANSFERHDRS) - -EXTRA_DIST=tableinit24.c tableinittctemplate.c tabletranstemplate.c \ - tableinitcmtemplate.c tabletrans24template.c \ - zrleencodetemplate.c - -if HAVE_LIBZ -ZLIBSRCS = zlib.c zrle.c zrleoutstream.c zrlepalettehelper.c ../common/zywrletemplate.c -if HAVE_LIBJPEG -TIGHTSRCS = tight.c ../common/turbojpeg.c -endif -endif - -LIB_SRCS = main.c rfbserver.c rfbregion.c auth.c sockets.c $(WEBSOCKETSSRCS) \ - stats.c corre.c hextile.c rre.c translate.c cutpaste.c \ - httpd.c cursor.c font.c \ - draw.c selbox.c ../common/d3des.c ../common/vncauth.c cargs.c ../common/minilzo.c ultra.c scale.c \ - $(ZLIBSRCS) $(TIGHTSRCS) $(TIGHTVNCFILETRANSFERSRCS) - -libvncserver_la_SOURCES=$(LIB_SRCS) -libvncserver_la_LIBADD=$(WEBSOCKETSSSLLIBS) - -if WITH_SYSTEMD -AM_CPPFLAGS += -DLIBVNCSERVER_WITH_SYSTEMD -libvncserver_la_CFLAGS = $(LIBSYSTEMD_CFLAGS) -libvncserver_la_LIBADD += $(LIBSYSTEMD_LIBS) -endif - -lib_LTLIBRARIES=libvncserver.la -libvncserver_la_LDFLAGS = -version-info 1:0:0 - -if HAVE_RPM -$(PACKAGE)-$(VERSION).tar.gz: dist - -# Rule to build RPM distribution package -rpm: $(PACKAGE)-$(VERSION).tar.gz libvncserver.spec - cp $(PACKAGE)-$(VERSION).tar.gz @RPMSOURCEDIR@ - rpmbuild -ba libvncserver.spec -endif - - diff --git a/m4/.gitignore b/m4/.gitignore deleted file mode 100644 index 7c9f9ac..0000000 --- a/m4/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.m4 \ No newline at end of file diff --git a/m4/ax_prefix_config_h.m4 b/m4/ax_prefix_config_h.m4 deleted file mode 100644 index c17563f..0000000 --- a/m4/ax_prefix_config_h.m4 +++ /dev/null @@ -1,203 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prefix_config_h.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PREFIX_CONFIG_H [(OUTPUT-HEADER [,PREFIX [,ORIG-HEADER]])] -# -# DESCRIPTION -# -# Generate an installable config.h. -# -# A package should not normally install its config.h as a system header, -# but if it must, this macro can be used to avoid namespace pollution by -# making a copy of config.h with a prefix added to all the macro names. -# -# Each "#define SOMEDEF" line of the configuration header has the given -# prefix added, in the same case as the first character of the macro name. -# -# Defaults: -# -# OUTPUT-HEADER = $PACKAGE-config.h -# PREFIX = $PACKAGE -# ORIG-HEADER, from AM_CONFIG_HEADER(config.h) -# -# Your configure.ac script should contain both macros in this order. -# -# Example: -# -# AC_INIT(config.h.in) # config.h.in as created by "autoheader" -# AM_INIT_AUTOMAKE(testpkg, 0.1.1) # makes #undef VERSION and PACKAGE -# AM_CONFIG_HEADER(config.h) # prep config.h from config.h.in -# AX_PREFIX_CONFIG_H(mylib/_config.h) # prep mylib/_config.h from it.. -# AC_MEMORY_H # makes "#undef NEED_MEMORY_H" -# AC_C_CONST_H # makes "#undef const" -# AC_OUTPUT(Makefile) # creates the "config.h" now -# # and also mylib/_config.h -# -# If the argument to AX_PREFIX_CONFIG_H would have been omitted then the -# default output file would have been called simply "testpkg-config.h", -# but even under the name "mylib/_config.h" it contains prefix-defines -# like -# -# #ifndef TESTPKG_VERSION -# #define TESTPKG_VERSION "0.1.1" -# #endif -# #ifndef TESTPKG_NEED_MEMORY_H -# #define TESTPKG_NEED_MEMORY_H 1 -# #endif -# #ifndef _testpkg_const -# #define _testpkg_const _const -# #endif -# -# and this "mylib/_config.h" can be installed along with other header -# files, which is most convenient when creating a shared library (that has -# some headers) whose functionality depends on features detected at -# compile-time. No need to invent some "mylib-confdefs.h.in" manually. -# -# Note that some AC_DEFINEs that end up in the config.h file are actually -# self-referential - e.g. AC_C_INLINE, AC_C_CONST, and the AC_TYPE_OFF_T -# say that they "will define inline|const|off_t if the system does not do -# it by itself". You might want to clean up about these - consider an -# extra mylib/conf.h that reads something like: -# -# #include -# #ifndef _testpkg_const -# #define _testpkg_const const -# #endif -# -# and then start using _testpkg_const in the header files. That is also a -# good thing to differentiate whether some library-user has starting to -# take up with a different compiler, so perhaps it could read something -# like this: -# -# #ifdef _MSC_VER -# #include -# #else -# #include -# #endif -# #ifndef _testpkg_const -# #define _testpkg_const const -# #endif -# -# LICENSE -# -# Copyright (c) 2014 Reuben Thomas -# Copyright (c) 2008 Guido U. Draheim -# Copyright (c) 2008 Marten Svantesson -# Copyright (c) 2008 Gerald Point -# -# This program 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 3 of the License, or (at your -# option) any later version. -# -# This program 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 program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 15 - -AC_DEFUN([AX_PREFIX_CONFIG_H],[dnl -AC_PREREQ([2.62]) -AC_BEFORE([AC_CONFIG_HEADERS],[$0])dnl -AC_CONFIG_COMMANDS(m4_default([$1], [$PACKAGE-config.h]),[dnl -AS_VAR_PUSHDEF([_OUT],[ac_prefix_conf_OUT])dnl -AS_VAR_PUSHDEF([_DEF],[ac_prefix_conf_DEF])dnl -AS_VAR_PUSHDEF([_PKG],[ac_prefix_conf_PKG])dnl -AS_VAR_PUSHDEF([_LOW],[ac_prefix_conf_LOW])dnl -AS_VAR_PUSHDEF([_UPP],[ac_prefix_conf_UPP])dnl -AS_VAR_PUSHDEF([_INP],[ac_prefix_conf_INP])dnl -m4_pushdef([_script],[conftest.prefix])dnl -m4_pushdef([_symbol],[m4_cr_Letters[]m4_cr_digits[]_])dnl -_OUT=`echo m4_default([$1], [$PACKAGE-config.h])` -_DEF=`echo _$_OUT | sed -e "y:m4_cr_letters:m4_cr_LETTERS[]:" -e "s/@<:@^m4_cr_Letters@:>@/_/g"` -_PKG=`echo m4_default([$2], [$PACKAGE])` -_LOW=`echo _$_PKG | sed -e "y:m4_cr_LETTERS-:m4_cr_letters[]_:"` -_UPP=`echo $_PKG | sed -e "y:m4_cr_letters-:m4_cr_LETTERS[]_:" -e "/^@<:@m4_cr_digits@:>@/s/^/_/"` -_INP=`echo "$3" | sed -e 's/ *//'` -if test ".$_INP" = "."; then - for ac_file in : $CONFIG_HEADERS; do test "_$ac_file" = _: && continue - case "$ac_file" in - *.h) _INP=$ac_file ;; - *) - esac - test ".$_INP" != "." && break - done -fi -if test ".$_INP" = "."; then - case "$_OUT" in - */*) _INP=`basename "$_OUT"` - ;; - *-*) _INP=`echo "$_OUT" | sed -e "s/@<:@_symbol@:>@*-//"` - ;; - *) _INP=config.h - ;; - esac -fi -if test -z "$_PKG" ; then - AC_MSG_ERROR([no prefix for _PREFIX_PKG_CONFIG_H]) -else - if test ! -f "$_INP" ; then if test -f "$srcdir/$_INP" ; then - _INP="$srcdir/$_INP" - fi fi - AC_MSG_NOTICE(creating $_OUT - prefix $_UPP for $_INP defines) - if test -f $_INP ; then - AS_ECHO(["s/^@%:@undef *\\(@<:@m4_cr_LETTERS[]_@:>@\\)/@%:@undef $_UPP""_\\1/"]) > _script - AS_ECHO(["s/^@%:@undef *\\(@<:@m4_cr_letters@:>@\\)/@%:@undef $_LOW""_\\1/"]) >> _script - AS_ECHO(["s/^@%:@def[]ine *\\(@<:@m4_cr_LETTERS[]_@:>@@<:@_symbol@:>@*\\)\\(.*\\)/@%:@ifndef $_UPP""_\\1\\"]) >> _script - AS_ECHO(["@%:@def[]ine $_UPP""_\\1\\2\\"]) >> _script - AS_ECHO(["@%:@endif/"]) >> _script - AS_ECHO(["s/^@%:@def[]ine *\\(@<:@m4_cr_letters@:>@@<:@_symbol@:>@*\\)\\(.*\\)/@%:@ifndef $_LOW""_\\1\\"]) >> _script - AS_ECHO(["@%:@define $_LOW""_\\1\\2\\"]) >> _script - AS_ECHO(["@%:@endif/"]) >> _script - # now executing _script on _DEF input to create _OUT output file - echo "@%:@ifndef $_DEF" >$tmp/pconfig.h - echo "@%:@def[]ine $_DEF 1" >>$tmp/pconfig.h - echo ' ' >>$tmp/pconfig.h - echo /'*' $_OUT. Generated automatically at end of configure. '*'/ >>$tmp/pconfig.h - - sed -f _script $_INP >>$tmp/pconfig.h - echo ' ' >>$tmp/pconfig.h - echo '/* once:' $_DEF '*/' >>$tmp/pconfig.h - echo "@%:@endif" >>$tmp/pconfig.h - if cmp -s $_OUT $tmp/pconfig.h 2>/dev/null; then - AC_MSG_NOTICE([$_OUT is unchanged]) - else - ac_dir=`AS_DIRNAME(["$_OUT"])` - AS_MKDIR_P(["$ac_dir"]) - rm -f "$_OUT" - mv $tmp/pconfig.h "$_OUT" - fi - else - AC_MSG_ERROR([input file $_INP does not exist - skip generating $_OUT]) - fi - rm -f conftest.* -fi -m4_popdef([_symbol])dnl -m4_popdef([_script])dnl -AS_VAR_POPDEF([_INP])dnl -AS_VAR_POPDEF([_UPP])dnl -AS_VAR_POPDEF([_LOW])dnl -AS_VAR_POPDEF([_PKG])dnl -AS_VAR_POPDEF([_DEF])dnl -AS_VAR_POPDEF([_OUT])dnl -],[PACKAGE="$PACKAGE"])]) diff --git a/m4/ax_type_socklen_t.m4 b/m4/ax_type_socklen_t.m4 deleted file mode 100644 index 834c4cf..0000000 --- a/m4/ax_type_socklen_t.m4 +++ /dev/null @@ -1,61 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_type_socklen_t.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_TYPE_SOCKLEN_T -# -# DESCRIPTION -# -# Check whether sys/socket.h defines type socklen_t. Please note that some -# systems require sys/types.h to be included before sys/socket.h can be -# compiled. -# -# LICENSE -# -# Copyright (c) 2008 Lars Brinkhoff -# -# This program 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 program 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 program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 5 - -AU_ALIAS([TYPE_SOCKLEN_T], [AX_TYPE_SOCKLEN_T]) -AC_DEFUN([AX_TYPE_SOCKLEN_T], -[AC_CACHE_CHECK([for socklen_t], ac_cv_ax_type_socklen_t, -[ - AC_TRY_COMPILE( - [#include - #include ], - [socklen_t len = 42; return 0;], - ac_cv_ax_type_socklen_t=yes, - ac_cv_ax_type_socklen_t=no) -]) - if test $ac_cv_ax_type_socklen_t != yes; then - AC_DEFINE(socklen_t, int, [Substitute for socklen_t]) - fi -]) diff --git a/m4/libgcrypt.m4 b/m4/libgcrypt.m4 deleted file mode 100644 index 831dc0c..0000000 --- a/m4/libgcrypt.m4 +++ /dev/null @@ -1,123 +0,0 @@ -dnl Autoconf macros for libgcrypt -dnl Copyright (C) 2002, 2004 Free Software Foundation, Inc. -dnl -dnl This file is free software; as a special exception the author gives -dnl unlimited permission to copy and/or distribute it, with or without -dnl modifications, as long as this notice is preserved. -dnl -dnl This file is distributed in the hope that it will be useful, but -dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - -dnl AM_PATH_LIBGCRYPT([MINIMUM-VERSION, -dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) -dnl Test for libgcrypt and define LIBGCRYPT_CFLAGS and LIBGCRYPT_LIBS. -dnl MINIMUN-VERSION is a string with the version number optionalliy prefixed -dnl with the API version to also check the API compatibility. Example: -dnl a MINIMUN-VERSION of 1:1.2.5 won't pass the test unless the installed -dnl version of libgcrypt is at least 1.2.5 *and* the API number is 1. Using -dnl this features allows to prevent build against newer versions of libgcrypt -dnl with a changed API. -dnl -AC_DEFUN([AM_PATH_LIBGCRYPT], -[ AC_ARG_WITH(libgcrypt-prefix, - AC_HELP_STRING([--with-libgcrypt-prefix=PFX], - [prefix where LIBGCRYPT is installed (optional)]), - libgcrypt_config_prefix="$withval", libgcrypt_config_prefix="") - if test x$libgcrypt_config_prefix != x ; then - if test x${LIBGCRYPT_CONFIG+set} != xset ; then - LIBGCRYPT_CONFIG=$libgcrypt_config_prefix/bin/libgcrypt-config - fi - fi - - AC_PATH_TOOL(LIBGCRYPT_CONFIG, libgcrypt-config, no) - tmp=ifelse([$1], ,1:1.2.0,$1) - if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then - req_libgcrypt_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` - min_libgcrypt_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` - else - req_libgcrypt_api=0 - min_libgcrypt_version="$tmp" - fi - - AC_MSG_CHECKING(for LIBGCRYPT - version >= $min_libgcrypt_version) - ok=no - if test "$LIBGCRYPT_CONFIG" != "no" ; then - req_major=`echo $min_libgcrypt_version | \ - sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` - req_minor=`echo $min_libgcrypt_version | \ - sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` - req_micro=`echo $min_libgcrypt_version | \ - sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` - libgcrypt_config_version=`$LIBGCRYPT_CONFIG --version` - major=`echo $libgcrypt_config_version | \ - sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` - minor=`echo $libgcrypt_config_version | \ - sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` - micro=`echo $libgcrypt_config_version | \ - sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'` - if test "$major" -gt "$req_major"; then - ok=yes - else - if test "$major" -eq "$req_major"; then - if test "$minor" -gt "$req_minor"; then - ok=yes - else - if test "$minor" -eq "$req_minor"; then - if test "$micro" -ge "$req_micro"; then - ok=yes - fi - fi - fi - fi - fi - fi - if test $ok = yes; then - AC_MSG_RESULT([yes ($libgcrypt_config_version)]) - else - AC_MSG_RESULT(no) - fi - if test $ok = yes; then - # If we have a recent libgcrypt, we should also check that the - # API is compatible - if test "$req_libgcrypt_api" -gt 0 ; then - tmp=`$LIBGCRYPT_CONFIG --api-version 2>/dev/null || echo 0` - if test "$tmp" -gt 0 ; then - AC_MSG_CHECKING([LIBGCRYPT API version]) - if test "$req_libgcrypt_api" -eq "$tmp" ; then - AC_MSG_RESULT([okay]) - else - ok=no - AC_MSG_RESULT([does not match. want=$req_libgcrypt_api got=$tmp]) - fi - fi - fi - fi - if test $ok = yes; then - LIBGCRYPT_CFLAGS=`$LIBGCRYPT_CONFIG --cflags` - LIBGCRYPT_LIBS=`$LIBGCRYPT_CONFIG --libs` - ifelse([$2], , :, [$2]) - if test x"$host" != x ; then - libgcrypt_config_host=`$LIBGCRYPT_CONFIG --host 2>/dev/null || echo none` - if test x"$libgcrypt_config_host" != xnone ; then - if test x"$libgcrypt_config_host" != x"$host" ; then - AC_MSG_WARN([[ -*** -*** The config script $LIBGCRYPT_CONFIG was -*** built for $libgcrypt_config_host and thus may not match the -*** used host $host. -*** You may want to use the configure option --with-libgcrypt-prefix -*** to specify a matching config script. -***]]) - fi - fi - fi - else - LIBGCRYPT_CFLAGS="" - LIBGCRYPT_LIBS="" - ifelse([$3], , :, [$3]) - fi - AC_SUBST(LIBGCRYPT_CFLAGS) - AC_SUBST(LIBGCRYPT_LIBS) -]) diff --git a/test/Makefile.am b/test/Makefile.am deleted file mode 100644 index f07fc82..0000000 --- a/test/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -check_PROGRAMS = - -if HAVE_LIBJPEG -# TurboJPEG wrapper tests -check_PROGRAMS += tjunittest tjbench -tjunittest_SOURCES=tjunittest.c ../common/turbojpeg.c ../common/turbojpeg.h \ - tjutil.c tjutil.h -tjbench_SOURCES=tjbench.c ../common/turbojpeg.c ../common/turbojpeg.h \ - tjutil.c tjutil.h bmp.c bmp.h -tjbench_LDADD=$(LDADD) -lm -endif - -AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/common -LDADD = ../libvncserver/libvncserver.la ../libvncclient/libvncclient.la @WSOCKLIB@ - -if HAVE_LIBPTHREAD -BACKGROUND_TEST=blooptest -ENCODINGS_TEST=encodingstest -endif - -copyrecttest_LDADD=$(LDADD) -lm - -check_PROGRAMS += $(ENCODINGS_TEST) cargstest copyrecttest $(BACKGROUND_TEST) \ - cursortest - -test: encodingstest$(EXEEXT) cargstest$(EXEEXT) copyrecttest$(EXEEXT) - ./encodingstest && ./cargstest - diff --git a/webclients/Makefile.am b/webclients/Makefile.am deleted file mode 100644 index 6c2db84..0000000 --- a/webclients/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -SUBDIRS = java-applet -DIST_SUBDIRS = java-applet -EXTRA_DIST=index.vnc novnc - diff --git a/webclients/java-applet/Makefile.am b/webclients/java-applet/Makefile.am deleted file mode 100644 index d6d10e4..0000000 --- a/webclients/java-applet/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -EXTRA_DIST=VncViewer.jar javaviewer.pseudo_proxy.patch - -SUBDIRS = ssl -DIST_SUBDIRS = ssl - diff --git a/webclients/java-applet/ssl/Makefile.am b/webclients/java-applet/ssl/Makefile.am deleted file mode 100644 index fd1c201..0000000 --- a/webclients/java-applet/ssl/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -EXTRA_DIST=VncViewer.jar index.vnc SignedVncViewer.jar proxy.vnc README ss_vncviewer onetimekey UltraViewerSSL.jar SignedUltraViewerSSL.jar ultra.vnc ultrasigned.vnc ultraproxy.vnc - -- cgit v1.2.3 From 75f04c14e49e084e41bdd5491edad8823773a08c Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Tue, 14 Feb 2017 12:42:04 +0100 Subject: Ensure compatibility with gtk-vnc 0.7.0+ --- libvncserver/websockets.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'libvncserver') diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index 72396c2..0b2d46f 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -245,7 +245,10 @@ webSocketsCheck (rfbClientPtr cl) return FALSE; } - if (strncmp(bbuf, "<", 1) == 0) { + if (strncmp(bbuf, "RFB ", 4) == 0) { + rfbLog("Normal socket connection\n"); + return TRUE; + } else if (strncmp(bbuf, "<", 1) == 0) { rfbLog("Got Flash policy request, sending response\n"); if (rfbWriteExact(cl, FLASH_POLICY_RESPONSE, SZ_FLASH_POLICY_RESPONSE) < 0) { -- cgit v1.2.3 From 425e24196b7de15875d08c94c5ff59a6a3642654 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Mon, 20 Feb 2017 20:47:42 +0100 Subject: Fix building in C89 mode FIXME: this should probably be refactored into a common header. --- libvncserver/scale.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'libvncserver') diff --git a/libvncserver/scale.c b/libvncserver/scale.c index 3ca76dc..2325dc3 100644 --- a/libvncserver/scale.c +++ b/libvncserver/scale.c @@ -66,7 +66,18 @@ (double) ((int) (x)) : (double) ((int) (x) + 1) ) #define FLOOR(x) ( (double) ((int) (x)) ) -static inline int pad4(int value) +#ifdef WIN32 +#define InlineX __inline +#else +# ifndef __STRICT_ANSI__ +# define InlineX inline +# else +# define InlineX +# endif +#endif + + +static InlineX int pad4(int value) { int remainder = value & 3; if (!remainder) return value; -- cgit v1.2.3 From 5935c1be4fd77d3304e0666ba6e3e87aa70d8050 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Tue, 21 Feb 2017 19:07:15 +0100 Subject: Add an rfbLogPError that shows something on WIN32 --- libvncserver/main.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'libvncserver') diff --git a/libvncserver/main.c b/libvncserver/main.c index dbda77d..27b5437 100644 --- a/libvncserver/main.c +++ b/libvncserver/main.c @@ -261,7 +261,16 @@ rfbLogProc rfbErr=rfbDefaultLog; void rfbLogPerror(const char *str) { +#ifdef WIN32 + wchar_t *s = NULL; + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&s, 0, NULL); + rfbErr("%s: %S\n", str, s); + LocalFree(s); +#else rfbErr("%s: %s\n", str, strerror(errno)); +#endif } void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy) -- cgit v1.2.3 From 6cb0522ecbbf60872270ce8835fce2a9366534a2 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Tue, 21 Feb 2017 19:37:43 +0100 Subject: rfbInitServer: only init Winsock once --- libvncserver/main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'libvncserver') diff --git a/libvncserver/main.c b/libvncserver/main.c index 27b5437..95c3da5 100644 --- a/libvncserver/main.c +++ b/libvncserver/main.c @@ -1061,7 +1061,15 @@ void rfbInitServer(rfbScreenInfoPtr screen) { #ifdef WIN32 WSADATA trash; - WSAStartup(MAKEWORD(2,2),&trash); + static rfbBool WSAinitted=FALSE; + if(!WSAinitted) { + int i=WSAStartup(MAKEWORD(2,0),&trash); + if(i!=0) { + rfbErr("Couldn't init Windows Sockets\n"); + return 0; + } + WSAinitted=TRUE; + } #endif rfbInitSockets(screen); rfbHttpInitSockets(screen); -- cgit v1.2.3 From c550e1ac697f14da594a6c8f5a83ffdabd046847 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 10 May 2017 10:58:55 -0400 Subject: font: Fix a small resource leak in a failure case in rfbLoadConsoleFont() The file handle wouldn't be closed in this instance. --- libvncserver/font.c | 1 + 1 file changed, 1 insertion(+) (limited to 'libvncserver') diff --git a/libvncserver/font.c b/libvncserver/font.c index a9091d2..9935e91 100644 --- a/libvncserver/font.c +++ b/libvncserver/font.c @@ -174,6 +174,7 @@ rfbFontDataPtr rfbLoadConsoleFont(char *filename) if(1!=fread(p->data,4096,1,f)) { free(p->data); free(p); + fclose(f); return NULL; } fclose(f); -- cgit v1.2.3 From aac95a9dcf4bbba87b76c72706c3221a842ca433 Mon Sep 17 00:00:00 2001 From: Andreas Weigel Date: Wed, 15 Feb 2017 12:31:05 +0100 Subject: fix overflow and refactor websockets decode (Hybi) fix critical heap-based buffer overflow which allowed easy modification of a return address via an overwritten function pointer fix bug causing connections to fail due a "one websocket frame = one ws_read" assumption, which failed with LibVNCServer-0.9.11 refactor websocket Hybi decode to use a simple state machine for decoding of websocket frames --- libvncserver/websockets.c | 595 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 463 insertions(+), 132 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index 72396c2..4ed04c7 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -77,6 +77,9 @@ #define B64LEN(__x) (((__x + 2) / 3) * 12 / 3) #define WSHLENMAX 14 /* 2 + sizeof(uint64_t) + sizeof(uint32_t) */ +#define WS_HYBI_MASK_LEN 4 + +#define ARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))) / (size_t)(!(sizeof(a) % sizeof((a[0]))))) enum { WEBSOCKETS_VERSION_HIXIE, @@ -93,20 +96,20 @@ static int gettid() { typedef int (*wsEncodeFunc)(rfbClientPtr cl, const char *src, int len, char **dst); typedef int (*wsDecodeFunc)(rfbClientPtr cl, char *dst, int len); -typedef struct ws_ctx_s { - char codeBufDecode[B64LEN(UPDATE_BUF_SIZE) + WSHLENMAX]; /* base64 + maximum frame header length */ - char codeBufEncode[B64LEN(UPDATE_BUF_SIZE) + WSHLENMAX]; /* base64 + maximum frame header length */ - char readbuf[8192]; - int readbufstart; - int readbuflen; - int dblen; - char carryBuf[3]; /* For base64 carry-over */ - int carrylen; - int version; - int base64; - wsEncodeFunc encode; - wsDecodeFunc decode; -} ws_ctx_t; + +enum { + /* header not yet received completely */ + WS_HYBI_STATE_HEADER_PENDING, + /* data available */ + WS_HYBI_STATE_DATA_AVAILABLE, + WS_HYBI_STATE_DATA_NEEDED, + /* received a complete frame */ + WS_HYBI_STATE_FRAME_COMPLETE, + /* received part of a 'close' frame */ + WS_HYBI_STATE_CLOSE_REASON_PENDING, + /* */ + WS_HYBI_STATE_ERR +}; typedef union ws_mask_s { char c[4]; @@ -146,6 +149,38 @@ __attribute__ ((__packed__)) } u; } ws_header_t; +typedef struct ws_header_data_s { + ws_header_t *data; + /** bytes read */ + int nRead; + /** mask value */ + ws_mask_t mask; + /** length of frame header including payload len, but without mask */ + int headerLen; + /** length of the payload data */ + int payloadLen; + /** opcode */ + unsigned char opcode; +} ws_header_data_t; + +typedef struct ws_ctx_s { + char codeBufDecode[B64LEN(UPDATE_BUF_SIZE) + WSHLENMAX]; /* base64 + maximum frame header length */ + char codeBufEncode[B64LEN(UPDATE_BUF_SIZE) + WSHLENMAX]; /* base64 + maximum frame header length */ + char *writePos; + unsigned char *readPos; + int readlen; + int hybiDecodeState; + char carryBuf[3]; /* For base64 carry-over */ + int carrylen; + int version; + int base64; + ws_header_data_t header; + int nReadRaw; + int nToRead; + wsEncodeFunc encode; + wsDecodeFunc decode; +} ws_ctx_t; + enum { WS_OPCODE_CONTINUATION = 0x0, @@ -206,6 +241,8 @@ static int webSocketsEncodeHixie(rfbClientPtr cl, const char *src, int len, char static int webSocketsDecodeHybi(rfbClientPtr cl, char *dst, int len); static int webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len); +static void hybiDecodeCleanup(ws_ctx_t *wsctx); + static int min (int a, int b) { return a < b ? a : b; @@ -467,10 +504,11 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) wsctx->decode = webSocketsDecodeHixie; } wsctx->base64 = base64; + hybiDecodeCleanup(wsctx); cl->wsctx = (wsCtx *)wsctx; return TRUE; } - + void webSocketsGenMd5(char * target, char *key1, char *key2, char *key3) { @@ -662,146 +700,439 @@ webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len) } static int -webSocketsDecodeHybi(rfbClientPtr cl, char *dst, int len) +hybiRemaining(ws_ctx_t *wsctx) { - char *buf, *payload; - uint32_t *payload32; - int ret = -1, result = -1; - int total = 0; - ws_mask_t mask; - ws_header_t *header; - int i; - unsigned char opcode; - ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; - int flength, fhlen; - /* int fin; */ /* not used atm */ + return wsctx->nToRead - wsctx->nReadRaw; +} - /* rfbLog(" <== %s[%d]: %d cl: %p, wsctx: %p-%p (%d)\n", __func__, gettid(), len, cl, wsctx, (char *)wsctx + sizeof(ws_ctx_t), sizeof(ws_ctx_t)); */ +static void +hybiDecodeCleanup(ws_ctx_t *wsctx) +{ + wsctx->header.payloadLen = 0; + wsctx->header.mask.u = 0; + wsctx->nReadRaw = 0; + wsctx->nToRead= 0; + wsctx->carrylen = 0; + wsctx->readPos = (unsigned char *)wsctx->codeBufDecode; + wsctx->readlen = 0; + wsctx->hybiDecodeState = WS_HYBI_STATE_HEADER_PENDING; + wsctx->writePos = NULL; + rfbLog("cleaned up wsctx\n"); +} - if (wsctx->readbuflen) { - /* simply return what we have */ - if (wsctx->readbuflen > len) { - memcpy(dst, wsctx->readbuf + wsctx->readbufstart, len); - result = len; - wsctx->readbuflen -= len; - wsctx->readbufstart += len; +/** + * Return payload data that has been decoded/unmasked from + * a websocket frame. + * + * @param[out] dst destination buffer + * @param[in] len bytes to copy to destination buffer + * @param[in,out] wsctx internal state of decoding procedure + * @param[out] number of bytes actually written to dst buffer + * @return next hybi decoding state + */ +static int +hybiReturnData(char *dst, int len, ws_ctx_t *wsctx, int *nWritten) +{ + int nextState = WS_HYBI_STATE_ERR; + + /* if we have something already decoded copy and return */ + if (wsctx->readlen > 0) { + /* simply return what we have */ + if (wsctx->readlen > len) { + rfbLog("copy to %d bytes to dst buffer; readPos=%p, readLen=%d\n", len, wsctx->readPos, wsctx->readlen); + memcpy(dst, wsctx->readPos, len); + *nWritten = len; + wsctx->readlen -= len; + wsctx->readPos += len; + nextState = WS_HYBI_STATE_DATA_AVAILABLE; + } else { + rfbLog("copy to %d bytes to dst buffer; readPos=%p, readLen=%d\n", wsctx->readlen, wsctx->readPos, wsctx->readlen); + memcpy(dst, wsctx->readPos, wsctx->readlen); + *nWritten = wsctx->readlen; + wsctx->readlen = 0; + wsctx->readPos = NULL; + if (hybiRemaining(wsctx) == 0) { + nextState = WS_HYBI_STATE_FRAME_COMPLETE; } else { - memcpy(dst, wsctx->readbuf + wsctx->readbufstart, wsctx->readbuflen); - result = wsctx->readbuflen; - wsctx->readbuflen = 0; - wsctx->readbufstart = 0; + nextState = WS_HYBI_STATE_DATA_NEEDED; } - goto spor; } + rfbLog("after copy: readPos=%p, readLen=%d\n", wsctx->readPos, wsctx->readlen); + } else if (wsctx->hybiDecodeState == WS_HYBI_STATE_CLOSE_REASON_PENDING) { + nextState = WS_HYBI_STATE_CLOSE_REASON_PENDING; + } + return nextState; +} - buf = wsctx->codeBufDecode; - header = (ws_header_t *)wsctx->codeBufDecode; - - ret = ws_peek(cl, buf, B64LEN(len) + WSHLENMAX); - - if (ret < 2) { - /* save errno because rfbErr() will tamper it */ - if (-1 == ret) { - int olderrno = errno; - rfbErr("%s: peek; %m\n", __func__); - errno = olderrno; - } else if (0 == ret) { - result = 0; - } else { - errno = EAGAIN; - } - goto spor; +/** + * Read an RFC 6455 websocket frame (IETF hybi working group). + * + * Internal state is updated according to bytes received and the + * decoding of header information. + * + * @param[in] cl client ptr with ptr to raw socket and ws_ctx_t ptr + * @param[out] sockRet emulated recv return value + * @return next hybi decoding state; WS_HYBI_STATE_HEADER_PENDING indicates + * that the header was not received completely. + */ +static int +hybiReadHeader(rfbClientPtr cl, int *sockRet) +{ + int ret; + ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; + char *headerDst = wsctx->codeBufDecode + wsctx->nReadRaw; + int n = WSHLENMAX - wsctx->nReadRaw; + + rfbLog("header_read to %p with len=%d\n", headerDst, n); + ret = ws_read(cl, headerDst, n); + rfbLog("read %d bytes from socket\n", ret); + if (ret <= 0) { + if (-1 == ret) { + /* save errno because rfbErr() will tamper it */ + int olderrno = errno; + rfbErr("%s: peek; %m\n", __func__); + errno = olderrno; + *sockRet = -1; + } else { + *sockRet = 0; } + return WS_HYBI_STATE_ERR; + } + + wsctx->nReadRaw += ret; + if (wsctx->nReadRaw < 2) { + /* cannot decode header with less than two bytes */ + errno = EAGAIN; + *sockRet = -1; + return WS_HYBI_STATE_HEADER_PENDING; + } + + /* first two header bytes received; interpret header data and get rest */ + wsctx->header.data = (ws_header_t *)wsctx->codeBufDecode; + + wsctx->header.opcode = wsctx->header.data->b0 & 0x0f; + + /* fin = (header->b0 & 0x80) >> 7; */ /* not used atm */ + wsctx->header.payloadLen = wsctx->header.data->b1 & 0x7f; + rfbLog("first header bytes received; opcode=%d lenbyte=%d\n", wsctx->header.opcode, wsctx->header.payloadLen); + + /* + * 4.3. Client-to-Server Masking + * + * The client MUST mask all frames sent to the server. A server MUST + * close the connection upon receiving a frame with the MASK bit set to 0. + **/ + if (!(wsctx->header.data->b1 & 0x80)) { + rfbErr("%s: got frame without mask ret=%d\n", __func__, ret); + errno = EIO; + *sockRet = -1; + return WS_HYBI_STATE_ERR; + } + + if (wsctx->header.payloadLen < 126 && wsctx->nReadRaw >= 6) { + wsctx->header.headerLen = 2 + WS_HYBI_MASK_LEN; + wsctx->header.mask = wsctx->header.data->u.m; + } else if (wsctx->header.payloadLen == 126 && 8 <= wsctx->nReadRaw) { + wsctx->header.headerLen = 4 + WS_HYBI_MASK_LEN; + wsctx->header.payloadLen = WS_NTOH16(wsctx->header.data->u.s16.l16); + wsctx->header.mask = wsctx->header.data->u.s16.m16; + } else if (wsctx->header.payloadLen == 127 && 14 <= wsctx->nReadRaw) { + wsctx->header.headerLen = 10 + WS_HYBI_MASK_LEN; + wsctx->header.payloadLen = WS_NTOH64(wsctx->header.data->u.s64.l64); + wsctx->header.mask = wsctx->header.data->u.s64.m64; + } else { + /* Incomplete frame header, try again */ + rfbErr("%s: incomplete frame header; ret=%d\n", __func__, ret); + errno = EAGAIN; + *sockRet = -1; + return WS_HYBI_STATE_HEADER_PENDING; + } + + /* absolute length of frame */ + wsctx->nToRead = wsctx->header.headerLen + wsctx->header.payloadLen; + + /* set payload pointer just after header */ + wsctx->writePos = wsctx->codeBufDecode + wsctx->nReadRaw; + + wsctx->readPos = (unsigned char *)(wsctx->codeBufDecode + wsctx->header.headerLen); + + rfbLog("header complete: state=%d flen=%d writeTo=%p\n", wsctx->hybiDecodeState, wsctx->nToRead, wsctx->writePos); + + return WS_HYBI_STATE_DATA_NEEDED; +} - opcode = header->b0 & 0x0f; - /* fin = (header->b0 & 0x80) >> 7; */ /* not used atm */ - flength = header->b1 & 0x7f; +static int +hybiWsFrameComplete(ws_ctx_t *wsctx) +{ + return wsctx != NULL && hybiRemaining(wsctx) == 0; +} - /* - * 4.3. Client-to-Server Masking - * - * The client MUST mask all frames sent to the server. A server MUST - * close the connection upon receiving a frame with the MASK bit set to 0. - **/ - if (!(header->b1 & 0x80)) { - rfbErr("%s: got frame without mask\n", __func__, ret); - errno = EIO; - goto spor; - } - - if (flength < 126) { - fhlen = 2; - mask = header->u.m; - } else if (flength == 126 && 4 <= ret) { - flength = WS_NTOH16(header->u.s16.l16); - fhlen = 4; - mask = header->u.s16.m16; - } else if (flength == 127 && 10 <= ret) { - flength = WS_NTOH64(header->u.s64.l64); - fhlen = 10; - mask = header->u.s64.m64; - } else { - /* Incomplete frame header */ - rfbErr("%s: incomplete frame header\n", __func__, ret); - errno = EIO; - goto spor; - } +static char * +hybiPayloadStart(ws_ctx_t *wsctx) +{ + return wsctx->codeBufDecode + wsctx->header.headerLen; +} - /* absolute length of frame */ - total = fhlen + flength + 4; - payload = buf + fhlen + 4; /* header length + mask */ - if (-1 == (ret = ws_read(cl, buf, total))) { +/** + * Read the remaining payload bytes from associated raw socket. + * + * - try to read remaining bytes from socket + * - unmask all multiples of 4 + * - if frame incomplete but some bytes are left, these are copied to + * the carry buffer + * - if opcode is TEXT: Base64-decode all unmasked received bytes + * - set state for reading decoded data + * - reset write position to begin of buffer (+ header) + * --> before we retrieve more data we let the caller clear all bytes + * from the reception buffer + * - execute return data routine + * + * Sets errno corresponding to what it gets from the underlying + * socket or EIO if some internal sanity check fails. + * + * @param[in] cl client ptr with raw socket reference + * @param[out] dst destination buffer + * @param[in] len size of destination buffer + * @param[out] sockRet emulated recv return value + * @return next hybi decode state + */ +static int +hybiReadAndDecode(rfbClientPtr cl, char *dst, int len, int *sockRet) +{ + int n; + int i; + int toReturn; + int toDecode; + int bufsize; + int nextRead; + unsigned char *data; + uint32_t *data32; + ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; + + /* if data was carried over, copy to start of buffer */ + memcpy(wsctx->writePos, wsctx->carryBuf, wsctx->carrylen); + wsctx->writePos += wsctx->carrylen; + + /* -1 accounts for potential '\0' terminator for base64 decoding */ + bufsize = wsctx->codeBufDecode + ARRAYSIZE(wsctx->codeBufDecode) - wsctx->writePos - 1; + if (hybiRemaining(wsctx) > bufsize) { + nextRead = bufsize; + } else { + nextRead = hybiRemaining(wsctx); + } + + rfbLog("calling read with buf=%p and len=%d (decodebuf=%p headerLen=%d\n)", wsctx->writePos, nextRead, wsctx->codeBufDecode, wsctx->header.headerLen); + + if (wsctx->nReadRaw < wsctx->nToRead) { + /* decode more data */ + if (-1 == (n = ws_read(cl, wsctx->writePos, nextRead))) { int olderrno = errno; rfbErr("%s: read; %m", __func__); errno = olderrno; - return ret; - } else if (ret < total) { - /* GT TODO: hmm? */ - rfbLog("%s: read; got partial data\n", __func__); - } else { - buf[ret] = '\0'; + *sockRet = -1; + return WS_HYBI_STATE_ERR; + } else if (n == 0) { + *sockRet = 0; + return WS_HYBI_STATE_ERR; } - - /* process 1 frame (32 bit op) */ - payload32 = (uint32_t *)payload; - for (i = 0; i < flength / 4; i++) { - payload32[i] ^= mask.u; + wsctx->nReadRaw += n; + rfbLog("read %d bytes from socket; nRead=%d\n", n, wsctx->nReadRaw); + } else { + n = 0; + } + + wsctx->writePos += n; + + if (wsctx->nReadRaw >= wsctx->nToRead) { + if (wsctx->nReadRaw > wsctx->nToRead) { + rfbErr("%s: internal error, read past websocket frame", __func__); + errno=EIO; + *sockRet = -1; + return WS_HYBI_STATE_ERR; } + } + + toDecode = wsctx->writePos - hybiPayloadStart(wsctx); + rfbLog("toDecode=%d from n=%d carrylen=%d headerLen=%d\n", toDecode, n, wsctx->carrylen, wsctx->header.headerLen); + if (toDecode < 0) { + rfbErr("%s: internal error; negative number of bytes to decode: %d", __func__, toDecode); + errno=EIO; + *sockRet = -1; + return WS_HYBI_STATE_ERR; + } + + /* for a possible base64 decoding, we decode multiples of 4 bytes until + * the whole frame is received and carry over any remaining bytes in the carry buf*/ + data = (unsigned char *)hybiPayloadStart(wsctx); + data32= (uint32_t *)data; + + for (i = 0; i < (toDecode >> 2); i++) { + data32[i] ^= wsctx->header.mask.u; + } + rfbLog("mask decoding; i=%d toDecode=%d\n", i, toDecode); + + if (wsctx->hybiDecodeState == WS_HYBI_STATE_FRAME_COMPLETE) { /* process the remaining bytes (if any) */ - for (i*=4; i < flength; i++) { - payload[i] ^= mask.c[i % 4]; - } - - switch (opcode) { - case WS_OPCODE_CLOSE: - rfbLog("got closure, reason %d\n", WS_NTOH16(((uint16_t *)payload)[0])); - errno = ECONNRESET; - break; - case WS_OPCODE_TEXT_FRAME: - if (-1 == (flength = b64_pton(payload, (unsigned char *)wsctx->codeBufDecode, sizeof(wsctx->codeBufDecode)))) { - rfbErr("%s: Base64 decode error; %m\n", __func__); - break; - } - payload = wsctx->codeBufDecode; - /* fall through */ - case WS_OPCODE_BINARY_FRAME: - if (flength > len) { - memcpy(wsctx->readbuf, payload + len, flength - len); - wsctx->readbufstart = 0; - wsctx->readbuflen = flength - len; - flength = len; - } - memcpy(dst, payload, flength); - result = flength; - break; + for (i*=4; i < toDecode; i++) { + data[i] ^= wsctx->header.mask.c[i % 4]; + } + + /* all data is here, no carrying */ + wsctx->carrylen = 0; + } else { + /* carry over remaining, non-multiple-of-four bytes */ + wsctx->carrylen = toDecode - (i * 4); + if (wsctx->carrylen < 0 || wsctx->carrylen > ARRAYSIZE(wsctx->carryBuf)) { + rfbErr("%s: internal error, invalid carry over size: carrylen=%d, toDecode=%d, i=%d", __func__, wsctx->carrylen, toDecode, i); + *sockRet = -1; + errno = EIO; + return WS_HYBI_STATE_ERR; + } + rfbLog("carrying over %d bytes from %p to %p\n", wsctx->carrylen, wsctx->writePos + (i * 4), wsctx->carryBuf); + memcpy(wsctx->carryBuf, data + (i * 4), wsctx->carrylen); + } + + toReturn = toDecode - wsctx->carrylen; + + switch (wsctx->header.opcode) { + case WS_OPCODE_CLOSE: + + /* this data is not returned as payload data */ + if (hybiWsFrameComplete(wsctx)) { + rfbLog("got closure, reason %d\n", WS_NTOH16(((uint16_t *)data)[0])); + errno = ECONNRESET; + *sockRet = -1; + return WS_HYBI_STATE_FRAME_COMPLETE; + } else { + rfbErr("%s: close reason with long frame not supported", __func__); + errno = EIO; + *sockRet = -1; + return WS_HYBI_STATE_ERR; + } + break; + case WS_OPCODE_TEXT_FRAME: + data[toReturn] = '\0'; + rfbLog("Initiate Base64 decoding in %p with max size %d and '\\0' at %p\n", data, bufsize, data + toReturn); + if (-1 == (wsctx->readlen = b64_pton((char *)data, data, bufsize))) { + rfbErr("Base64 decode error in %s; data=%p bufsize=%d", __func__, data, bufsize); + rfbErr("%s: Base64 decode error; %m\n", __func__); + } + wsctx->writePos = hybiPayloadStart(wsctx); + break; + case WS_OPCODE_BINARY_FRAME: + wsctx->readlen = toReturn; + wsctx->writePos = hybiPayloadStart(wsctx); + break; + default: + rfbErr("%s: unhandled opcode %d, b0: %02x, b1: %02x\n", __func__, (int)wsctx->header.opcode, wsctx->header.data->b0, wsctx->header.data->b1); + } + wsctx->readPos = data; + + return hybiReturnData(dst, len, wsctx, sockRet); +} + +/** + * Read function for websocket-socket emulation. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-------+-+-------------+-------------------------------+ + * |F|R|R|R| opcode|M| Payload len | Extended payload length | + * |I|S|S|S| (4) |A| (7) | (16/64) | + * |N|V|V|V| |S| | (if payload len==126/127) | + * | |1|2|3| |K| | | + * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + * | Extended payload length continued, if payload len == 127 | + * + - - - - - - - - - - - - - - - +-------------------------------+ + * | |Masking-key, if MASK set to 1 | + * +-------------------------------+-------------------------------+ + * | Masking-key (continued) | Payload Data | + * +-------------------------------- - - - - - - - - - - - - - - - + + * : Payload Data continued ... : + * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + * | Payload Data continued ... | + * +---------------------------------------------------------------+ + * + * Using the decode buffer, this function: + * - reads the complete header from the underlying socket + * - reads any remaining data bytes + * - unmasks the payload data using the provided mask + * - decodes Base64 encoded text data + * - copies len bytes of decoded payload data into dst + * + * Emulates a read call on a socket. + */ +static int +webSocketsDecodeHybi(rfbClientPtr cl, char *dst, int len) +{ + int result = -1; + ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; + /* int fin; */ /* not used atm */ + + /* rfbLog(" <== %s[%d]: %d cl: %p, wsctx: %p-%p (%d)\n", __func__, gettid(), len, cl, wsctx, (char *)wsctx + sizeof(ws_ctx_t), sizeof(ws_ctx_t)); */ + rfbLog("%s_enter: len=%d; " + "CTX: readlen=%d readPos=%p " + "writeTo=%p " + "state=%d toRead=%d remaining=%d " + " nReadRaw=%d carrylen=%d carryBuf=%p\n", + __func__, len, + wsctx->readlen, wsctx->readPos, + wsctx->writePos, + wsctx->hybiDecodeState, wsctx->nToRead, hybiRemaining(wsctx), + wsctx->nReadRaw, wsctx->carrylen, wsctx->carryBuf); + + switch (wsctx->hybiDecodeState){ + case WS_HYBI_STATE_HEADER_PENDING: + wsctx->hybiDecodeState = hybiReadHeader(cl, &result); + if (wsctx->hybiDecodeState == WS_HYBI_STATE_ERR) { + goto spor; + } + if (wsctx->hybiDecodeState != WS_HYBI_STATE_HEADER_PENDING) { + + /* when header is complete, try to read some more data */ + wsctx->hybiDecodeState = hybiReadAndDecode(cl, dst, len, &result); + } + break; + case WS_HYBI_STATE_DATA_AVAILABLE: + wsctx->hybiDecodeState = hybiReturnData(dst, len, wsctx, &result); + break; + case WS_HYBI_STATE_DATA_NEEDED: + wsctx->hybiDecodeState = hybiReadAndDecode(cl, dst, len, &result); + break; + case WS_HYBI_STATE_CLOSE_REASON_PENDING: + wsctx->hybiDecodeState = hybiReadAndDecode(cl, dst, len, &result); + break; default: - rfbErr("%s: unhandled opcode %d, b0: %02x, b1: %02x\n", __func__, (int)opcode, header->b0, header->b1); + /* invalid state */ + rfbErr("%s: called with invalid state %d\n", wsctx->hybiDecodeState); + result = -1; + errno = EIO; + wsctx->hybiDecodeState = WS_HYBI_STATE_ERR; } /* single point of return, if someone has questions :-) */ spor: /* rfbLog("%s: ret: %d/%d\n", __func__, result, len); */ + if (wsctx->hybiDecodeState == WS_HYBI_STATE_FRAME_COMPLETE) { + rfbLog("frame received successfully, cleaning up: read=%d hlen=%d plen=%d\n", wsctx->header.nRead, wsctx->header.headerLen, wsctx->header.payloadLen); + /* frame finished, cleanup state */ + hybiDecodeCleanup(wsctx); + } else if (wsctx->hybiDecodeState == WS_HYBI_STATE_ERR) { + hybiDecodeCleanup(wsctx); + } + rfbLog("%s_exit: len=%d; " + "CTX: readlen=%d readPos=%p " + "writePos=%p " + "state=%d toRead=%d remaining=%d " + "nRead=%d carrylen=%d carryBuf=%p " + "result=%d\n", + __func__, len, + wsctx->readlen, wsctx->readPos, + wsctx->writePos, + wsctx->hybiDecodeState, wsctx->nToRead, hybiRemaining(wsctx), + wsctx->nReadRaw, wsctx->carrylen, wsctx->carryBuf, + result); return result; } @@ -951,7 +1282,7 @@ webSocketsHasDataInBuffer(rfbClientPtr cl) { ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; - if (wsctx && wsctx->readbuflen) + if (wsctx && wsctx->readlen) return TRUE; return (cl->sslctx && rfbssl_pending(cl) > 0); -- cgit v1.2.3 From bcefa591cd7b4f8c635a9cadd3438bb5bf5ad814 Mon Sep 17 00:00:00 2001 From: Andreas Weigel Date: Thu, 16 Feb 2017 10:10:33 +0100 Subject: factor out hybi decode part to make it testable remove direct dependency on rfbClientPtr structure in hybi decode function(s) --- libvncserver/websockets.c | 603 ++-------------------------------------------- libvncserver/ws_decode.c | 448 ++++++++++++++++++++++++++++++++++ libvncserver/ws_decode.h | 160 ++++++++++++ 3 files changed, 631 insertions(+), 580 deletions(-) create mode 100644 libvncserver/ws_decode.c create mode 100644 libvncserver/ws_decode.h (limited to 'libvncserver') diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index 4ed04c7..ab947ae 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -34,10 +34,6 @@ /* errno */ #include -#ifndef _MSC_VER -#include /* __b64_ntop */ -#endif - #ifdef LIBVNCSERVER_HAVE_ENDIAN_H #include #elif LIBVNCSERVER_HAVE_SYS_ENDIAN_H @@ -55,36 +51,8 @@ #include "rfb/rfbconfig.h" #include "rfbssl.h" #include "rfbcrypto.h" +#include "ws_decode.h" -#if defined(__APPLE__) - -#include -#define WS_NTOH64(n) OSSwapBigToHostInt64(n) -#define WS_NTOH32(n) OSSwapBigToHostInt32(n) -#define WS_NTOH16(n) OSSwapBigToHostInt16(n) -#define WS_HTON64(n) OSSwapHostToBigInt64(n) -#define WS_HTON16(n) OSSwapHostToBigInt16(n) - -#else - -#define WS_NTOH64(n) htobe64(n) -#define WS_NTOH32(n) htobe32(n) -#define WS_NTOH16(n) htobe16(n) -#define WS_HTON64(n) htobe64(n) -#define WS_HTON16(n) htobe16(n) - -#endif - -#define B64LEN(__x) (((__x + 2) / 3) * 12 / 3) -#define WSHLENMAX 14 /* 2 + sizeof(uint64_t) + sizeof(uint32_t) */ -#define WS_HYBI_MASK_LEN 4 - -#define ARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))) / (size_t)(!(sizeof(a) % sizeof((a[0]))))) - -enum { - WEBSOCKETS_VERSION_HIXIE, - WEBSOCKETS_VERSION_HYBI -}; #if 0 #include @@ -93,104 +61,6 @@ static int gettid() { } #endif -typedef int (*wsEncodeFunc)(rfbClientPtr cl, const char *src, int len, char **dst); -typedef int (*wsDecodeFunc)(rfbClientPtr cl, char *dst, int len); - - -enum { - /* header not yet received completely */ - WS_HYBI_STATE_HEADER_PENDING, - /* data available */ - WS_HYBI_STATE_DATA_AVAILABLE, - WS_HYBI_STATE_DATA_NEEDED, - /* received a complete frame */ - WS_HYBI_STATE_FRAME_COMPLETE, - /* received part of a 'close' frame */ - WS_HYBI_STATE_CLOSE_REASON_PENDING, - /* */ - WS_HYBI_STATE_ERR -}; - -typedef union ws_mask_s { - char c[4]; - uint32_t u; -} ws_mask_t; - -/* XXX: The union and the structs do not need to be named. - * We are working around a bug present in GCC < 4.6 which prevented - * it from recognizing anonymous structs and unions. - * See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=4784 - */ -typedef struct -#if __GNUC__ -__attribute__ ((__packed__)) -#endif -ws_header_s { - unsigned char b0; - unsigned char b1; - union { - struct -#if __GNUC__ - __attribute__ ((__packed__)) -#endif - { - uint16_t l16; - ws_mask_t m16; - } s16; - struct -#if __GNUC__ -__attribute__ ((__packed__)) -#endif - { - uint64_t l64; - ws_mask_t m64; - } s64; - ws_mask_t m; - } u; -} ws_header_t; - -typedef struct ws_header_data_s { - ws_header_t *data; - /** bytes read */ - int nRead; - /** mask value */ - ws_mask_t mask; - /** length of frame header including payload len, but without mask */ - int headerLen; - /** length of the payload data */ - int payloadLen; - /** opcode */ - unsigned char opcode; -} ws_header_data_t; - -typedef struct ws_ctx_s { - char codeBufDecode[B64LEN(UPDATE_BUF_SIZE) + WSHLENMAX]; /* base64 + maximum frame header length */ - char codeBufEncode[B64LEN(UPDATE_BUF_SIZE) + WSHLENMAX]; /* base64 + maximum frame header length */ - char *writePos; - unsigned char *readPos; - int readlen; - int hybiDecodeState; - char carryBuf[3]; /* For base64 carry-over */ - int carrylen; - int version; - int base64; - ws_header_data_t header; - int nReadRaw; - int nToRead; - wsEncodeFunc encode; - wsDecodeFunc decode; -} ws_ctx_t; - -enum -{ - WS_OPCODE_CONTINUATION = 0x0, - WS_OPCODE_TEXT_FRAME, - WS_OPCODE_BINARY_FRAME, - WS_OPCODE_CLOSE = 0x8, - WS_OPCODE_PING, - WS_OPCODE_PONG -}; - #define FLASH_POLICY_RESPONSE "\n" #define SZ_FLASH_POLICY_RESPONSE 93 @@ -238,10 +108,11 @@ void webSocketsGenMd5(char * target, char *key1, char *key2, char *key3); static int webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst); static int webSocketsEncodeHixie(rfbClientPtr cl, const char *src, int len, char **dst); -static int webSocketsDecodeHybi(rfbClientPtr cl, char *dst, int len); -static int webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len); +static int webSocketsDecodeHixie(ws_ctx_t *wsctx, char *dst, int len); + +static int ws_read(void *cl, char *buf, int len); +static int ws_peek(void *cl, char *buf, int len); -static void hybiDecodeCleanup(ws_ctx_t *wsctx); static int min (int a, int b) { @@ -503,6 +374,8 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) wsctx->encode = webSocketsEncodeHixie; wsctx->decode = webSocketsDecodeHixie; } + wsctx->ctxInfo.readFunc = ws_read; + wsctx->ctxInfo.peekFunc = ws_peek; wsctx->base64 = base64; hybiDecodeCleanup(wsctx); cl->wsctx = (wsCtx *)wsctx; @@ -578,9 +451,10 @@ webSocketsEncodeHixie(rfbClientPtr cl, const char *src, int len, char **dst) } static int -ws_read(rfbClientPtr cl, char *buf, int len) +ws_read(void *ctxPtr, char *buf, int len) { int n; + rfbClientPtr cl = ctxPtr; if (cl->sslctx) { n = rfbssl_read(cl, buf, len); } else { @@ -590,9 +464,10 @@ ws_read(rfbClientPtr cl, char *buf, int len) } static int -ws_peek(rfbClientPtr cl, char *buf, int len) +ws_peek(void *ctxPtr, char *buf, int len) { int n; + rfbClientPtr cl = ctxPtr; if (cl->sslctx) { n = rfbssl_peek(cl, buf, len); } else { @@ -605,15 +480,15 @@ ws_peek(rfbClientPtr cl, char *buf, int len) } static int -webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len) +webSocketsDecodeHixie(ws_ctx_t *wsctx, char *dst, int len) { int retlen = 0, n, i, avail, modlen, needlen; char *buf, *end = NULL; - ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; buf = wsctx->codeBufDecode; - n = ws_peek(cl, buf, len*2+2); + //n = ws_peek(cl, buf, len*2+2); + n = wsctx->ctxInfo.peekFunc(wsctx->ctxInfo.ctxPtr, buf, len*2+2); if (n <= 0) { /* save errno because rfbErr() will tamper it */ @@ -627,7 +502,8 @@ webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len) /* Base64 encoded WebSockets stream */ if (buf[0] == '\xff') { - i = ws_read(cl, buf, 1); /* Consume marker */ + //i = ws_read(cl, buf, 1); /* Consume marker */ + i = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, buf, 1); buf++; n--; } @@ -636,7 +512,8 @@ webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len) return -1; } if (buf[0] == '\x00') { - i = ws_read(cl, buf, 1); /* Consume marker */ + //i = ws_read(cl, buf, 1); /* Consume marker */ + i = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, buf, 1); buf++; n--; } @@ -686,7 +563,8 @@ webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len) retlen += n; /* Consume the data from socket */ - i = ws_read(cl, buf, needlen); + //i = ws_read(cl, buf, needlen); + i = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, buf, needlen); wsctx->carrylen = n - len; retlen -= wsctx->carrylen; @@ -699,443 +577,6 @@ webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len) return retlen; } -static int -hybiRemaining(ws_ctx_t *wsctx) -{ - return wsctx->nToRead - wsctx->nReadRaw; -} - -static void -hybiDecodeCleanup(ws_ctx_t *wsctx) -{ - wsctx->header.payloadLen = 0; - wsctx->header.mask.u = 0; - wsctx->nReadRaw = 0; - wsctx->nToRead= 0; - wsctx->carrylen = 0; - wsctx->readPos = (unsigned char *)wsctx->codeBufDecode; - wsctx->readlen = 0; - wsctx->hybiDecodeState = WS_HYBI_STATE_HEADER_PENDING; - wsctx->writePos = NULL; - rfbLog("cleaned up wsctx\n"); -} - -/** - * Return payload data that has been decoded/unmasked from - * a websocket frame. - * - * @param[out] dst destination buffer - * @param[in] len bytes to copy to destination buffer - * @param[in,out] wsctx internal state of decoding procedure - * @param[out] number of bytes actually written to dst buffer - * @return next hybi decoding state - */ -static int -hybiReturnData(char *dst, int len, ws_ctx_t *wsctx, int *nWritten) -{ - int nextState = WS_HYBI_STATE_ERR; - - /* if we have something already decoded copy and return */ - if (wsctx->readlen > 0) { - /* simply return what we have */ - if (wsctx->readlen > len) { - rfbLog("copy to %d bytes to dst buffer; readPos=%p, readLen=%d\n", len, wsctx->readPos, wsctx->readlen); - memcpy(dst, wsctx->readPos, len); - *nWritten = len; - wsctx->readlen -= len; - wsctx->readPos += len; - nextState = WS_HYBI_STATE_DATA_AVAILABLE; - } else { - rfbLog("copy to %d bytes to dst buffer; readPos=%p, readLen=%d\n", wsctx->readlen, wsctx->readPos, wsctx->readlen); - memcpy(dst, wsctx->readPos, wsctx->readlen); - *nWritten = wsctx->readlen; - wsctx->readlen = 0; - wsctx->readPos = NULL; - if (hybiRemaining(wsctx) == 0) { - nextState = WS_HYBI_STATE_FRAME_COMPLETE; - } else { - nextState = WS_HYBI_STATE_DATA_NEEDED; - } - } - rfbLog("after copy: readPos=%p, readLen=%d\n", wsctx->readPos, wsctx->readlen); - } else if (wsctx->hybiDecodeState == WS_HYBI_STATE_CLOSE_REASON_PENDING) { - nextState = WS_HYBI_STATE_CLOSE_REASON_PENDING; - } - return nextState; -} - -/** - * Read an RFC 6455 websocket frame (IETF hybi working group). - * - * Internal state is updated according to bytes received and the - * decoding of header information. - * - * @param[in] cl client ptr with ptr to raw socket and ws_ctx_t ptr - * @param[out] sockRet emulated recv return value - * @return next hybi decoding state; WS_HYBI_STATE_HEADER_PENDING indicates - * that the header was not received completely. - */ -static int -hybiReadHeader(rfbClientPtr cl, int *sockRet) -{ - int ret; - ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; - char *headerDst = wsctx->codeBufDecode + wsctx->nReadRaw; - int n = WSHLENMAX - wsctx->nReadRaw; - - rfbLog("header_read to %p with len=%d\n", headerDst, n); - ret = ws_read(cl, headerDst, n); - rfbLog("read %d bytes from socket\n", ret); - if (ret <= 0) { - if (-1 == ret) { - /* save errno because rfbErr() will tamper it */ - int olderrno = errno; - rfbErr("%s: peek; %m\n", __func__); - errno = olderrno; - *sockRet = -1; - } else { - *sockRet = 0; - } - return WS_HYBI_STATE_ERR; - } - - wsctx->nReadRaw += ret; - if (wsctx->nReadRaw < 2) { - /* cannot decode header with less than two bytes */ - errno = EAGAIN; - *sockRet = -1; - return WS_HYBI_STATE_HEADER_PENDING; - } - - /* first two header bytes received; interpret header data and get rest */ - wsctx->header.data = (ws_header_t *)wsctx->codeBufDecode; - - wsctx->header.opcode = wsctx->header.data->b0 & 0x0f; - - /* fin = (header->b0 & 0x80) >> 7; */ /* not used atm */ - wsctx->header.payloadLen = wsctx->header.data->b1 & 0x7f; - rfbLog("first header bytes received; opcode=%d lenbyte=%d\n", wsctx->header.opcode, wsctx->header.payloadLen); - - /* - * 4.3. Client-to-Server Masking - * - * The client MUST mask all frames sent to the server. A server MUST - * close the connection upon receiving a frame with the MASK bit set to 0. - **/ - if (!(wsctx->header.data->b1 & 0x80)) { - rfbErr("%s: got frame without mask ret=%d\n", __func__, ret); - errno = EIO; - *sockRet = -1; - return WS_HYBI_STATE_ERR; - } - - if (wsctx->header.payloadLen < 126 && wsctx->nReadRaw >= 6) { - wsctx->header.headerLen = 2 + WS_HYBI_MASK_LEN; - wsctx->header.mask = wsctx->header.data->u.m; - } else if (wsctx->header.payloadLen == 126 && 8 <= wsctx->nReadRaw) { - wsctx->header.headerLen = 4 + WS_HYBI_MASK_LEN; - wsctx->header.payloadLen = WS_NTOH16(wsctx->header.data->u.s16.l16); - wsctx->header.mask = wsctx->header.data->u.s16.m16; - } else if (wsctx->header.payloadLen == 127 && 14 <= wsctx->nReadRaw) { - wsctx->header.headerLen = 10 + WS_HYBI_MASK_LEN; - wsctx->header.payloadLen = WS_NTOH64(wsctx->header.data->u.s64.l64); - wsctx->header.mask = wsctx->header.data->u.s64.m64; - } else { - /* Incomplete frame header, try again */ - rfbErr("%s: incomplete frame header; ret=%d\n", __func__, ret); - errno = EAGAIN; - *sockRet = -1; - return WS_HYBI_STATE_HEADER_PENDING; - } - - /* absolute length of frame */ - wsctx->nToRead = wsctx->header.headerLen + wsctx->header.payloadLen; - - /* set payload pointer just after header */ - wsctx->writePos = wsctx->codeBufDecode + wsctx->nReadRaw; - - wsctx->readPos = (unsigned char *)(wsctx->codeBufDecode + wsctx->header.headerLen); - - rfbLog("header complete: state=%d flen=%d writeTo=%p\n", wsctx->hybiDecodeState, wsctx->nToRead, wsctx->writePos); - - return WS_HYBI_STATE_DATA_NEEDED; -} - -static int -hybiWsFrameComplete(ws_ctx_t *wsctx) -{ - return wsctx != NULL && hybiRemaining(wsctx) == 0; -} - -static char * -hybiPayloadStart(ws_ctx_t *wsctx) -{ - return wsctx->codeBufDecode + wsctx->header.headerLen; -} - - -/** - * Read the remaining payload bytes from associated raw socket. - * - * - try to read remaining bytes from socket - * - unmask all multiples of 4 - * - if frame incomplete but some bytes are left, these are copied to - * the carry buffer - * - if opcode is TEXT: Base64-decode all unmasked received bytes - * - set state for reading decoded data - * - reset write position to begin of buffer (+ header) - * --> before we retrieve more data we let the caller clear all bytes - * from the reception buffer - * - execute return data routine - * - * Sets errno corresponding to what it gets from the underlying - * socket or EIO if some internal sanity check fails. - * - * @param[in] cl client ptr with raw socket reference - * @param[out] dst destination buffer - * @param[in] len size of destination buffer - * @param[out] sockRet emulated recv return value - * @return next hybi decode state - */ -static int -hybiReadAndDecode(rfbClientPtr cl, char *dst, int len, int *sockRet) -{ - int n; - int i; - int toReturn; - int toDecode; - int bufsize; - int nextRead; - unsigned char *data; - uint32_t *data32; - ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; - - /* if data was carried over, copy to start of buffer */ - memcpy(wsctx->writePos, wsctx->carryBuf, wsctx->carrylen); - wsctx->writePos += wsctx->carrylen; - - /* -1 accounts for potential '\0' terminator for base64 decoding */ - bufsize = wsctx->codeBufDecode + ARRAYSIZE(wsctx->codeBufDecode) - wsctx->writePos - 1; - if (hybiRemaining(wsctx) > bufsize) { - nextRead = bufsize; - } else { - nextRead = hybiRemaining(wsctx); - } - - rfbLog("calling read with buf=%p and len=%d (decodebuf=%p headerLen=%d\n)", wsctx->writePos, nextRead, wsctx->codeBufDecode, wsctx->header.headerLen); - - if (wsctx->nReadRaw < wsctx->nToRead) { - /* decode more data */ - if (-1 == (n = ws_read(cl, wsctx->writePos, nextRead))) { - int olderrno = errno; - rfbErr("%s: read; %m", __func__); - errno = olderrno; - *sockRet = -1; - return WS_HYBI_STATE_ERR; - } else if (n == 0) { - *sockRet = 0; - return WS_HYBI_STATE_ERR; - } - wsctx->nReadRaw += n; - rfbLog("read %d bytes from socket; nRead=%d\n", n, wsctx->nReadRaw); - } else { - n = 0; - } - - wsctx->writePos += n; - - if (wsctx->nReadRaw >= wsctx->nToRead) { - if (wsctx->nReadRaw > wsctx->nToRead) { - rfbErr("%s: internal error, read past websocket frame", __func__); - errno=EIO; - *sockRet = -1; - return WS_HYBI_STATE_ERR; - } - } - - toDecode = wsctx->writePos - hybiPayloadStart(wsctx); - rfbLog("toDecode=%d from n=%d carrylen=%d headerLen=%d\n", toDecode, n, wsctx->carrylen, wsctx->header.headerLen); - if (toDecode < 0) { - rfbErr("%s: internal error; negative number of bytes to decode: %d", __func__, toDecode); - errno=EIO; - *sockRet = -1; - return WS_HYBI_STATE_ERR; - } - - /* for a possible base64 decoding, we decode multiples of 4 bytes until - * the whole frame is received and carry over any remaining bytes in the carry buf*/ - data = (unsigned char *)hybiPayloadStart(wsctx); - data32= (uint32_t *)data; - - for (i = 0; i < (toDecode >> 2); i++) { - data32[i] ^= wsctx->header.mask.u; - } - rfbLog("mask decoding; i=%d toDecode=%d\n", i, toDecode); - - if (wsctx->hybiDecodeState == WS_HYBI_STATE_FRAME_COMPLETE) { - /* process the remaining bytes (if any) */ - for (i*=4; i < toDecode; i++) { - data[i] ^= wsctx->header.mask.c[i % 4]; - } - - /* all data is here, no carrying */ - wsctx->carrylen = 0; - } else { - /* carry over remaining, non-multiple-of-four bytes */ - wsctx->carrylen = toDecode - (i * 4); - if (wsctx->carrylen < 0 || wsctx->carrylen > ARRAYSIZE(wsctx->carryBuf)) { - rfbErr("%s: internal error, invalid carry over size: carrylen=%d, toDecode=%d, i=%d", __func__, wsctx->carrylen, toDecode, i); - *sockRet = -1; - errno = EIO; - return WS_HYBI_STATE_ERR; - } - rfbLog("carrying over %d bytes from %p to %p\n", wsctx->carrylen, wsctx->writePos + (i * 4), wsctx->carryBuf); - memcpy(wsctx->carryBuf, data + (i * 4), wsctx->carrylen); - } - - toReturn = toDecode - wsctx->carrylen; - - switch (wsctx->header.opcode) { - case WS_OPCODE_CLOSE: - - /* this data is not returned as payload data */ - if (hybiWsFrameComplete(wsctx)) { - rfbLog("got closure, reason %d\n", WS_NTOH16(((uint16_t *)data)[0])); - errno = ECONNRESET; - *sockRet = -1; - return WS_HYBI_STATE_FRAME_COMPLETE; - } else { - rfbErr("%s: close reason with long frame not supported", __func__); - errno = EIO; - *sockRet = -1; - return WS_HYBI_STATE_ERR; - } - break; - case WS_OPCODE_TEXT_FRAME: - data[toReturn] = '\0'; - rfbLog("Initiate Base64 decoding in %p with max size %d and '\\0' at %p\n", data, bufsize, data + toReturn); - if (-1 == (wsctx->readlen = b64_pton((char *)data, data, bufsize))) { - rfbErr("Base64 decode error in %s; data=%p bufsize=%d", __func__, data, bufsize); - rfbErr("%s: Base64 decode error; %m\n", __func__); - } - wsctx->writePos = hybiPayloadStart(wsctx); - break; - case WS_OPCODE_BINARY_FRAME: - wsctx->readlen = toReturn; - wsctx->writePos = hybiPayloadStart(wsctx); - break; - default: - rfbErr("%s: unhandled opcode %d, b0: %02x, b1: %02x\n", __func__, (int)wsctx->header.opcode, wsctx->header.data->b0, wsctx->header.data->b1); - } - wsctx->readPos = data; - - return hybiReturnData(dst, len, wsctx, sockRet); -} - -/** - * Read function for websocket-socket emulation. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-------+-+-------------+-------------------------------+ - * |F|R|R|R| opcode|M| Payload len | Extended payload length | - * |I|S|S|S| (4) |A| (7) | (16/64) | - * |N|V|V|V| |S| | (if payload len==126/127) | - * | |1|2|3| |K| | | - * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + - * | Extended payload length continued, if payload len == 127 | - * + - - - - - - - - - - - - - - - +-------------------------------+ - * | |Masking-key, if MASK set to 1 | - * +-------------------------------+-------------------------------+ - * | Masking-key (continued) | Payload Data | - * +-------------------------------- - - - - - - - - - - - - - - - + - * : Payload Data continued ... : - * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - * | Payload Data continued ... | - * +---------------------------------------------------------------+ - * - * Using the decode buffer, this function: - * - reads the complete header from the underlying socket - * - reads any remaining data bytes - * - unmasks the payload data using the provided mask - * - decodes Base64 encoded text data - * - copies len bytes of decoded payload data into dst - * - * Emulates a read call on a socket. - */ -static int -webSocketsDecodeHybi(rfbClientPtr cl, char *dst, int len) -{ - int result = -1; - ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; - /* int fin; */ /* not used atm */ - - /* rfbLog(" <== %s[%d]: %d cl: %p, wsctx: %p-%p (%d)\n", __func__, gettid(), len, cl, wsctx, (char *)wsctx + sizeof(ws_ctx_t), sizeof(ws_ctx_t)); */ - rfbLog("%s_enter: len=%d; " - "CTX: readlen=%d readPos=%p " - "writeTo=%p " - "state=%d toRead=%d remaining=%d " - " nReadRaw=%d carrylen=%d carryBuf=%p\n", - __func__, len, - wsctx->readlen, wsctx->readPos, - wsctx->writePos, - wsctx->hybiDecodeState, wsctx->nToRead, hybiRemaining(wsctx), - wsctx->nReadRaw, wsctx->carrylen, wsctx->carryBuf); - - switch (wsctx->hybiDecodeState){ - case WS_HYBI_STATE_HEADER_PENDING: - wsctx->hybiDecodeState = hybiReadHeader(cl, &result); - if (wsctx->hybiDecodeState == WS_HYBI_STATE_ERR) { - goto spor; - } - if (wsctx->hybiDecodeState != WS_HYBI_STATE_HEADER_PENDING) { - - /* when header is complete, try to read some more data */ - wsctx->hybiDecodeState = hybiReadAndDecode(cl, dst, len, &result); - } - break; - case WS_HYBI_STATE_DATA_AVAILABLE: - wsctx->hybiDecodeState = hybiReturnData(dst, len, wsctx, &result); - break; - case WS_HYBI_STATE_DATA_NEEDED: - wsctx->hybiDecodeState = hybiReadAndDecode(cl, dst, len, &result); - break; - case WS_HYBI_STATE_CLOSE_REASON_PENDING: - wsctx->hybiDecodeState = hybiReadAndDecode(cl, dst, len, &result); - break; - default: - /* invalid state */ - rfbErr("%s: called with invalid state %d\n", wsctx->hybiDecodeState); - result = -1; - errno = EIO; - wsctx->hybiDecodeState = WS_HYBI_STATE_ERR; - } - - /* single point of return, if someone has questions :-) */ -spor: - /* rfbLog("%s: ret: %d/%d\n", __func__, result, len); */ - if (wsctx->hybiDecodeState == WS_HYBI_STATE_FRAME_COMPLETE) { - rfbLog("frame received successfully, cleaning up: read=%d hlen=%d plen=%d\n", wsctx->header.nRead, wsctx->header.headerLen, wsctx->header.payloadLen); - /* frame finished, cleanup state */ - hybiDecodeCleanup(wsctx); - } else if (wsctx->hybiDecodeState == WS_HYBI_STATE_ERR) { - hybiDecodeCleanup(wsctx); - } - rfbLog("%s_exit: len=%d; " - "CTX: readlen=%d readPos=%p " - "writePos=%p " - "state=%d toRead=%d remaining=%d " - "nRead=%d carrylen=%d carryBuf=%p " - "result=%d\n", - __func__, len, - wsctx->readlen, wsctx->readPos, - wsctx->writePos, - wsctx->hybiDecodeState, wsctx->nToRead, hybiRemaining(wsctx), - wsctx->nReadRaw, wsctx->carrylen, wsctx->carryBuf, - result); - return result; -} - static int webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst) { @@ -1210,7 +651,9 @@ webSocketsEncode(rfbClientPtr cl, const char *src, int len, char **dst) int webSocketsDecode(rfbClientPtr cl, char *dst, int len) { - return ((ws_ctx_t *)cl->wsctx)->decode(cl, dst, len); + ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; + wsctx->ctxInfo.ctxPtr = cl; + return wsctx->decode(wsctx, dst, len); } diff --git a/libvncserver/ws_decode.c b/libvncserver/ws_decode.c new file mode 100644 index 0000000..e74a33c --- /dev/null +++ b/libvncserver/ws_decode.c @@ -0,0 +1,448 @@ +#include "ws_decode.h" + +#include +#include +#include + +#define WS_HYBI_MASK_LEN 4 + + +static int +hybiRemaining(ws_ctx_t *wsctx) +{ + return wsctx->nToRead - wsctx->nReadRaw; +} + +void +hybiDecodeCleanup(ws_ctx_t *wsctx) +{ + wsctx->header.payloadLen = 0; + wsctx->header.mask.u = 0; + wsctx->nReadRaw = 0; + wsctx->nToRead= 0; + wsctx->carrylen = 0; + wsctx->readPos = (unsigned char *)wsctx->codeBufDecode; + wsctx->readlen = 0; + wsctx->hybiDecodeState = WS_HYBI_STATE_HEADER_PENDING; + wsctx->writePos = NULL; + rfbLog("cleaned up wsctx\n"); +} + +/** + * Return payload data that has been decoded/unmasked from + * a websocket frame. + * + * @param[out] dst destination buffer + * @param[in] len bytes to copy to destination buffer + * @param[in,out] wsctx internal state of decoding procedure + * @param[out] number of bytes actually written to dst buffer + * @return next hybi decoding state + */ +static int +hybiReturnData(char *dst, int len, ws_ctx_t *wsctx, int *nWritten) +{ + int nextState = WS_HYBI_STATE_ERR; + + /* if we have something already decoded copy and return */ + if (wsctx->readlen > 0) { + /* simply return what we have */ + if (wsctx->readlen > len) { + rfbLog("copy to %d bytes to dst buffer; readPos=%p, readLen=%d\n", len, wsctx->readPos, wsctx->readlen); + memcpy(dst, wsctx->readPos, len); + *nWritten = len; + wsctx->readlen -= len; + wsctx->readPos += len; + nextState = WS_HYBI_STATE_DATA_AVAILABLE; + } else { + rfbLog("copy to %d bytes to dst buffer; readPos=%p, readLen=%d\n", wsctx->readlen, wsctx->readPos, wsctx->readlen); + memcpy(dst, wsctx->readPos, wsctx->readlen); + *nWritten = wsctx->readlen; + wsctx->readlen = 0; + wsctx->readPos = NULL; + if (hybiRemaining(wsctx) == 0) { + nextState = WS_HYBI_STATE_FRAME_COMPLETE; + } else { + nextState = WS_HYBI_STATE_DATA_NEEDED; + } + } + rfbLog("after copy: readPos=%p, readLen=%d\n", wsctx->readPos, wsctx->readlen); + } else if (wsctx->hybiDecodeState == WS_HYBI_STATE_CLOSE_REASON_PENDING) { + nextState = WS_HYBI_STATE_CLOSE_REASON_PENDING; + } + return nextState; +} + +/** + * Read an RFC 6455 websocket frame (IETF hybi working group). + * + * Internal state is updated according to bytes received and the + * decoding of header information. + * + * @param[in] cl client ptr with ptr to raw socket and ws_ctx_t ptr + * @param[out] sockRet emulated recv return value + * @return next hybi decoding state; WS_HYBI_STATE_HEADER_PENDING indicates + * that the header was not received completely. + */ +static int +hybiReadHeader(ws_ctx_t *wsctx, int *sockRet) +{ + int ret; + char *headerDst = wsctx->codeBufDecode + wsctx->nReadRaw; + int n = WSHLENMAX - wsctx->nReadRaw; + + rfbLog("header_read to %p with len=%d\n", headerDst, n); + //ret = ws_read(cl, headerDst, n); + ret = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, headerDst, n); + rfbLog("read %d bytes from socket\n", ret); + if (ret <= 0) { + if (-1 == ret) { + /* save errno because rfbErr() will tamper it */ + int olderrno = errno; + rfbErr("%s: peek; %m\n", __func__); + errno = olderrno; + *sockRet = -1; + } else { + *sockRet = 0; + } + return WS_HYBI_STATE_ERR; + } + + wsctx->nReadRaw += ret; + if (wsctx->nReadRaw < 2) { + /* cannot decode header with less than two bytes */ + errno = EAGAIN; + *sockRet = -1; + return WS_HYBI_STATE_HEADER_PENDING; + } + + /* first two header bytes received; interpret header data and get rest */ + wsctx->header.data = (ws_header_t *)wsctx->codeBufDecode; + + wsctx->header.opcode = wsctx->header.data->b0 & 0x0f; + + /* fin = (header->b0 & 0x80) >> 7; */ /* not used atm */ + wsctx->header.payloadLen = wsctx->header.data->b1 & 0x7f; + rfbLog("first header bytes received; opcode=%d lenbyte=%d\n", wsctx->header.opcode, wsctx->header.payloadLen); + + /* + * 4.3. Client-to-Server Masking + * + * The client MUST mask all frames sent to the server. A server MUST + * close the connection upon receiving a frame with the MASK bit set to 0. + **/ + if (!(wsctx->header.data->b1 & 0x80)) { + rfbErr("%s: got frame without mask ret=%d\n", __func__, ret); + syslog(LOG_ERR, "%s: got frame without mask; ret=%d\n", __func__, ret); + errno = EIO; + *sockRet = -1; + return WS_HYBI_STATE_ERR; + } + + if (wsctx->header.payloadLen < 126 && wsctx->nReadRaw >= 6) { + wsctx->header.headerLen = 2 + WS_HYBI_MASK_LEN; + wsctx->header.mask = wsctx->header.data->u.m; + } else if (wsctx->header.payloadLen == 126 && 8 <= wsctx->nReadRaw) { + wsctx->header.headerLen = 4 + WS_HYBI_MASK_LEN; + wsctx->header.payloadLen = WS_NTOH16(wsctx->header.data->u.s16.l16); + wsctx->header.mask = wsctx->header.data->u.s16.m16; + } else if (wsctx->header.payloadLen == 127 && 14 <= wsctx->nReadRaw) { + wsctx->header.headerLen = 10 + WS_HYBI_MASK_LEN; + wsctx->header.payloadLen = WS_NTOH64(wsctx->header.data->u.s64.l64); + wsctx->header.mask = wsctx->header.data->u.s64.m64; + } else { + /* Incomplete frame header, try again */ + rfbErr("%s: incomplete frame header; ret=%d\n", __func__, ret); + errno = EAGAIN; + *sockRet = -1; + return WS_HYBI_STATE_HEADER_PENDING; + } + + /* absolute length of frame */ + wsctx->nToRead = wsctx->header.headerLen + wsctx->header.payloadLen; + + /* update write position for next bytes */ + wsctx->writePos = wsctx->codeBufDecode + wsctx->nReadRaw; + + /* set payload pointer just after header */ + wsctx->readPos = (unsigned char *)(wsctx->codeBufDecode + wsctx->header.headerLen); + + rfbLog("header complete: state=%d flen=%d writeTo=%p\n", wsctx->hybiDecodeState, wsctx->nToRead, wsctx->writePos); + + return WS_HYBI_STATE_DATA_NEEDED; +} + +static int +hybiWsFrameComplete(ws_ctx_t *wsctx) +{ + return wsctx != NULL && hybiRemaining(wsctx) == 0; +} + +static char * +hybiPayloadStart(ws_ctx_t *wsctx) +{ + return wsctx->codeBufDecode + wsctx->header.headerLen; +} + + +/** + * Read the remaining payload bytes from associated raw socket. + * + * - try to read remaining bytes from socket + * - unmask all multiples of 4 + * - if frame incomplete but some bytes are left, these are copied to + * the carry buffer + * - if opcode is TEXT: Base64-decode all unmasked received bytes + * - set state for reading decoded data + * - reset write position to begin of buffer (+ header) + * --> before we retrieve more data we let the caller clear all bytes + * from the reception buffer + * - execute return data routine + * + * Sets errno corresponding to what it gets from the underlying + * socket or EIO if some internal sanity check fails. + * + * @param[in] cl client ptr with raw socket reference + * @param[out] dst destination buffer + * @param[in] len size of destination buffer + * @param[out] sockRet emulated recv return value + * @return next hybi decode state + */ +static int +hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet) +{ + int n; + int i; + int toReturn; + int toDecode; + int bufsize; + int nextRead; + unsigned char *data; + uint32_t *data32; + + /* if data was carried over, copy to start of buffer */ + memcpy(wsctx->writePos, wsctx->carryBuf, wsctx->carrylen); + wsctx->writePos += wsctx->carrylen; + + /* -1 accounts for potential '\0' terminator for base64 decoding */ + bufsize = wsctx->codeBufDecode + ARRAYSIZE(wsctx->codeBufDecode) - wsctx->writePos - 1; + if (hybiRemaining(wsctx) > bufsize) { + nextRead = bufsize; + } else { + nextRead = hybiRemaining(wsctx); + } + + rfbLog("calling read with buf=%p and len=%d (decodebuf=%p headerLen=%d)\n", wsctx->writePos, nextRead, wsctx->codeBufDecode, wsctx->header.headerLen); + + if (wsctx->nReadRaw < wsctx->nToRead) { + /* decode more data */ + //if (-1 == (n = ws_read(cl, wsctx->writePos, nextRead))) { + if (-1 == (n = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, wsctx->writePos, nextRead))) { + int olderrno = errno; + rfbErr("%s: read; %m", __func__); + errno = olderrno; + *sockRet = -1; + return WS_HYBI_STATE_ERR; + } else if (n == 0) { + *sockRet = 0; + return WS_HYBI_STATE_ERR; + } + wsctx->nReadRaw += n; + rfbLog("read %d bytes from socket; nRead=%d\n", n, wsctx->nReadRaw); + } else { + n = 0; + } + + wsctx->writePos += n; + + if (wsctx->nReadRaw >= wsctx->nToRead) { + if (wsctx->nReadRaw > wsctx->nToRead) { + rfbErr("%s: internal error, read past websocket frame", __func__); + errno=EIO; + *sockRet = -1; + return WS_HYBI_STATE_ERR; + } + } + + toDecode = wsctx->writePos - hybiPayloadStart(wsctx); + rfbLog("toDecode=%d from n=%d carrylen=%d headerLen=%d\n", toDecode, n, wsctx->carrylen, wsctx->header.headerLen); + if (toDecode < 0) { + rfbErr("%s: internal error; negative number of bytes to decode: %d", __func__, toDecode); + errno=EIO; + *sockRet = -1; + return WS_HYBI_STATE_ERR; + } + + /* for a possible base64 decoding, we decode multiples of 4 bytes until + * the whole frame is received and carry over any remaining bytes in the carry buf*/ + data = (unsigned char *)hybiPayloadStart(wsctx); + data32= (uint32_t *)data; + + for (i = 0; i < (toDecode >> 2); i++) { + data32[i] ^= wsctx->header.mask.u; + } + rfbLog("mask decoding; i=%d toDecode=%d\n", i, toDecode); + + if (wsctx->hybiDecodeState == WS_HYBI_STATE_FRAME_COMPLETE) { + /* process the remaining bytes (if any) */ + for (i*=4; i < toDecode; i++) { + data[i] ^= wsctx->header.mask.c[i % 4]; + } + + /* all data is here, no carrying */ + wsctx->carrylen = 0; + } else { + /* carry over remaining, non-multiple-of-four bytes */ + wsctx->carrylen = toDecode - (i * 4); + if (wsctx->carrylen < 0 || wsctx->carrylen > ARRAYSIZE(wsctx->carryBuf)) { + syslog(LOG_ERR, "%s: internal error, invalid carry over size: carrylen=%d, toDecode=%d, i=%d", __func__, wsctx->carrylen, toDecode, i); + *sockRet = -1; + errno = EIO; + return WS_HYBI_STATE_ERR; + } + rfbLog("carrying over %d bytes from %p to %p\n", wsctx->carrylen, wsctx->writePos + (i * 4), wsctx->carryBuf); + memcpy(wsctx->carryBuf, data + (i * 4), wsctx->carrylen); + } + + toReturn = toDecode - wsctx->carrylen; + + switch (wsctx->header.opcode) { + case WS_OPCODE_CLOSE: + + /* this data is not returned as payload data */ + if (hybiWsFrameComplete(wsctx)) { + rfbLog("got closure, reason %d\n", WS_NTOH16(((uint16_t *)data)[0])); + rfbLog("got close cmd, reason %d\n", WS_NTOH16(((uint16_t *)data)[0])); + errno = ECONNRESET; + *sockRet = -1; + return WS_HYBI_STATE_FRAME_COMPLETE; + } else { + rfbErr("%s: close reason with long frame not supported", __func__); + errno = EIO; + *sockRet = -1; + return WS_HYBI_STATE_ERR; + } + break; + case WS_OPCODE_TEXT_FRAME: + data[toReturn] = '\0'; + rfbLog("Initiate Base64 decoding in %p with max size %d and '\\0' at %p\n", data, bufsize, data + toReturn); + if (-1 == (wsctx->readlen = b64_pton((char *)data, data, bufsize))) { + syslog(LOG_ERR, "Base64 decode error in %s; data=%p bufsize=%d", __func__, data, bufsize); + rfbErr("%s: Base64 decode error; %m\n", __func__); + } + wsctx->writePos = hybiPayloadStart(wsctx); + break; + case WS_OPCODE_BINARY_FRAME: + wsctx->readlen = toReturn; + wsctx->writePos = hybiPayloadStart(wsctx); + rfbLog("set readlen=%d writePos=%p\n", wsctx->readlen, wsctx->writePos); + break; + default: + rfbErr("%s: unhandled opcode %d, b0: %02x, b1: %02x\n", __func__, (int)wsctx->header.opcode, wsctx->header.data->b0, wsctx->header.data->b1); + } + wsctx->readPos = data; + + return hybiReturnData(dst, len, wsctx, sockRet); +} + +/** + * Read function for websocket-socket emulation. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-------+-+-------------+-------------------------------+ + * |F|R|R|R| opcode|M| Payload len | Extended payload length | + * |I|S|S|S| (4) |A| (7) | (16/64) | + * |N|V|V|V| |S| | (if payload len==126/127) | + * | |1|2|3| |K| | | + * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + * | Extended payload length continued, if payload len == 127 | + * + - - - - - - - - - - - - - - - +-------------------------------+ + * | |Masking-key, if MASK set to 1 | + * +-------------------------------+-------------------------------+ + * | Masking-key (continued) | Payload Data | + * +-------------------------------- - - - - - - - - - - - - - - - + + * : Payload Data continued ... : + * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + * | Payload Data continued ... | + * +---------------------------------------------------------------+ + * + * Using the decode buffer, this function: + * - reads the complete header from the underlying socket + * - reads any remaining data bytes + * - unmasks the payload data using the provided mask + * - decodes Base64 encoded text data + * - copies len bytes of decoded payload data into dst + * + * Emulates a read call on a socket. + */ +int +webSocketsDecodeHybi(ws_ctx_t *wsctx, char *dst, int len) +{ + int result = -1; + /* int fin; */ /* not used atm */ + + /* rfbLog(" <== %s[%d]: %d cl: %p, wsctx: %p-%p (%d)\n", __func__, gettid(), len, cl, wsctx, (char *)wsctx + sizeof(ws_ctx_t), sizeof(ws_ctx_t)); */ + rfbLog("%s_enter: len=%d; " + "CTX: readlen=%d readPos=%p " + "writeTo=%p " + "state=%d toRead=%d remaining=%d " + " nReadRaw=%d carrylen=%d carryBuf=%p\n", + __func__, len, + wsctx->readlen, wsctx->readPos, + wsctx->writePos, + wsctx->hybiDecodeState, wsctx->nToRead, hybiRemaining(wsctx), + wsctx->nReadRaw, wsctx->carrylen, wsctx->carryBuf); + + switch (wsctx->hybiDecodeState){ + case WS_HYBI_STATE_HEADER_PENDING: + wsctx->hybiDecodeState = hybiReadHeader(wsctx, &result); + if (wsctx->hybiDecodeState == WS_HYBI_STATE_ERR) { + goto spor; + } + if (wsctx->hybiDecodeState != WS_HYBI_STATE_HEADER_PENDING) { + + /* when header is complete, try to read some more data */ + wsctx->hybiDecodeState = hybiReadAndDecode(wsctx, dst, len, &result); + } + break; + case WS_HYBI_STATE_DATA_AVAILABLE: + wsctx->hybiDecodeState = hybiReturnData(dst, len, wsctx, &result); + break; + case WS_HYBI_STATE_DATA_NEEDED: + wsctx->hybiDecodeState = hybiReadAndDecode(wsctx, dst, len, &result); + break; + case WS_HYBI_STATE_CLOSE_REASON_PENDING: + wsctx->hybiDecodeState = hybiReadAndDecode(wsctx, dst, len, &result); + break; + default: + /* invalid state */ + rfbErr("%s: called with invalid state %d\n", wsctx->hybiDecodeState); + result = -1; + errno = EIO; + wsctx->hybiDecodeState = WS_HYBI_STATE_ERR; + } + + /* single point of return, if someone has questions :-) */ +spor: + /* rfbLog("%s: ret: %d/%d\n", __func__, result, len); */ + if (wsctx->hybiDecodeState == WS_HYBI_STATE_FRAME_COMPLETE) { + rfbLog("frame received successfully, cleaning up: read=%d hlen=%d plen=%d\n", wsctx->header.nRead, wsctx->header.headerLen, wsctx->header.payloadLen); + /* frame finished, cleanup state */ + hybiDecodeCleanup(wsctx); + } else if (wsctx->hybiDecodeState == WS_HYBI_STATE_ERR) { + hybiDecodeCleanup(wsctx); + } + rfbLog("%s_exit: len=%d; " + "CTX: readlen=%d readPos=%p " + "writePos=%p " + "state=%d toRead=%d remaining=%d " + "nRead=%d carrylen=%d carryBuf=%p " + "result=%d\n", + __func__, len, + wsctx->readlen, wsctx->readPos, + wsctx->writePos, + wsctx->hybiDecodeState, wsctx->nToRead, hybiRemaining(wsctx), + wsctx->nReadRaw, wsctx->carrylen, wsctx->carryBuf, + result); + return result; +} diff --git a/libvncserver/ws_decode.h b/libvncserver/ws_decode.h new file mode 100644 index 0000000..e75c4d1 --- /dev/null +++ b/libvncserver/ws_decode.h @@ -0,0 +1,160 @@ +#ifndef _WS_DECODE_H_ +#define _WS_DECODE_H_ + +#include +#include +#ifndef _MSC_VER +#include /* __b64_ntop */ +#endif + + + +enum { + WEBSOCKETS_VERSION_HIXIE, + WEBSOCKETS_VERSION_HYBI +}; + +#if defined(__APPLE__) + +#include +#define WS_NTOH64(n) OSSwapBigToHostInt64(n) +#define WS_NTOH32(n) OSSwapBigToHostInt32(n) +#define WS_NTOH16(n) OSSwapBigToHostInt16(n) +#define WS_HTON64(n) OSSwapHostToBigInt64(n) +#define WS_HTON16(n) OSSwapHostToBigInt16(n) + +#else + +#define WS_NTOH64(n) htobe64(n) +#define WS_NTOH32(n) htobe32(n) +#define WS_NTOH16(n) htobe16(n) +#define WS_HTON64(n) htobe64(n) +#define WS_HTON16(n) htobe16(n) + +#endif + +#define B64LEN(__x) (((__x + 2) / 3) * 12 / 3) +#define WSHLENMAX 14 /* 2 + sizeof(uint64_t) + sizeof(uint32_t) */ +#define WS_HYBI_MASK_LEN 4 + +#define ARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))) / (size_t)(!(sizeof(a) % sizeof((a[0]))))) + +enum { + WEBSOCKETS_VERSION_HIXIE, + WEBSOCKETS_VERSION_HYBI +}; + +struct ws_ctx_s; +typedef struct ws_ctx_s ws_ctx_t; + +typedef int (*wsEncodeFunc)(rfbClientPtr cl, const char *src, int len, char **dst); +typedef int (*wsDecodeFunc)(ws_ctx_t *wsctx, char *dst, int len); + +typedef int (*wsReadFunc)(void *ctx, char *dst, int len); +typedef int (*wsPeekFunc)(void *ctx, char *dst, int len); + +typedef struct ctxInfo_s{ + void *ctxPtr; + wsReadFunc readFunc; + wsPeekFunc peekFunc; +} ctxInfo_t; + +enum { + /* header not yet received completely */ + WS_HYBI_STATE_HEADER_PENDING, + /* data available */ + WS_HYBI_STATE_DATA_AVAILABLE, + WS_HYBI_STATE_DATA_NEEDED, + /* received a complete frame */ + WS_HYBI_STATE_FRAME_COMPLETE, + /* received part of a 'close' frame */ + WS_HYBI_STATE_CLOSE_REASON_PENDING, + /* */ + WS_HYBI_STATE_ERR +}; + +typedef union ws_mask_s { + char c[4]; + uint32_t u; +} ws_mask_t; + +/* XXX: The union and the structs do not need to be named. + * We are working around a bug present in GCC < 4.6 which prevented + * it from recognizing anonymous structs and unions. + * See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=4784 + */ +typedef struct +#if __GNUC__ +__attribute__ ((__packed__)) +#endif +ws_header_s { + unsigned char b0; + unsigned char b1; + union { + struct +#if __GNUC__ + __attribute__ ((__packed__)) +#endif + { + uint16_t l16; + ws_mask_t m16; + } s16; + struct +#if __GNUC__ +__attribute__ ((__packed__)) +#endif + { + uint64_t l64; + ws_mask_t m64; + } s64; + ws_mask_t m; + } u; +} ws_header_t; + +typedef struct ws_header_data_s { + ws_header_t *data; + /** bytes read */ + int nRead; + /** mask value */ + ws_mask_t mask; + /** length of frame header including payload len, but without mask */ + int headerLen; + /** length of the payload data */ + int payloadLen; + /** opcode */ + unsigned char opcode; +} ws_header_data_t; + +typedef struct ws_ctx_s { + char codeBufDecode[2048 + WSHLENMAX]; /* base64 + maximum frame header length */ + char codeBufEncode[B64LEN(UPDATE_BUF_SIZE) + WSHLENMAX]; /* base64 + maximum frame header length */ + char *writePos; + unsigned char *readPos; + int readlen; + int hybiDecodeState; + char carryBuf[3]; /* For base64 carry-over */ + int carrylen; + int version; + int base64; + ws_header_data_t header; + int nReadRaw; + int nToRead; + wsEncodeFunc encode; + wsDecodeFunc decode; + ctxInfo_t ctxInfo; +} ws_ctx_t; + +enum +{ + WS_OPCODE_CONTINUATION = 0x0, + WS_OPCODE_TEXT_FRAME, + WS_OPCODE_BINARY_FRAME, + WS_OPCODE_CLOSE = 0x8, + WS_OPCODE_PING, + WS_OPCODE_PONG +}; + +int webSocketsDecodeHybi(ws_ctx_t *wsctx, char *dst, int len); + +void hybiDecodeCleanup(ws_ctx_t *wsctx); +#endif -- cgit v1.2.3 From a2322e70069b30fb4f86248d6a6bce6d2a9c11e1 Mon Sep 17 00:00:00 2001 From: Andreas Weigel Date: Thu, 16 Feb 2017 10:24:20 +0100 Subject: remove obsolete hixie protocol support --- libvncserver/websockets.c | 297 ++++++++-------------------------------------- 1 file changed, 51 insertions(+), 246 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index ab947ae..364225b 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -70,14 +70,6 @@ static int gettid() { */ #define GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" -#define SERVER_HANDSHAKE_HIXIE "HTTP/1.1 101 Web Socket Protocol Handshake\r\n\ -Upgrade: WebSocket\r\n\ -Connection: Upgrade\r\n\ -%sWebSocket-Origin: %s\r\n\ -%sWebSocket-Location: %s://%s%s\r\n\ -%sWebSocket-Protocol: %s\r\n\ -\r\n%s" - #define SERVER_HANDSHAKE_HYBI "HTTP/1.1 101 Switching Protocols\r\n\ Upgrade: websocket\r\n\ Connection: Upgrade\r\n\ @@ -107,8 +99,6 @@ static rfbBool webSocketsHandshake(rfbClientPtr cl, char *scheme); void webSocketsGenMd5(char * target, char *key1, char *key2, char *key3); static int webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst); -static int webSocketsEncodeHixie(rfbClientPtr cl, const char *src, int len, char **dst); -static int webSocketsDecodeHixie(ws_ctx_t *wsctx, char *dst, int len); static int ws_read(void *cl, char *buf, int len); static int ws_peek(void *cl, char *buf, int len); @@ -221,8 +211,8 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) rfbLog("webSocketsHandshake: client gone\n"); else rfbLogPerror("webSocketsHandshake: read"); - free(response); - free(buf); + free(response); + free(buf); return FALSE; } @@ -275,24 +265,33 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) /* rfbLog("Got key2: %s\n", key2); */ /* HyBI */ - } else if ((strncasecmp("sec-websocket-protocol: ", line, min(llen,24))) == 0) { + } else if ((strncasecmp("sec-websocket-protocol: ", line, min(llen,24))) == 0) { protocol = line+24; buf[len-2] = '\0'; rfbLog("Got protocol: %s\n", protocol); } else if ((strncasecmp("sec-websocket-origin: ", line, min(llen,22))) == 0) { - sec_ws_origin = line+22; + sec_ws_origin = line+22; buf[len-2] = '\0'; } else if ((strncasecmp("sec-websocket-key: ", line, min(llen,19))) == 0) { - sec_ws_key = line+19; + sec_ws_key = line+19; buf[len-2] = '\0'; } else if ((strncasecmp("sec-websocket-version: ", line, min(llen,23))) == 0) { - sec_ws_version = strtol(line+23, NULL, 10); + sec_ws_version = strtol(line+23, NULL, 10); buf[len-2] = '\0'; - } + } linestart = len; } } + + /* older hixie handshake, this could be removed if + * a final standard is established -- removed now */ + if (!sec_ws_version) { + rfbErr("Hixie no longer supported\n"); + free(response); + free(buf); + return FALSE; + } if (!(path && host && (origin || sec_ws_origin))) { rfbErr("webSocketsHandshake: incomplete client handshake\n"); @@ -302,12 +301,6 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) } if ((protocol) && (strstr(protocol, "binary"))) { - if (! sec_ws_version) { - rfbErr("webSocketsHandshake: 'binary' protocol not supported with Hixie\n"); - free(response); - free(buf); - return FALSE; - } rfbLog(" - webSocketsHandshake: using binary/raw encoding\n"); base64 = FALSE; protocol = "binary"; @@ -325,32 +318,16 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) * Generate the WebSockets server response based on the the headers sent * by the client. */ + char accept[B64LEN(SHA1_HASH_SIZE) + 1]; + rfbLog(" - WebSockets client version hybi-%02d\n", sec_ws_version); + webSocketsGenSha1Key(accept, sizeof(accept), sec_ws_key); - if (sec_ws_version) { - char accept[B64LEN(SHA1_HASH_SIZE) + 1]; - rfbLog(" - WebSockets client version hybi-%02d\n", sec_ws_version); - webSocketsGenSha1Key(accept, sizeof(accept), sec_ws_key); - if(strlen(protocol) > 0) - len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN, - SERVER_HANDSHAKE_HYBI, accept, protocol); - else - len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN, - SERVER_HANDSHAKE_HYBI_NO_PROTOCOL, accept); + if(strlen(protocol) > 0) { + len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN, + SERVER_HANDSHAKE_HYBI, accept, protocol); } else { - /* older hixie handshake, this could be removed if - * a final standard is established */ - if (!(key1 && key2 && key3)) { - rfbLog(" - WebSockets client version hixie-75\n"); - prefix[0] = '\0'; - trailer[0] = '\0'; - } else { - rfbLog(" - WebSockets client version hixie-76\n"); - snprintf(prefix, 5, "Sec-"); - webSocketsGenMd5(trailer, key1, key2, key3); - } - len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN, - SERVER_HANDSHAKE_HIXIE, prefix, origin, prefix, scheme, - host, path, prefix, protocol, trailer); + len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN, + SERVER_HANDSHAKE_HYBI_NO_PROTOCOL, accept); } if (rfbWriteExact(cl, response, len) < 0) { @@ -363,17 +340,10 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) free(response); free(buf); - wsctx = calloc(1, sizeof(ws_ctx_t)); - if (sec_ws_version) { - wsctx->version = WEBSOCKETS_VERSION_HYBI; - wsctx->encode = webSocketsEncodeHybi; - wsctx->decode = webSocketsDecodeHybi; - } else { - wsctx->version = WEBSOCKETS_VERSION_HIXIE; - wsctx->encode = webSocketsEncodeHixie; - wsctx->decode = webSocketsDecodeHixie; - } + wsctx->version = WEBSOCKETS_VERSION_HYBI; + wsctx->encode = webSocketsEncodeHybi; + wsctx->decode = webSocketsDecodeHybi; wsctx->ctxInfo.readFunc = ws_read; wsctx->ctxInfo.peekFunc = ws_peek; wsctx->base64 = base64; @@ -432,33 +402,15 @@ webSocketsGenMd5(char * target, char *key1, char *key2, char *key3) return; } -static int -webSocketsEncodeHixie(rfbClientPtr cl, const char *src, int len, char **dst) -{ - int sz = 0; - ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; - - wsctx->codeBufEncode[sz++] = '\x00'; - len = b64_ntop((unsigned char *)src, len, wsctx->codeBufEncode+sz, sizeof(wsctx->codeBufEncode) - (sz + 1)); - if (len < 0) { - return len; - } - sz += len; - - wsctx->codeBufEncode[sz++] = '\xff'; - *dst = wsctx->codeBufEncode; - return sz; -} - static int ws_read(void *ctxPtr, char *buf, int len) { int n; rfbClientPtr cl = ctxPtr; if (cl->sslctx) { - n = rfbssl_read(cl, buf, len); + n = rfbssl_read(cl, buf, len); } else { - n = read(cl->sock, buf, len); + n = read(cl->sock, buf, len); } return n; } @@ -469,114 +421,16 @@ ws_peek(void *ctxPtr, char *buf, int len) int n; rfbClientPtr cl = ctxPtr; if (cl->sslctx) { - n = rfbssl_peek(cl, buf, len); + n = rfbssl_peek(cl, buf, len); } else { - while (-1 == (n = recv(cl->sock, buf, len, MSG_PEEK))) { - if (errno != EAGAIN) - break; - } + while (-1 == (n = recv(cl->sock, buf, len, MSG_PEEK))) { + if (errno != EAGAIN) + break; + } } return n; } -static int -webSocketsDecodeHixie(ws_ctx_t *wsctx, char *dst, int len) -{ - int retlen = 0, n, i, avail, modlen, needlen; - char *buf, *end = NULL; - - buf = wsctx->codeBufDecode; - - //n = ws_peek(cl, buf, len*2+2); - n = wsctx->ctxInfo.peekFunc(wsctx->ctxInfo.ctxPtr, buf, len*2+2); - - if (n <= 0) { - /* save errno because rfbErr() will tamper it */ - int olderrno = errno; - rfbErr("%s: peek (%d) %m\n", __func__, errno); - errno = olderrno; - return n; - } - - - /* Base64 encoded WebSockets stream */ - - if (buf[0] == '\xff') { - //i = ws_read(cl, buf, 1); /* Consume marker */ - i = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, buf, 1); - buf++; - n--; - } - if (n == 0) { - errno = EAGAIN; - return -1; - } - if (buf[0] == '\x00') { - //i = ws_read(cl, buf, 1); /* Consume marker */ - i = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, buf, 1); - buf++; - n--; - } - if (n == 0) { - errno = EAGAIN; - return -1; - } - - /* end = memchr(buf, '\xff', len*2+2); */ - end = memchr(buf, '\xff', n); - if (!end) { - end = buf + n; - } - avail = end - buf; - - len -= wsctx->carrylen; - - /* Determine how much base64 data we need */ - modlen = len + (len+2)/3; - needlen = modlen; - if (needlen % 4) { - needlen += 4 - (needlen % 4); - } - - if (needlen > avail) { - /* rfbLog("Waiting for more base64 data\n"); */ - errno = EAGAIN; - return -1; - } - - /* Any carryover from previous decode */ - for (i=0; i < wsctx->carrylen; i++) { - /* rfbLog("Adding carryover %d\n", wsctx->carryBuf[i]); */ - dst[i] = wsctx->carryBuf[i]; - retlen += 1; - } - - /* Decode the rest of what we need */ - buf[needlen] = '\x00'; /* Replace end marker with end of string */ - /* rfbLog("buf: %s\n", buf); */ - n = b64_pton(buf, (unsigned char *)dst+retlen, 2+len); - if (n < len) { - rfbErr("Base64 decode error\n"); - errno = EIO; - return -1; - } - retlen += n; - - /* Consume the data from socket */ - //i = ws_read(cl, buf, needlen); - i = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, buf, needlen); - - wsctx->carrylen = n - len; - retlen -= wsctx->carrylen; - for (i=0; i < wsctx->carrylen; i++) { - /* rfbLog("Saving carryover %d\n", dst[retlen + i]); */ - wsctx->carryBuf[i] = dst[retlen + i]; - } - - /* rfbLog("<< webSocketsDecode, retlen: %d\n", retlen); */ - return retlen; -} - static int webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst) { @@ -602,12 +456,12 @@ webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst) header = (ws_header_t *)wsctx->codeBufEncode; if (wsctx->base64) { - opcode = WS_OPCODE_TEXT_FRAME; - /* calculate the resulting size */ - blen = B64LEN(len); + opcode = WS_OPCODE_TEXT_FRAME; + /* calculate the resulting size */ + blen = B64LEN(len); } else { - opcode = WS_OPCODE_BINARY_FRAME; - blen = len; + opcode = WS_OPCODE_BINARY_FRAME; + blen = len; } header->b0 = 0x80 | (opcode & 0x0f); @@ -626,15 +480,15 @@ webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst) if (wsctx->base64) { if (-1 == (ret = b64_ntop((unsigned char *)src, len, wsctx->codeBufEncode + sz, sizeof(wsctx->codeBufEncode) - sz))) { - rfbErr("%s: Base 64 encode failed\n", __func__); - } else { - if (ret != blen) - rfbErr("%s: Base 64 encode; something weird happened\n", __func__); - ret += sz; - } + rfbErr("%s: Base 64 encode failed\n", __func__); + } else { + if (ret != blen) + rfbErr("%s: Base 64 encode; something weird happened\n", __func__); + ret += sz; + } } else { - memcpy(wsctx->codeBufEncode + sz, src, len); - ret = sz + len; + memcpy(wsctx->codeBufEncode + sz, src, len); + ret = sz + len; } *dst = wsctx->codeBufEncode; @@ -645,7 +499,7 @@ webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst) int webSocketsEncode(rfbClientPtr cl, const char *src, int len, char **dst) { - return ((ws_ctx_t *)cl->wsctx)->encode(cl, src, len, dst); + return webSocketsEncodeHybi(cl, src, len, dst); } int @@ -653,67 +507,18 @@ webSocketsDecode(rfbClientPtr cl, char *dst, int len) { ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; wsctx->ctxInfo.ctxPtr = cl; - return wsctx->decode(wsctx, dst, len); + return webSocketsDecodeHybi(wsctx, dst, len); } /* returns TRUE if client sent a close frame or a single 'end of frame' * marker was received, FALSE otherwise * - * Note: This is a Hixie-only hack! + * Note: This was a Hixie-only hack! **/ rfbBool webSocketCheckDisconnect(rfbClientPtr cl) { - ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; - /* With Base64 encoding we need at least 4 bytes */ - char peekbuf[4]; - int n; - - if (wsctx->version == WEBSOCKETS_VERSION_HYBI) - return FALSE; - - if (cl->sslctx) - n = rfbssl_peek(cl, peekbuf, 4); - else - n = recv(cl->sock, peekbuf, 4, MSG_PEEK); - - if (n <= 0) { - if (n != 0) - rfbErr("%s: peek; %m", __func__); - rfbCloseClient(cl); - return TRUE; - } - - if (peekbuf[0] == '\xff') { - int doclose = 0; - /* Make sure we don't miss a client disconnect on an end frame - * marker. Because we use a peek buffer in some cases it is not - * applicable to wait for more data per select(). */ - switch (n) { - case 3: - if (peekbuf[1] == '\xff' && peekbuf[2] == '\x00') - doclose = 1; - break; - case 2: - if (peekbuf[1] == '\x00') - doclose = 1; - break; - default: - return FALSE; - } - - if (cl->sslctx) - n = rfbssl_read(cl, peekbuf, n); - else - n = read(cl->sock, peekbuf, n); - - if (doclose) { - rfbErr("%s: websocket close frame received\n", __func__); - rfbCloseClient(cl); - } - return TRUE; - } return FALSE; } @@ -726,7 +531,7 @@ webSocketsHasDataInBuffer(rfbClientPtr cl) ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; if (wsctx && wsctx->readlen) - return TRUE; + return TRUE; return (cl->sslctx && rfbssl_pending(cl) > 0); } -- cgit v1.2.3 From f19d6ee225ff35eb54ca06927a921c98ff721adc Mon Sep 17 00:00:00 2001 From: Andreas Weigel Date: Mon, 20 Feb 2017 11:24:18 +0100 Subject: add ws_decode tests modify automake to include ws_decode test add python frame generator for decode tests modify configure to only include ws_decode test if preconditions are fulfilled --- .gitignore | 3 + libvncserver/websockets.c | 22 +----- libvncserver/ws_decode.c | 56 ++++++++----- libvncserver/ws_decode.h | 4 +- test/wsmaketestframe.py | 121 ++++++++++++++++++++++++++++ test/wstest.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 360 insertions(+), 41 deletions(-) create mode 100755 test/wsmaketestframe.py create mode 100644 test/wstest.c (limited to 'libvncserver') diff --git a/.gitignore b/.gitignore index fccd7af..a24f81a 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,9 @@ test/cargstest test/copyrecttest test/cursortest test/encodingstest +test/wstest +test/wsmaketestframe.py +test/wstestdata.in /test/tjbench /test/tjunittest vncterm/LinuxVNC diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index 364225b..ab9cabb 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -100,8 +100,7 @@ void webSocketsGenMd5(char * target, char *key1, char *key2, char *key3); static int webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst); -static int ws_read(void *cl, char *buf, int len); -static int ws_peek(void *cl, char *buf, int len); +static int ws_read(void *cl, char *buf, size_t len); static int @@ -345,7 +344,6 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) wsctx->encode = webSocketsEncodeHybi; wsctx->decode = webSocketsDecodeHybi; wsctx->ctxInfo.readFunc = ws_read; - wsctx->ctxInfo.peekFunc = ws_peek; wsctx->base64 = base64; hybiDecodeCleanup(wsctx); cl->wsctx = (wsCtx *)wsctx; @@ -403,7 +401,7 @@ webSocketsGenMd5(char * target, char *key1, char *key2, char *key3) } static int -ws_read(void *ctxPtr, char *buf, int len) +ws_read(void *ctxPtr, char *buf, size_t len) { int n; rfbClientPtr cl = ctxPtr; @@ -415,22 +413,6 @@ ws_read(void *ctxPtr, char *buf, int len) return n; } -static int -ws_peek(void *ctxPtr, char *buf, int len) -{ - int n; - rfbClientPtr cl = ctxPtr; - if (cl->sslctx) { - n = rfbssl_peek(cl, buf, len); - } else { - while (-1 == (n = recv(cl->sock, buf, len, MSG_PEEK))) { - if (errno != EAGAIN) - break; - } - } - return n; -} - static int webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst) { diff --git a/libvncserver/ws_decode.c b/libvncserver/ws_decode.c index e74a33c..3bd17f4 100644 --- a/libvncserver/ws_decode.c +++ b/libvncserver/ws_decode.c @@ -1,11 +1,12 @@ #include "ws_decode.h" -#include #include #include #define WS_HYBI_MASK_LEN 4 - +#define WS_HYBI_HEADER_LEN_SHORT 2 + WS_HYBI_MASK_LEN +#define WS_HYBI_HEADER_LEN_EXTENDED 4 + WS_HYBI_MASK_LEN +#define WS_HYBI_HEADER_LEN_LONG 10 + WS_HYBI_MASK_LEN static int hybiRemaining(ws_ctx_t *wsctx) @@ -66,8 +67,12 @@ hybiReturnData(char *dst, int len, ws_ctx_t *wsctx, int *nWritten) } } rfbLog("after copy: readPos=%p, readLen=%d\n", wsctx->readPos, wsctx->readlen); - } else if (wsctx->hybiDecodeState == WS_HYBI_STATE_CLOSE_REASON_PENDING) { - nextState = WS_HYBI_STATE_CLOSE_REASON_PENDING; + } else { + /* it may happen that we read some bytes but could not decode them, + * in that case, set errno to EAGAIN and return -1 */ + nextState = wsctx->hybiDecodeState; + errno = EAGAIN; + *nWritten = -1; } return nextState; } @@ -98,7 +103,7 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet) if (-1 == ret) { /* save errno because rfbErr() will tamper it */ int olderrno = errno; - rfbErr("%s: peek; %m\n", __func__); + rfbErr("%s: read; %s\n", __func__, strerror(errno)); errno = olderrno; *sockRet = -1; } else { @@ -131,22 +136,22 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet) * close the connection upon receiving a frame with the MASK bit set to 0. **/ if (!(wsctx->header.data->b1 & 0x80)) { - rfbErr("%s: got frame without mask ret=%d\n", __func__, ret); - syslog(LOG_ERR, "%s: got frame without mask; ret=%d\n", __func__, ret); - errno = EIO; + rfbErr("%s: got frame without mask; ret=%d\n", __func__, ret); + errno = EPROTO; *sockRet = -1; return WS_HYBI_STATE_ERR; } + if (wsctx->header.payloadLen < 126 && wsctx->nReadRaw >= 6) { - wsctx->header.headerLen = 2 + WS_HYBI_MASK_LEN; + wsctx->header.headerLen = WS_HYBI_HEADER_LEN_SHORT; wsctx->header.mask = wsctx->header.data->u.m; } else if (wsctx->header.payloadLen == 126 && 8 <= wsctx->nReadRaw) { - wsctx->header.headerLen = 4 + WS_HYBI_MASK_LEN; + wsctx->header.headerLen = WS_HYBI_HEADER_LEN_EXTENDED; wsctx->header.payloadLen = WS_NTOH16(wsctx->header.data->u.s16.l16); wsctx->header.mask = wsctx->header.data->u.s16.m16; } else if (wsctx->header.payloadLen == 127 && 14 <= wsctx->nReadRaw) { - wsctx->header.headerLen = 10 + WS_HYBI_MASK_LEN; + wsctx->header.headerLen = WS_HYBI_HEADER_LEN_LONG; wsctx->header.payloadLen = WS_NTOH64(wsctx->header.data->u.s64.l64); wsctx->header.mask = wsctx->header.data->u.s64.m64; } else { @@ -157,6 +162,19 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet) return WS_HYBI_STATE_HEADER_PENDING; } + /* while RFC 6455 mandates that lengths MUST be encoded with the minimum + * number of bytes, it does not specify for the server how to react on + * 'wrongly' encoded frames --- this implementation rejects them*/ + if ((wsctx->header.headerLen > WS_HYBI_HEADER_LEN_SHORT + && wsctx->header.payloadLen < 126) + || (wsctx->header.headerLen > WS_HYBI_HEADER_LEN_EXTENDED + && wsctx->header.payloadLen < 65536)) { + rfbErr("%s: invalid length field; headerLen=%d payloadLen=%llu\n", __func__, wsctx->header.headerLen, wsctx->header.payloadLen); + errno = EPROTO; + *sockRet = -1; + return WS_HYBI_STATE_ERR; + } + /* absolute length of frame */ wsctx->nToRead = wsctx->header.headerLen + wsctx->header.payloadLen; @@ -238,7 +256,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet) //if (-1 == (n = ws_read(cl, wsctx->writePos, nextRead))) { if (-1 == (n = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, wsctx->writePos, nextRead))) { int olderrno = errno; - rfbErr("%s: read; %m", __func__); + rfbErr("%s: read; %s", __func__, strerror(errno)); errno = olderrno; *sockRet = -1; return WS_HYBI_STATE_ERR; @@ -260,6 +278,8 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet) errno=EIO; *sockRet = -1; return WS_HYBI_STATE_ERR; + } else { + wsctx->hybiDecodeState = WS_HYBI_STATE_FRAME_COMPLETE; } } @@ -294,7 +314,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet) /* carry over remaining, non-multiple-of-four bytes */ wsctx->carrylen = toDecode - (i * 4); if (wsctx->carrylen < 0 || wsctx->carrylen > ARRAYSIZE(wsctx->carryBuf)) { - syslog(LOG_ERR, "%s: internal error, invalid carry over size: carrylen=%d, toDecode=%d, i=%d", __func__, wsctx->carrylen, toDecode, i); + rfbErr("%s: internal error, invalid carry over size: carrylen=%d, toDecode=%d, i=%d", __func__, wsctx->carrylen, toDecode, i); *sockRet = -1; errno = EIO; return WS_HYBI_STATE_ERR; @@ -310,7 +330,6 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet) /* this data is not returned as payload data */ if (hybiWsFrameComplete(wsctx)) { - rfbLog("got closure, reason %d\n", WS_NTOH16(((uint16_t *)data)[0])); rfbLog("got close cmd, reason %d\n", WS_NTOH16(((uint16_t *)data)[0])); errno = ECONNRESET; *sockRet = -1; @@ -326,8 +345,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet) data[toReturn] = '\0'; rfbLog("Initiate Base64 decoding in %p with max size %d and '\\0' at %p\n", data, bufsize, data + toReturn); if (-1 == (wsctx->readlen = b64_pton((char *)data, data, bufsize))) { - syslog(LOG_ERR, "Base64 decode error in %s; data=%p bufsize=%d", __func__, data, bufsize); - rfbErr("%s: Base64 decode error; %m\n", __func__); + rfbErr("%s: Base64 decode error; %s\n", __func__, strerror(errno)); } wsctx->writePos = hybiPayloadStart(wsctx); break; @@ -437,12 +455,14 @@ spor: "writePos=%p " "state=%d toRead=%d remaining=%d " "nRead=%d carrylen=%d carryBuf=%p " - "result=%d\n", + "result=%d " + "errno=%d\n", __func__, len, wsctx->readlen, wsctx->readPos, wsctx->writePos, wsctx->hybiDecodeState, wsctx->nToRead, hybiRemaining(wsctx), wsctx->nReadRaw, wsctx->carrylen, wsctx->carryBuf, - result); + result, + errno); return result; } diff --git a/libvncserver/ws_decode.h b/libvncserver/ws_decode.h index e75c4d1..fac3c68 100644 --- a/libvncserver/ws_decode.h +++ b/libvncserver/ws_decode.h @@ -50,13 +50,11 @@ typedef struct ws_ctx_s ws_ctx_t; typedef int (*wsEncodeFunc)(rfbClientPtr cl, const char *src, int len, char **dst); typedef int (*wsDecodeFunc)(ws_ctx_t *wsctx, char *dst, int len); -typedef int (*wsReadFunc)(void *ctx, char *dst, int len); -typedef int (*wsPeekFunc)(void *ctx, char *dst, int len); +typedef int (*wsReadFunc)(void *ctx, char *dst, size_t len); typedef struct ctxInfo_s{ void *ctxPtr; wsReadFunc readFunc; - wsPeekFunc peekFunc; } ctxInfo_t; enum { diff --git a/test/wsmaketestframe.py b/test/wsmaketestframe.py new file mode 100755 index 0000000..d0053a2 --- /dev/null +++ b/test/wsmaketestframe.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +# Copyright (C)2017 Andreas Weigel. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# - Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# - Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import websockets +import base64 +import errno + +def add_field(s, name, value, first=False): + deli = ",\n\t\t" + if first: + deli = "\t\t" + s += "{2}.{0}={1}".format(name, value, deli) + return s + + +class Testframe(): + def __init__(self, frame, descr, retbytes=[], modify_bytes={}, experrno=0, mask=True): + self.frame = frame + self.descr = descr + self.retbytes = retbytes + self.modify_bytes = modify_bytes + self.experrno = experrno + self.b64 = True if frame.opcode == 1 else False + self.mask = mask + + def to_carray_initializer(self, buf): + values = [] + for i in range(len(buf)): + values.append("0X{0:02X}".format(buf[i])) + + if self.modify_bytes != {}: + for k in self.modify_bytes: + values[k] = "0X{0:02X}".format(self.modify_bytes[k]) + + return "{{{0}}}".format(", ".join(values)) + + + def set_frame_buf(self, buf): + self.frame_carray = self.to_carray_initializer(buf) + self.framelen = len(buf) + + def __str__(self): + #print("processing frame: {0}".format(self.descr)) + the_frame = self.frame + if self.b64: + olddata = self.frame.data + newdata = base64.b64encode(self.frame.data) + #print("converting\n{0}\nto{1}\n".format(olddata, newdata)) + the_frame = websockets.framing.Frame(self.frame.fin, self.frame.opcode, base64.b64encode(olddata)) + + websockets.framing.write_frame(the_frame, self.set_frame_buf, self.mask) + s = "\t{\n" + s = add_field(s, "frame", "{0}".format(self.frame_carray), True) + s = add_field(s, "expectedDecodeBuf", self.to_carray_initializer(self.frame.data)) + s = add_field(s, "frame_len", self.framelen) + s = add_field(s, "raw_payload_len", len(self.frame.data)) + s = add_field(s, "expected_errno", self.experrno) + s = add_field(s, "descr", "\"{0}\"".format(self.descr)) + s = add_field(s, "ret_bytes", "{{{0}}}".format(", ".join(self.retbytes))) + s = add_field(s, "ret_bytes_len", len(self.retbytes)) + s = add_field(s, "i", "0") + s = add_field(s, "simulate_sock_malfunction_at", "0") + s = add_field(s, "errno_val", "0") + s = add_field(s, "close_sock_at", "0") + s += "\n\t}" + return s + +### create test frames +flist = [] +### standard text frames with different lengths +flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("Testit", encoding="utf-8")), "Short valid text frame", {})) +flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("Frame2 does contain much more text and even goes beyond the 126 byte len field. Frame2 does contain much more text and even goes beyond the 126 byte len field.", encoding="utf-8")), + "Mid-long valid text frame", {})) +flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray([(x % 26) + 65 for x in range(100000)])), "100k text frame (ABC..YZABC..)", {})) + +### standard binary frames with different lengths +flist.append(Testframe(websockets.framing.Frame(1, 2, bytearray("Testit", encoding="utf-8")), "Short valid binary frame", {})) +flist.append(Testframe(websockets.framing.Frame(1, 2, bytearray("Frame2 does contain much more text and even goes beyond the 126 byte len field. Frame2 does contain much more text and even goes beyond the 126 byte len field.", encoding="utf-8")), + "Mid-long valid binary frame", {})) +flist.append(Testframe(websockets.framing.Frame(1, 2, bytearray([(x % 26) + 65 for x in range(100000)])), "100k binary frame (ABC..YZABC..)", {})) + +### some conn reset frames, one with no close message, one with close message (the latter should cause an error) +flist.append(Testframe(websockets.framing.Frame(1, 8, bytearray(list([0x03, 0xEB]))), "Close frame (Reason 1003)", {}, experrno=errno.ECONNRESET)) +flist.append(Testframe(websockets.framing.Frame(1, 8, bytearray(list([0x03, 0xEB])) + bytearray("I'm a close reason", encoding="utf-8")), "Close frame (Reason 1003) and msg", {}, experrno=errno.EIO)) + +### invalid header values +flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("Testit", encoding="utf-8")), "Invalid frame: Wrong masking", {}, experrno=errno.EPROTO, mask=False)) +flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("..Lore Ipsum", encoding="utf-8")), "Invalid frame: Length of < 126 with add. 16 bit len field", {}, experrno=errno.EPROTO, modify_bytes={ 1: 0xFE, 2: 0x00, 3: 0x0F})) +flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("........Lore Ipsum", encoding="utf-8")), "Invalid frame: Length of < 126 with add. 64 bit len field", {}, experrno=errno.EPROTO, modify_bytes={ 1: 0xFF, 2: 0x00, 3: 0x00, 4: 0x00, 5: 0x00, 6: 0x80, 7: 0x40})) + +s = "struct ws_frame_test tests[] = {\n" +for i in range(len(flist)): + s += flist[i].__str__() + if (i + 1 < len(flist)): + s += "," + s += "\n" +s += "};\n" + +with open("wstestdata.in", "w") as cdatafile: + cdatafile.write(s) diff --git a/test/wstest.c b/test/wstest.c new file mode 100644 index 0000000..30324cb --- /dev/null +++ b/test/wstest.c @@ -0,0 +1,195 @@ +/* + * Copyright (C)2017 Andreas Weigel. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 + +#define TEST_BUF_SIZE B64LEN(131072) + WSHLENMAX +#define RND_SEED 100 +#define WS_TMP_LOG "ws_tmp.log" + +enum { + OK, + FAIL_DATA, + FAIL_ERRNO, + FAIL_CLOSED, +}; + +const char *result_descr[] = { + "", + "Data buffers do not match", + "Wrong errno", + "Wrongly reported closed socket", + "Internal test error" +}; + +struct ws_frame_test { + char frame[TEST_BUF_SIZE]; + char *pos; + char expectedDecodeBuf[TEST_BUF_SIZE]; + uint64_t frame_len; + uint64_t raw_payload_len; + int expected_errno; + const char *descr; + int ret_bytes[16]; + int ret_bytes_len; + int i; + int simulate_sock_malfunction_at; + int errno_val; + int close_sock_at; +}; + +char el_log[1000000]; +char *el_pos; + +static void logtest(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + size_t left = el_log + sizeof(el_log) - el_pos; + size_t off = vsnprintf(el_pos, left, fmt, args); + el_pos += off; + va_end(args); +} + +static int emu_read(void *ctx, char *dst, size_t len); + +static int emu_read(void *ctx, char *dst, size_t len) +{ + struct ws_frame_test *ft = (struct ws_frame_test *)ctx; + ssize_t nret; + int r; + ssize_t modu; + + rfbLog("emu_read called with dst=%p and len=%lu\n", dst, len); + if (ft->simulate_sock_malfunction_at > 0 && ft->simulate_sock_malfunction_at == ft->i) { + rfbLog("simulating IO error with errno=%d\n", ft->errno_val); + errno = ft->errno_val; + return -1; + } + + /* return something */ + r = rand(); + modu = (ft->frame + ft->frame_len) - ft->pos; + rfbLog("r=%d modu=%ld frame=%p pos=%p\n", r, modu, ft->frame, ft->pos); + nret = (r % modu) + 1; + nret = nret > len ? len : nret; + + rfbLog("copy and return %ld bytes\n", nret); + memcpy(dst, ft->pos, nret); + ft->pos += nret; + rfbLog("leaving %s; pos=%p framebuf=%p nret=%ld\n", __func__, ft->pos, ft->frame, nret); + return nret; +} + +static uint64_t run_test(struct ws_frame_test *ft, ws_ctx_t *ctx) +{ + uint64_t nleft = ft->raw_payload_len; + char dstbuf[ft->raw_payload_len]; + char *dst = dstbuf; + ssize_t n; + + ft->pos = ft->frame; + + ctx->ctxInfo.ctxPtr = (void *)ft; + + while (nleft > 0) { + rfbLog("calling ws_decode with dst=%p, len=%lu\n", dst, nleft); + n = ctx->decode(ctx, dst, nleft); + rfbLog("read n=%ld\n", n); + if (n == 0) { + if (ft->close_sock_at > 0) { + return OK; + } else { + return FAIL_CLOSED; + } + } else if (n < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* ok, just call again */ + } else { + if (ft->expected_errno == errno) { + rfbLog("errno=%d as expected\n", errno); + return OK; + } else { + rfbLog("errno=%d != expected(%d)\n", errno, ft->expected_errno); + return FAIL_ERRNO; + } + } + } else { + nleft -= n; + dst += n; + rfbLog("read n=%ld from decode; dst=%p, nleft=%lu\n", n, dst, nleft); + } + } + + if (memcmp(ft->expectedDecodeBuf, dstbuf, ft->raw_payload_len) != 0) { + ft->expectedDecodeBuf[ft->raw_payload_len] = '\0'; + dstbuf[ft->raw_payload_len] = '\0'; + rfbLog("decoded result not equal:\nexpected:\n%s\ngot\n%s\n\n", ft->expectedDecodeBuf, dstbuf); + return FAIL_DATA; + } + + return OK; +} + +#include "wstestdata.in" + +int main() +{ + ws_ctx_t ctx; + int retall= 0; + srand(RND_SEED); + + for (int i = 0; i < ARRAYSIZE(tests); i++) { + int ret; + + el_pos = el_log; + rfbLog = logtest; + rfbErr = logtest; + + hybiDecodeCleanup(&ctx); + ctx.decode = webSocketsDecodeHybi; + ctx.version = WEBSOCKETS_VERSION_HYBI; + + ctx.ctxInfo.readFunc = emu_read; + + ret = run_test(&tests[i], &ctx); + printf("%s: \"%s\"\n", ret == 0 ? "PASS" : "FAIL", tests[i].descr); + if (ret != 0) { + *el_pos = '\0'; + printf("%s", el_log); + retall = -1; + } + } + return retall; +} + +#endif -- cgit v1.2.3 From 826e0f9e39a49ae3598f8709218180f835af269b Mon Sep 17 00:00:00 2001 From: Andreas Weigel Date: Mon, 20 Feb 2017 15:13:03 +0100 Subject: add generation wstest to cmake add wstestdata.c, because the python data generation script has too many dependencies remove some redundance from jpeg test creation add support for decoding close messages --- .gitignore | 2 - CMakeLists.txt | 41 +++++++++++++----- libvncserver/ws_decode.c | 44 +++++++++++-------- libvncserver/ws_decode.h | 7 --- test/wsmaketestframe.py | 44 ++++++++++--------- test/wstest.c | 23 +++++++--- test/wstestdata.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 207 insertions(+), 64 deletions(-) create mode 100644 test/wstestdata.c (limited to 'libvncserver') diff --git a/.gitignore b/.gitignore index a24f81a..03bdf0f 100644 --- a/.gitignore +++ b/.gitignore @@ -67,8 +67,6 @@ test/copyrecttest test/cursortest test/encodingstest test/wstest -test/wsmaketestframe.py -test/wstestdata.in /test/tjbench /test/tjunittest vncterm/LinuxVNC diff --git a/CMakeLists.txt b/CMakeLists.txt index cf6017d..8c6da06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,7 +49,6 @@ option(WITH_IPv6 "Enable IPv6 Support" ON) option(WITH_WEBSOCKETS "Build with websockets support" ON) - if(WITH_ZLIB) find_package(ZLIB) endif(WITH_ZLIB) @@ -387,6 +386,7 @@ if(LIBVNCSERVER_WITH_WEBSOCKETS) set(LIBVNCSERVER_SOURCES ${LIBVNCSERVER_SOURCES} ${LIBVNCSERVER_DIR}/websockets.c + ${LIBVNCSERVER_DIR}/ws_decode.c ${WSSRCS} ) endif(LIBVNCSERVER_WITH_WEBSOCKETS) @@ -500,11 +500,9 @@ foreach(e ${LIBVNCCLIENT_EXAMPLES}) target_link_libraries(client_examples_${e} vncclient ${CMAKE_THREAD_LIBS_INIT} ${SDL_LIBRARY} ${FFMPEG_LIBRARIES}) endforeach(e ${LIBVNCCLIENT_EXAMPLES}) - # # them tests # - if(UNIX) set(ADDITIONAL_TEST_LIBS m) endif(UNIX) @@ -512,18 +510,41 @@ endif(UNIX) set(SIMPLETESTS cargstest copyrecttest + wstest ) -if(CMAKE_USE_PTHREADS_INIT) - set(SIMPLETESTS - ${SIMPLETESTS} - encodingstest +add_test(NAME cargs COMMAND test_cargstest) +add_test(NAME websockets_decode COMMAND test_wstest) + +if(CMAKE_USE_PTHREADS_INI) + list(APPEND SIMPLETESTS encodingstest) +endif(CMAKE_USE_PTHREADS_INI) + +if(FOUND_LIBJPEG_TURBO) + list(APPEND SIMPLETESTS tjunittest tjbench) + set(tjunittest_add_src + ${TESTS_DIR}/tjutil.c + ${TESTS_DIR}/tjutil.h + ${COMMON_DIR}/turbojpeg.c + ${COMMON_DIR}/turbojpeg.h ) -endif(CMAKE_USE_PTHREADS_INIT) + + set(tjbench_add_src + ${TESTS_DIR}/tjbench.c + ${TESTS_DIR}/tjutil.c + ${TESTS_DIR}/tjutil.h + ${TESTS_DIR}/bmp.c + ${TESTS_DIR}/bmp.h + ${COMMON_DIR}/turbojpeg.c + ${COMMON_DIR}/turbojpeg.h + ) + + add_test(NAME turbojpeg COMMAND test_tjunittest) +endif(FOUND_LIBJPEG_TURBO) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test) foreach(t ${SIMPLETESTS}) - add_executable(test_${t} ${TESTS_DIR}/${t}.c) + add_executable(test_${t} ${TESTS_DIR}/${t}.c ${${t}_add_src}) set_target_properties(test_${t} PROPERTIES OUTPUT_NAME ${t}) set_target_properties(test_${t} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test) target_link_libraries(test_${t} vncserver vncclient ${ADDITIONAL_TEST_LIBS}) @@ -561,8 +582,6 @@ if(FOUND_LIBJPEG_TURBO) add_test(NAME turbojpeg COMMAND test_tjunittest) endif(FOUND_LIBJPEG_TURBO) - - # # this gets the libraries needed by TARGET in "-libx -liby ..." form # diff --git a/libvncserver/ws_decode.c b/libvncserver/ws_decode.c index 3bd17f4..472a44a 100644 --- a/libvncserver/ws_decode.c +++ b/libvncserver/ws_decode.c @@ -85,11 +85,12 @@ hybiReturnData(char *dst, int len, ws_ctx_t *wsctx, int *nWritten) * * @param[in] cl client ptr with ptr to raw socket and ws_ctx_t ptr * @param[out] sockRet emulated recv return value + * @param[out] nPayload number of payload bytes already read * @return next hybi decoding state; WS_HYBI_STATE_HEADER_PENDING indicates * that the header was not received completely. */ static int -hybiReadHeader(ws_ctx_t *wsctx, int *sockRet) +hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) { int ret; char *headerDst = wsctx->codeBufDecode + wsctx->nReadRaw; @@ -184,7 +185,8 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet) /* set payload pointer just after header */ wsctx->readPos = (unsigned char *)(wsctx->codeBufDecode + wsctx->header.headerLen); - rfbLog("header complete: state=%d flen=%d writeTo=%p\n", wsctx->hybiDecodeState, wsctx->nToRead, wsctx->writePos); + *nPayload = wsctx->nReadRaw - wsctx->header.headerLen; + rfbLog("header complete: state=%d flen=%d writeTo=%p nPayload=%d\n", wsctx->hybiDecodeState, wsctx->nToRead, wsctx->writePos, *nPayload); return WS_HYBI_STATE_DATA_NEEDED; } @@ -217,21 +219,24 @@ hybiPayloadStart(ws_ctx_t *wsctx) * - execute return data routine * * Sets errno corresponding to what it gets from the underlying - * socket or EIO if some internal sanity check fails. + * socket or EPROTO if some invalid data is in the received frame + * or ECONNRESET if a close reason + message is received. EIO is used if + * an internal sanity check fails. * * @param[in] cl client ptr with raw socket reference * @param[out] dst destination buffer * @param[in] len size of destination buffer * @param[out] sockRet emulated recv return value + * @param[in] nInBuf number of undecoded bytes before writePos from header read * @return next hybi decode state */ static int -hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet) +hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) { int n; int i; - int toReturn; - int toDecode; + int toReturn; /* number of data bytes to return */ + int toDecode; /* number of bytes to decode starting at wsctx->writePos */ int bufsize; int nextRead; unsigned char *data; @@ -253,7 +258,6 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet) if (wsctx->nReadRaw < wsctx->nToRead) { /* decode more data */ - //if (-1 == (n = ws_read(cl, wsctx->writePos, nextRead))) { if (-1 == (n = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, wsctx->writePos, nextRead))) { int olderrno = errno; rfbErr("%s: read; %s", __func__, strerror(errno)); @@ -283,7 +287,9 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet) } } - toDecode = wsctx->writePos - hybiPayloadStart(wsctx); + /* number of not yet unmasked payload bytes: what we read here + what was + * carried over + what was read with the header */ + toDecode = n + wsctx->carrylen + nInBuf; rfbLog("toDecode=%d from n=%d carrylen=%d headerLen=%d\n", toDecode, n, wsctx->carrylen, wsctx->header.headerLen); if (toDecode < 0) { rfbErr("%s: internal error; negative number of bytes to decode: %d", __func__, toDecode); @@ -294,7 +300,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet) /* for a possible base64 decoding, we decode multiples of 4 bytes until * the whole frame is received and carry over any remaining bytes in the carry buf*/ - data = (unsigned char *)hybiPayloadStart(wsctx); + data = (unsigned char *)(wsctx->writePos - toDecode); data32= (uint32_t *)data; for (i = 0; i < (toDecode >> 2); i++) { @@ -321,24 +327,25 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet) } rfbLog("carrying over %d bytes from %p to %p\n", wsctx->carrylen, wsctx->writePos + (i * 4), wsctx->carryBuf); memcpy(wsctx->carryBuf, data + (i * 4), wsctx->carrylen); + wsctx->writePos -= wsctx->carrylen; } toReturn = toDecode - wsctx->carrylen; switch (wsctx->header.opcode) { case WS_OPCODE_CLOSE: - /* this data is not returned as payload data */ if (hybiWsFrameComplete(wsctx)) { - rfbLog("got close cmd, reason %d\n", WS_NTOH16(((uint16_t *)data)[0])); + *(wsctx->writePos) = '\0'; + rfbLog("got close cmd %d, reason %d: %s\n", (int)(wsctx->writePos - hybiPayloadStart(wsctx)), WS_NTOH16(((uint16_t *)hybiPayloadStart(wsctx))[0]), &hybiPayloadStart(wsctx)[2]); errno = ECONNRESET; *sockRet = -1; return WS_HYBI_STATE_FRAME_COMPLETE; } else { - rfbErr("%s: close reason with long frame not supported", __func__); - errno = EIO; + rfbLog("got close cmd; waiting for %d more bytes to arrive\n", hybiRemaining(wsctx)); *sockRet = -1; - return WS_HYBI_STATE_ERR; + errno = EAGAIN; + return WS_HYBI_STATE_CLOSE_REASON_PENDING; } break; case WS_OPCODE_TEXT_FRAME: @@ -412,25 +419,26 @@ webSocketsDecodeHybi(ws_ctx_t *wsctx, char *dst, int len) wsctx->nReadRaw, wsctx->carrylen, wsctx->carryBuf); switch (wsctx->hybiDecodeState){ + int nInBuf; case WS_HYBI_STATE_HEADER_PENDING: - wsctx->hybiDecodeState = hybiReadHeader(wsctx, &result); + wsctx->hybiDecodeState = hybiReadHeader(wsctx, &result, &nInBuf); if (wsctx->hybiDecodeState == WS_HYBI_STATE_ERR) { goto spor; } if (wsctx->hybiDecodeState != WS_HYBI_STATE_HEADER_PENDING) { /* when header is complete, try to read some more data */ - wsctx->hybiDecodeState = hybiReadAndDecode(wsctx, dst, len, &result); + wsctx->hybiDecodeState = hybiReadAndDecode(wsctx, dst, len, &result, nInBuf); } break; case WS_HYBI_STATE_DATA_AVAILABLE: wsctx->hybiDecodeState = hybiReturnData(dst, len, wsctx, &result); break; case WS_HYBI_STATE_DATA_NEEDED: - wsctx->hybiDecodeState = hybiReadAndDecode(wsctx, dst, len, &result); + wsctx->hybiDecodeState = hybiReadAndDecode(wsctx, dst, len, &result, 0); break; case WS_HYBI_STATE_CLOSE_REASON_PENDING: - wsctx->hybiDecodeState = hybiReadAndDecode(wsctx, dst, len, &result); + wsctx->hybiDecodeState = hybiReadAndDecode(wsctx, dst, len, &result, 0); break; default: /* invalid state */ diff --git a/libvncserver/ws_decode.h b/libvncserver/ws_decode.h index fac3c68..0dcbc83 100644 --- a/libvncserver/ws_decode.h +++ b/libvncserver/ws_decode.h @@ -7,13 +7,6 @@ #include /* __b64_ntop */ #endif - - -enum { - WEBSOCKETS_VERSION_HIXIE, - WEBSOCKETS_VERSION_HYBI -}; - #if defined(__APPLE__) #include diff --git a/test/wsmaketestframe.py b/test/wsmaketestframe.py index d0053a2..3412754 100755 --- a/test/wsmaketestframe.py +++ b/test/wsmaketestframe.py @@ -26,6 +26,14 @@ import websockets import base64 import errno +''' + Create websocket frames for the wstest websocket decoding unit test. + + Generates c ws_frame_test structure definitions + included by wstest.c. +''' + + def add_field(s, name, value, first=False): deli = ",\n\t\t" if first: @@ -35,10 +43,9 @@ def add_field(s, name, value, first=False): class Testframe(): - def __init__(self, frame, descr, retbytes=[], modify_bytes={}, experrno=0, mask=True): + def __init__(self, frame, descr, modify_bytes={}, experrno=0, mask=True): self.frame = frame self.descr = descr - self.retbytes = retbytes self.modify_bytes = modify_bytes self.experrno = experrno self.b64 = True if frame.opcode == 1 else False @@ -53,7 +60,7 @@ class Testframe(): for k in self.modify_bytes: values[k] = "0X{0:02X}".format(self.modify_bytes[k]) - return "{{{0}}}".format(", ".join(values)) + return "{{{0}}}".format(",".join(values)) def set_frame_buf(self, buf): @@ -61,14 +68,13 @@ class Testframe(): self.framelen = len(buf) def __str__(self): - #print("processing frame: {0}".format(self.descr)) + print("processing frame: {0}".format(self.descr)) the_frame = self.frame if self.b64: olddata = self.frame.data newdata = base64.b64encode(self.frame.data) #print("converting\n{0}\nto{1}\n".format(olddata, newdata)) the_frame = websockets.framing.Frame(self.frame.fin, self.frame.opcode, base64.b64encode(olddata)) - websockets.framing.write_frame(the_frame, self.set_frame_buf, self.mask) s = "\t{\n" s = add_field(s, "frame", "{0}".format(self.frame_carray), True) @@ -77,8 +83,6 @@ class Testframe(): s = add_field(s, "raw_payload_len", len(self.frame.data)) s = add_field(s, "expected_errno", self.experrno) s = add_field(s, "descr", "\"{0}\"".format(self.descr)) - s = add_field(s, "ret_bytes", "{{{0}}}".format(", ".join(self.retbytes))) - s = add_field(s, "ret_bytes_len", len(self.retbytes)) s = add_field(s, "i", "0") s = add_field(s, "simulate_sock_malfunction_at", "0") s = add_field(s, "errno_val", "0") @@ -89,25 +93,25 @@ class Testframe(): ### create test frames flist = [] ### standard text frames with different lengths -flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("Testit", encoding="utf-8")), "Short valid text frame", {})) +flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("Testit", encoding="utf-8")), "Short valid text frame")) flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("Frame2 does contain much more text and even goes beyond the 126 byte len field. Frame2 does contain much more text and even goes beyond the 126 byte len field.", encoding="utf-8")), - "Mid-long valid text frame", {})) -flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray([(x % 26) + 65 for x in range(100000)])), "100k text frame (ABC..YZABC..)", {})) + "Mid-long valid text frame")) +#flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray([(x % 26) + 65 for x in range(100000)])), "100k text frame (ABC..YZABC..)")) ### standard binary frames with different lengths -flist.append(Testframe(websockets.framing.Frame(1, 2, bytearray("Testit", encoding="utf-8")), "Short valid binary frame", {})) +flist.append(Testframe(websockets.framing.Frame(1, 2, bytearray("Testit", encoding="utf-8")), "Short valid binary frame")) flist.append(Testframe(websockets.framing.Frame(1, 2, bytearray("Frame2 does contain much more text and even goes beyond the 126 byte len field. Frame2 does contain much more text and even goes beyond the 126 byte len field.", encoding="utf-8")), - "Mid-long valid binary frame", {})) -flist.append(Testframe(websockets.framing.Frame(1, 2, bytearray([(x % 26) + 65 for x in range(100000)])), "100k binary frame (ABC..YZABC..)", {})) + "Mid-long valid binary frame")) +#flist.append(Testframe(websockets.framing.Frame(1, 2, bytearray([(x % 26) + 65 for x in range(100000)])), "100k binary frame (ABC..YZABC..)")) -### some conn reset frames, one with no close message, one with close message (the latter should cause an error) -flist.append(Testframe(websockets.framing.Frame(1, 8, bytearray(list([0x03, 0xEB]))), "Close frame (Reason 1003)", {}, experrno=errno.ECONNRESET)) -flist.append(Testframe(websockets.framing.Frame(1, 8, bytearray(list([0x03, 0xEB])) + bytearray("I'm a close reason", encoding="utf-8")), "Close frame (Reason 1003) and msg", {}, experrno=errno.EIO)) +### some conn reset frames, one with no close message, one with close message +flist.append(Testframe(websockets.framing.Frame(1, 8, bytearray(list([0x03, 0xEB]))), "Close frame (Reason 1003)", experrno=errno.ECONNRESET)) +flist.append(Testframe(websockets.framing.Frame(1, 8, bytearray(list([0x03, 0xEB])) + bytearray("I'm a close reason and much more than that!", encoding="utf-8")), "Close frame (Reason 1003) and msg", experrno=errno.ECONNRESET)) ### invalid header values -flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("Testit", encoding="utf-8")), "Invalid frame: Wrong masking", {}, experrno=errno.EPROTO, mask=False)) -flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("..Lore Ipsum", encoding="utf-8")), "Invalid frame: Length of < 126 with add. 16 bit len field", {}, experrno=errno.EPROTO, modify_bytes={ 1: 0xFE, 2: 0x00, 3: 0x0F})) -flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("........Lore Ipsum", encoding="utf-8")), "Invalid frame: Length of < 126 with add. 64 bit len field", {}, experrno=errno.EPROTO, modify_bytes={ 1: 0xFF, 2: 0x00, 3: 0x00, 4: 0x00, 5: 0x00, 6: 0x80, 7: 0x40})) +flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("Testit", encoding="utf-8")), "Invalid frame: Wrong masking", experrno=errno.EPROTO, mask=False)) +flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("..Lore Ipsum", encoding="utf-8")), "Invalid frame: Length of < 126 with add. 16 bit len field", experrno=errno.EPROTO, modify_bytes={ 1: 0xFE, 2: 0x00, 3: 0x0F})) +flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("........Lore Ipsum", encoding="utf-8")), "Invalid frame: Length of < 126 with add. 64 bit len field", experrno=errno.EPROTO, modify_bytes={ 1: 0xFF, 2: 0x00, 3: 0x00, 4: 0x00, 5: 0x00, 6: 0x80, 7: 0x40})) s = "struct ws_frame_test tests[] = {\n" for i in range(len(flist)): @@ -117,5 +121,5 @@ for i in range(len(flist)): s += "\n" s += "};\n" -with open("wstestdata.in", "w") as cdatafile: +with open("wstestdata.c", "w") as cdatafile: cdatafile.write(s) diff --git a/test/wstest.c b/test/wstest.c index 30324cb..4a5ba91 100644 --- a/test/wstest.c +++ b/test/wstest.c @@ -23,6 +23,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#ifndef _WIN32 + #include #include #include @@ -30,11 +32,11 @@ #include #include -#ifndef _WIN32 - +/* incoming data frames should not be larger than that */ #define TEST_BUF_SIZE B64LEN(131072) + WSHLENMAX + +/* seed is fixed deliberately to get reproducible test cases */ #define RND_SEED 100 -#define WS_TMP_LOG "ws_tmp.log" enum { OK, @@ -55,6 +57,7 @@ struct ws_frame_test { char frame[TEST_BUF_SIZE]; char *pos; char expectedDecodeBuf[TEST_BUF_SIZE]; + uint64_t n_compare; uint64_t frame_len; uint64_t raw_payload_len; int expected_errno; @@ -67,6 +70,8 @@ struct ws_frame_test { int close_sock_at; }; +#include "wstestdata.c" + char el_log[1000000]; char *el_pos; @@ -160,15 +165,15 @@ static uint64_t run_test(struct ws_frame_test *ft, ws_ctx_t *ctx) return OK; } -#include "wstestdata.in" int main() { ws_ctx_t ctx; - int retall= 0; + int retall= 0; + int i; srand(RND_SEED); - for (int i = 0; i < ARRAYSIZE(tests); i++) { + for (i = 0; i < ARRAYSIZE(tests); i++) { int ret; el_pos = el_log; @@ -192,4 +197,10 @@ int main() return retall; } +#else + +int main() { + return 0; +} + #endif diff --git a/test/wstestdata.c b/test/wstestdata.c new file mode 100644 index 0000000..628bdb1 --- /dev/null +++ b/test/wstestdata.c @@ -0,0 +1,110 @@ +struct ws_frame_test tests[] = { + { + .frame={0X81,0X88,0XB7,0XDB,0X16,0X16,0XE1,0X9C,0X40,0X6C,0XD3,0X9C,0X7A,0X26}, + .expectedDecodeBuf={0X54,0X65,0X73,0X74,0X69,0X74}, + .frame_len=14, + .raw_payload_len=6, + .expected_errno=0, + .descr="Short valid text frame", + .i=0, + .simulate_sock_malfunction_at=0, + .errno_val=0, + .close_sock_at=0 + }, + { + .frame={0X81,0XFE,0X00,0XD4,0X67,0XFE,0X8A,0X31,0X35,0X90,0XC0,0X59,0X05,0XA9,0XDF,0X48,0X2E,0XB9,0XD8,0X47,0X3D,0XA6,0XC7,0X56,0X3E,0XCC,0XB3,0X44,0X03,0XB9,0XCC,0X41,0X05,0X97,0XC8,0X45,0X03,0XA9,0XC4,0X5E,0X2E,0XB9,0XBB,0X47,0X04,0X93,0XDF,0X56,0X03,0XB9,0XDC,0X05,0X03,0XBD,0XC8,0X59,0X05,0X93,0XDB,0X56,0X3D,0XA6,0XD0,0X5D,0X05,0X97,0XC8,0X5F,0X05,0XCC,0XDC,0X4B,0X2E,0XB9,0XC0,0X5D,0X02,0XA9,0XB3,0X44,0X3D,0XBD,0XC8,0X01,0X06,0XB9,0XDF,0X56,0X2A,0XAA,0XC3,0X03,0X2E,0XB9,0XC0,0X04,0X03,0XB9,0XDF,0X56,0X05,0XB9,0XDC,0X44,0X2E,0XB9,0XD0,0X41,0X3D,0XA9,0XF2,0X5A,0X2B,0X97,0XC8,0X76,0X04,0X93,0XCC,0X45,0X3D,0XAA,0XC3,0X56,0X3D,0XB9,0XB3,0X5D,0X04,0X87,0XC8,0X5B,0X05,0XCC,0XBF,0X01,0X3E,0XA9,0XE6,0X44,0X2E,0XB9,0XBB,0X00,0X3E,0XCC,0XED,0X56,0X05,0XA9,0XB3,0X48,0X3D,0XAD,0XC8,0X01,0X3D,0XA6,0XE2,0X01,0X2E,0XB9,0XCC,0X44,0X3D,0XBD,0XC8,0X5D,0X03,0X93,0XDC,0X44,0X2E,0XB9,0XEE,0X47,0X3D,0XA6,0XC7,0X56,0X3E,0X93,0XDC,0X04,0X05,0XCC,0XBF,0X5A,0X2E,0XB6,0XD8,0X5E,0X3D,0XAD,0XCB,0X49,0X2A,0X94,0XD3,0X56,0X3E,0X90,0XE6,0X01,0X3D,0XAD,0XC8,0X42,0X3D,0XA9,0XBE,0X56,0X3D,0X93,0XE6,0X5D,0X05,0XB9,0XDB,0X44}, + .expectedDecodeBuf={0X46,0X72,0X61,0X6D,0X65,0X32,0X20,0X64,0X6F,0X65,0X73,0X20,0X63,0X6F,0X6E,0X74,0X61,0X69,0X6E,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X65,0X78,0X74,0X20,0X61,0X6E,0X64,0X20,0X65,0X76,0X65,0X6E,0X20,0X67,0X6F,0X65,0X73,0X20,0X62,0X65,0X79,0X6F,0X6E,0X64,0X20,0X74,0X68,0X65,0X20,0X31,0X32,0X36,0X20,0X62,0X79,0X74,0X65,0X20,0X6C,0X65,0X6E,0X20,0X66,0X69,0X65,0X6C,0X64,0X2E,0X20,0X46,0X72,0X61,0X6D,0X65,0X32,0X20,0X64,0X6F,0X65,0X73,0X20,0X63,0X6F,0X6E,0X74,0X61,0X69,0X6E,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X65,0X78,0X74,0X20,0X61,0X6E,0X64,0X20,0X65,0X76,0X65,0X6E,0X20,0X67,0X6F,0X65,0X73,0X20,0X62,0X65,0X79,0X6F,0X6E,0X64,0X20,0X74,0X68,0X65,0X20,0X31,0X32,0X36,0X20,0X62,0X79,0X74,0X65,0X20,0X6C,0X65,0X6E,0X20,0X66,0X69,0X65,0X6C,0X64,0X2E}, + .frame_len=220, + .raw_payload_len=159, + .expected_errno=0, + .descr="Mid-long valid text frame", + .i=0, + .simulate_sock_malfunction_at=0, + .errno_val=0, + .close_sock_at=0 + }, + { + .frame={0X82,0X86,0X90,0X5E,0X2B,0X8E,0XC4,0X3B,0X58,0XFA,0XF9,0X2A}, + .expectedDecodeBuf={0X54,0X65,0X73,0X74,0X69,0X74}, + .frame_len=12, + .raw_payload_len=6, + .expected_errno=0, + .descr="Short valid binary frame", + .i=0, + .simulate_sock_malfunction_at=0, + .errno_val=0, + .close_sock_at=0 + }, + { + .frame={0X82,0XFE,0X00,0X9F,0X7D,0X97,0X6B,0XA2,0X3B,0XE5,0X0A,0XCF,0X18,0XA5,0X4B,0XC6,0X12,0XF2,0X18,0X82,0X1E,0XF8,0X05,0XD6,0X1C,0XFE,0X05,0X82,0X10,0XE2,0X08,0XCA,0X5D,0XFA,0X04,0XD0,0X18,0XB7,0X1F,0XC7,0X05,0XE3,0X4B,0XC3,0X13,0XF3,0X4B,0XC7,0X0B,0XF2,0X05,0X82,0X1A,0XF8,0X0E,0XD1,0X5D,0XF5,0X0E,0XDB,0X12,0XF9,0X0F,0X82,0X09,0XFF,0X0E,0X82,0X4C,0XA5,0X5D,0X82,0X1F,0XEE,0X1F,0XC7,0X5D,0XFB,0X0E,0XCC,0X5D,0XF1,0X02,0XC7,0X11,0XF3,0X45,0X82,0X3B,0XE5,0X0A,0XCF,0X18,0XA5,0X4B,0XC6,0X12,0XF2,0X18,0X82,0X1E,0XF8,0X05,0XD6,0X1C,0XFE,0X05,0X82,0X10,0XE2,0X08,0XCA,0X5D,0XFA,0X04,0XD0,0X18,0XB7,0X1F,0XC7,0X05,0XE3,0X4B,0XC3,0X13,0XF3,0X4B,0XC7,0X0B,0XF2,0X05,0X82,0X1A,0XF8,0X0E,0XD1,0X5D,0XF5,0X0E,0XDB,0X12,0XF9,0X0F,0X82,0X09,0XFF,0X0E,0X82,0X4C,0XA5,0X5D,0X82,0X1F,0XEE,0X1F,0XC7,0X5D,0XFB,0X0E,0XCC,0X5D,0XF1,0X02,0XC7,0X11,0XF3,0X45}, + .expectedDecodeBuf={0X46,0X72,0X61,0X6D,0X65,0X32,0X20,0X64,0X6F,0X65,0X73,0X20,0X63,0X6F,0X6E,0X74,0X61,0X69,0X6E,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X65,0X78,0X74,0X20,0X61,0X6E,0X64,0X20,0X65,0X76,0X65,0X6E,0X20,0X67,0X6F,0X65,0X73,0X20,0X62,0X65,0X79,0X6F,0X6E,0X64,0X20,0X74,0X68,0X65,0X20,0X31,0X32,0X36,0X20,0X62,0X79,0X74,0X65,0X20,0X6C,0X65,0X6E,0X20,0X66,0X69,0X65,0X6C,0X64,0X2E,0X20,0X46,0X72,0X61,0X6D,0X65,0X32,0X20,0X64,0X6F,0X65,0X73,0X20,0X63,0X6F,0X6E,0X74,0X61,0X69,0X6E,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X65,0X78,0X74,0X20,0X61,0X6E,0X64,0X20,0X65,0X76,0X65,0X6E,0X20,0X67,0X6F,0X65,0X73,0X20,0X62,0X65,0X79,0X6F,0X6E,0X64,0X20,0X74,0X68,0X65,0X20,0X31,0X32,0X36,0X20,0X62,0X79,0X74,0X65,0X20,0X6C,0X65,0X6E,0X20,0X66,0X69,0X65,0X6C,0X64,0X2E}, + .frame_len=167, + .raw_payload_len=159, + .expected_errno=0, + .descr="Mid-long valid binary frame", + .i=0, + .simulate_sock_malfunction_at=0, + .errno_val=0, + .close_sock_at=0 + }, + { + .frame={0X88,0X82,0X71,0X1D,0X00,0XFE,0X72,0XF6}, + .expectedDecodeBuf={0X03,0XEB}, + .frame_len=8, + .raw_payload_len=2, + .expected_errno=104, + .descr="Close frame (Reason 1003)", + .i=0, + .simulate_sock_malfunction_at=0, + .errno_val=0, + .close_sock_at=0 + }, + { + .frame={0X88,0XAD,0XD0,0X8D,0X26,0XD8,0XD3,0X66,0X6F,0XFF,0XBD,0XAD,0X47,0XF8,0XB3,0XE1,0X49,0XAB,0XB5,0XAD,0X54,0XBD,0XB1,0XFE,0X49,0XB6,0XF0,0XEC,0X48,0XBC,0XF0,0XE0,0X53,0XBB,0XB8,0XAD,0X4B,0XB7,0XA2,0XE8,0X06,0XAC,0XB8,0XEC,0X48,0XF8,0XA4,0XE5,0X47,0XAC,0XF1}, + .expectedDecodeBuf={0X03,0XEB,0X49,0X27,0X6D,0X20,0X61,0X20,0X63,0X6C,0X6F,0X73,0X65,0X20,0X72,0X65,0X61,0X73,0X6F,0X6E,0X20,0X61,0X6E,0X64,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X68,0X61,0X6E,0X20,0X74,0X68,0X61,0X74,0X21}, + .frame_len=51, + .raw_payload_len=45, + .expected_errno=104, + .descr="Close frame (Reason 1003) and msg", + .i=0, + .simulate_sock_malfunction_at=0, + .errno_val=0, + .close_sock_at=0 + }, + { + .frame={0X81,0X08,0X56,0X47,0X56,0X7A,0X64,0X47,0X6C,0X30}, + .expectedDecodeBuf={0X54,0X65,0X73,0X74,0X69,0X74}, + .frame_len=10, + .raw_payload_len=6, + .expected_errno=71, + .descr="Invalid frame: Wrong masking", + .i=0, + .simulate_sock_malfunction_at=0, + .errno_val=0, + .close_sock_at=0 + }, + { + .frame={0X81,0XFE,0X00,0X0F,0X24,0X22,0X8D,0X9C,0X11,0X6F,0XA3,0XC6,0X6E,0X4E,0X88,0XB0,0X48,0X55,0XA2,0XC6,0X72,0X56}, + .expectedDecodeBuf={0X2E,0XFE,0X00,0X0F,0X72,0X65,0X20,0X49,0X70,0X73,0X75,0X6D}, + .frame_len=22, + .raw_payload_len=12, + .expected_errno=71, + .descr="Invalid frame: Length of < 126 with add. 16 bit len field", + .i=0, + .simulate_sock_malfunction_at=0, + .errno_val=0, + .close_sock_at=0 + }, + { + .frame={0X81,0XFF,0X00,0X00,0X00,0X00,0X80,0X40,0X7D,0XBB,0X03,0X56,0X7D,0XBB,0X03,0X56,0X7C,0X83,0X2D,0X0C,0X03,0XA2,0X06,0X7A,0X25,0XB9,0X2C,0X0C,0X1F,0XBA}, + .expectedDecodeBuf={0X2E,0XFF,0X00,0X00,0X00,0X00,0X80,0X40,0X4C,0X6F,0X72,0X65,0X20,0X49,0X70,0X73,0X75,0X6D}, + .frame_len=30, + .raw_payload_len=18, + .expected_errno=71, + .descr="Invalid frame: Length of < 126 with add. 64 bit len field", + .i=0, + .simulate_sock_malfunction_at=0, + .errno_val=0, + .close_sock_at=0 + } +}; -- cgit v1.2.3 From a90a43cda546f6f4304623ebd5e6dd9cdb87fc16 Mon Sep 17 00:00:00 2001 From: Andreas Weigel Date: Thu, 23 Feb 2017 10:05:40 +0100 Subject: remove Hixie-specific MD5 and check functions --- libvncserver/rfbserver.c | 5 ---- libvncserver/websockets.c | 63 ----------------------------------------------- rfb/rfb.h | 1 - 3 files changed, 69 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index 040238d..116c488 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -1999,11 +1999,6 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) char encBuf[64]; char encBuf2[64]; -#ifdef LIBVNCSERVER_WITH_WEBSOCKETS - if (cl->wsctx && webSocketCheckDisconnect(cl)) - return; -#endif - if ((n = rfbReadExact(cl, (char *)&msg, 1)) <= 0) { if (n != 0) rfbLogPerror("rfbProcessClientNormalMessage: read"); diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index ab9cabb..73ad81c 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -96,7 +96,6 @@ struct timeval #endif static rfbBool webSocketsHandshake(rfbClientPtr cl, char *scheme); -void webSocketsGenMd5(char * target, char *key1, char *key2, char *key3); static int webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst); @@ -350,56 +349,6 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) return TRUE; } -void -webSocketsGenMd5(char * target, char *key1, char *key2, char *key3) -{ - unsigned int i, spaces1 = 0, spaces2 = 0; - unsigned long num1 = 0, num2 = 0; - unsigned char buf[17]; - struct iovec iov[1]; - - for (i=0; i < strlen(key1); i++) { - if (key1[i] == ' ') { - spaces1 += 1; - } - if ((key1[i] >= 48) && (key1[i] <= 57)) { - num1 = num1 * 10 + (key1[i] - 48); - } - } - num1 = num1 / spaces1; - - for (i=0; i < strlen(key2); i++) { - if (key2[i] == ' ') { - spaces2 += 1; - } - if ((key2[i] >= 48) && (key2[i] <= 57)) { - num2 = num2 * 10 + (key2[i] - 48); - } - } - num2 = num2 / spaces2; - - /* Pack it big-endian */ - buf[0] = (num1 & 0xff000000) >> 24; - buf[1] = (num1 & 0xff0000) >> 16; - buf[2] = (num1 & 0xff00) >> 8; - buf[3] = num1 & 0xff; - - buf[4] = (num2 & 0xff000000) >> 24; - buf[5] = (num2 & 0xff0000) >> 16; - buf[6] = (num2 & 0xff00) >> 8; - buf[7] = num2 & 0xff; - - strncpy((char *)buf+8, key3, 8); - buf[16] = '\0'; - - iov[0].iov_base = buf; - iov[0].iov_len = 16; - digestmd5(iov, 1, target); - target[16] = '\0'; - - return; -} - static int ws_read(void *ctxPtr, char *buf, size_t len) { @@ -492,18 +441,6 @@ webSocketsDecode(rfbClientPtr cl, char *dst, int len) return webSocketsDecodeHybi(wsctx, dst, len); } - -/* returns TRUE if client sent a close frame or a single 'end of frame' - * marker was received, FALSE otherwise - * - * Note: This was a Hixie-only hack! - **/ -rfbBool -webSocketCheckDisconnect(rfbClientPtr cl) -{ - return FALSE; -} - /* returns TRUE if there is data waiting to be read in our internal buffer * or if is there any pending data in the buffer of the SSL implementation */ diff --git a/rfb/rfb.h b/rfb/rfb.h index f982b40..9aace0d 100644 --- a/rfb/rfb.h +++ b/rfb/rfb.h @@ -763,7 +763,6 @@ extern rfbBool rfbSetNonBlocking(int sock); /* websockets.c */ extern rfbBool webSocketsCheck(rfbClientPtr cl); -extern rfbBool webSocketCheckDisconnect(rfbClientPtr cl); extern int webSocketsEncode(rfbClientPtr cl, const char *src, int len, char **dst); extern int webSocketsDecode(rfbClientPtr cl, char *dst, int len); extern rfbBool webSocketsHasDataInBuffer(rfbClientPtr cl); -- cgit v1.2.3 From 5d9d6a87124a5439d3432c37a67f9b2babe04407 Mon Sep 17 00:00:00 2001 From: Andreas Weigel Date: Mon, 27 Feb 2017 08:45:32 +0100 Subject: add decode support for continuation frames use FIN bit and implement opcode 0x00 make consistent use of uint64_t for big frame sizes --- libvncserver/websockets.c | 3 +- libvncserver/ws_decode.c | 137 +++++++++++++++++++++++++++++++++++++--------- libvncserver/ws_decode.h | 32 +++++------ test/wsmaketestframe.py | 15 +++-- test/wstest.c | 29 +++++----- test/wstestdata.inc | 54 +++++++++++++++--- 6 files changed, 196 insertions(+), 74 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index 73ad81c..921015d 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -339,12 +339,11 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) free(buf); wsctx = calloc(1, sizeof(ws_ctx_t)); - wsctx->version = WEBSOCKETS_VERSION_HYBI; wsctx->encode = webSocketsEncodeHybi; wsctx->decode = webSocketsDecodeHybi; wsctx->ctxInfo.readFunc = ws_read; wsctx->base64 = base64; - hybiDecodeCleanup(wsctx); + hybiDecodeCleanupComplete(wsctx); cl->wsctx = (wsCtx *)wsctx; return TRUE; } diff --git a/libvncserver/ws_decode.c b/libvncserver/ws_decode.c index 472a44a..485478d 100644 --- a/libvncserver/ws_decode.c +++ b/libvncserver/ws_decode.c @@ -8,17 +8,27 @@ #define WS_HYBI_HEADER_LEN_EXTENDED 4 + WS_HYBI_MASK_LEN #define WS_HYBI_HEADER_LEN_LONG 10 + WS_HYBI_MASK_LEN -static int +static inline int +isControlFrame(ws_ctx_t *wsctx) +{ + return 0 != (wsctx->header.opcode & 0x08); +} + +static uint64_t hybiRemaining(ws_ctx_t *wsctx) { return wsctx->nToRead - wsctx->nReadRaw; } -void -hybiDecodeCleanup(ws_ctx_t *wsctx) +static void +hybiDecodeCleanupBasics(ws_ctx_t *wsctx) { + /* keep opcode, cleanup rest */ + wsctx->header.opcode = WS_OPCODE_INVALID; wsctx->header.payloadLen = 0; wsctx->header.mask.u = 0; + wsctx->header.headerLen = 0; + wsctx->header.data = NULL; wsctx->nReadRaw = 0; wsctx->nToRead= 0; wsctx->carrylen = 0; @@ -26,9 +36,24 @@ hybiDecodeCleanup(ws_ctx_t *wsctx) wsctx->readlen = 0; wsctx->hybiDecodeState = WS_HYBI_STATE_HEADER_PENDING; wsctx->writePos = NULL; - rfbLog("cleaned up wsctx\n"); } +static void +hybiDecodeCleanupForContinuation(ws_ctx_t *wsctx) +{ + hybiDecodeCleanupBasics(wsctx); + rfbLog("clean up frame, but expect continuation with opcode %d\n", wsctx->continuation_opcode); +} + +void +hybiDecodeCleanupComplete(ws_ctx_t *wsctx) +{ + hybiDecodeCleanupBasics(wsctx); + wsctx->continuation_opcode = WS_OPCODE_INVALID; + rfbLog("cleaned up wsctx completely\n"); +} + + /** * Return payload data that has been decoded/unmasked from * a websocket frame. @@ -94,10 +119,9 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) { int ret; char *headerDst = wsctx->codeBufDecode + wsctx->nReadRaw; - int n = WSHLENMAX - wsctx->nReadRaw; + int n = ((uint64_t)WSHLENMAX) - wsctx->nReadRaw; rfbLog("header_read to %p with len=%d\n", headerDst, n); - //ret = ws_read(cl, headerDst, n); ret = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, headerDst, n); rfbLog("read %d bytes from socket\n", ret); if (ret <= 0) { @@ -106,29 +130,65 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) int olderrno = errno; rfbErr("%s: read; %s\n", __func__, strerror(errno)); errno = olderrno; - *sockRet = -1; + goto err_cleanup_state; } else { *sockRet = 0; + goto err_cleanup_state_sock_closed; } - return WS_HYBI_STATE_ERR; } wsctx->nReadRaw += ret; if (wsctx->nReadRaw < 2) { /* cannot decode header with less than two bytes */ - errno = EAGAIN; - *sockRet = -1; - return WS_HYBI_STATE_HEADER_PENDING; + goto ret_header_pending; } /* first two header bytes received; interpret header data and get rest */ wsctx->header.data = (ws_header_t *)wsctx->codeBufDecode; wsctx->header.opcode = wsctx->header.data->b0 & 0x0f; + wsctx->header.fin = (wsctx->header.data->b0 & 0x80) >> 7; + if (isControlFrame(wsctx)) { + rfbLog("is control frame\n"); + /* is a control frame, leave remembered continuation opcode unchanged; + * just check if there is a wrong fragmentation */ + if (wsctx->header.fin == 0) { + + /* we only accept text/binary continuation frames; RFC6455: + * Control frames (see Section 5.5) MAY be injected in the middle of + * a fragmented message. Control frames themselves MUST NOT be + * fragmented. */ + rfbErr("control frame with FIN bit cleared received, aborting\n"); + errno = EPROTO; + goto err_cleanup_state; + } + } else { + rfbLog("not a control frame\n"); + /* not a control frame, check for continuation opcode */ + if (wsctx->header.opcode == WS_OPCODE_CONTINUATION) { + rfbLog("cont_frame\n"); + /* do we have state (i.e., opcode) for continuation frame? */ + if (wsctx->continuation_opcode == WS_OPCODE_INVALID) { + rfbErr("no continuation state\n"); + errno = EPROTO; + goto err_cleanup_state; + } - /* fin = (header->b0 & 0x80) >> 7; */ /* not used atm */ - wsctx->header.payloadLen = wsctx->header.data->b1 & 0x7f; - rfbLog("first header bytes received; opcode=%d lenbyte=%d\n", wsctx->header.opcode, wsctx->header.payloadLen); + /* otherwise, set opcode = continuation_opcode */ + wsctx->header.opcode = wsctx->continuation_opcode; + rfbLog("set opcode to continuation_opcode: %d\n", wsctx->header.opcode); + } else { + if (wsctx->header.fin == 0) { + wsctx->continuation_opcode = wsctx->header.opcode; + } else { + wsctx->continuation_opcode = WS_OPCODE_INVALID; + } + rfbLog("set continuation_opcode to %d\n", wsctx->continuation_opcode); + } + } + + wsctx->header.payloadLen = (uint64_t)(wsctx->header.data->b1 & 0x7f); + rfbLog("first header bytes received; opcode=%d lenbyte=%d fin=%d\n", wsctx->header.opcode, wsctx->header.payloadLen, wsctx->header.fin); /* * 4.3. Client-to-Server Masking @@ -139,8 +199,7 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) if (!(wsctx->header.data->b1 & 0x80)) { rfbErr("%s: got frame without mask; ret=%d\n", __func__, ret); errno = EPROTO; - *sockRet = -1; - return WS_HYBI_STATE_ERR; + goto err_cleanup_state; } @@ -158,22 +217,27 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) } else { /* Incomplete frame header, try again */ rfbErr("%s: incomplete frame header; ret=%d\n", __func__, ret); - errno = EAGAIN; - *sockRet = -1; - return WS_HYBI_STATE_HEADER_PENDING; + goto ret_header_pending; } + char *h = wsctx->codeBufDecode; + int i; + rfbLog("Header:\n"); + for (i=0; i <10; i++) { + rfbLog("0x%02X\n", (unsigned char)h[i]); + } + rfbLog("\n"); + /* while RFC 6455 mandates that lengths MUST be encoded with the minimum * number of bytes, it does not specify for the server how to react on * 'wrongly' encoded frames --- this implementation rejects them*/ if ((wsctx->header.headerLen > WS_HYBI_HEADER_LEN_SHORT - && wsctx->header.payloadLen < 126) + && wsctx->header.payloadLen < (uint64_t)126) || (wsctx->header.headerLen > WS_HYBI_HEADER_LEN_EXTENDED - && wsctx->header.payloadLen < 65536)) { + && wsctx->header.payloadLen < (uint64_t)65536)) { rfbErr("%s: invalid length field; headerLen=%d payloadLen=%llu\n", __func__, wsctx->header.headerLen, wsctx->header.payloadLen); errno = EPROTO; - *sockRet = -1; - return WS_HYBI_STATE_ERR; + goto err_cleanup_state; } /* absolute length of frame */ @@ -186,9 +250,20 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) wsctx->readPos = (unsigned char *)(wsctx->codeBufDecode + wsctx->header.headerLen); *nPayload = wsctx->nReadRaw - wsctx->header.headerLen; - rfbLog("header complete: state=%d flen=%d writeTo=%p nPayload=%d\n", wsctx->hybiDecodeState, wsctx->nToRead, wsctx->writePos, *nPayload); + rfbLog("header complete: state=%d flen=%llu writeTo=%p nPayload=%d\n", wsctx->hybiDecodeState, wsctx->nToRead, wsctx->writePos, *nPayload); return WS_HYBI_STATE_DATA_NEEDED; + +ret_header_pending: + errno = EAGAIN; + *sockRet = -1; + return WS_HYBI_STATE_HEADER_PENDING; + +err_cleanup_state: + *sockRet = -1; +err_cleanup_state_sock_closed: + hybiDecodeCleanupComplete(wsctx); + return WS_HYBI_STATE_ERR; } static int @@ -248,6 +323,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) /* -1 accounts for potential '\0' terminator for base64 decoding */ bufsize = wsctx->codeBufDecode + ARRAYSIZE(wsctx->codeBufDecode) - wsctx->writePos - 1; + rfbLog("bufsize=%d\n", bufsize); if (hybiRemaining(wsctx) > bufsize) { nextRead = bufsize; } else { @@ -453,11 +529,18 @@ spor: /* rfbLog("%s: ret: %d/%d\n", __func__, result, len); */ if (wsctx->hybiDecodeState == WS_HYBI_STATE_FRAME_COMPLETE) { rfbLog("frame received successfully, cleaning up: read=%d hlen=%d plen=%d\n", wsctx->header.nRead, wsctx->header.headerLen, wsctx->header.payloadLen); - /* frame finished, cleanup state */ - hybiDecodeCleanup(wsctx); + if (wsctx->header.fin && !isControlFrame(wsctx)) { + /* frame finished, cleanup state */ + hybiDecodeCleanupComplete(wsctx); + } else { + /* always retain continuation opcode for unfinished data frames + * or control frames, which may interleave with data frames */ + hybiDecodeCleanupForContinuation(wsctx); + } } else if (wsctx->hybiDecodeState == WS_HYBI_STATE_ERR) { - hybiDecodeCleanup(wsctx); + hybiDecodeCleanupComplete(wsctx); } + rfbLog("%s_exit: len=%d; " "CTX: readlen=%d readPos=%p " "writePos=%p " diff --git a/libvncserver/ws_decode.h b/libvncserver/ws_decode.h index 0dcbc83..07d37bd 100644 --- a/libvncserver/ws_decode.h +++ b/libvncserver/ws_decode.h @@ -27,16 +27,11 @@ #endif #define B64LEN(__x) (((__x + 2) / 3) * 12 / 3) -#define WSHLENMAX 14 /* 2 + sizeof(uint64_t) + sizeof(uint32_t) */ +#define WSHLENMAX 14LL /* 2 + sizeof(uint64_t) + sizeof(uint32_t) */ #define WS_HYBI_MASK_LEN 4 #define ARRAYSIZE(a) ((sizeof(a) / sizeof((a[0]))) / (size_t)(!(sizeof(a) % sizeof((a[0]))))) -enum { - WEBSOCKETS_VERSION_HIXIE, - WEBSOCKETS_VERSION_HYBI -}; - struct ws_ctx_s; typedef struct ws_ctx_s ws_ctx_t; @@ -111,9 +106,11 @@ typedef struct ws_header_data_s { /** length of frame header including payload len, but without mask */ int headerLen; /** length of the payload data */ - int payloadLen; + uint64_t payloadLen; /** opcode */ unsigned char opcode; + /** fin bit */ + unsigned char fin; } ws_header_data_t; typedef struct ws_ctx_s { @@ -125,11 +122,11 @@ typedef struct ws_ctx_s { int hybiDecodeState; char carryBuf[3]; /* For base64 carry-over */ int carrylen; - int version; int base64; ws_header_data_t header; - int nReadRaw; - int nToRead; + uint64_t nReadRaw; + uint64_t nToRead; + unsigned char continuation_opcode; wsEncodeFunc encode; wsDecodeFunc decode; ctxInfo_t ctxInfo; @@ -137,15 +134,16 @@ typedef struct ws_ctx_s { enum { - WS_OPCODE_CONTINUATION = 0x0, - WS_OPCODE_TEXT_FRAME, - WS_OPCODE_BINARY_FRAME, - WS_OPCODE_CLOSE = 0x8, - WS_OPCODE_PING, - WS_OPCODE_PONG + WS_OPCODE_CONTINUATION = 0x00, + WS_OPCODE_TEXT_FRAME = 0x01, + WS_OPCODE_BINARY_FRAME = 0x02, + WS_OPCODE_CLOSE = 0x08, + WS_OPCODE_PING = 0x09, + WS_OPCODE_PONG = 0x0A, + WS_OPCODE_INVALID = 0xFF }; int webSocketsDecodeHybi(ws_ctx_t *wsctx, char *dst, int len); -void hybiDecodeCleanup(ws_ctx_t *wsctx); +void hybiDecodeCleanupComplete(ws_ctx_t *wsctx); #endif diff --git a/test/wsmaketestframe.py b/test/wsmaketestframe.py index 1d4d24d..fc03e39 100755 --- a/test/wsmaketestframe.py +++ b/test/wsmaketestframe.py @@ -42,12 +42,12 @@ def add_field(s, name, value, first=False): class Testframe(): - def __init__(self, frame, descr, modify_bytes={}, experrno=0, mask=True): + def __init__(self, frame, descr, modify_bytes={}, experrno=0, mask=True, opcode_overwrite=False): self.frame = frame self.descr = descr self.modify_bytes = modify_bytes self.experrno = experrno - self.b64 = True if frame.opcode == 1 else False + self.b64 = True if frame.opcode == 1 or opcode_overwrite == 1 else False self.mask = mask def to_carray_initializer(self, buf): @@ -110,7 +110,14 @@ flist.append(Testframe(websockets.framing.Frame(1, 8, bytearray(list([0x03, 0xEB ### invalid header values flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("Testit", encoding="utf-8")), "Invalid frame: Wrong masking", experrno="EPROTO", mask=False)) flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("..Lore Ipsum", encoding="utf-8")), "Invalid frame: Length of < 126 with add. 16 bit len field", experrno="EPROTO", modify_bytes={ 1: 0xFE, 2: 0x00, 3: 0x0F})) -flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("........Lore Ipsum", encoding="utf-8")), "Invalid frame: Length of < 126 with add. 64 bit len field", experrno="EPROTO", modify_bytes={ 1: 0xFF, 2: 0x00, 3: 0x00, 4: 0x00, 5: 0x00, 6: 0x80, 7: 0x40})) +flist.append(Testframe(websockets.framing.Frame(1, 1, bytearray("........Lore Ipsum", encoding="utf-8")), "Invalid frame: Length of < 126 with add. 64 bit len field", experrno="EPROTO", modify_bytes={ 1: 0xFF, 2: 0x00, 3: 0x00, 4: 0x00, 5: 0x00, 6: 0x00, 7: 0x00, 8: 0x80, 9: 0x40})) + +frag1 = websockets.framing.Frame(0, 1, bytearray("This is a fragmented websocket...", encoding="utf-8")) +frag2 = websockets.framing.Frame(0, 0, bytearray("... and it goes on...", encoding="utf-8")) +frag3 = websockets.framing.Frame(1, 0, bytearray("and on and stop", encoding="utf-8")) +flist.append(Testframe(frag1, "Continuation test frag1")) +flist.append(Testframe(frag2, "Continuation test frag2", opcode_overwrite=1)) +flist.append(Testframe(frag3, "Continuation test frag3", opcode_overwrite=1)) s = "struct ws_frame_test tests[] = {\n" for i in range(len(flist)): @@ -120,5 +127,5 @@ for i in range(len(flist)): s += "\n" s += "};\n" -with open("wstestdata.c", "w") as cdatafile: +with open("wstestdata.inc", "w") as cdatafile: cdatafile.write(s) diff --git a/test/wstest.c b/test/wstest.c index 69cd174..042b75b 100644 --- a/test/wstest.c +++ b/test/wstest.c @@ -98,10 +98,10 @@ static int emu_read(void *ctx, char *dst, size_t len) rfbLog("emu_read called with dst=%p and len=%lu\n", dst, len); if (ft->simulate_sock_malfunction_at > 0 && ft->simulate_sock_malfunction_at == ft->i) { rfbLog("simulating IO error with errno=%d\n", ft->errno_val); - errno = ft->errno_val; + errno = ft->errno_val; return -1; } - + /* return something */ r = rand(); modu = (ft->frame + ft->frame_len) - ft->pos; @@ -130,7 +130,7 @@ static uint64_t run_test(struct ws_frame_test *ft, ws_ctx_t *ctx) while (nleft > 0) { rfbLog("calling ws_decode with dst=%p, len=%lu\n", dst, nleft); n = ctx->decode(ctx, dst, nleft); - rfbLog("read n=%ld\n", n); + rfbLog("read n=%ld\n", n); if (n == 0) { if (ft->close_sock_at > 0) { return OK; @@ -155,7 +155,7 @@ static uint64_t run_test(struct ws_frame_test *ft, ws_ctx_t *ctx) rfbLog("read n=%ld from decode; dst=%p, nleft=%lu\n", n, dst, nleft); } } - + if (memcmp(ft->expectedDecodeBuf, dstbuf, ft->raw_payload_len) != 0) { ft->expectedDecodeBuf[ft->raw_payload_len] = '\0'; dstbuf[ft->raw_payload_len] = '\0'; @@ -168,24 +168,23 @@ static uint64_t run_test(struct ws_frame_test *ft, ws_ctx_t *ctx) int main() -{ +{ ws_ctx_t ctx; int retall= 0; int i; - srand(RND_SEED); + srand(RND_SEED); + hybiDecodeCleanupComplete(&ctx); + ctx.decode = webSocketsDecodeHybi; + ctx.ctxInfo.readFunc = emu_read; + rfbLog = logtest; + rfbErr = logtest; + for (i = 0; i < ARRAYSIZE(tests); i++) { int ret; + /* reset output log buffer to begin */ el_pos = el_log; - rfbLog = logtest; - rfbErr = logtest; - - hybiDecodeCleanup(&ctx); - ctx.decode = webSocketsDecodeHybi; - ctx.version = WEBSOCKETS_VERSION_HYBI; - - ctx.ctxInfo.readFunc = emu_read; ret = run_test(&tests[i], &ctx); printf("%s: \"%s\"\n", ret == 0 ? "PASS" : "FAIL", tests[i].descr); @@ -198,7 +197,7 @@ int main() return retall; } -#else +#else int main() { return 0; diff --git a/test/wstestdata.inc b/test/wstestdata.inc index 9dc919e..595b891 100644 --- a/test/wstestdata.inc +++ b/test/wstestdata.inc @@ -1,6 +1,6 @@ struct ws_frame_test tests[] = { { - .frame={0X81,0X88,0XB7,0XDB,0X16,0X16,0XE1,0X9C,0X40,0X6C,0XD3,0X9C,0X7A,0X26}, + .frame={0X81,0X88,0X2F,0X2A,0X17,0X41,0X79,0X6D,0X41,0X3B,0X4B,0X6D,0X7B,0X71}, .expectedDecodeBuf={0X54,0X65,0X73,0X74,0X69,0X74}, .frame_len=14, .raw_payload_len=6, @@ -12,7 +12,7 @@ struct ws_frame_test tests[] = { .close_sock_at=0 }, { - .frame={0X81,0XFE,0X00,0XD4,0X67,0XFE,0X8A,0X31,0X35,0X90,0XC0,0X59,0X05,0XA9,0XDF,0X48,0X2E,0XB9,0XD8,0X47,0X3D,0XA6,0XC7,0X56,0X3E,0XCC,0XB3,0X44,0X03,0XB9,0XCC,0X41,0X05,0X97,0XC8,0X45,0X03,0XA9,0XC4,0X5E,0X2E,0XB9,0XBB,0X47,0X04,0X93,0XDF,0X56,0X03,0XB9,0XDC,0X05,0X03,0XBD,0XC8,0X59,0X05,0X93,0XDB,0X56,0X3D,0XA6,0XD0,0X5D,0X05,0X97,0XC8,0X5F,0X05,0XCC,0XDC,0X4B,0X2E,0XB9,0XC0,0X5D,0X02,0XA9,0XB3,0X44,0X3D,0XBD,0XC8,0X01,0X06,0XB9,0XDF,0X56,0X2A,0XAA,0XC3,0X03,0X2E,0XB9,0XC0,0X04,0X03,0XB9,0XDF,0X56,0X05,0XB9,0XDC,0X44,0X2E,0XB9,0XD0,0X41,0X3D,0XA9,0XF2,0X5A,0X2B,0X97,0XC8,0X76,0X04,0X93,0XCC,0X45,0X3D,0XAA,0XC3,0X56,0X3D,0XB9,0XB3,0X5D,0X04,0X87,0XC8,0X5B,0X05,0XCC,0XBF,0X01,0X3E,0XA9,0XE6,0X44,0X2E,0XB9,0XBB,0X00,0X3E,0XCC,0XED,0X56,0X05,0XA9,0XB3,0X48,0X3D,0XAD,0XC8,0X01,0X3D,0XA6,0XE2,0X01,0X2E,0XB9,0XCC,0X44,0X3D,0XBD,0XC8,0X5D,0X03,0X93,0XDC,0X44,0X2E,0XB9,0XEE,0X47,0X3D,0XA6,0XC7,0X56,0X3E,0X93,0XDC,0X04,0X05,0XCC,0XBF,0X5A,0X2E,0XB6,0XD8,0X5E,0X3D,0XAD,0XCB,0X49,0X2A,0X94,0XD3,0X56,0X3E,0X90,0XE6,0X01,0X3D,0XAD,0XC8,0X42,0X3D,0XA9,0XBE,0X56,0X3D,0X93,0XE6,0X5D,0X05,0XB9,0XDB,0X44}, + .frame={0X81,0XFE,0X00,0XD4,0X66,0X27,0XE5,0X24,0X34,0X49,0XAF,0X4C,0X04,0X70,0XB0,0X5D,0X2F,0X60,0XB7,0X52,0X3C,0X7F,0XA8,0X43,0X3F,0X15,0XDC,0X51,0X02,0X60,0XA3,0X54,0X04,0X4E,0XA7,0X50,0X02,0X70,0XAB,0X4B,0X2F,0X60,0XD4,0X52,0X05,0X4A,0XB0,0X43,0X02,0X60,0XB3,0X10,0X02,0X64,0XA7,0X4C,0X04,0X4A,0XB4,0X43,0X3C,0X7F,0XBF,0X48,0X04,0X4E,0XA7,0X4A,0X04,0X15,0XB3,0X5E,0X2F,0X60,0XAF,0X48,0X03,0X70,0XDC,0X51,0X3C,0X64,0XA7,0X14,0X07,0X60,0XB0,0X43,0X2B,0X73,0XAC,0X16,0X2F,0X60,0XAF,0X11,0X02,0X60,0XB0,0X43,0X04,0X60,0XB3,0X51,0X2F,0X60,0XBF,0X54,0X3C,0X70,0X9D,0X4F,0X2A,0X4E,0XA7,0X63,0X05,0X4A,0XA3,0X50,0X3C,0X73,0XAC,0X43,0X3C,0X60,0XDC,0X48,0X05,0X5E,0XA7,0X4E,0X04,0X15,0XD0,0X14,0X3F,0X70,0X89,0X51,0X2F,0X60,0XD4,0X15,0X3F,0X15,0X82,0X43,0X04,0X70,0XDC,0X5D,0X3C,0X74,0XA7,0X14,0X3C,0X7F,0X8D,0X14,0X2F,0X60,0XA3,0X51,0X3C,0X64,0XA7,0X48,0X02,0X4A,0XB3,0X51,0X2F,0X60,0X81,0X52,0X3C,0X7F,0XA8,0X43,0X3F,0X4A,0XB3,0X11,0X04,0X15,0XD0,0X4F,0X2F,0X6F,0XB7,0X4B,0X3C,0X74,0XA4,0X5C,0X2B,0X4D,0XBC,0X43,0X3F,0X49,0X89,0X14,0X3C,0X74,0XA7,0X57,0X3C,0X70,0XD1,0X43,0X3C,0X4A,0X89,0X48,0X04,0X60,0XB4,0X51}, .expectedDecodeBuf={0X46,0X72,0X61,0X6D,0X65,0X32,0X20,0X64,0X6F,0X65,0X73,0X20,0X63,0X6F,0X6E,0X74,0X61,0X69,0X6E,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X65,0X78,0X74,0X20,0X61,0X6E,0X64,0X20,0X65,0X76,0X65,0X6E,0X20,0X67,0X6F,0X65,0X73,0X20,0X62,0X65,0X79,0X6F,0X6E,0X64,0X20,0X74,0X68,0X65,0X20,0X31,0X32,0X36,0X20,0X62,0X79,0X74,0X65,0X20,0X6C,0X65,0X6E,0X20,0X66,0X69,0X65,0X6C,0X64,0X2E,0X20,0X46,0X72,0X61,0X6D,0X65,0X32,0X20,0X64,0X6F,0X65,0X73,0X20,0X63,0X6F,0X6E,0X74,0X61,0X69,0X6E,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X65,0X78,0X74,0X20,0X61,0X6E,0X64,0X20,0X65,0X76,0X65,0X6E,0X20,0X67,0X6F,0X65,0X73,0X20,0X62,0X65,0X79,0X6F,0X6E,0X64,0X20,0X74,0X68,0X65,0X20,0X31,0X32,0X36,0X20,0X62,0X79,0X74,0X65,0X20,0X6C,0X65,0X6E,0X20,0X66,0X69,0X65,0X6C,0X64,0X2E}, .frame_len=220, .raw_payload_len=159, @@ -24,7 +24,7 @@ struct ws_frame_test tests[] = { .close_sock_at=0 }, { - .frame={0X82,0X86,0X90,0X5E,0X2B,0X8E,0XC4,0X3B,0X58,0XFA,0XF9,0X2A}, + .frame={0X82,0X86,0XDD,0X9B,0XD8,0X56,0X89,0XFE,0XAB,0X22,0XB4,0XEF}, .expectedDecodeBuf={0X54,0X65,0X73,0X74,0X69,0X74}, .frame_len=12, .raw_payload_len=6, @@ -36,7 +36,7 @@ struct ws_frame_test tests[] = { .close_sock_at=0 }, { - .frame={0X82,0XFE,0X00,0X9F,0X7D,0X97,0X6B,0XA2,0X3B,0XE5,0X0A,0XCF,0X18,0XA5,0X4B,0XC6,0X12,0XF2,0X18,0X82,0X1E,0XF8,0X05,0XD6,0X1C,0XFE,0X05,0X82,0X10,0XE2,0X08,0XCA,0X5D,0XFA,0X04,0XD0,0X18,0XB7,0X1F,0XC7,0X05,0XE3,0X4B,0XC3,0X13,0XF3,0X4B,0XC7,0X0B,0XF2,0X05,0X82,0X1A,0XF8,0X0E,0XD1,0X5D,0XF5,0X0E,0XDB,0X12,0XF9,0X0F,0X82,0X09,0XFF,0X0E,0X82,0X4C,0XA5,0X5D,0X82,0X1F,0XEE,0X1F,0XC7,0X5D,0XFB,0X0E,0XCC,0X5D,0XF1,0X02,0XC7,0X11,0XF3,0X45,0X82,0X3B,0XE5,0X0A,0XCF,0X18,0XA5,0X4B,0XC6,0X12,0XF2,0X18,0X82,0X1E,0XF8,0X05,0XD6,0X1C,0XFE,0X05,0X82,0X10,0XE2,0X08,0XCA,0X5D,0XFA,0X04,0XD0,0X18,0XB7,0X1F,0XC7,0X05,0XE3,0X4B,0XC3,0X13,0XF3,0X4B,0XC7,0X0B,0XF2,0X05,0X82,0X1A,0XF8,0X0E,0XD1,0X5D,0XF5,0X0E,0XDB,0X12,0XF9,0X0F,0X82,0X09,0XFF,0X0E,0X82,0X4C,0XA5,0X5D,0X82,0X1F,0XEE,0X1F,0XC7,0X5D,0XFB,0X0E,0XCC,0X5D,0XF1,0X02,0XC7,0X11,0XF3,0X45}, + .frame={0X82,0XFE,0X00,0X9F,0XB5,0X6E,0X7F,0X4C,0XF3,0X1C,0X1E,0X21,0XD0,0X5C,0X5F,0X28,0XDA,0X0B,0X0C,0X6C,0XD6,0X01,0X11,0X38,0XD4,0X07,0X11,0X6C,0XD8,0X1B,0X1C,0X24,0X95,0X03,0X10,0X3E,0XD0,0X4E,0X0B,0X29,0XCD,0X1A,0X5F,0X2D,0XDB,0X0A,0X5F,0X29,0XC3,0X0B,0X11,0X6C,0XD2,0X01,0X1A,0X3F,0X95,0X0C,0X1A,0X35,0XDA,0X00,0X1B,0X6C,0XC1,0X06,0X1A,0X6C,0X84,0X5C,0X49,0X6C,0XD7,0X17,0X0B,0X29,0X95,0X02,0X1A,0X22,0X95,0X08,0X16,0X29,0XD9,0X0A,0X51,0X6C,0XF3,0X1C,0X1E,0X21,0XD0,0X5C,0X5F,0X28,0XDA,0X0B,0X0C,0X6C,0XD6,0X01,0X11,0X38,0XD4,0X07,0X11,0X6C,0XD8,0X1B,0X1C,0X24,0X95,0X03,0X10,0X3E,0XD0,0X4E,0X0B,0X29,0XCD,0X1A,0X5F,0X2D,0XDB,0X0A,0X5F,0X29,0XC3,0X0B,0X11,0X6C,0XD2,0X01,0X1A,0X3F,0X95,0X0C,0X1A,0X35,0XDA,0X00,0X1B,0X6C,0XC1,0X06,0X1A,0X6C,0X84,0X5C,0X49,0X6C,0XD7,0X17,0X0B,0X29,0X95,0X02,0X1A,0X22,0X95,0X08,0X16,0X29,0XD9,0X0A,0X51}, .expectedDecodeBuf={0X46,0X72,0X61,0X6D,0X65,0X32,0X20,0X64,0X6F,0X65,0X73,0X20,0X63,0X6F,0X6E,0X74,0X61,0X69,0X6E,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X65,0X78,0X74,0X20,0X61,0X6E,0X64,0X20,0X65,0X76,0X65,0X6E,0X20,0X67,0X6F,0X65,0X73,0X20,0X62,0X65,0X79,0X6F,0X6E,0X64,0X20,0X74,0X68,0X65,0X20,0X31,0X32,0X36,0X20,0X62,0X79,0X74,0X65,0X20,0X6C,0X65,0X6E,0X20,0X66,0X69,0X65,0X6C,0X64,0X2E,0X20,0X46,0X72,0X61,0X6D,0X65,0X32,0X20,0X64,0X6F,0X65,0X73,0X20,0X63,0X6F,0X6E,0X74,0X61,0X69,0X6E,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X65,0X78,0X74,0X20,0X61,0X6E,0X64,0X20,0X65,0X76,0X65,0X6E,0X20,0X67,0X6F,0X65,0X73,0X20,0X62,0X65,0X79,0X6F,0X6E,0X64,0X20,0X74,0X68,0X65,0X20,0X31,0X32,0X36,0X20,0X62,0X79,0X74,0X65,0X20,0X6C,0X65,0X6E,0X20,0X66,0X69,0X65,0X6C,0X64,0X2E}, .frame_len=167, .raw_payload_len=159, @@ -48,7 +48,7 @@ struct ws_frame_test tests[] = { .close_sock_at=0 }, { - .frame={0X88,0X82,0X71,0X1D,0X00,0XFE,0X72,0XF6}, + .frame={0X88,0X82,0X6B,0X33,0X77,0X94,0X68,0XD8}, .expectedDecodeBuf={0X03,0XEB}, .frame_len=8, .raw_payload_len=2, @@ -60,7 +60,7 @@ struct ws_frame_test tests[] = { .close_sock_at=0 }, { - .frame={0X88,0XAD,0XD0,0X8D,0X26,0XD8,0XD3,0X66,0X6F,0XFF,0XBD,0XAD,0X47,0XF8,0XB3,0XE1,0X49,0XAB,0XB5,0XAD,0X54,0XBD,0XB1,0XFE,0X49,0XB6,0XF0,0XEC,0X48,0XBC,0XF0,0XE0,0X53,0XBB,0XB8,0XAD,0X4B,0XB7,0XA2,0XE8,0X06,0XAC,0XB8,0XEC,0X48,0XF8,0XA4,0XE5,0X47,0XAC,0XF1}, + .frame={0X88,0XAD,0X4B,0XA1,0XCE,0XE8,0X48,0X4A,0X87,0XCF,0X26,0X81,0XAF,0XC8,0X28,0XCD,0XA1,0X9B,0X2E,0X81,0XBC,0X8D,0X2A,0XD2,0XA1,0X86,0X6B,0XC0,0XA0,0X8C,0X6B,0XCC,0XBB,0X8B,0X23,0X81,0XA3,0X87,0X39,0XC4,0XEE,0X9C,0X23,0XC0,0XA0,0XC8,0X3F,0XC9,0XAF,0X9C,0X6A}, .expectedDecodeBuf={0X03,0XEB,0X49,0X27,0X6D,0X20,0X61,0X20,0X63,0X6C,0X6F,0X73,0X65,0X20,0X72,0X65,0X61,0X73,0X6F,0X6E,0X20,0X61,0X6E,0X64,0X20,0X6D,0X75,0X63,0X68,0X20,0X6D,0X6F,0X72,0X65,0X20,0X74,0X68,0X61,0X6E,0X20,0X74,0X68,0X61,0X74,0X21}, .frame_len=51, .raw_payload_len=45, @@ -84,7 +84,7 @@ struct ws_frame_test tests[] = { .close_sock_at=0 }, { - .frame={0X81,0XFE,0X00,0X0F,0X24,0X22,0X8D,0X9C,0X11,0X6F,0XA3,0XC6,0X6E,0X4E,0X88,0XB0,0X48,0X55,0XA2,0XC6,0X72,0X56}, + .frame={0X81,0XFE,0X00,0X0F,0X71,0XE9,0X29,0X79,0X44,0XA4,0X07,0X23,0X3B,0X85,0X2C,0X55,0X1D,0X9E,0X06,0X23,0X27,0X9D}, .expectedDecodeBuf={0X2E,0XFE,0X00,0X0F,0X72,0X65,0X20,0X49,0X70,0X73,0X75,0X6D}, .frame_len=22, .raw_payload_len=12, @@ -96,8 +96,8 @@ struct ws_frame_test tests[] = { .close_sock_at=0 }, { - .frame={0X81,0XFF,0X00,0X00,0X00,0X00,0X80,0X40,0X7D,0XBB,0X03,0X56,0X7D,0XBB,0X03,0X56,0X7C,0X83,0X2D,0X0C,0X03,0XA2,0X06,0X7A,0X25,0XB9,0X2C,0X0C,0X1F,0XBA}, - .expectedDecodeBuf={0X2E,0XFF,0X00,0X00,0X00,0X00,0X80,0X40,0X4C,0X6F,0X72,0X65,0X20,0X49,0X70,0X73,0X75,0X6D}, + .frame={0X81,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X80,0X40,0X2F,0X40,0XF3,0X5B,0X2F,0X40,0XF2,0X63,0X01,0X1A,0X8D,0X42,0X2A,0X6C,0XAB,0X59,0X00,0X1A,0X91,0X5A}, + .expectedDecodeBuf={0X2E,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X80,0X40,0X72,0X65,0X20,0X49,0X70,0X73,0X75,0X6D}, .frame_len=30, .raw_payload_len=18, .expected_errno=EPROTO, @@ -106,5 +106,41 @@ struct ws_frame_test tests[] = { .simulate_sock_malfunction_at=0, .errno_val=0, .close_sock_at=0 + }, + { + .frame={0X01,0XAC,0XC9,0X6E,0XC7,0X6E,0X9F,0X29,0XAF,0X1E,0XAA,0X17,0X85,0X1E,0XAA,0X17,0X85,0X06,0X80,0X29,0X9D,0X17,0X90,0X39,0XA3,0X1A,0X93,0X39,0XF2,0X5E,0X93,0X39,0X96,0X09,0XAD,0X5C,0X91,0X07,0XAA,0X5C,0XFE,0X04,0XA8,0X5C,0X91,0X5E,0X85,0X07,0XF3,0X1B}, + .expectedDecodeBuf={0X54,0X68,0X69,0X73,0X20,0X69,0X73,0X20,0X61,0X20,0X66,0X72,0X61,0X67,0X6D,0X65,0X6E,0X74,0X65,0X64,0X20,0X77,0X65,0X62,0X73,0X6F,0X63,0X6B,0X65,0X74,0X2E,0X2E,0X2E}, + .frame_len=50, + .raw_payload_len=33, + .expected_errno=0, + .descr="Continuation test frag1", + .i=0, + .simulate_sock_malfunction_at=0, + .errno_val=0, + .close_sock_at=0 + }, + { + .frame={0X00,0X9C,0X52,0XBC,0XD5,0X99,0X1E,0XD5,0XE1,0XEC,0X1B,0XFB,0X93,0XEC,0X08,0XFF,0X97,0XE9,0X36,0XFF,0X97,0XF7,0X30,0X8E,0X83,0XE3,0X1B,0XFB,0XEC,0XEC,0X1E,0XD5,0XE1,0XEC}, + .expectedDecodeBuf={0X2E,0X2E,0X2E,0X20,0X61,0X6E,0X64,0X20,0X69,0X74,0X20,0X67,0X6F,0X65,0X73,0X20,0X6F,0X6E,0X2E,0X2E,0X2E}, + .frame_len=34, + .raw_payload_len=21, + .expected_errno=0, + .descr="Continuation test frag2", + .i=0, + .simulate_sock_malfunction_at=0, + .errno_val=0, + .close_sock_at=0 + }, + { + .frame={0X80,0X94,0X3B,0X88,0XA1,0XE9,0X62,0XDF,0X94,0X82,0X72,0XCF,0X98,0X9C,0X72,0XCF,0XE7,0X9C,0X61,0XCB,0XE3,0X93,0X5F,0XCF,0X98,0X9E}, + .expectedDecodeBuf={0X61,0X6E,0X64,0X20,0X6F,0X6E,0X20,0X61,0X6E,0X64,0X20,0X73,0X74,0X6F,0X70}, + .frame_len=26, + .raw_payload_len=15, + .expected_errno=0, + .descr="Continuation test frag3", + .i=0, + .simulate_sock_malfunction_at=0, + .errno_val=0, + .close_sock_at=0 } }; -- cgit v1.2.3 From ef8d2852f546135c94282a4d634fe4ac9e7558a4 Mon Sep 17 00:00:00 2001 From: Andreas Weigel Date: Mon, 27 Feb 2017 09:00:19 +0100 Subject: remove potential 64 bit len overflow calculation --- libvncserver/ws_decode.c | 66 ++++++++++++++++++++++-------------------------- libvncserver/ws_decode.h | 3 +-- 2 files changed, 31 insertions(+), 38 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/ws_decode.c b/libvncserver/ws_decode.c index 485478d..4616fdc 100644 --- a/libvncserver/ws_decode.c +++ b/libvncserver/ws_decode.c @@ -14,10 +14,10 @@ isControlFrame(ws_ctx_t *wsctx) return 0 != (wsctx->header.opcode & 0x08); } -static uint64_t +static uint64_t hybiRemaining(ws_ctx_t *wsctx) { - return wsctx->nToRead - wsctx->nReadRaw; + return wsctx->header.payloadLen - wsctx->nReadPayload; } static void @@ -29,8 +29,8 @@ hybiDecodeCleanupBasics(ws_ctx_t *wsctx) wsctx->header.mask.u = 0; wsctx->header.headerLen = 0; wsctx->header.data = NULL; - wsctx->nReadRaw = 0; - wsctx->nToRead= 0; + wsctx->header.nRead = 0; + wsctx->nReadPayload = 0; wsctx->carrylen = 0; wsctx->readPos = (unsigned char *)wsctx->codeBufDecode; wsctx->readlen = 0; @@ -118,8 +118,9 @@ static int hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) { int ret; - char *headerDst = wsctx->codeBufDecode + wsctx->nReadRaw; - int n = ((uint64_t)WSHLENMAX) - wsctx->nReadRaw; + char *headerDst = wsctx->codeBufDecode + wsctx->header.nRead; + int n = ((uint64_t)WSHLENMAX) - wsctx->header.nRead; + rfbLog("header_read to %p with len=%d\n", headerDst, n); ret = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, headerDst, n); @@ -137,8 +138,8 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) } } - wsctx->nReadRaw += ret; - if (wsctx->nReadRaw < 2) { + wsctx->header.nRead += ret; + if (wsctx->header.nRead < 2) { /* cannot decode header with less than two bytes */ goto ret_header_pending; } @@ -203,14 +204,14 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) } - if (wsctx->header.payloadLen < 126 && wsctx->nReadRaw >= 6) { + if (wsctx->header.payloadLen < 126 && wsctx->header.nRead >= 6) { wsctx->header.headerLen = WS_HYBI_HEADER_LEN_SHORT; wsctx->header.mask = wsctx->header.data->u.m; - } else if (wsctx->header.payloadLen == 126 && 8 <= wsctx->nReadRaw) { + } else if (wsctx->header.payloadLen == 126 && 8 <= wsctx->header.nRead) { wsctx->header.headerLen = WS_HYBI_HEADER_LEN_EXTENDED; wsctx->header.payloadLen = WS_NTOH16(wsctx->header.data->u.s16.l16); wsctx->header.mask = wsctx->header.data->u.s16.m16; - } else if (wsctx->header.payloadLen == 127 && 14 <= wsctx->nReadRaw) { + } else if (wsctx->header.payloadLen == 127 && 14 <= wsctx->header.nRead) { wsctx->header.headerLen = WS_HYBI_HEADER_LEN_LONG; wsctx->header.payloadLen = WS_NTOH64(wsctx->header.data->u.s64.l64); wsctx->header.mask = wsctx->header.data->u.s64.m64; @@ -240,17 +241,16 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) goto err_cleanup_state; } - /* absolute length of frame */ - wsctx->nToRead = wsctx->header.headerLen + wsctx->header.payloadLen; - /* update write position for next bytes */ - wsctx->writePos = wsctx->codeBufDecode + wsctx->nReadRaw; + wsctx->writePos = wsctx->codeBufDecode + wsctx->header.nRead; /* set payload pointer just after header */ wsctx->readPos = (unsigned char *)(wsctx->codeBufDecode + wsctx->header.headerLen); - *nPayload = wsctx->nReadRaw - wsctx->header.headerLen; - rfbLog("header complete: state=%d flen=%llu writeTo=%p nPayload=%d\n", wsctx->hybiDecodeState, wsctx->nToRead, wsctx->writePos, *nPayload); + *nPayload = wsctx->header.nRead - wsctx->header.headerLen; + wsctx->nReadPayload = *nPayload; + + rfbLog("header complete: state=%d headerlen=%d payloadlen=%llu writeTo=%p nPayload=%d\n", wsctx->hybiDecodeState, wsctx->header.headerLen, wsctx->header.payloadLen, wsctx->writePos, *nPayload); return WS_HYBI_STATE_DATA_NEEDED; @@ -332,7 +332,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) rfbLog("calling read with buf=%p and len=%d (decodebuf=%p headerLen=%d)\n", wsctx->writePos, nextRead, wsctx->codeBufDecode, wsctx->header.headerLen); - if (wsctx->nReadRaw < wsctx->nToRead) { + if (nextRead > 0) { /* decode more data */ if (-1 == (n = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, wsctx->writePos, nextRead))) { int olderrno = errno; @@ -343,24 +343,18 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) } else if (n == 0) { *sockRet = 0; return WS_HYBI_STATE_ERR; + } else { + rfbLog("read %d bytes from socket; nRead=%d\n", n, wsctx->nReadPayload); } - wsctx->nReadRaw += n; - rfbLog("read %d bytes from socket; nRead=%d\n", n, wsctx->nReadRaw); } else { n = 0; } + wsctx->nReadPayload += n; wsctx->writePos += n; - if (wsctx->nReadRaw >= wsctx->nToRead) { - if (wsctx->nReadRaw > wsctx->nToRead) { - rfbErr("%s: internal error, read past websocket frame", __func__); - errno=EIO; - *sockRet = -1; - return WS_HYBI_STATE_ERR; - } else { - wsctx->hybiDecodeState = WS_HYBI_STATE_FRAME_COMPLETE; - } + if (hybiRemaining(wsctx) == 0) { + wsctx->hybiDecodeState = WS_HYBI_STATE_FRAME_COMPLETE; } /* number of not yet unmasked payload bytes: what we read here + what was @@ -486,13 +480,13 @@ webSocketsDecodeHybi(ws_ctx_t *wsctx, char *dst, int len) rfbLog("%s_enter: len=%d; " "CTX: readlen=%d readPos=%p " "writeTo=%p " - "state=%d toRead=%d remaining=%d " - " nReadRaw=%d carrylen=%d carryBuf=%p\n", + "state=%d payloadtoRead=%d payloadRemaining=%llu " + " nReadPayload=%d carrylen=%d carryBuf=%p\n", __func__, len, wsctx->readlen, wsctx->readPos, wsctx->writePos, - wsctx->hybiDecodeState, wsctx->nToRead, hybiRemaining(wsctx), - wsctx->nReadRaw, wsctx->carrylen, wsctx->carryBuf); + wsctx->hybiDecodeState, wsctx->header.payloadLen, hybiRemaining(wsctx), + wsctx->nReadPayload, wsctx->carrylen, wsctx->carryBuf); switch (wsctx->hybiDecodeState){ int nInBuf; @@ -544,15 +538,15 @@ spor: rfbLog("%s_exit: len=%d; " "CTX: readlen=%d readPos=%p " "writePos=%p " - "state=%d toRead=%d remaining=%d " + "state=%d payloadtoRead=%d payloadRemaining=%d " "nRead=%d carrylen=%d carryBuf=%p " "result=%d " "errno=%d\n", __func__, len, wsctx->readlen, wsctx->readPos, wsctx->writePos, - wsctx->hybiDecodeState, wsctx->nToRead, hybiRemaining(wsctx), - wsctx->nReadRaw, wsctx->carrylen, wsctx->carryBuf, + wsctx->hybiDecodeState, wsctx->header.payloadLen, hybiRemaining(wsctx), + wsctx->nReadPayload, wsctx->carrylen, wsctx->carryBuf, result, errno); return result; diff --git a/libvncserver/ws_decode.h b/libvncserver/ws_decode.h index 07d37bd..2923e3d 100644 --- a/libvncserver/ws_decode.h +++ b/libvncserver/ws_decode.h @@ -124,8 +124,7 @@ typedef struct ws_ctx_s { int carrylen; int base64; ws_header_data_t header; - uint64_t nReadRaw; - uint64_t nToRead; + uint64_t nReadPayload; unsigned char continuation_opcode; wsEncodeFunc encode; wsDecodeFunc decode; -- cgit v1.2.3 From f48921becf48355e215d663cebbbbaa720b28a95 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sun, 14 May 2017 20:49:57 +0200 Subject: websockets: restore webSocketCheckDisconnect() to keep API compatibility --- libvncserver/websockets.c | 11 +++++++++++ rfb/rfb.h | 1 + 2 files changed, 12 insertions(+) (limited to 'libvncserver') diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index 921015d..d10d992 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -440,6 +440,17 @@ webSocketsDecode(rfbClientPtr cl, char *dst, int len) return webSocketsDecodeHybi(wsctx, dst, len); } +/** + * This is a stub function that was once used for Hixie-encoding. + * We keep it for API compatibility. + */ +rfbBool +webSocketCheckDisconnect(rfbClientPtr cl) +{ + return FALSE; +} + + /* returns TRUE if there is data waiting to be read in our internal buffer * or if is there any pending data in the buffer of the SSL implementation */ diff --git a/rfb/rfb.h b/rfb/rfb.h index 9aace0d..f982b40 100644 --- a/rfb/rfb.h +++ b/rfb/rfb.h @@ -763,6 +763,7 @@ extern rfbBool rfbSetNonBlocking(int sock); /* websockets.c */ extern rfbBool webSocketsCheck(rfbClientPtr cl); +extern rfbBool webSocketCheckDisconnect(rfbClientPtr cl); extern int webSocketsEncode(rfbClientPtr cl, const char *src, int len, char **dst); extern int webSocketsDecode(rfbClientPtr cl, char *dst, int len); extern rfbBool webSocketsHasDataInBuffer(rfbClientPtr cl); -- cgit v1.2.3 From 051fe2a0090516f3688b40c6e6d966d95be0c326 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Mon, 15 May 2017 00:17:53 +0200 Subject: websockets: hide decode debug output per default --- libvncserver/ws_decode.c | 73 +++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 32 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/ws_decode.c b/libvncserver/ws_decode.c index 4616fdc..513fd4b 100644 --- a/libvncserver/ws_decode.c +++ b/libvncserver/ws_decode.c @@ -8,6 +8,17 @@ #define WS_HYBI_HEADER_LEN_EXTENDED 4 + WS_HYBI_MASK_LEN #define WS_HYBI_HEADER_LEN_LONG 10 + WS_HYBI_MASK_LEN +#undef WS_DECODE_DEBUG +/* set to 1 to produce very fine debugging output */ +#define WS_DECODE_DEBUG 0 + +#if WS_DECODE_DEBUG == 1 +#define ws_dbg(fmt, ...) rfbLog((fmt), ##__VA_ARGS) +#else +#define ws_dbg(fmt, ...) +#endif + + static inline int isControlFrame(ws_ctx_t *wsctx) { @@ -42,7 +53,7 @@ static void hybiDecodeCleanupForContinuation(ws_ctx_t *wsctx) { hybiDecodeCleanupBasics(wsctx); - rfbLog("clean up frame, but expect continuation with opcode %d\n", wsctx->continuation_opcode); + ws_dbg("clean up frame, but expect continuation with opcode %d\n", wsctx->continuation_opcode); } void @@ -50,7 +61,7 @@ hybiDecodeCleanupComplete(ws_ctx_t *wsctx) { hybiDecodeCleanupBasics(wsctx); wsctx->continuation_opcode = WS_OPCODE_INVALID; - rfbLog("cleaned up wsctx completely\n"); + ws_dbg("cleaned up wsctx completely\n"); } @@ -73,14 +84,14 @@ hybiReturnData(char *dst, int len, ws_ctx_t *wsctx, int *nWritten) if (wsctx->readlen > 0) { /* simply return what we have */ if (wsctx->readlen > len) { - rfbLog("copy to %d bytes to dst buffer; readPos=%p, readLen=%d\n", len, wsctx->readPos, wsctx->readlen); + ws_dbg("copy to %d bytes to dst buffer; readPos=%p, readLen=%d\n", len, wsctx->readPos, wsctx->readlen); memcpy(dst, wsctx->readPos, len); *nWritten = len; wsctx->readlen -= len; wsctx->readPos += len; nextState = WS_HYBI_STATE_DATA_AVAILABLE; } else { - rfbLog("copy to %d bytes to dst buffer; readPos=%p, readLen=%d\n", wsctx->readlen, wsctx->readPos, wsctx->readlen); + ws_dbg("copy to %d bytes to dst buffer; readPos=%p, readLen=%d\n", wsctx->readlen, wsctx->readPos, wsctx->readlen); memcpy(dst, wsctx->readPos, wsctx->readlen); *nWritten = wsctx->readlen; wsctx->readlen = 0; @@ -91,7 +102,7 @@ hybiReturnData(char *dst, int len, ws_ctx_t *wsctx, int *nWritten) nextState = WS_HYBI_STATE_DATA_NEEDED; } } - rfbLog("after copy: readPos=%p, readLen=%d\n", wsctx->readPos, wsctx->readlen); + ws_dbg("after copy: readPos=%p, readLen=%d\n", wsctx->readPos, wsctx->readlen); } else { /* it may happen that we read some bytes but could not decode them, * in that case, set errno to EAGAIN and return -1 */ @@ -122,9 +133,9 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) int n = ((uint64_t)WSHLENMAX) - wsctx->header.nRead; - rfbLog("header_read to %p with len=%d\n", headerDst, n); + ws_dbg("header_read to %p with len=%d\n", headerDst, n); ret = wsctx->ctxInfo.readFunc(wsctx->ctxInfo.ctxPtr, headerDst, n); - rfbLog("read %d bytes from socket\n", ret); + ws_dbg("read %d bytes from socket\n", ret); if (ret <= 0) { if (-1 == ret) { /* save errno because rfbErr() will tamper it */ @@ -150,7 +161,7 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) wsctx->header.opcode = wsctx->header.data->b0 & 0x0f; wsctx->header.fin = (wsctx->header.data->b0 & 0x80) >> 7; if (isControlFrame(wsctx)) { - rfbLog("is control frame\n"); + ws_dbg("is control frame\n"); /* is a control frame, leave remembered continuation opcode unchanged; * just check if there is a wrong fragmentation */ if (wsctx->header.fin == 0) { @@ -164,10 +175,10 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) goto err_cleanup_state; } } else { - rfbLog("not a control frame\n"); + ws_dbg("not a control frame\n"); /* not a control frame, check for continuation opcode */ if (wsctx->header.opcode == WS_OPCODE_CONTINUATION) { - rfbLog("cont_frame\n"); + ws_dbg("cont_frame\n"); /* do we have state (i.e., opcode) for continuation frame? */ if (wsctx->continuation_opcode == WS_OPCODE_INVALID) { rfbErr("no continuation state\n"); @@ -177,19 +188,19 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) /* otherwise, set opcode = continuation_opcode */ wsctx->header.opcode = wsctx->continuation_opcode; - rfbLog("set opcode to continuation_opcode: %d\n", wsctx->header.opcode); + ws_dbg("set opcode to continuation_opcode: %d\n", wsctx->header.opcode); } else { if (wsctx->header.fin == 0) { wsctx->continuation_opcode = wsctx->header.opcode; } else { wsctx->continuation_opcode = WS_OPCODE_INVALID; } - rfbLog("set continuation_opcode to %d\n", wsctx->continuation_opcode); + ws_dbg("set continuation_opcode to %d\n", wsctx->continuation_opcode); } } wsctx->header.payloadLen = (uint64_t)(wsctx->header.data->b1 & 0x7f); - rfbLog("first header bytes received; opcode=%d lenbyte=%d fin=%d\n", wsctx->header.opcode, wsctx->header.payloadLen, wsctx->header.fin); + ws_dbg("first header bytes received; opcode=%d lenbyte=%d fin=%d\n", wsctx->header.opcode, wsctx->header.payloadLen, wsctx->header.fin); /* * 4.3. Client-to-Server Masking @@ -223,11 +234,11 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) char *h = wsctx->codeBufDecode; int i; - rfbLog("Header:\n"); + ws_dbg("Header:\n"); for (i=0; i <10; i++) { - rfbLog("0x%02X\n", (unsigned char)h[i]); + ws_dbg("0x%02X\n", (unsigned char)h[i]); } - rfbLog("\n"); + ws_dbg("\n"); /* while RFC 6455 mandates that lengths MUST be encoded with the minimum * number of bytes, it does not specify for the server how to react on @@ -250,7 +261,7 @@ hybiReadHeader(ws_ctx_t *wsctx, int *sockRet, int *nPayload) *nPayload = wsctx->header.nRead - wsctx->header.headerLen; wsctx->nReadPayload = *nPayload; - rfbLog("header complete: state=%d headerlen=%d payloadlen=%llu writeTo=%p nPayload=%d\n", wsctx->hybiDecodeState, wsctx->header.headerLen, wsctx->header.payloadLen, wsctx->writePos, *nPayload); + ws_dbg("header complete: state=%d headerlen=%d payloadlen=%llu writeTo=%p nPayload=%d\n", wsctx->hybiDecodeState, wsctx->header.headerLen, wsctx->header.payloadLen, wsctx->writePos, *nPayload); return WS_HYBI_STATE_DATA_NEEDED; @@ -323,14 +334,14 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) /* -1 accounts for potential '\0' terminator for base64 decoding */ bufsize = wsctx->codeBufDecode + ARRAYSIZE(wsctx->codeBufDecode) - wsctx->writePos - 1; - rfbLog("bufsize=%d\n", bufsize); + ws_dbg("bufsize=%d\n", bufsize); if (hybiRemaining(wsctx) > bufsize) { nextRead = bufsize; } else { nextRead = hybiRemaining(wsctx); } - rfbLog("calling read with buf=%p and len=%d (decodebuf=%p headerLen=%d)\n", wsctx->writePos, nextRead, wsctx->codeBufDecode, wsctx->header.headerLen); + ws_dbg("calling read with buf=%p and len=%d (decodebuf=%p headerLen=%d)\n", wsctx->writePos, nextRead, wsctx->codeBufDecode, wsctx->header.headerLen); if (nextRead > 0) { /* decode more data */ @@ -344,7 +355,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) *sockRet = 0; return WS_HYBI_STATE_ERR; } else { - rfbLog("read %d bytes from socket; nRead=%d\n", n, wsctx->nReadPayload); + ws_dbg("read %d bytes from socket; nRead=%d\n", n, wsctx->nReadPayload); } } else { n = 0; @@ -360,7 +371,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) /* number of not yet unmasked payload bytes: what we read here + what was * carried over + what was read with the header */ toDecode = n + wsctx->carrylen + nInBuf; - rfbLog("toDecode=%d from n=%d carrylen=%d headerLen=%d\n", toDecode, n, wsctx->carrylen, wsctx->header.headerLen); + ws_dbg("toDecode=%d from n=%d carrylen=%d headerLen=%d\n", toDecode, n, wsctx->carrylen, wsctx->header.headerLen); if (toDecode < 0) { rfbErr("%s: internal error; negative number of bytes to decode: %d", __func__, toDecode); errno=EIO; @@ -376,7 +387,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) for (i = 0; i < (toDecode >> 2); i++) { data32[i] ^= wsctx->header.mask.u; } - rfbLog("mask decoding; i=%d toDecode=%d\n", i, toDecode); + ws_dbg("mask decoding; i=%d toDecode=%d\n", i, toDecode); if (wsctx->hybiDecodeState == WS_HYBI_STATE_FRAME_COMPLETE) { /* process the remaining bytes (if any) */ @@ -395,7 +406,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) errno = EIO; return WS_HYBI_STATE_ERR; } - rfbLog("carrying over %d bytes from %p to %p\n", wsctx->carrylen, wsctx->writePos + (i * 4), wsctx->carryBuf); + ws_dbg("carrying over %d bytes from %p to %p\n", wsctx->carrylen, wsctx->writePos + (i * 4), wsctx->carryBuf); memcpy(wsctx->carryBuf, data + (i * 4), wsctx->carrylen); wsctx->writePos -= wsctx->carrylen; } @@ -407,12 +418,12 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) /* this data is not returned as payload data */ if (hybiWsFrameComplete(wsctx)) { *(wsctx->writePos) = '\0'; - rfbLog("got close cmd %d, reason %d: %s\n", (int)(wsctx->writePos - hybiPayloadStart(wsctx)), WS_NTOH16(((uint16_t *)hybiPayloadStart(wsctx))[0]), &hybiPayloadStart(wsctx)[2]); + ws_dbg("got close cmd %d, reason %d: %s\n", (int)(wsctx->writePos - hybiPayloadStart(wsctx)), WS_NTOH16(((uint16_t *)hybiPayloadStart(wsctx))[0]), &hybiPayloadStart(wsctx)[2]); errno = ECONNRESET; *sockRet = -1; return WS_HYBI_STATE_FRAME_COMPLETE; } else { - rfbLog("got close cmd; waiting for %d more bytes to arrive\n", hybiRemaining(wsctx)); + ws_dbg("got close cmd; waiting for %d more bytes to arrive\n", hybiRemaining(wsctx)); *sockRet = -1; errno = EAGAIN; return WS_HYBI_STATE_CLOSE_REASON_PENDING; @@ -420,7 +431,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) break; case WS_OPCODE_TEXT_FRAME: data[toReturn] = '\0'; - rfbLog("Initiate Base64 decoding in %p with max size %d and '\\0' at %p\n", data, bufsize, data + toReturn); + ws_dbg("Initiate Base64 decoding in %p with max size %d and '\\0' at %p\n", data, bufsize, data + toReturn); if (-1 == (wsctx->readlen = b64_pton((char *)data, data, bufsize))) { rfbErr("%s: Base64 decode error; %s\n", __func__, strerror(errno)); } @@ -429,7 +440,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) case WS_OPCODE_BINARY_FRAME: wsctx->readlen = toReturn; wsctx->writePos = hybiPayloadStart(wsctx); - rfbLog("set readlen=%d writePos=%p\n", wsctx->readlen, wsctx->writePos); + ws_dbg("set readlen=%d writePos=%p\n", wsctx->readlen, wsctx->writePos); break; default: rfbErr("%s: unhandled opcode %d, b0: %02x, b1: %02x\n", __func__, (int)wsctx->header.opcode, wsctx->header.data->b0, wsctx->header.data->b1); @@ -476,8 +487,7 @@ webSocketsDecodeHybi(ws_ctx_t *wsctx, char *dst, int len) int result = -1; /* int fin; */ /* not used atm */ - /* rfbLog(" <== %s[%d]: %d cl: %p, wsctx: %p-%p (%d)\n", __func__, gettid(), len, cl, wsctx, (char *)wsctx + sizeof(ws_ctx_t), sizeof(ws_ctx_t)); */ - rfbLog("%s_enter: len=%d; " + ws_dbg("%s_enter: len=%d; " "CTX: readlen=%d readPos=%p " "writeTo=%p " "state=%d payloadtoRead=%d payloadRemaining=%llu " @@ -520,9 +530,8 @@ webSocketsDecodeHybi(ws_ctx_t *wsctx, char *dst, int len) /* single point of return, if someone has questions :-) */ spor: - /* rfbLog("%s: ret: %d/%d\n", __func__, result, len); */ if (wsctx->hybiDecodeState == WS_HYBI_STATE_FRAME_COMPLETE) { - rfbLog("frame received successfully, cleaning up: read=%d hlen=%d plen=%d\n", wsctx->header.nRead, wsctx->header.headerLen, wsctx->header.payloadLen); + ws_dbg("frame received successfully, cleaning up: read=%d hlen=%d plen=%d\n", wsctx->header.nRead, wsctx->header.headerLen, wsctx->header.payloadLen); if (wsctx->header.fin && !isControlFrame(wsctx)) { /* frame finished, cleanup state */ hybiDecodeCleanupComplete(wsctx); @@ -535,7 +544,7 @@ spor: hybiDecodeCleanupComplete(wsctx); } - rfbLog("%s_exit: len=%d; " + ws_dbg("%s_exit: len=%d; " "CTX: readlen=%d readPos=%p " "writePos=%p " "state=%d payloadtoRead=%d payloadRemaining=%d " -- cgit v1.2.3 From e8a1ca20352f14bf3b527bb1f148610fc1fb5247 Mon Sep 17 00:00:00 2001 From: Jocelyn Le Sage Date: Tue, 21 Feb 2017 06:36:15 -0500 Subject: Fixed compilation of websockets on system where there is no implementation of base64 functions. --- CMakeLists.txt | 30 +---- common/base64.c | 315 ++++++++++++++++++++++++++++++++++++++++++++++ common/base64.h | 10 ++ libvncserver/websockets.c | 8 +- libvncserver/ws_decode.c | 3 +- libvncserver/ws_decode.h | 3 - 6 files changed, 335 insertions(+), 34 deletions(-) create mode 100644 common/base64.c create mode 100644 common/base64.h (limited to 'libvncserver') diff --git a/CMakeLists.txt b/CMakeLists.txt index 75d6470..16f235e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,28 +174,6 @@ check_function_exists(strdup LIBVNCSERVER_HAVE_STRDUP) check_function_exists(strerror LIBVNCSERVER_HAVE_STRERROR) check_function_exists(strstr LIBVNCSERVER_HAVE_STRSTR) -# On systems such as GNU/Linux with glibc, __b64_ntop is defined in a -# separate library, libresolv. On some others, such as FreeBSD, it is -# part of libc itself. We first check if __b64_ntop is found without -# additional libraries, and then try looking for it with libresolv if -# the first test fails. -check_function_exists(__b64_ntop HAVE_B64_IN_LIBC) -if(NOT HAVE_B64_IN_LIBC) - set(CMAKE_REQUIRED_LIBRARIES resolv) - check_function_exists(__b64_ntop HAVE_B64_IN_LIBRESOLV) - set(CMAKE_REQUIRED_LIBRARIES) - - if(HAVE_B64_IN_LIBRESOLV) - set(RESOLV_LIB "resolv") - endif(HAVE_B64_IN_LIBRESOLV) - - # the function check somehow fails for apple but the function is there - if(APPLE) - set(RESOLV_LIB "resolv") - endif(APPLE) - -endif(NOT HAVE_B64_IN_LIBC) - if(Threads_FOUND) set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) endif(Threads_FOUND) @@ -225,16 +203,16 @@ if(WITH_WEBSOCKETS AND LIBVNCSERVER_HAVE_SYS_UIO_H) if(GNUTLS_FOUND) set(LIBVNCSERVER_WITH_CLIENT_TLS 1) message(STATUS "Building websockets with GnuTLS") - set(WEBSOCKET_LIBRARIES ${RESOLV_LIB} ${GNUTLS_LIBRARIES}) + set(WEBSOCKET_LIBRARIES ${GNUTLS_LIBRARIES}) set(WSSRCS ${LIBVNCSERVER_DIR}/rfbssl_gnutls ${LIBVNCSERVER_DIR}/rfbcrypto_gnutls) include_directories(${GNUTLS_INCLUDE_DIR}) elseif(OPENSSL_FOUND) message(STATUS "Building websockets with OpenSSL") - set(WEBSOCKET_LIBRARIES ${RESOLV_LIB} ${OPENSSL_LIBRARIES}) + set(WEBSOCKET_LIBRARIES ${OPENSSL_LIBRARIES}) set(WSSRCS ${LIBVNCSERVER_DIR}/rfbssl_openssl ${LIBVNCSERVER_DIR}/rfbcrypto_openssl) else() message(STATUS "Building websockets without SSL") - set(WEBSOCKET_LIBRARIES ${RESOLV_LIB}) + set(WEBSOCKET_LIBRARIES) set(WSSRCS ${LIBVNCSERVER_DIR}/rfbssl_none.c ${LIBVNCSERVER_DIR}/rfbcrypto_included.c ${COMMON_DIR}/md5.c ${COMMON_DIR}/sha1.c) endif() endif(WITH_WEBSOCKETS AND LIBVNCSERVER_HAVE_SYS_UIO_H) @@ -388,11 +366,11 @@ if(LIBVNCSERVER_WITH_WEBSOCKETS) ${LIBVNCSERVER_SOURCES} ${LIBVNCSERVER_DIR}/websockets.c ${LIBVNCSERVER_DIR}/ws_decode.c + ${COMMON_DIR}/base64.c ${WSSRCS} ) endif(LIBVNCSERVER_WITH_WEBSOCKETS) - add_library(vncclient ${LIBVNCCLIENT_SOURCES}) add_library(vncserver ${LIBVNCSERVER_SOURCES}) if(WIN32) diff --git a/common/base64.c b/common/base64.c new file mode 100644 index 0000000..4e3685a --- /dev/null +++ b/common/base64.c @@ -0,0 +1,315 @@ +/* $OpenBSD: base64.c,v 1.8 2015/01/16 16:48:51 deraadt Exp $ */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +int +__b64_ntop(src, srclength, target, targsize) + u_char const *src; + size_t srclength; + char *target; + size_t targsize; +{ + size_t datalength = 0; + u_char input[3]; + u_char output[4]; + int i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +__b64_pton(src, target, targsize) + char const *src; + u_char *target; + size_t targsize; +{ + int tarindex, state, ch; + u_char nextbyte; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = (unsigned char)*src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + nextbyte = ((pos - Base64) & 0x0f) << 4; + if (tarindex + 1 < targsize) + target[tarindex+1] = nextbyte; + else if (nextbyte) + return (-1); + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + nextbyte = ((pos - Base64) & 0x03) << 6; + if (tarindex + 1 < targsize) + target[tarindex+1] = nextbyte; + else if (nextbyte) + return (-1); + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = (unsigned char)*src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = (unsigned char)*src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = (unsigned char)*src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = (unsigned char)*src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && tarindex < targsize && + target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} diff --git a/common/base64.h b/common/base64.h new file mode 100644 index 0000000..9b86fc1 --- /dev/null +++ b/common/base64.h @@ -0,0 +1,10 @@ +#ifndef _BASE64_H +#define _BASE64_H + +extern int __b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize); +extern int __b64_pton(char const *src, u_char *target, size_t targsize); + +#define rfbBase64NtoP __b64_ntop +#define rfbBase64PtoN __b64_pton + +#endif /* _BASE64_H */ diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index b9947c4..4ebff72 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -52,7 +52,7 @@ #include "rfbssl.h" #include "rfbcrypto.h" #include "ws_decode.h" - +#include "base64.h" #if 0 #include @@ -117,8 +117,8 @@ static void webSocketsGenSha1Key(char *target, int size, char *key) iov[1].iov_base = GUID; iov[1].iov_len = sizeof(GUID) - 1; digestsha1(iov, 2, hash); - if (-1 == b64_ntop(hash, sizeof(hash), target, size)) - rfbErr("b64_ntop failed\n"); + if (-1 == rfbBase64NtoP(hash, sizeof(hash), target, size)) + rfbErr("rfbBase64NtoP failed\n"); } /* @@ -412,7 +412,7 @@ webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst) } if (wsctx->base64) { - if (-1 == (ret = b64_ntop((unsigned char *)src, len, wsctx->codeBufEncode + sz, sizeof(wsctx->codeBufEncode) - sz))) { + if (-1 == (ret = rfbBase64NtoP((unsigned char *)src, len, wsctx->codeBufEncode + sz, sizeof(wsctx->codeBufEncode) - sz))) { rfbErr("%s: Base 64 encode failed\n", __func__); } else { if (ret != blen) diff --git a/libvncserver/ws_decode.c b/libvncserver/ws_decode.c index 513fd4b..441ebc7 100644 --- a/libvncserver/ws_decode.c +++ b/libvncserver/ws_decode.c @@ -1,4 +1,5 @@ #include "ws_decode.h" +#include "base64.h" #include #include @@ -432,7 +433,7 @@ hybiReadAndDecode(ws_ctx_t *wsctx, char *dst, int len, int *sockRet, int nInBuf) case WS_OPCODE_TEXT_FRAME: data[toReturn] = '\0'; ws_dbg("Initiate Base64 decoding in %p with max size %d and '\\0' at %p\n", data, bufsize, data + toReturn); - if (-1 == (wsctx->readlen = b64_pton((char *)data, data, bufsize))) { + if (-1 == (wsctx->readlen = rfbBase64PtoN((char *)data, data, bufsize))) { rfbErr("%s: Base64 decode error; %s\n", __func__, strerror(errno)); } wsctx->writePos = hybiPayloadStart(wsctx); diff --git a/libvncserver/ws_decode.h b/libvncserver/ws_decode.h index 2923e3d..709477a 100644 --- a/libvncserver/ws_decode.h +++ b/libvncserver/ws_decode.h @@ -3,9 +3,6 @@ #include #include -#ifndef _MSC_VER -#include /* __b64_ntop */ -#endif #if defined(__APPLE__) -- cgit v1.2.3 From 2c2f103304a674c2744b2e8eb58b25b9a8d8708c Mon Sep 17 00:00:00 2001 From: Wu Zongyong Date: Sun, 25 Jun 2017 22:43:44 +0800 Subject: fix: the function should not return a value --- libvncserver/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libvncserver') diff --git a/libvncserver/main.c b/libvncserver/main.c index 95c3da5..05b4b13 100644 --- a/libvncserver/main.c +++ b/libvncserver/main.c @@ -1066,7 +1066,7 @@ void rfbInitServer(rfbScreenInfoPtr screen) int i=WSAStartup(MAKEWORD(2,0),&trash); if(i!=0) { rfbErr("Couldn't init Windows Sockets\n"); - return 0; + return; } WSAinitted=TRUE; } -- cgit v1.2.3 From 28afb6c537dc82ba04d5f245b15ca7205c6dbb9c Mon Sep 17 00:00:00 2001 From: Petr Písař Date: Mon, 26 Feb 2018 13:48:00 +0100 Subject: Limit client cut text length to 1 MB This patch constrains a client cut text length to 1 MB. Otherwise a client could make server allocate 2 GB of memory and that seems to be to much to classify it as a denial of service. The limit also prevents from an integer overflow followed by copying an uninitilized memory when processing msg.cct.length value larger than SIZE_MAX or INT_MAX - sz_rfbClientCutTextMsg. This patch also corrects accepting length value of zero (malloc(0) is interpreted on differnet systems differently). CVE-2018-7225 --- libvncserver/rfbserver.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'libvncserver') diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index 116c488..4fc4d9d 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -88,6 +88,8 @@ #include /* strftime() */ #include +/* PRIu32 */ +#include #ifdef LIBVNCSERVER_WITH_WEBSOCKETS #include "rfbssl.h" @@ -2575,7 +2577,23 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) msg.cct.length = Swap32IfLE(msg.cct.length); - str = (char *)malloc(msg.cct.length); + /* uint32_t input is passed to malloc()'s size_t argument, + * to rfbReadExact()'s int argument, to rfbStatRecordMessageRcvd()'s int + * argument increased of sz_rfbClientCutTextMsg, and to setXCutText()'s int + * argument. Here we impose a limit of 1 MB so that the value fits + * into all of the types to prevent from misinterpretation and thus + * from accessing uninitialized memory (CVE-2018-7225) and also to + * prevent from a denial-of-service by allocating to much memory in + * the server. */ + if (msg.cct.length > 1<<20) { + rfbLog("rfbClientCutText: too big cut text length requested: %" PRIu32 "\n", + msg.cct.length); + rfbCloseClient(cl); + return; + } + + /* Allow zero-length client cut text. */ + str = (char *)calloc(msg.cct.length ? msg.cct.length : 1, 1); if (str == NULL) { rfbLogPerror("rfbProcessClientNormalMessage: not enough memory"); rfbCloseClient(cl); -- cgit v1.2.3 From 449cbe90282dcb5d0eb3b59f0409134f4ea11871 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sat, 24 Mar 2018 02:30:13 +0100 Subject: rfbserver: get rid of inttypes.h again --- libvncserver/rfbserver.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index 4fc4d9d..44be1c3 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -88,8 +88,6 @@ #include /* strftime() */ #include -/* PRIu32 */ -#include #ifdef LIBVNCSERVER_WITH_WEBSOCKETS #include "rfbssl.h" @@ -2586,8 +2584,7 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) * prevent from a denial-of-service by allocating to much memory in * the server. */ if (msg.cct.length > 1<<20) { - rfbLog("rfbClientCutText: too big cut text length requested: %" PRIu32 "\n", - msg.cct.length); + rfbLog("rfbClientCutText: too big cut text length requested: %u B > 1 MB\n", (unsigned int)msg.cct.length); rfbCloseClient(cl); return; } -- cgit v1.2.3 From f23248a415ab1abab7c4e5330a9985d5bb10987b Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sat, 24 Mar 2018 02:30:34 +0100 Subject: rfbserver: fix a typo --- libvncserver/rfbserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libvncserver') diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index 44be1c3..7af6aed 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -2581,7 +2581,7 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) * argument. Here we impose a limit of 1 MB so that the value fits * into all of the types to prevent from misinterpretation and thus * from accessing uninitialized memory (CVE-2018-7225) and also to - * prevent from a denial-of-service by allocating to much memory in + * prevent from a denial-of-service by allocating too much memory in * the server. */ if (msg.cct.length > 1<<20) { rfbLog("rfbClientCutText: too big cut text length requested: %u B > 1 MB\n", (unsigned int)msg.cct.length); -- cgit v1.2.3 From dd873fce451e4b7d7cc69056a62e107aae7c8e7a Mon Sep 17 00:00:00 2001 From: Eddie James Date: Mon, 18 Jun 2018 16:17:41 -0500 Subject: Tight: export SendCompressedData and SendTightHeader functions These functions can be used to send already compressed jpegs to a client, circumventing the usual rect/region update methods which operate on a raw rgb framebuffer. Rename the functions with the usual rfb prefix and add the prototypes in rfb.h. Signed-off-by: Eddie James --- libvncserver/tight.c | 25 +++++++++++-------------- rfb/rfb.h | 2 ++ 2 files changed, 13 insertions(+), 14 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/tight.c b/libvncserver/tight.c index bca374d..1081c8f 100644 --- a/libvncserver/tight.c +++ b/libvncserver/tight.c @@ -191,7 +191,6 @@ static rfbBool CheckSolidTile32 (rfbClientPtr cl, int x, int y, int w, int h, static rfbBool SendRectSimple (rfbClientPtr cl, int x, int y, int w, int h); static rfbBool SendSubrect (rfbClientPtr cl, int x, int y, int w, int h); -static rfbBool SendTightHeader (rfbClientPtr cl, int x, int y, int w, int h); static rfbBool SendSolidRect (rfbClientPtr cl); static rfbBool SendMonoRect (rfbClientPtr cl, int x, int y, int w, int h); @@ -200,8 +199,6 @@ static rfbBool SendFullColorRect (rfbClientPtr cl, int x, int y, int w, int h); static rfbBool CompressData (rfbClientPtr cl, int streamId, int dataLen, int zlibLevel, int zlibStrategy); -static rfbBool SendCompressedData (rfbClientPtr cl, char *buf, - int compressedLen); static void FillPalette8 (int count); static void FillPalette16 (int count); @@ -430,7 +427,7 @@ SendRectEncodingTight(rfbClientPtr cl, /* Send solid-color rectangle. */ - if (!SendTightHeader(cl, x_best, y_best, w_best, h_best)) + if (!rfbSendTightHeader(cl, x_best, y_best, w_best, h_best)) return FALSE; fbptr = (cl->scaledScreen->frameBuffer + @@ -683,7 +680,7 @@ SendSubrect(rfbClientPtr cl, return FALSE; } - if (!SendTightHeader(cl, x, y, w, h)) + if (!rfbSendTightHeader(cl, x, y, w, h)) return FALSE; fbptr = (cl->scaledScreen->frameBuffer @@ -767,8 +764,8 @@ SendSubrect(rfbClientPtr cl, return success; } -static rfbBool -SendTightHeader(rfbClientPtr cl, +rfbBool +rfbSendTightHeader(rfbClientPtr cl, int x, int y, int w, @@ -1044,7 +1041,7 @@ CompressData(rfbClientPtr cl, } if (zlibLevel == 0) - return SendCompressedData (cl, tightBeforeBuf, dataLen); + return rfbSendCompressedDataTight(cl, tightBeforeBuf, dataLen); pz = &cl->zsStruct[streamId]; @@ -1083,12 +1080,12 @@ CompressData(rfbClientPtr cl, return FALSE; } - return SendCompressedData(cl, tightAfterBuf, - tightAfterBufSize - pz->avail_out); + return rfbSendCompressedDataTight(cl, tightAfterBuf, + tightAfterBufSize - pz->avail_out); } -static rfbBool SendCompressedData(rfbClientPtr cl, char *buf, - int compressedLen) +rfbBool rfbSendCompressedDataTight(rfbClientPtr cl, char *buf, + int compressedLen) { int i, portionLen; @@ -1665,7 +1662,7 @@ SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, int quality) cl->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4); rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1); - return SendCompressedData(cl, tightAfterBuf, (int)size); + return rfbSendCompressedDataTight(cl, tightAfterBuf, (int)size); } static void @@ -1899,6 +1896,6 @@ static rfbBool SendPngRect(rfbClientPtr cl, int x, int y, int w, int h) { rfbStatRecordEncodingSentAdd(cl, cl->tightEncoding, 1); /* rfbLog("<< SendPngRect\n"); */ - return SendCompressedData(cl, tightAfterBuf, pngDstDataLen); + return rfbSendCompressedDataTight(cl, tightAfterBuf, pngDstDataLen); } #endif diff --git a/rfb/rfb.h b/rfb/rfb.h index f982b40..6401e78 100644 --- a/rfb/rfb.h +++ b/rfb/rfb.h @@ -895,6 +895,8 @@ extern rfbBool rfbTightDisableGradient; extern int rfbNumCodedRectsTight(rfbClientPtr cl, int x,int y,int w,int h); extern rfbBool rfbSendRectEncodingTight(rfbClientPtr cl, int x,int y,int w,int h); +extern rfbBool rfbSendTightHeader(rfbClientPtr cl, int x, int y, int w, int h); +extern rfbBool rfbSendCompressedDataTight(rfbClientPtr cl, char *buf, int compressedLen); #if defined(LIBVNCSERVER_HAVE_LIBPNG) extern rfbBool rfbSendRectEncodingTightPng(rfbClientPtr cl, int x,int y,int w,int h); -- cgit v1.2.3 From 85fb69515cf1739bea53ce62b832a17e08ab3647 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Fri, 29 Jun 2018 12:30:17 +0200 Subject: crypto: move to common As of now, only LibVNCServer makes uses of these digest functions _and_ they depend on sys/uio.h, but in the future LibVNCClient will need those as well. --- CMakeLists.txt | 29 ++++++++++++++++++----- common/rfbcrypto.h | 16 +++++++++++++ common/rfbcrypto_gnutls.c | 50 +++++++++++++++++++++++++++++++++++++++ common/rfbcrypto_included.c | 49 ++++++++++++++++++++++++++++++++++++++ common/rfbcrypto_openssl.c | 49 ++++++++++++++++++++++++++++++++++++++ common/rfbcrypto_polarssl.c | 26 ++++++++++++++++++++ libvncserver/rfbcrypto.h | 16 ------------- libvncserver/rfbcrypto_gnutls.c | 50 --------------------------------------- libvncserver/rfbcrypto_included.c | 49 -------------------------------------- libvncserver/rfbcrypto_openssl.c | 49 -------------------------------------- libvncserver/rfbcrypto_polarssl.c | 26 -------------------- 11 files changed, 213 insertions(+), 196 deletions(-) create mode 100644 common/rfbcrypto.h create mode 100644 common/rfbcrypto_gnutls.c create mode 100644 common/rfbcrypto_included.c create mode 100644 common/rfbcrypto_openssl.c create mode 100644 common/rfbcrypto_polarssl.c delete mode 100644 libvncserver/rfbcrypto.h delete mode 100644 libvncserver/rfbcrypto_gnutls.c delete mode 100644 libvncserver/rfbcrypto_included.c delete mode 100644 libvncserver/rfbcrypto_openssl.c delete mode 100644 libvncserver/rfbcrypto_polarssl.c (limited to 'libvncserver') diff --git a/CMakeLists.txt b/CMakeLists.txt index b533494..26c686a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -204,25 +204,40 @@ if(SYSTEMD_FOUND) set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${SYSTEMD_LIBRARIES}) endif(SYSTEMD_FOUND) +if(LIBVNCSERVER_HAVE_SYS_UIO_H) + if(GNUTLS_FOUND) + message(STATUS "Building crypto with GnuTLS") + set(CRYPTO_LIBRARIES ${GNUTLS_LIBRARIES}) + set(CRYPTO_SOURCES ${COMMON_DIR}/rfbcrypto_gnutls) + include_directories(${GNUTLS_INCLUDE_DIR}) + elseif(OPENSSL_FOUND) + message(STATUS "Building crypto with OpenSSL") + set(CRYPTO_LIBRARIES ${OPENSSL_LIBRARIES}) + set(CRYPTO_SOURCES ${COMMON_DIR}/rfbcrypto_openssl) + else() + message(STATUS "Building crypto with builtin functions") + set(CRYPTO_SOURCES ${COMMON_DIR}/rfbcrypto_included.c ${COMMON_DIR}/md5.c ${COMMON_DIR}/sha1.c) + endif() +endif(LIBVNCSERVER_HAVE_SYS_UIO_H) + -if(WITH_WEBSOCKETS AND LIBVNCSERVER_HAVE_SYS_UIO_H) +if(WITH_WEBSOCKETS) set(LIBVNCSERVER_WITH_WEBSOCKETS 1) if(GNUTLS_FOUND) - set(LIBVNCSERVER_WITH_CLIENT_TLS 1) message(STATUS "Building websockets with GnuTLS") set(WEBSOCKET_LIBRARIES ${GNUTLS_LIBRARIES}) - set(WSSRCS ${LIBVNCSERVER_DIR}/rfbssl_gnutls ${LIBVNCSERVER_DIR}/rfbcrypto_gnutls) + set(WSSRCS ${LIBVNCSERVER_DIR}/rfbssl_gnutls) include_directories(${GNUTLS_INCLUDE_DIR}) elseif(OPENSSL_FOUND) message(STATUS "Building websockets with OpenSSL") set(WEBSOCKET_LIBRARIES ${OPENSSL_LIBRARIES}) - set(WSSRCS ${LIBVNCSERVER_DIR}/rfbssl_openssl ${LIBVNCSERVER_DIR}/rfbcrypto_openssl) + set(WSSRCS ${LIBVNCSERVER_DIR}/rfbssl_openssl) else() message(STATUS "Building websockets without SSL") set(WEBSOCKET_LIBRARIES) - set(WSSRCS ${LIBVNCSERVER_DIR}/rfbssl_none.c ${LIBVNCSERVER_DIR}/rfbcrypto_included.c ${COMMON_DIR}/md5.c ${COMMON_DIR}/sha1.c) + set(WSSRCS ${LIBVNCSERVER_DIR}/rfbssl_none.c) endif() -endif(WITH_WEBSOCKETS AND LIBVNCSERVER_HAVE_SYS_UIO_H) +endif(WITH_WEBSOCKETS) if(WITH_GCRYPT AND LIBGCRYPT_LIBRARIES) message(STATUS "Found libgcrypt: ${LIBGCRYPT_LIBRARIES}") @@ -400,6 +415,7 @@ if(LIBVNCSERVER_WITH_WEBSOCKETS) ${LIBVNCSERVER_DIR}/websockets.c ${LIBVNCSERVER_DIR}/ws_decode.c ${COMMON_DIR}/base64.c + ${CRYPTO_SOURCES} ${WSSRCS} ) endif(LIBVNCSERVER_WITH_WEBSOCKETS) @@ -422,6 +438,7 @@ target_link_libraries(vncserver ${ZLIB_LIBRARIES} ${JPEG_LIBRARIES} ${PNG_LIBRARIES} + ${CRYPTO_LIBRARIES} ${WEBSOCKET_LIBRARIES} ) diff --git a/common/rfbcrypto.h b/common/rfbcrypto.h new file mode 100644 index 0000000..fec095e --- /dev/null +++ b/common/rfbcrypto.h @@ -0,0 +1,16 @@ +#ifndef _RFB_CRYPTO_H +#define _RFB_CRYPTO_H 1 + +#include "rfb/rfbconfig.h" + +#define SHA1_HASH_SIZE 20 +#define MD5_HASH_SIZE 16 + +#ifdef LIBVNCSERVER_HAVE_SYS_UIO_H +#include + +void digestmd5(const struct iovec *iov, int iovcnt, void *dest); +void digestsha1(const struct iovec *iov, int iovcnt, void *dest); +#endif + +#endif diff --git a/common/rfbcrypto_gnutls.c b/common/rfbcrypto_gnutls.c new file mode 100644 index 0000000..2ecb2da --- /dev/null +++ b/common/rfbcrypto_gnutls.c @@ -0,0 +1,50 @@ +/* + * rfbcrypto_gnutls.c - Crypto wrapper (gnutls version) + */ + +/* + * Copyright (C) 2011 Gernot Tenchio + * + * 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. + */ + +#include +#include +#include "rfbcrypto.h" + +void digestmd5(const struct iovec *iov, int iovcnt, void *dest) +{ + gcry_md_hd_t c; + int i; + + gcry_md_open(&c, GCRY_MD_MD5, 0); + for (i = 0; i < iovcnt; i++) + gcry_md_write(c, iov[i].iov_base, iov[i].iov_len); + gcry_md_final(c); + memcpy(dest, gcry_md_read(c, 0), gcry_md_get_algo_dlen(GCRY_MD_MD5)); +} + +void digestsha1(const struct iovec *iov, int iovcnt, void *dest) +{ + gcry_md_hd_t c; + int i; + + gcry_md_open(&c, GCRY_MD_SHA1, 0); + for (i = 0; i < iovcnt; i++) + gcry_md_write(c, iov[i].iov_base, iov[i].iov_len); + gcry_md_final(c); + memcpy(dest, gcry_md_read(c, 0), gcry_md_get_algo_dlen(GCRY_MD_SHA1)); +} diff --git a/common/rfbcrypto_included.c b/common/rfbcrypto_included.c new file mode 100644 index 0000000..7feff61 --- /dev/null +++ b/common/rfbcrypto_included.c @@ -0,0 +1,49 @@ +/* + * rfbcrypto_included.c - Crypto wrapper (included version) + */ + +/* + * Copyright (C) 2011 Gernot Tenchio + * + * 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. + */ + +#include +#include "md5.h" +#include "sha.h" +#include "rfbcrypto.h" + +void digestmd5(const struct iovec *iov, int iovcnt, void *dest) +{ + struct md5_ctx c; + int i; + + __md5_init_ctx(&c); + for (i = 0; i < iovcnt; i++) + __md5_process_bytes(iov[i].iov_base, iov[i].iov_len, &c); + __md5_finish_ctx(&c, dest); +} + +void digestsha1(const struct iovec *iov, int iovcnt, void *dest) +{ + SHA1Context c; + int i; + + SHA1Reset(&c); + for (i = 0; i < iovcnt; i++) + SHA1Input(&c, iov[i].iov_base, iov[i].iov_len); + SHA1Result(&c, dest); +} diff --git a/common/rfbcrypto_openssl.c b/common/rfbcrypto_openssl.c new file mode 100644 index 0000000..29ec5c1 --- /dev/null +++ b/common/rfbcrypto_openssl.c @@ -0,0 +1,49 @@ +/* + * rfbcrypto_openssl.c - Crypto wrapper (openssl version) + */ + +/* + * Copyright (C) 2011 Gernot Tenchio + * + * 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. + */ + +#include +#include +#include +#include "rfbcrypto.h" + +void digestmd5(const struct iovec *iov, int iovcnt, void *dest) +{ + MD5_CTX c; + int i; + + MD5_Init(&c); + for (i = 0; i < iovcnt; i++) + MD5_Update(&c, iov[i].iov_base, iov[i].iov_len); + MD5_Final(dest, &c); +} + +void digestsha1(const struct iovec *iov, int iovcnt, void *dest) +{ + SHA_CTX c; + int i; + + SHA1_Init(&c); + for (i = 0; i < iovcnt; i++) + SHA1_Update(&c, iov[i].iov_base, iov[i].iov_len); + SHA1_Final(dest, &c); +} diff --git a/common/rfbcrypto_polarssl.c b/common/rfbcrypto_polarssl.c new file mode 100644 index 0000000..55e3a7b --- /dev/null +++ b/common/rfbcrypto_polarssl.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include "rfbcrypto.h" + +void digestmd5(const struct iovec *iov, int iovcnt, void *dest) +{ + md5_context c; + int i; + + md5_starts(&c); + for (i = 0; i < iovcnt; i++) + md5_update(&c, iov[i].iov_base, iov[i].iov_len); + md5_finish(&c, dest); +} + +void digestsha1(const struct iovec *iov, int iovcnt, void *dest) +{ + sha1_context c; + int i; + + sha1_starts(&c); + for (i = 0; i < iovcnt; i++) + sha1_update(&c, iov[i].iov_base, iov[i].iov_len); + sha1_finish(&c, dest); +} diff --git a/libvncserver/rfbcrypto.h b/libvncserver/rfbcrypto.h deleted file mode 100644 index fec095e..0000000 --- a/libvncserver/rfbcrypto.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _RFB_CRYPTO_H -#define _RFB_CRYPTO_H 1 - -#include "rfb/rfbconfig.h" - -#define SHA1_HASH_SIZE 20 -#define MD5_HASH_SIZE 16 - -#ifdef LIBVNCSERVER_HAVE_SYS_UIO_H -#include - -void digestmd5(const struct iovec *iov, int iovcnt, void *dest); -void digestsha1(const struct iovec *iov, int iovcnt, void *dest); -#endif - -#endif diff --git a/libvncserver/rfbcrypto_gnutls.c b/libvncserver/rfbcrypto_gnutls.c deleted file mode 100644 index 2ecb2da..0000000 --- a/libvncserver/rfbcrypto_gnutls.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * rfbcrypto_gnutls.c - Crypto wrapper (gnutls version) - */ - -/* - * Copyright (C) 2011 Gernot Tenchio - * - * 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. - */ - -#include -#include -#include "rfbcrypto.h" - -void digestmd5(const struct iovec *iov, int iovcnt, void *dest) -{ - gcry_md_hd_t c; - int i; - - gcry_md_open(&c, GCRY_MD_MD5, 0); - for (i = 0; i < iovcnt; i++) - gcry_md_write(c, iov[i].iov_base, iov[i].iov_len); - gcry_md_final(c); - memcpy(dest, gcry_md_read(c, 0), gcry_md_get_algo_dlen(GCRY_MD_MD5)); -} - -void digestsha1(const struct iovec *iov, int iovcnt, void *dest) -{ - gcry_md_hd_t c; - int i; - - gcry_md_open(&c, GCRY_MD_SHA1, 0); - for (i = 0; i < iovcnt; i++) - gcry_md_write(c, iov[i].iov_base, iov[i].iov_len); - gcry_md_final(c); - memcpy(dest, gcry_md_read(c, 0), gcry_md_get_algo_dlen(GCRY_MD_SHA1)); -} diff --git a/libvncserver/rfbcrypto_included.c b/libvncserver/rfbcrypto_included.c deleted file mode 100644 index 7feff61..0000000 --- a/libvncserver/rfbcrypto_included.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * rfbcrypto_included.c - Crypto wrapper (included version) - */ - -/* - * Copyright (C) 2011 Gernot Tenchio - * - * 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. - */ - -#include -#include "md5.h" -#include "sha.h" -#include "rfbcrypto.h" - -void digestmd5(const struct iovec *iov, int iovcnt, void *dest) -{ - struct md5_ctx c; - int i; - - __md5_init_ctx(&c); - for (i = 0; i < iovcnt; i++) - __md5_process_bytes(iov[i].iov_base, iov[i].iov_len, &c); - __md5_finish_ctx(&c, dest); -} - -void digestsha1(const struct iovec *iov, int iovcnt, void *dest) -{ - SHA1Context c; - int i; - - SHA1Reset(&c); - for (i = 0; i < iovcnt; i++) - SHA1Input(&c, iov[i].iov_base, iov[i].iov_len); - SHA1Result(&c, dest); -} diff --git a/libvncserver/rfbcrypto_openssl.c b/libvncserver/rfbcrypto_openssl.c deleted file mode 100644 index 29ec5c1..0000000 --- a/libvncserver/rfbcrypto_openssl.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * rfbcrypto_openssl.c - Crypto wrapper (openssl version) - */ - -/* - * Copyright (C) 2011 Gernot Tenchio - * - * 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. - */ - -#include -#include -#include -#include "rfbcrypto.h" - -void digestmd5(const struct iovec *iov, int iovcnt, void *dest) -{ - MD5_CTX c; - int i; - - MD5_Init(&c); - for (i = 0; i < iovcnt; i++) - MD5_Update(&c, iov[i].iov_base, iov[i].iov_len); - MD5_Final(dest, &c); -} - -void digestsha1(const struct iovec *iov, int iovcnt, void *dest) -{ - SHA_CTX c; - int i; - - SHA1_Init(&c); - for (i = 0; i < iovcnt; i++) - SHA1_Update(&c, iov[i].iov_base, iov[i].iov_len); - SHA1_Final(dest, &c); -} diff --git a/libvncserver/rfbcrypto_polarssl.c b/libvncserver/rfbcrypto_polarssl.c deleted file mode 100644 index 55e3a7b..0000000 --- a/libvncserver/rfbcrypto_polarssl.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include -#include "rfbcrypto.h" - -void digestmd5(const struct iovec *iov, int iovcnt, void *dest) -{ - md5_context c; - int i; - - md5_starts(&c); - for (i = 0; i < iovcnt; i++) - md5_update(&c, iov[i].iov_base, iov[i].iov_len); - md5_finish(&c, dest); -} - -void digestsha1(const struct iovec *iov, int iovcnt, void *dest) -{ - sha1_context c; - int i; - - sha1_starts(&c); - for (i = 0; i < iovcnt; i++) - sha1_update(&c, iov[i].iov_base, iov[i].iov_len); - sha1_finish(&c, dest); -} -- cgit v1.2.3 From 96e163bdae65aa2c68e4301cf9ebe29e9f53f3d9 Mon Sep 17 00:00:00 2001 From: Quentin BUATHIER Date: Wed, 8 Aug 2018 16:14:39 +0200 Subject: Fix use-after-free --- libvncserver/main.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/main.c b/libvncserver/main.c index 05b4b13..106ebab 100644 --- a/libvncserver/main.c +++ b/libvncserver/main.c @@ -1081,15 +1081,21 @@ void rfbInitServer(rfbScreenInfoPtr screen) void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) { if(disconnectClients) { - rfbClientPtr cl; rfbClientIteratorPtr iter = rfbGetClientIterator(screen); - while( (cl = rfbClientIteratorNext(iter)) ) { - if (cl->sock > -1) { - /* we don't care about maxfd here, because the server goes away */ - rfbCloseClient(cl); - rfbClientConnectionGone(cl); + rfbClientPtr nextCl, currentCl = rfbClientIteratorNext(iter); + + while(currentCl) { + nextCl = rfbClientIteratorNext(iter); + if (currentCl->sock > -1) { + /* we don't care about maxfd here, because the server goes away */ + rfbCloseClient(currentCl); } + + rfbClientConnectionGone(currentCl); + + currentCl = nextCl; } + rfbReleaseClientIterator(iter); } -- cgit v1.2.3 From cedae6e6f97b14f5df3ea7c5f7efd59f2bc9ad82 Mon Sep 17 00:00:00 2001 From: Quentin BUATHIER Date: Thu, 9 Aug 2018 09:33:59 +0200 Subject: Fix the concurrent issue hapenning between the freeing of the client and the clientOutput thread --- libvncserver/main.c | 29 ++++++++++++++++++++++++++--- libvncserver/rfbserver.c | 5 +++++ rfb/rfb.h | 1 + 3 files changed, 32 insertions(+), 3 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/main.c b/libvncserver/main.c index 106ebab..c34ae7e 100644 --- a/libvncserver/main.c +++ b/libvncserver/main.c @@ -33,6 +33,7 @@ #include #include #include +#include #endif #include @@ -533,6 +534,7 @@ clientInput(void *data) FD_ZERO(&rfds); FD_SET(cl->sock, &rfds); + FD_SET(cl->pipe_notify_client_thread[0], &rfds); FD_ZERO(&efds); FD_SET(cl->sock, &efds); @@ -541,9 +543,13 @@ clientInput(void *data) if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1)) FD_SET(cl->sock, &wfds); + int nfds = cl->pipe_notify_client_thread[0] > cl->sock ? cl->pipe_notify_client_thread[0] : cl->sock; + tv.tv_sec = 60; /* 1 minute */ tv.tv_usec = 0; - n = select(cl->sock + 1, &rfds, &wfds, &efds, &tv); + + n = select(nfds + 1, &rfds, &wfds, &efds, &tv); + if (n < 0) { rfbLogPerror("ReadExact: select"); break; @@ -558,6 +564,13 @@ clientInput(void *data) if (FD_ISSET(cl->sock, &wfds)) rfbSendFileTransferChunk(cl); + if (FD_ISSET(cl->pipe_notify_client_thread[0], &rfds)) + { + // Reset the pipe + char buf; + while (read(cl->pipe_notify_client_thread[0], &buf, sizeof(buf)) == sizeof(buf)); + } + if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds)) { #ifdef LIBVNCSERVER_WITH_WEBSOCKETS @@ -628,8 +641,12 @@ rfbStartOnHoldClient(rfbClientPtr cl) { cl->onHold = FALSE; #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD - if(cl->screen->backgroundLoop) - pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl); + if(cl->screen->backgroundLoop) { + pipe(cl->pipe_notify_client_thread); + fcntl(cl->pipe_notify_client_thread[0], F_SETFL, O_NONBLOCK); + + pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl); + } #endif } @@ -1091,7 +1108,13 @@ void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) { rfbCloseClient(currentCl); } +#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD + // Notify the thread and join it + write(currentCl->pipe_notify_client_thread[1], "\x00", 1); + pthread_join(currentCl->client_thread, NULL); +#else rfbClientConnectionGone(currentCl); +#endif currentCl = nextCl; } diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index 7af6aed..f13050d 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -621,6 +621,11 @@ rfbClientConnectionGone(rfbClientPtr cl) UNLOCK(cl->sendMutex); TINI_MUTEX(cl->sendMutex); +#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD + close(cl->pipe_notify_client_thread[0]); + close(cl->pipe_notify_client_thread[1]); +#endif + rfbPrintStats(cl); rfbResetStats(cl); diff --git a/rfb/rfb.h b/rfb/rfb.h index 3d6d31e..9c60f3d 100644 --- a/rfb/rfb.h +++ b/rfb/rfb.h @@ -465,6 +465,7 @@ typedef struct _rfbClientRec { int protocolMinorVersion; #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD + int pipe_notify_client_thread[2]; pthread_t client_thread; #endif -- cgit v1.2.3 From 7063f607e4d6ab26dc0c67d628caea785888d7a0 Mon Sep 17 00:00:00 2001 From: DRC Date: Sun, 30 Sep 2018 19:37:14 +0200 Subject: Fix compilaton with gcc 4.4.x Closes #204 Signed-off-by: Christian Beier --- libvncserver/ws_decode.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/ws_decode.h b/libvncserver/ws_decode.h index 709477a..eb774a4 100644 --- a/libvncserver/ws_decode.h +++ b/libvncserver/ws_decode.h @@ -110,7 +110,7 @@ typedef struct ws_header_data_s { unsigned char fin; } ws_header_data_t; -typedef struct ws_ctx_s { +struct ws_ctx_s { char codeBufDecode[2048 + WSHLENMAX]; /* base64 + maximum frame header length */ char codeBufEncode[B64LEN(UPDATE_BUF_SIZE) + WSHLENMAX]; /* base64 + maximum frame header length */ char *writePos; @@ -126,7 +126,7 @@ typedef struct ws_ctx_s { wsEncodeFunc encode; wsDecodeFunc decode; ctxInfo_t ctxInfo; -} ws_ctx_t; +}; enum { -- cgit v1.2.3 From de3a2f46b5c4913ba55dfb8c6f7c8b52136bf27a Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Mon, 1 Oct 2018 20:04:00 +0200 Subject: httpd: send proper MIME type for Javascript files re #148 --- libvncserver/httpd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libvncserver') diff --git a/libvncserver/httpd.c b/libvncserver/httpd.c index 26d49af..efb97b3 100644 --- a/libvncserver/httpd.c +++ b/libvncserver/httpd.c @@ -462,6 +462,8 @@ httpProcessInput(rfbScreenInfoPtr rfbScreen) contentType = "Content-Type: text/css\r\n"; else if(ext && strcasecmp(ext, ".svg") == 0) contentType = "Content-Type: image/svg+xml\r\n"; + else if(ext && strcasecmp(ext, ".js") == 0) + contentType = "Content-Type: application/javascript\r\n"; rfbWriteExact(&cl, contentType, strlen(contentType)); /* end the header */ rfbWriteExact(&cl, "\r\n", 2); -- cgit v1.2.3 From 459046efc023161642c599809c6a5ef733035a12 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Mon, 1 Oct 2018 21:13:11 +0200 Subject: websockets: remove Flash fallback Closes #162 --- libvncserver/rfbserver.c | 4 +--- libvncserver/websockets.c | 10 ---------- 2 files changed, 1 insertion(+), 13 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index 7af6aed..ed1365a 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -463,9 +463,7 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen, #ifdef LIBVNCSERVER_WITH_WEBSOCKETS /* - * Wait a few ms for the client to send one of: - * - Flash policy request - * - WebSockets connection (TLS/SSL or plain) + * Wait a few ms for the client to send WebSockets connection (TLS/SSL or plain) */ if (!webSocketsCheck(cl)) { /* Error reporting handled in webSocketsHandshake */ diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index 4ebff72..d91c4f2 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -61,9 +61,6 @@ static int gettid() { } #endif -#define FLASH_POLICY_RESPONSE "\n" -#define SZ_FLASH_POLICY_RESPONSE 93 - /* * draft-ietf-hybi-thewebsocketprotocol-10 * 5.2.2. Sending the Server's Opening Handshake @@ -144,13 +141,6 @@ webSocketsCheck (rfbClientPtr cl) if (strncmp(bbuf, "RFB ", 4) == 0) { rfbLog("Normal socket connection\n"); return TRUE; - } else if (strncmp(bbuf, "<", 1) == 0) { - rfbLog("Got Flash policy request, sending response\n"); - if (rfbWriteExact(cl, FLASH_POLICY_RESPONSE, - SZ_FLASH_POLICY_RESPONSE) < 0) { - rfbErr("webSocketsHandshake: failed sending Flash policy response"); - } - return FALSE; } else if (strncmp(bbuf, "\x16", 1) == 0 || strncmp(bbuf, "\x80", 1) == 0) { rfbLog("Got TLS/SSL WebSockets connection\n"); if (-1 == rfbssl_init(cl)) { -- cgit v1.2.3 From 502821828ed00b4a2c4bef90683d0fd88ce495de Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sun, 21 Oct 2018 20:21:30 +0200 Subject: LibVNCServer: fix heap out-of-bound write access Closes #243 --- libvncserver/rfbserver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libvncserver') diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index ed1365a..6ca511f 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -1465,7 +1465,7 @@ char *rfbProcessFileTransferReadBuffer(rfbClientPtr cl, uint32_t length) rfbLog("rfbProcessFileTransferReadBuffer(%dlen)\n", length); */ if (length>0) { - buffer=malloc(length+1); + buffer=malloc((uint64_t)length+1); if (buffer!=NULL) { if ((n = rfbReadExact(cl, (char *)buffer, length)) <= 0) { if (n != 0) -- cgit v1.2.3 From ca2a5ac02fbbadd0a21fabba779c1ea69173d10b Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sun, 21 Oct 2018 20:52:04 +0200 Subject: tightvnc-filetransfer: fix heap use-after-free One can only guess what the intended semantics were here, but as every other rfbCloseClient() call in this file is followed by an immediate return, let's assume this was forgotton in this case. Anyway, don't forget to clean up to not leak memory. Closes #241 --- libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libvncserver') diff --git a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c index c511eed..0473783 100644 --- a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c +++ b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c @@ -585,6 +585,8 @@ HandleFileDownloadCancelRequest(rfbClientPtr cl, rfbTightClientPtr rtcp) "FileDownloadCancelMsg\n", __FILE__, __FUNCTION__); rfbCloseClient(cl); + free(reason); + return; } rfbLog("File [%s]: Method [%s]: File Download Cancel Request received:" -- cgit v1.2.3 From 89419fb1a0cef42b63528e6930f4e545cfef4c95 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sun, 21 Oct 2018 23:38:40 +0200 Subject: tightvnc-filetransfer: tie the download thread to the control structure re #242 --- libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c | 3 +-- libvncserver/tightvnc-filetransfer/rfbtightproto.h | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c index 0473783..8e38f88 100644 --- a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c +++ b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c @@ -508,7 +508,6 @@ RunFileDownloadThread(void* client) void HandleFileDownload(rfbClientPtr cl, rfbTightClientPtr rtcp) { - pthread_t fileDownloadThread; FileTransferMsg fileDownloadMsg; memset(&fileDownloadMsg, 0, sizeof(FileTransferMsg)); @@ -521,7 +520,7 @@ HandleFileDownload(rfbClientPtr cl, rfbTightClientPtr rtcp) rtcp->rcft.rcfd.downloadInProgress = FALSE; rtcp->rcft.rcfd.downloadFD = -1; - if(pthread_create(&fileDownloadThread, NULL, RunFileDownloadThread, (void*) + if(pthread_create(&rtcp->rcft.rcfd.downloadThread, NULL, RunFileDownloadThread, (void*) cl) != 0) { FileTransferMsg ftm = GetFileDownLoadErrMsg(); diff --git a/libvncserver/tightvnc-filetransfer/rfbtightproto.h b/libvncserver/tightvnc-filetransfer/rfbtightproto.h index d0fe642..30fc5f5 100644 --- a/libvncserver/tightvnc-filetransfer/rfbtightproto.h +++ b/libvncserver/tightvnc-filetransfer/rfbtightproto.h @@ -148,6 +148,7 @@ typedef struct _rfbClientFileDownload { int downloadInProgress; unsigned long mTime; int downloadFD; + pthread_t downloadThread; } rfbClientFileDownload ; typedef struct _rfbClientFileUpload { -- cgit v1.2.3 From f8912fee5a58fb3975eda2589f6d4686f0c1ae68 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sun, 21 Oct 2018 23:44:39 +0200 Subject: tightvnc-filetransfer: refactor CloseUndoneFileTransfer() into two functions ...for closing upload and download separately. re #242 --- libvncserver/tightvnc-filetransfer/filetransfermsg.c | 12 ++++++++++-- libvncserver/tightvnc-filetransfer/filetransfermsg.h | 3 ++- .../tightvnc-filetransfer/handlefiletransferrequest.c | 8 ++++---- 3 files changed, 16 insertions(+), 7 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/tightvnc-filetransfer/filetransfermsg.c b/libvncserver/tightvnc-filetransfer/filetransfermsg.c index 5f84e7f..f674b92 100644 --- a/libvncserver/tightvnc-filetransfer/filetransfermsg.c +++ b/libvncserver/tightvnc-filetransfer/filetransfermsg.c @@ -672,7 +672,7 @@ ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr rtcp, char* pBuf) char reason[] = "Error writing file data"; int reasonLen = strlen(reason); ftm = CreateFileUploadErrMsg(reason, reasonLen); - CloseUndoneFileTransfer(cl, rtcp); + CloseUndoneFileUpload(cl, rtcp); } return ftm; } @@ -735,7 +735,7 @@ CreateFileUploadErrMsg(char* reason, unsigned int reasonLen) ******************************************************************************/ void -CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr rtcp) +CloseUndoneFileUpload(rfbClientPtr cl, rfbTightClientPtr rtcp) { /* TODO :: File Upload case is not handled currently */ /* TODO :: In case of concurrency we need to use Critical Section */ @@ -759,6 +759,14 @@ CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr rtcp) memset(rtcp->rcft.rcfu.fName, 0 , PATH_MAX); } +} + + +void +CloseUndoneFileDownload(rfbClientPtr cl, rfbTightClientPtr rtcp) +{ + if(cl == NULL) + return; if(rtcp->rcft.rcfd.downloadInProgress == TRUE) { rtcp->rcft.rcfd.downloadInProgress = FALSE; diff --git a/libvncserver/tightvnc-filetransfer/filetransfermsg.h b/libvncserver/tightvnc-filetransfer/filetransfermsg.h index 3b27bd0..bbb9148 100644 --- a/libvncserver/tightvnc-filetransfer/filetransfermsg.h +++ b/libvncserver/tightvnc-filetransfer/filetransfermsg.h @@ -51,7 +51,8 @@ FileTransferMsg ChkFileUploadWriteErr(rfbClientPtr cl, rfbTightClientPtr data, c void CreateDirectory(char* dirName); void FileUpdateComplete(rfbClientPtr cl, rfbTightClientPtr data); -void CloseUndoneFileTransfer(rfbClientPtr cl, rfbTightClientPtr data); +void CloseUndoneFileUpload(rfbClientPtr cl, rfbTightClientPtr data); +void CloseUndoneFileDownload(rfbClientPtr cl, rfbTightClientPtr data); void FreeFileTransferMsg(FileTransferMsg ftm); diff --git a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c index 8e38f88..31163d0 100644 --- a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c +++ b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c @@ -492,7 +492,7 @@ RunFileDownloadThread(void* client) if(cl != NULL) { rfbCloseClient(cl); - CloseUndoneFileTransfer(cl, rtcp); + CloseUndoneFileDownload(cl, rtcp); } FreeFileTransferMsg(fileDownloadMsg); @@ -592,7 +592,7 @@ HandleFileDownloadCancelRequest(rfbClientPtr cl, rfbTightClientPtr rtcp) " reason <%s>\n", __FILE__, __FUNCTION__, reason); pthread_mutex_lock(&fileDownloadMutex); - CloseUndoneFileTransfer(cl, rtcp); + CloseUndoneFileDownload(cl, rtcp); pthread_mutex_unlock(&fileDownloadMutex); if(reason != NULL) { @@ -835,7 +835,7 @@ HandleFileUploadDataRequest(rfbClientPtr cl, rfbTightClientPtr rtcp) FreeFileTransferMsg(ftm); } - CloseUndoneFileTransfer(cl, rtcp); + CloseUndoneFileUpload(cl, rtcp); if(pBuf != NULL) { free(pBuf); @@ -935,7 +935,7 @@ HandleFileUploadFailedRequest(rfbClientPtr cl, rfbTightClientPtr rtcp) rfbLog("File [%s]: Method [%s]: File Upload Failed Request received:" " reason <%s>\n", __FILE__, __FUNCTION__, reason); - CloseUndoneFileTransfer(cl, rtcp); + CloseUndoneFileUpload(cl, rtcp); if(reason != NULL) { free(reason); -- cgit v1.2.3 From 73cb96fec028a576a5a24417b57723b55854ad7b Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sun, 21 Oct 2018 23:59:39 +0200 Subject: tightvnc-filetransfer: wait for download thread end in CloseUndoneFileDownload() ...and use it when deregistering the file transfer extension. Closes #242 --- libvncserver/tightvnc-filetransfer/filetransfermsg.c | 2 ++ libvncserver/tightvnc-filetransfer/rfbtightserver.c | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/tightvnc-filetransfer/filetransfermsg.c b/libvncserver/tightvnc-filetransfer/filetransfermsg.c index f674b92..0003b11 100644 --- a/libvncserver/tightvnc-filetransfer/filetransfermsg.c +++ b/libvncserver/tightvnc-filetransfer/filetransfermsg.c @@ -770,6 +770,8 @@ CloseUndoneFileDownload(rfbClientPtr cl, rfbTightClientPtr rtcp) if(rtcp->rcft.rcfd.downloadInProgress == TRUE) { rtcp->rcft.rcfd.downloadInProgress = FALSE; + /* the thread will return if downloadInProgress is FALSE */ + pthread_join(rtcp->rcft.rcfd.downloadThread, NULL); if(rtcp->rcft.rcfd.downloadFD != -1) { close(rtcp->rcft.rcfd.downloadFD); diff --git a/libvncserver/tightvnc-filetransfer/rfbtightserver.c b/libvncserver/tightvnc-filetransfer/rfbtightserver.c index 67d4cb5..651d8fb 100644 --- a/libvncserver/tightvnc-filetransfer/rfbtightserver.c +++ b/libvncserver/tightvnc-filetransfer/rfbtightserver.c @@ -26,6 +26,7 @@ #include #include "rfbtightproto.h" #include "handlefiletransferrequest.h" +#include "filetransfermsg.h" /* * Get my data! @@ -448,9 +449,11 @@ rfbTightExtensionMsgHandler(struct _rfbClientRec* cl, void* data, void rfbTightExtensionClientClose(rfbClientPtr cl, void* data) { - if(data != NULL) + if(data != NULL) { + CloseUndoneFileUpload(cl, data); + CloseUndoneFileDownload(cl, data); free(data); - + } } void -- cgit v1.2.3 From 2d939267a176bf4976dbad36399638956ad8cc34 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Mon, 22 Oct 2018 00:39:50 +0200 Subject: tightvnc-filetransfer: when creating a new download thread, make sure the previous one ends re #242 --- libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c index 31163d0..70e105f 100644 --- a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c +++ b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c @@ -517,8 +517,7 @@ HandleFileDownload(rfbClientPtr cl, rfbTightClientPtr rtcp) FreeFileTransferMsg(fileDownloadMsg); return; } - rtcp->rcft.rcfd.downloadInProgress = FALSE; - rtcp->rcft.rcfd.downloadFD = -1; + CloseUndoneFileDownload(cl, rtcp); if(pthread_create(&rtcp->rcft.rcfd.downloadThread, NULL, RunFileDownloadThread, (void*) cl) != 0) { -- cgit v1.2.3 From c422847e2c5f32ed9531c461650c7f627516d951 Mon Sep 17 00:00:00 2001 From: Tobias Junghans Date: Mon, 5 Nov 2018 15:15:57 +0100 Subject: LibVNCClient: fix integer shifts for cursor colors Shifting values > 32768 by 16 places can cause undefined results for signed integers. Therefore cast color components to unsigned integer before shifting. --- libvncserver/cursor.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/cursor.c b/libvncserver/cursor.c index c071dd9..8779470 100644 --- a/libvncserver/cursor.c +++ b/libvncserver/cursor.c @@ -456,10 +456,10 @@ void rfbMakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor fore+=4-bpp; } - background=cursor->backRed<redShift| - cursor->backGreen<greenShift|cursor->backBlue<blueShift; - foreground=cursor->foreRed<redShift| - cursor->foreGreen<greenShift|cursor->foreBlue<blueShift; + background=(uint32_t)cursor->backRed<redShift| + (uint32_t)cursor->backGreen<greenShift|(uint32_t)cursor->backBlue<blueShift; + foreground=(uint32_t)cursor->foreRed<redShift| + (uint32_t)cursor->foreGreen<greenShift|(uint32_t)cursor->foreBlue<blueShift; for(j=0;jheight;j++) for(i=0,bit=0x80;iwidth;i++,bit=(bit&1)?0x80:bit>>1,cp+=bpp) -- cgit v1.2.3 From 09b2ed438177a86bcf29e01bf0851ce815b6ef8d Mon Sep 17 00:00:00 2001 From: Tobias Junghans Date: Tue, 6 Nov 2018 10:32:14 +0100 Subject: Undef error codes before redefining them for WSA Fixes compiler warnings about redefined macros from errno.h. --- libvncclient/sasl.c | 3 +++ libvncclient/sockets.c | 3 +++ libvncserver/sockets.c | 6 ++++++ 3 files changed, 12 insertions(+) (limited to 'libvncserver') diff --git a/libvncclient/sasl.c b/libvncclient/sasl.c index 0530307..db240c1 100644 --- a/libvncclient/sasl.c +++ b/libvncclient/sasl.c @@ -41,6 +41,9 @@ #ifdef WIN32 #undef SOCKET #include +#ifdef EWOULDBLOCK +#undef EWOULDBLOCK +#endif #define EWOULDBLOCK WSAEWOULDBLOCK #define socklen_t int #define close closesocket diff --git a/libvncclient/sockets.c b/libvncclient/sockets.c index ed2deef..f042472 100644 --- a/libvncclient/sockets.c +++ b/libvncclient/sockets.c @@ -40,6 +40,9 @@ #ifdef WIN32 #undef SOCKET #include +#ifdef EWOULDBLOCK +#undef EWOULDBLOCK +#endif #define EWOULDBLOCK WSAEWOULDBLOCK #define close closesocket #define read(sock,buf,len) recv(sock,buf,len,0) diff --git a/libvncserver/sockets.c b/libvncserver/sockets.c index bbc3d90..fe54a37 100644 --- a/libvncserver/sockets.c +++ b/libvncserver/sockets.c @@ -109,7 +109,13 @@ int deny_severity=LOG_WARNING; #pragma warning (disable: 4018 4761) #endif #define read(sock,buf,len) recv(sock,buf,len,0) +#ifdef EWOULDBLOCK +#undef EWOULDBLOCK +#endif #define EWOULDBLOCK WSAEWOULDBLOCK +#ifdef ETIMEDOUT +#undef ETIMEDOUT +#endif #define ETIMEDOUT WSAETIMEDOUT #define write(sock,buf,len) send(sock,buf,len,0) #else -- cgit v1.2.3 From 495ffa3f3a213ab058eee1d7da48fa5ef71914d8 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sat, 10 Nov 2018 17:33:00 +0100 Subject: tightvnc-filetransfer: do not close stuff from within a thread ... as this crashes badly and the client is closed by the main thread machinery afterwards. re #242 --- libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c index 70e105f..71fb085 100644 --- a/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c +++ b/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c @@ -489,12 +489,6 @@ RunFileDownloadThread(void* client) if(rfbWriteExact(cl, fileDownloadMsg.data, fileDownloadMsg.length) < 0) { rfbLog("File [%s]: Method [%s]: Error while writing to socket \n" , __FILE__, __FUNCTION__); - - if(cl != NULL) { - rfbCloseClient(cl); - CloseUndoneFileDownload(cl, rtcp); - } - FreeFileTransferMsg(fileDownloadMsg); return NULL; } -- cgit v1.2.3 From aa8a1aa76880ffb8f23b98d0dbe35988b2609877 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sun, 11 Nov 2018 17:48:38 +0100 Subject: Add SSL options to rfbUsage output --- libvncserver/cargs.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libvncserver') diff --git a/libvncserver/cargs.c b/libvncserver/cargs.c index 4da04b5..85b937d 100644 --- a/libvncserver/cargs.c +++ b/libvncserver/cargs.c @@ -43,6 +43,10 @@ rfbUsage(void) "new non-shared\n" " connection comes in (refuse new connection " "instead)\n"); +#ifdef LIBVNCSERVER_WITH_WEBSOCKETS + fprintf(stderr, "-sslkeyfile path set path to private key file for encrypted WebSockets connections\n"); + fprintf(stderr, "-sslcertfile path set path to certificate file for encrypted WebSockets connections\n"); +#endif fprintf(stderr, "-httpdir dir-path enable http server using dir-path home\n"); fprintf(stderr, "-httpport portnum use portnum for http connection\n"); #ifdef LIBVNCSERVER_IPv6 -- cgit v1.2.3 From 2411769962b1c95015bfc2d0c817a34213afbbc9 Mon Sep 17 00:00:00 2001 From: Tobias Junghans Date: Wed, 7 Nov 2018 13:03:16 +0100 Subject: LibVNCServer: properly use thread-local storage The TLS macro never has been defined due to the missing LIBVNCSERVER_HAVE_TLS macro. This revises the macro logic to also cover Win32 builds with MSVC. --- libvncserver/tight.c | 7 ++++--- libvncserver/zlib.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/tight.c b/libvncserver/tight.c index 1081c8f..d6f4749 100644 --- a/libvncserver/tight.c +++ b/libvncserver/tight.c @@ -57,10 +57,11 @@ * that we resort to using thread local storage instead of having * per-client data. */ -#if LIBVNCSERVER_HAVE_LIBPTHREAD && LIBVNCSERVER_HAVE_TLS && !defined(TLS) && defined(__linux__) +#if defined(__GNUC__) #define TLS __thread -#endif -#ifndef TLS +#elif defined(_MSC_VER) +#define TLS __declspec(thread) +#else #define TLS #endif diff --git a/libvncserver/zlib.c b/libvncserver/zlib.c index 45a1314..6fee4df 100644 --- a/libvncserver/zlib.c +++ b/libvncserver/zlib.c @@ -45,10 +45,11 @@ * tight. N.B. ZRLE does it the traditional way with per-client storage * (and so at least ZRLE will work threaded on older systems.) */ -#if LIBVNCSERVER_HAVE_LIBPTHREAD && LIBVNCSERVER_HAVE_TLS && !defined(TLS) && defined(__linux__) +#if defined(__GNUC__) #define TLS __thread -#endif -#ifndef TLS +#elif defined(_MSC_VER) +#define TLS __declspec(thread) +#else #define TLS #endif -- cgit v1.2.3 From e66a8a17f3fb2dc87ebd35535c9a310068ba3b4a Mon Sep 17 00:00:00 2001 From: Tobias Junghans Date: Thu, 22 Nov 2018 15:19:37 +0100 Subject: Allow to use global LZO library instead of miniLZO The complete LZO library nowadays is installed on many systems so we can optionally make use of it and omit internal miniLZO implementation. --- .travis.yml | 2 +- CMakeLists.txt | 27 +++++++++++++++++++++++++-- cmake/Modules/FindLZO.cmake | 31 +++++++++++++++++++++++++++++++ libvncclient/rfbproto.c | 4 ++++ libvncserver/ultra.c | 4 ++++ rfb/rfbconfig.h.cmakein | 3 +++ 6 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 cmake/Modules/FindLZO.cmake (limited to 'libvncserver') diff --git a/.travis.yml b/.travis.yml index ea8b9e5..dde1238 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ before_install: script: - mkdir build - cd build - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update; sudo apt-get --no-install-suggests --no-install-recommends install libsdl2-dev; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update; sudo apt-get --no-install-suggests --no-install-recommends install libsdl2-dev liblzo2-dev; fi - if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then brew update; brew install sdl2; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cmake .. -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl; else cmake ..; fi - cmake --build . diff --git a/CMakeLists.txt b/CMakeLists.txt index 727c970..68cd843 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CM # all the build configuration switches option(BUILD_SHARED_LIBS "Build shared libraries" ${UNIX}) option(WITH_ZLIB "Search for the zlib compression library to support additional encodings" ON) +option(WITH_LZO "Search for the LZO compression library to omit internal miniLZO implementation" ON) option(WITH_JPEG "Search for the libjpeg compression library to support additional encodings" ON) option(WITH_PNG "Search for the PNG compression library to support additional encodings" ON) option(WITH_SDL "Search for the Simple Direct Media Layer library to build an example SDL vnc client" ON) @@ -56,6 +57,9 @@ if(WITH_ZLIB) find_package(ZLIB) endif(WITH_ZLIB) +if(WITH_LZO) + find_package(LZO) +endif() if(WITH_JPEG) find_package(JPEG) @@ -189,6 +193,11 @@ if(ZLIB_FOUND) else() unset(ZLIB_LIBRARIES) # would otherwise contain -NOTFOUND, confusing target_link_libraries() endif(ZLIB_FOUND) +if(LZO_FOUND) + set(LIBVNCSERVER_HAVE_LZO 1) +else() + unset(LZO_LIBRARIES CACHE) # would otherwise contain -NOTFOUND, confusing target_link_libraries() +endif() if(JPEG_FOUND) set(LIBVNCSERVER_HAVE_LIBJPEG 1) else() @@ -317,7 +326,6 @@ set(LIBVNCSERVER_SOURCES ${COMMON_DIR}/d3des.c ${COMMON_DIR}/vncauth.c ${LIBVNCSERVER_DIR}/cargs.c - ${COMMON_DIR}/minilzo.c ${LIBVNCSERVER_DIR}/ultra.c ${LIBVNCSERVER_DIR}/scale.c ) @@ -328,7 +336,6 @@ set(LIBVNCCLIENT_SOURCES ${LIBVNCCLIENT_DIR}/rfbproto.c ${LIBVNCCLIENT_DIR}/sockets.c ${LIBVNCCLIENT_DIR}/vncviewer.c - ${COMMON_DIR}/minilzo.c ) if(JPEG_FOUND) @@ -388,6 +395,20 @@ if(ZLIB_FOUND) ) endif(ZLIB_FOUND) +if(LZO_FOUND) + add_definitions(-DLIBVNCSERVER_HAVE_LZO) + include_directories(${LZO_INCLUDE_DIR}) +else() + set(LIBVNCSERVER_SOURCES + ${LIBVNCSERVER_SOURCES} + ${COMMON_DIR}/minilzo.c + ) + set(LIBVNCCLIENT_SOURCES + ${LIBVNCCLIENT_SOURCES} + ${COMMON_DIR}/minilzo.c + ) +endif() + if(JPEG_FOUND) add_definitions(-DLIBVNCSERVER_HAVE_LIBJPEG) include_directories(${JPEG_INCLUDE_DIR}) @@ -434,6 +455,7 @@ endif(WIN32) target_link_libraries(vncclient ${ADDITIONAL_LIBS} ${ZLIB_LIBRARIES} + ${LZO_LIBRARIES} ${JPEG_LIBRARIES} ${GNUTLS_LIBRARIES} ${OPENSSL_LIBRARIES} @@ -441,6 +463,7 @@ target_link_libraries(vncclient target_link_libraries(vncserver ${ADDITIONAL_LIBS} ${ZLIB_LIBRARIES} + ${LZO_LIBRARIES} ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${CRYPTO_LIBRARIES} diff --git a/cmake/Modules/FindLZO.cmake b/cmake/Modules/FindLZO.cmake new file mode 100644 index 0000000..d313fae --- /dev/null +++ b/cmake/Modules/FindLZO.cmake @@ -0,0 +1,31 @@ +# Find liblzo2 +# LZO_FOUND - system has the LZO library +# LZO_INCLUDE_DIR - the LZO include directory +# LZO_LIBRARIES - The libraries needed to use LZO + +if (LZO_INCLUDE_DIR AND LZO_LIBRARIES) + # in cache already + SET(LZO_FOUND TRUE) +else (LZO_INCLUDE_DIR AND LZO_LIBRARIES) + FIND_PATH(LZO_INCLUDE_DIR NAMES lzo/lzo1x.h) + + FIND_LIBRARY(LZO_LIBRARIES NAMES lzo2) + + if (LZO_INCLUDE_DIR AND LZO_LIBRARIES) + set(LZO_FOUND TRUE) + endif (LZO_INCLUDE_DIR AND LZO_LIBRARIES) + + if (LZO_FOUND) + if (NOT LZO_FIND_QUIETLY) + message(STATUS "Found LZO: ${LZO_LIBRARIES}") + endif (NOT LZO_FIND_QUIETLY) + else (LZO_FOUND) + if (LZO_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find LZO") + else() + message(STATUS "Could NOT find LZO") + endif (LZO_FIND_REQUIRED) + endif (LZO_FOUND) + +# MARK_AS_ADVANCED(LZO_INCLUDE_DIR LZO_LIBRARIES) +endif (LZO_INCLUDE_DIR AND LZO_LIBRARIES) diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c index 4541e0d..82536cd 100644 --- a/libvncclient/rfbproto.c +++ b/libvncclient/rfbproto.c @@ -61,7 +61,11 @@ #endif #include "sasl.h" +#ifdef LIBVNCSERVER_HAVE_LZO +#include +#else #include "minilzo.h" +#endif #include "tls.h" #ifdef _MSC_VER diff --git a/libvncserver/ultra.c b/libvncserver/ultra.c index 83bddaa..cd625a5 100644 --- a/libvncserver/ultra.c +++ b/libvncserver/ultra.c @@ -8,7 +8,11 @@ */ #include +#ifdef LIBVNCSERVER_HAVE_LZO +#include +#else #include "minilzo.h" +#endif /* * cl->beforeEncBuf contains pixel data in the client's format. diff --git a/rfb/rfbconfig.h.cmakein b/rfb/rfbconfig.h.cmakein index 2d165c5..f5d8d78 100644 --- a/rfb/rfbconfig.h.cmakein +++ b/rfb/rfbconfig.h.cmakein @@ -72,6 +72,9 @@ /* Define to 1 if you have the `z' library (-lz). */ #cmakedefine LIBVNCSERVER_HAVE_LIBZ 1 +/* Define to 1 if you have the `lzo2' library (-llzo2). */ +#cmakedefine LIBVNCSERVER_HAVE_LZO 1 + /* Define to 1 if you have the header file. */ #cmakedefine LIBVNCSERVER_HAVE_NETINET_IN_H 1 -- cgit v1.2.3 From 716bd27235fe6462271e799a758f2682fa4cb1de Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Wed, 28 Nov 2018 21:08:15 +0100 Subject: Fix -Wmisleading-indentation warnings --- common/turbojpeg.c | 6 ++++-- common/vncauth.c | 5 +++-- libvncserver/tableinit24.c | 11 ++++++----- libvncserver/websockets.c | 11 +++++++---- test/tjbench.c | 15 +++++++++------ 5 files changed, 29 insertions(+), 19 deletions(-) (limited to 'libvncserver') diff --git a/common/turbojpeg.c b/common/turbojpeg.c index 09df173..934e4f1 100644 --- a/common/turbojpeg.c +++ b/common/turbojpeg.c @@ -468,7 +468,8 @@ static tjhandle _tjInitCompress(tjinstance *this) if(setjmp(this->jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. */ - if(this) free(this); return NULL; + if(this) free(this); + return NULL; } jpeg_create_compress(&this->cinfo); @@ -652,7 +653,8 @@ static tjhandle _tjInitDecompress(tjinstance *this) if(setjmp(this->jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. */ - if(this) free(this); return NULL; + if(this) free(this); + return NULL; } jpeg_create_decompress(&this->dinfo); diff --git a/common/vncauth.c b/common/vncauth.c index 2a5d96f..81bb10b 100644 --- a/common/vncauth.c +++ b/common/vncauth.c @@ -207,8 +207,9 @@ rfbEncryptBytes2(unsigned char *where, const int length, unsigned char *key) { where[i] ^= key[i]; rfbDes(where, where); for (i = 8; i < length; i += 8) { - for (j = 0; j < 8; j++) + for (j = 0; j < 8; j++) { where[i + j] ^= where[i + j - 8]; - rfbDes(where + i, where + i); + } + rfbDes(where + i, where + i); } } diff --git a/libvncserver/tableinit24.c b/libvncserver/tableinit24.c index 39e9920..5c5823c 100644 --- a/libvncserver/tableinit24.c +++ b/libvncserver/tableinit24.c @@ -147,11 +147,12 @@ rfbInitOneRGBTable24 (uint8_t *table, int inMax, int outMax, int outShift, for (i = 0; i < nEntries; i++) { outValue = ((i * outMax + inMax / 2) / inMax) << outShift; *(uint32_t *)&table[3*i] = outValue; - if(!rfbEndianTest) + if(!rfbEndianTest) { memmove(table+3*i,table+3*i+1,3); - if (swap) { - c = table[3*i]; table[3*i] = table[3*i+2]; - table[3*i+2] = c; - } + } + if (swap) { + c = table[3*i]; table[3*i] = table[3*i+2]; + table[3*i+2] = c; + } } } diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index d91c4f2..616c81c 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -198,12 +198,15 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) if ((n < 0) && (errno == ETIMEDOUT)) { break; } - if (n == 0) + if (n == 0) { rfbLog("webSocketsHandshake: client gone\n"); - else + } + else { rfbLogPerror("webSocketsHandshake: read"); - free(response); - free(buf); + } + + free(response); + free(buf); return FALSE; } diff --git a/test/tjbench.c b/test/tjbench.c index 29aa153..87e1591 100644 --- a/test/tjbench.c +++ b/test/tjbench.c @@ -178,7 +178,8 @@ int decomptest(unsigned char *srcbuf, unsigned char **jpegbuf, int y=(int)((double)srcbuf[rindex]*0.299 + (double)srcbuf[gindex]*0.587 + (double)srcbuf[bindex]*0.114 + 0.5); - if(y>255) y=255; if(y<0) y=0; + if(y>255) y=255; + if(y<0) y=0; dstbuf[rindex]=abs(dstbuf[rindex]-y); dstbuf[gindex]=abs(dstbuf[gindex]-y); dstbuf[bindex]=abs(dstbuf[bindex]-y); @@ -226,7 +227,8 @@ void dotest(unsigned char *srcbuf, int w, int h, int subsamp, int jpegqual, for(tilew=dotile? 8:w, tileh=dotile? 8:h; ; tilew*=2, tileh*=2) { - if(tilew>w) tilew=w; if(tileh>h) tileh=h; + if(tilew>w) tilew=w; + if(tileh>h) tileh=h; ntilesw=(w+tilew-1)/tilew; ntilesh=(h+tileh-1)/tileh; if((jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *) @@ -323,7 +325,7 @@ void dotest(unsigned char *srcbuf, int w, int h, int subsamp, int jpegqual, for(i=0; iw) tilew=w; if(tileh>h) tileh=h; + if(tilew>w) tilew=w; + if(tileh>h) tileh=h; ntilesw=(w+tilew-1)/tilew; ntilesh=(h+tileh-1)/tileh; if((jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *) @@ -455,7 +458,7 @@ void dodecomptest(char *filename) { for(i=0; i Date: Thu, 6 Dec 2018 09:16:51 +0100 Subject: Check the return code of pipe --- libvncserver/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'libvncserver') diff --git a/libvncserver/main.c b/libvncserver/main.c index c34ae7e..17bef7e 100644 --- a/libvncserver/main.c +++ b/libvncserver/main.c @@ -642,7 +642,10 @@ rfbStartOnHoldClient(rfbClientPtr cl) cl->onHold = FALSE; #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD if(cl->screen->backgroundLoop) { - pipe(cl->pipe_notify_client_thread); + if (pipe(cl->pipe_notify_client_thread) == -1) { + cl->pipe_notify_client_thread[0] = -1; + cl->pipe_notify_client_thread[1] = -1; + } fcntl(cl->pipe_notify_client_thread[0], F_SETFL, O_NONBLOCK); pthread_create(&cl->client_thread, NULL, clientInput, (void *)cl); -- cgit v1.2.3 From 15bb719c03cc70f14c36a843dcb16ed69b405707 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sun, 6 Jan 2019 15:13:56 +0100 Subject: Error out in rfbProcessFileTransferReadBuffer if length can not be allocated re #273 --- libvncserver/rfbserver.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index 6ca511f..e210a32 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -1461,11 +1461,21 @@ char *rfbProcessFileTransferReadBuffer(rfbClientPtr cl, uint32_t length) int n=0; FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, NULL); + /* - rfbLog("rfbProcessFileTransferReadBuffer(%dlen)\n", length); + We later alloc length+1, which might wrap around on 32-bit systems if length equals + 0XFFFFFFFF, i.e. SIZE_MAX for 32-bit systems. On 64-bit systems, a length of 0XFFFFFFFF + will safely be allocated since this check will never trigger and malloc() can digest length+1 + without problems as length is a uint32_t. */ + if(length == SIZE_MAX) { + rfbErr("rfbProcessFileTransferReadBuffer: too big file transfer length requested: %u", (unsigned int)length); + rfbCloseClient(cl); + return NULL; + } + if (length>0) { - buffer=malloc((uint64_t)length+1); + buffer=malloc((size_t)length+1); if (buffer!=NULL) { if ((n = rfbReadExact(cl, (char *)buffer, length)) <= 0) { if (n != 0) -- cgit v1.2.3 From 14c24e2bcc05578e37dfd64b6efe73774a288c90 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Sun, 6 Jan 2019 19:30:16 +0100 Subject: Fix comment style and be a bit more verbose ... explaining cedae6e6f97b14f5df3ea7c5f7efd59f2bc9ad82. --- libvncserver/main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'libvncserver') diff --git a/libvncserver/main.c b/libvncserver/main.c index 17bef7e..d3cd9b1 100644 --- a/libvncserver/main.c +++ b/libvncserver/main.c @@ -566,7 +566,7 @@ clientInput(void *data) if (FD_ISSET(cl->pipe_notify_client_thread[0], &rfds)) { - // Reset the pipe + /* Reset the pipe */ char buf; while (read(cl->pipe_notify_client_thread[0], &buf, sizeof(buf)) == sizeof(buf)); } @@ -1112,8 +1112,13 @@ void rfbShutdownServer(rfbScreenInfoPtr screen,rfbBool disconnectClients) { } #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD - // Notify the thread and join it + /* + Notify the thread. This simply writes a NULL byte to the notify pipe in order to get past the select() + in clientInput(), the loop in there will then break because the rfbCloseClient() above has set + currentCl->sock to -1. + */ write(currentCl->pipe_notify_client_thread[1], "\x00", 1); + /* And wait for it to finish. */ pthread_join(currentCl->client_thread, NULL); #else rfbClientConnectionGone(currentCl); -- cgit v1.2.3