diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | 0001-build-Set-rpath-on-executable.patch | 50 | ||||
| -rw-r--r-- | 0001-crypto-Don-t-compile-SHA1-support-when-Websockets-ar.patch | 92 | ||||
| -rw-r--r-- | 0001-libvncserver-Add-API-to-add-custom-I-O-entry-points.patch | 241 | ||||
| -rw-r--r-- | 0001-libvncserver-don-t-NULL-out-internal-of-the-default-.patch | 28 | ||||
| -rw-r--r-- | 0001-pipewire-stream-Don-t-leak-GSource-s.patch | 53 | ||||
| -rw-r--r-- | 0002-libvncserver-Add-channel-security-handlers.patch | 368 | ||||
| -rw-r--r-- | 0003-libvncserver-auth-don-t-keep-security-handlers-from-.patch | 32 | ||||
| -rw-r--r-- | 0004-zlib-Clear-buffer-pointers-on-cleanup-444.patch | 45 | ||||
| -rw-r--r-- | gnome-remote-desktop.spec | 312 | ||||
| -rw-r--r-- | gnutls-anontls.patch | 1544 | ||||
| -rw-r--r-- | libvncserver-LibVNCServer-0.9.13-system-crypto-policy.patch | 15 | ||||
| -rw-r--r-- | sources | 2 | 
13 files changed, 2784 insertions, 0 deletions
@@ -0,0 +1,2 @@ +/LibVNCServer-0.9.13.tar.gz +/gnome-remote-desktop-40.0.tar.xz diff --git a/0001-build-Set-rpath-on-executable.patch b/0001-build-Set-rpath-on-executable.patch new file mode 100644 index 0000000..12fe9f6 --- /dev/null +++ b/0001-build-Set-rpath-on-executable.patch @@ -0,0 +1,50 @@ +From 1a6737f4a26c38f3c703d84263d0a0779a607359 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Wed, 21 Apr 2021 14:49:36 +0200 +Subject: [PATCH] build: Set rpath on executable + +--- + meson.build       | 1 + + src/meson.build   | 1 + + tests/meson.build | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/meson.build b/meson.build +index 9d7bda1..9148eb9 100644 +--- a/meson.build ++++ b/meson.build +@@ -75,6 +75,7 @@ top_srcdir = meson.current_source_dir() + builddir = meson.current_build_dir() +  + prefix = get_option('prefix') ++libdir = join_paths(prefix, get_option('libdir')) + libexecdir = join_paths(prefix, get_option('libexecdir')) + datadir = join_paths(prefix, get_option('datadir')) + schemadir = join_paths(datadir, 'glib-2.0', 'schemas') +diff --git a/src/meson.build b/src/meson.build +index 843746d..3757afb 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -100,6 +100,7 @@ executable('gnome-remote-desktop-daemon', +            daemon_sources, +            dependencies: deps, +            include_directories: [configinc], ++           install_rpath: join_paths(libdir, 'gnome-remote-desktop'), +            install: true, +            install_dir: libexecdir) +  +diff --git a/tests/meson.build b/tests/meson.build +index 978ae23..ab74a28 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -5,6 +5,7 @@ if have_vnc +     dependencies: [glib_dep, +     libvncclient_dep], +     include_directories: [configinc], ++    install_rpath: join_paths(libdir, 'gnome-remote-desktop'), +     install: false) +  +   test_runner = find_program('vnc-test-runner.sh') +--  +2.31.1 + diff --git a/0001-crypto-Don-t-compile-SHA1-support-when-Websockets-ar.patch b/0001-crypto-Don-t-compile-SHA1-support-when-Websockets-ar.patch new file mode 100644 index 0000000..fddcb8b --- /dev/null +++ b/0001-crypto-Don-t-compile-SHA1-support-when-Websockets-ar.patch @@ -0,0 +1,92 @@ +From fdc71dd25c8505b3580e70afd4b4213cad8f8ebb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Mon, 25 Oct 2021 16:14:26 +0200 +Subject: [PATCH] crypto: Don't compile SHA1 support when Websockets are + disabled + +SHA1 is not ideal, security wise. Let's make sure we don't even have it +compiled when nothing depends on it, e.g. Websockets. +--- + common/crypto.h           | 2 ++ + common/crypto_included.c  | 2 ++ + common/crypto_libgcrypt.c | 2 ++ + common/crypto_openssl.c   | 2 ++ + 4 files changed, 8 insertions(+) + +diff --git a/common/crypto.h b/common/crypto.h +index 04be9304..c1f32194 100644 +--- a/common/crypto.h ++++ b/common/crypto.h +@@ -11,7 +11,9 @@ + int hash_md5(void *out, const void *in, const size_t in_len); +  + /* Generates an SHA1 hash of 'in' and writes it to 'out', which must be 20 bytes in size. */ ++#ifdef LIBVNCSERVER_WITH_WEBSOCKETS + int hash_sha1(void *out, const void *in, const size_t in_len); ++#endif +  + /* Fill 'out' with 'len' random bytes. */ + void random_bytes(void *out, size_t len); +diff --git a/common/crypto_included.c b/common/crypto_included.c +index b359336f..cf8d43c2 100644 +--- a/common/crypto_included.c ++++ b/common/crypto_included.c +@@ -33,6 +33,7 @@ int hash_md5(void *out, const void *in, const size_t in_len) +     return 0; + } +  ++#ifdef LIBVNCSERVER_WITH_WEBSOCKETS + int hash_sha1(void *out, const void *in, const size_t in_len) + { +     SHA1Context sha1; +@@ -45,6 +46,7 @@ int hash_sha1(void *out, const void *in, const size_t in_len) +  +     return 1; + } ++#endif /* LIBVNCSERVER_WITH_WEBSOCKETS */ +  + void random_bytes(void *out, size_t len) + { +diff --git a/common/crypto_libgcrypt.c b/common/crypto_libgcrypt.c +index 34d845b4..f62bdaf8 100644 +--- a/common/crypto_libgcrypt.c ++++ b/common/crypto_libgcrypt.c +@@ -74,6 +74,7 @@ int hash_md5(void *out, const void *in, const size_t in_len) +     return result; + } +  ++#ifdef LIBVNCSERVER_WITH_WEBSOCKETS + int hash_sha1(void *out, const void *in, const size_t in_len) + { +     int result = 0; +@@ -98,6 +99,7 @@ int hash_sha1(void *out, const void *in, const size_t in_len) +     gcry_md_close(sha1); +     return result; + } ++#endif /* LIBVNCSERVER_WITH_WEBSOCKETS */ +  + void random_bytes(void *out, size_t len) + { +diff --git a/common/crypto_openssl.c b/common/crypto_openssl.c +index 60d4bd4d..9816eb04 100644 +--- a/common/crypto_openssl.c ++++ b/common/crypto_openssl.c +@@ -49,6 +49,7 @@ int hash_md5(void *out, const void *in, const size_t in_len) +     return 1; + } +  ++#ifdef LIBVNCSERVER_WITH_WEBSOCKETS + int hash_sha1(void *out, const void *in, const size_t in_len) + { +     SHA_CTX sha1; +@@ -60,6 +61,7 @@ int hash_sha1(void *out, const void *in, const size_t in_len) + 	return 0; +     return 1; + } ++#endif /* LIBVNCSERVER_WITH_WEBSOCKETS */ +  + void random_bytes(void *out, size_t len) + { +--  +2.31.1 + diff --git a/0001-libvncserver-Add-API-to-add-custom-I-O-entry-points.patch b/0001-libvncserver-Add-API-to-add-custom-I-O-entry-points.patch new file mode 100644 index 0000000..5d85b09 --- /dev/null +++ b/0001-libvncserver-Add-API-to-add-custom-I-O-entry-points.patch @@ -0,0 +1,241 @@ +From e4849b01fec4494057728d1aa3a165ed21705682 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Mon, 11 Jun 2018 23:47:02 +0200 +Subject: [PATCH 1/4] libvncserver: Add API to add custom I/O entry points + +Add API to make it possible to channel RFB input and output through +another layer, for example TLS. This is done by making it possible to +override the default read/write/peek functions. +--- + libvncserver/rfbserver.c |  4 ++ + libvncserver/sockets.c   | 79 ++++++++++++++++++++++++++++++++++++---- + rfb/rfb.h                | 17 +++++++++ + 3 files changed, 93 insertions(+), 7 deletions(-) + +diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c +index e9eaa5fc..72e9ba79 100644 +--- a/libvncserver/rfbserver.c ++++ b/libvncserver/rfbserver.c +@@ -319,6 +319,10 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen, +  +     cl->screen = rfbScreen; +     cl->sock = sock; ++    cl->readFromSocket = rfbDefaultReadFromSocket; ++    cl->peekAtSocket = rfbDefaultPeekAtSocket; ++    cl->hasPendingOnSocket = rfbDefaultHasPendingOnSocket; ++    cl->writeToSocket = rfbDefaultWriteToSocket; +     cl->viewOnly = FALSE; +     /* setup pseudo scaling */ +     cl->scaledScreen = rfbScreen; +diff --git a/libvncserver/sockets.c b/libvncserver/sockets.c +index 2c87376b..4bb881ec 100644 +--- a/libvncserver/sockets.c ++++ b/libvncserver/sockets.c +@@ -101,6 +101,9 @@ int deny_severity=LOG_WARNING; + int rfbMaxClientWait = 20000;   /* time (ms) after which we decide client has +                                    gone away - needed to stop us hanging */ +  ++static rfbBool ++rfbHasPendingOnSocket(rfbClientPtr cl); ++ + static rfbBool + rfbNewConnectionFromSock(rfbScreenInfoPtr rfbScreen, rfbSocket sock) + { +@@ -364,16 +367,20 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec) + 	tv.tv_usec = usec; + 	nfds = select(rfbScreen->maxFd + 1, &fds, NULL, NULL /* &fds */, &tv); + 	if (nfds == 0) { ++            rfbBool hasPendingData = FALSE; ++ + 	    /* timed out, check for async events */ +             i = rfbGetClientIterator(rfbScreen); +             while((cl = rfbClientIteratorNext(i))) { +                 if (cl->onHold) +                     continue; ++                hasPendingData |= rfbHasPendingOnSocket(cl); +                 if (FD_ISSET(cl->sock, &(rfbScreen->allFds))) +                     rfbSendFileTransferChunk(cl); +             } +             rfbReleaseClientIterator(i); +-	    return result; ++            if (!hasPendingData) ++                return result; + 	} +  + 	if (nfds < 0) { +@@ -449,9 +456,11 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec) + 	    if (cl->onHold) + 		continue; +  +-            if (FD_ISSET(cl->sock, &(rfbScreen->allFds))) ++            if (rfbHasPendingOnSocket (cl) || ++                FD_ISSET(cl->sock, &(rfbScreen->allFds))) +             { +-                if (FD_ISSET(cl->sock, &fds)) ++                if (rfbHasPendingOnSocket (cl) || ++                    FD_ISSET(cl->sock, &fds)) +                 { + #ifdef LIBVNCSERVER_WITH_WEBSOCKETS +                     do { +@@ -614,6 +623,30 @@ rfbConnect(rfbScreenInfoPtr rfbScreen, +     return sock; + } +  ++int ++rfbDefaultReadFromSocket(rfbClientPtr cl, char *buf, int len) ++{ ++    return read(cl->sock, buf, len); ++} ++ ++static int ++rfbReadFromSocket(rfbClientPtr cl, char *buf, int len) ++{ ++    return cl->readFromSocket(cl, buf, len); ++} ++ ++rfbBool ++rfbDefaultHasPendingOnSocket(rfbClientPtr cl) ++{ ++    return FALSE; ++} ++ ++static rfbBool ++rfbHasPendingOnSocket(rfbClientPtr cl) ++{ ++    return cl->hasPendingOnSocket(cl); ++} ++ + /* +  * ReadExact reads an exact number of bytes from a client.  Returns 1 if +  * those bytes have been read, 0 if the other end has closed, or -1 if an error +@@ -635,10 +668,10 @@ rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout) +         } else if (cl->sslctx) { + 	    n = rfbssl_read(cl, buf, len); + 	} else { +-            n = read(sock, buf, len); ++            n = rfbReadFromSocket(cl, buf, len); +         } + #else +-        n = read(sock, buf, len); ++        n = rfbReadFromSocket(cl, buf, len); + #endif +  +         if (n > 0) { +@@ -670,6 +703,10 @@ rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout) + 		    continue; + 	    } + #endif ++ ++            if (rfbHasPendingOnSocket(cl)) ++                continue; ++ +             FD_ZERO(&fds); +             FD_SET(sock, &fds); +             tv.tv_sec = timeout / 1000; +@@ -706,6 +743,18 @@ int rfbReadExact(rfbClientPtr cl,char* buf,int len) +     return(rfbReadExactTimeout(cl,buf,len,rfbMaxClientWait)); + } +  ++int ++rfbDefaultPeekAtSocket(rfbClientPtr cl, char *buf, int len) ++{ ++    return recv(cl->sock, buf, len, MSG_PEEK); ++} ++ ++int ++rfbPeekAtSocket(rfbClientPtr cl, char *buf, int len) ++{ ++    cl->peekAtSocket(cl, buf, len); ++} ++ + /* +  * PeekExact peeks at an exact number of bytes from a client.  Returns 1 if +  * those bytes have been read, 0 if the other end has closed, or -1 if an +@@ -726,7 +775,7 @@ rfbPeekExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout) + 	    n = rfbssl_peek(cl, buf, len); + 	else + #endif +-	    n = recv(sock, buf, len, MSG_PEEK); ++            n = rfbPeekAtSocket(cl, buf, len); +  +         if (n == len) { +  +@@ -782,6 +831,22 @@ rfbPeekExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout) +     return 1; + } +  ++int ++rfbDefaultWriteToSocket(rfbClientPtr cl, ++			const char *buf, ++			int len) ++{ ++    return write(cl->sock, buf, len); ++} ++ ++static int ++rfbWriteToSocket(rfbClientPtr cl, ++		 const char *buf, ++		 int len) ++{ ++    return cl->writeToSocket(cl, buf, len); ++} ++ + /* +  * WriteExact writes an exact number of bytes to a client.  Returns 1 if +  * those bytes have been written, or -1 if an error occurred (errno is set to +@@ -826,7 +891,7 @@ rfbWriteExact(rfbClientPtr cl, + 	    n = rfbssl_write(cl, buf, len); + 	else + #endif +-	    n = write(sock, buf, len); ++	    n = rfbWriteToSocket(cl, buf, len); +  +         if (n > 0) { +  +diff --git a/rfb/rfb.h b/rfb/rfb.h +index 5e9ba86f..3c0b25a3 100644 +--- a/rfb/rfb.h ++++ b/rfb/rfb.h +@@ -387,6 +387,14 @@ typedef struct sraRegion* sraRegionPtr; + typedef void (*ClientGoneHookPtr)(struct _rfbClientRec* cl); + typedef void (*ClientFramebufferUpdateRequestHookPtr)(struct _rfbClientRec* cl, rfbFramebufferUpdateRequestMsg* furMsg); +  ++typedef int (*ClientReadFromSocket)(struct _rfbClientRec* cl, ++                                    char *buf, int len); ++typedef int (*ClientPeekAtSocket)(struct _rfbClientRec* cl, ++                                  char *buf, int len); ++typedef rfbBool (*ClientHasPendingOnSocket)(struct _rfbClientRec* cl); ++typedef int (*ClientWriteToSocket)(struct _rfbClientRec* cl, ++                                   const char *buf, int len); ++ + typedef struct _rfbFileTransferData { +   int fd; +   int compressionEnabled; +@@ -680,6 +688,11 @@ typedef struct _rfbClientRec { +     rfbBool useExtDesktopSize; +     int requestedDesktopSizeChange; +     int lastDesktopSizeChangeError; ++ ++    ClientReadFromSocket readFromSocket;         /* Read data from socket */ ++    ClientPeekAtSocket peekAtSocket;             /* Peek at data from socket */ ++    ClientHasPendingOnSocket hasPendingOnSocket; /* Peek at data from socket */ ++    ClientWriteToSocket writeToSocket;           /* Write data to socket */ + } rfbClientRec, *rfbClientPtr; +  + /** +@@ -732,8 +745,12 @@ extern void rfbDisconnectUDPSock(rfbScreenInfoPtr rfbScreen); + extern void rfbCloseClient(rfbClientPtr cl); + extern int rfbReadExact(rfbClientPtr cl, char *buf, int len); + extern int rfbReadExactTimeout(rfbClientPtr cl, char *buf, int len,int timeout); ++extern int rfbDefaultReadFromSocket(rfbClientPtr cl, char *buf, int len); + extern int rfbPeekExactTimeout(rfbClientPtr cl, char *buf, int len,int timeout); ++extern int rfbDefaultPeekAtSocket(rfbClientPtr cl, char *buf, int len); ++extern rfbBool rfbDefaultHasPendingOnSocket(rfbClientPtr cl); + extern int rfbWriteExact(rfbClientPtr cl, const char *buf, int len); ++extern int rfbDefaultWriteToSocket(rfbClientPtr cl, const char *buf, int len); + extern int rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec); + extern rfbSocket rfbConnect(rfbScreenInfoPtr rfbScreen, char* host, int port); + extern rfbSocket rfbConnectToTcpAddr(char* host, int port); +--  +2.28.0 + diff --git a/0001-libvncserver-don-t-NULL-out-internal-of-the-default-.patch b/0001-libvncserver-don-t-NULL-out-internal-of-the-default-.patch new file mode 100644 index 0000000..11d0f7e --- /dev/null +++ b/0001-libvncserver-don-t-NULL-out-internal-of-the-default-.patch @@ -0,0 +1,28 @@ +From d138cf90130b0e8d5062f136ecdbcaa85e734d5d Mon Sep 17 00:00:00 2001 +From: Christian Beier <info@christianbeier.net> +Date: Mon, 20 Jul 2020 22:33:29 +0200 +Subject: [PATCH] libvncserver: don't NULL out internal of the default cursor + +...otherwise an rfbScreen created after rfbScreenCleanup() was called +gets assigned an invalid cursor struct. +--- + libvncserver/main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libvncserver/main.c b/libvncserver/main.c +index 9149fda3..a3a711e3 100644 +--- a/libvncserver/main.c ++++ b/libvncserver/main.c +@@ -1110,7 +1110,8 @@ void rfbScreenCleanup(rfbScreenInfoPtr screen) +   FREE_IF(underCursorBuffer); +   TINI_MUTEX(screen->cursorMutex); +  +-  rfbFreeCursor(screen->cursor); ++  if(screen->cursor != &myCursor) ++      rfbFreeCursor(screen->cursor); +  + #ifdef LIBVNCSERVER_HAVE_LIBZ +   rfbZlibCleanup(screen); +--  +2.28.0 + diff --git a/0001-pipewire-stream-Don-t-leak-GSource-s.patch b/0001-pipewire-stream-Don-t-leak-GSource-s.patch new file mode 100644 index 0000000..ee4840a --- /dev/null +++ b/0001-pipewire-stream-Don-t-leak-GSource-s.patch @@ -0,0 +1,53 @@ +From 2fba1c597f272516759933ee439e6fef3f6142f3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Tue, 6 Apr 2021 11:32:14 +0200 +Subject: [PATCH] pipewire-stream: Don't leak GSource's + +The pipewire loop is owned by the source, and failing to free it means +pipewire will keep file descriptors open indefinitely. + +While we properly "destroy":ed the source, destroying it only removes it +from the context, it doesn't destroy or unref it. To also free it, we +also need to unref it. +--- + src/grd-rdp-pipewire-stream.c | 6 +++++- + src/grd-vnc-pipewire-stream.c | 6 +++++- + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/src/grd-rdp-pipewire-stream.c b/src/grd-rdp-pipewire-stream.c +index 09015e7..6c79312 100644 +--- a/src/grd-rdp-pipewire-stream.c ++++ b/src/grd-rdp-pipewire-stream.c +@@ -577,7 +577,11 @@ grd_rdp_pipewire_stream_finalize (GObject *object) +  +   g_clear_pointer (&stream->pipewire_core, pw_core_disconnect); +   g_clear_pointer (&stream->pipewire_context, pw_context_destroy); +-  g_clear_pointer (&stream->pipewire_source, g_source_destroy); ++  if (stream->pipewire_source) ++    { ++      g_source_destroy (stream->pipewire_source); ++      g_clear_pointer (&stream->pipewire_source, g_source_unref); ++    } +  +   G_OBJECT_CLASS (grd_rdp_pipewire_stream_parent_class)->finalize (object); + } +diff --git a/src/grd-vnc-pipewire-stream.c b/src/grd-vnc-pipewire-stream.c +index 82ceb9b..5085062 100644 +--- a/src/grd-vnc-pipewire-stream.c ++++ b/src/grd-vnc-pipewire-stream.c +@@ -594,7 +594,11 @@ grd_vnc_pipewire_stream_finalize (GObject *object) +  +   g_clear_pointer (&stream->pipewire_core, pw_core_disconnect); +   g_clear_pointer (&stream->pipewire_context, pw_context_destroy); +-  g_clear_pointer (&stream->pipewire_source, g_source_destroy); ++  if (stream->pipewire_source) ++    { ++      g_source_destroy (stream->pipewire_source); ++      g_clear_pointer (&stream->pipewire_source, g_source_unref); ++    } +  +   G_OBJECT_CLASS (grd_vnc_pipewire_stream_parent_class)->finalize (object); + } +--  +2.31.1 + diff --git a/0002-libvncserver-Add-channel-security-handlers.patch b/0002-libvncserver-Add-channel-security-handlers.patch new file mode 100644 index 0000000..eb2aa9f --- /dev/null +++ b/0002-libvncserver-Add-channel-security-handlers.patch @@ -0,0 +1,368 @@ +From c9131a78878a785c3de21e9d49521d7b68400ad7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Mon, 11 Jun 2018 23:50:05 +0200 +Subject: [PATCH 2/4] libvncserver: Add channel security handlers + +Add another type of security handler that is meant to be used initially +to set up a secure channel. Regular security handlers would be +advertised and processed after any channel security have succeeded. + +For example, this, together with the custom I/O functions allows a +LibVNCServer user to implement TLS in combination with VNCAuth. This is +done by adding a single channel security handler with the rfbTLS (18) +with a handler that initiates a TLS session, and when a TLS session is +initiated, the regular security handler list is sent. +--- + libvncserver/auth.c      | 164 ++++++++++++++++++++++++++++++--------- + libvncserver/rfbserver.c |   1 + + rfb/rfb.h                |  15 +++- + 3 files changed, 142 insertions(+), 38 deletions(-) + +diff --git a/libvncserver/auth.c b/libvncserver/auth.c +index 814a8142..55e0b3c9 100644 +--- a/libvncserver/auth.c ++++ b/libvncserver/auth.c +@@ -37,18 +37,17 @@ void rfbClientSendString(rfbClientPtr cl, const char *reason); +  * Handle security types +  */ +  ++/* Channel security handlers to set up a secure channel, e.g. TLS. */ ++static rfbSecurityHandler* channelSecurityHandlers = NULL; ++ ++/* Security handlers when channel security is established. */ + static rfbSecurityHandler* securityHandlers = NULL; +  +-/* +- * This method registers a list of new security types.   +- * It avoids same security type getting registered multiple times.  +- * The order is not preserved if multiple security types are +- * registered at one-go. +- */ + void +-rfbRegisterSecurityHandler(rfbSecurityHandler* handler) ++rfbRegisterSecurityHandlerTo(rfbSecurityHandler* handler, ++                             rfbSecurityHandler** handlerList) + { +-	rfbSecurityHandler *head = securityHandlers, *next = NULL; ++	rfbSecurityHandler *head = *handlerList, *next = NULL; +  + 	if(handler == NULL) + 		return; +@@ -57,39 +56,35 @@ rfbRegisterSecurityHandler(rfbSecurityHandler* handler) +  + 	while(head != NULL) { + 		if(head == handler) { +-			rfbRegisterSecurityHandler(next); ++			rfbRegisterSecurityHandlerTo(next, handlerList); + 			return; + 		} +  + 		head = head->next; + 	} +  +-	handler->next = securityHandlers; +-	securityHandlers = handler; ++	handler->next = *handlerList; ++	*handlerList = handler; +  +-	rfbRegisterSecurityHandler(next); ++	rfbRegisterSecurityHandlerTo(next, handlerList); + } +  +-/* +- * This method unregisters a list of security types.  +- * These security types won't be available for any new +- * client connection.  +- */ +-void +-rfbUnregisterSecurityHandler(rfbSecurityHandler* handler) ++static void ++rfbUnregisterSecurityHandlerFrom(rfbSecurityHandler* handler, ++                                 rfbSecurityHandler** handlerList) + { + 	rfbSecurityHandler *cur = NULL, *pre = NULL; +  + 	if(handler == NULL) + 		return; +  +-	if(securityHandlers == handler) { +-		securityHandlers = securityHandlers->next; +-		rfbUnregisterSecurityHandler(handler->next); ++	if(*handlerList == handler) { ++		*handlerList = (*handlerList)->next; ++		rfbUnregisterSecurityHandlerFrom(handler->next, handlerList); + 		return; + 	} +  +-	cur = pre = securityHandlers; ++	cur = pre = *handlerList; +  + 	while(cur) { + 		if(cur == handler) { +@@ -99,7 +94,50 @@ rfbUnregisterSecurityHandler(rfbSecurityHandler* handler) + 		pre = cur; + 		cur = cur->next; + 	} +-	rfbUnregisterSecurityHandler(handler->next); ++	rfbUnregisterSecurityHandlerFrom(handler->next, handlerList); ++} ++ ++void ++rfbRegisterChannelSecurityHandler(rfbSecurityHandler* handler) ++{ ++    rfbRegisterSecurityHandlerTo(handler, &channelSecurityHandlers); ++} ++ ++/* ++ * This method unregisters a list of security types. ++ * These security types won't be available for any new ++ * client connection. ++ */ ++ ++void ++rfbUnregisterChannelSecurityHandler(rfbSecurityHandler* handler) ++{ ++    rfbUnregisterSecurityHandlerFrom(handler, &channelSecurityHandlers); ++} ++ ++/* ++ * This method registers a list of new security types. ++ * It avoids same security type getting registered multiple times. ++ * The order is not preserved if multiple security types are ++ * registered at one-go. ++ */ ++ ++void ++rfbRegisterSecurityHandler(rfbSecurityHandler* handler) ++{ ++    rfbRegisterSecurityHandlerTo(handler, &securityHandlers); ++} ++ ++/* ++ * This method unregisters a list of security types. ++ * These security types won't be available for any new ++ * client connection. ++ */ ++ ++void ++rfbUnregisterSecurityHandler(rfbSecurityHandler* handler) ++{ ++    rfbUnregisterSecurityHandlerFrom(handler, &securityHandlers); + } +  + /* +@@ -197,9 +235,22 @@ static rfbSecurityHandler VncSecurityHandlerNone = { +     NULL + }; +                          ++static int32_t ++determinePrimarySecurityType(rfbClientPtr cl) ++{ ++    if (!cl->screen->authPasswdData || cl->reverseConnection) { ++        /* chk if this condition is valid or not. */ ++        return rfbSecTypeNone; ++    } else if (cl->screen->authPasswdData) { ++        return rfbSecTypeVncAuth; ++    } else { ++        return rfbSecTypeInvalid; ++    } ++} +  +-static void +-rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType) ++void ++rfbSendSecurityTypeList(rfbClientPtr cl, ++                        enum rfbSecurityTag exclude) + { +     /* The size of the message is the count of security types +1, +      * since the first byte is the number of types. */ +@@ -207,9 +258,10 @@ rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType) +     rfbSecurityHandler* handler; + #define MAX_SECURITY_TYPES 255 +     uint8_t buffer[MAX_SECURITY_TYPES+1]; +- ++    int32_t primaryType; +  +     /* Fill in the list of security types in the client structure. (NOTE: Not really in the client structure) */ ++    primaryType = determinePrimarySecurityType(cl); +     switch (primaryType) { +     case rfbSecTypeNone: +         rfbRegisterSecurityHandler(&VncSecurityHandlerNone); +@@ -221,6 +273,9 @@ rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType) +  +     for (handler = securityHandlers; + 	    handler && size<MAX_SECURITY_TYPES; handler = handler->next) { ++	if (exclude && (handler->securityTags & exclude)) ++	    continue; ++ + 	buffer[size] = handler->type; + 	size++; +     } +@@ -249,7 +304,29 @@ rfbSendSecurityTypeList(rfbClientPtr cl, int primaryType) +     cl->state = RFB_SECURITY_TYPE; + } +  ++static void ++rfbSendChannelSecurityTypeList(rfbClientPtr cl) ++{ ++    int size = 1; ++    rfbSecurityHandler* handler; ++    uint8_t buffer[MAX_SECURITY_TYPES+1]; ++ ++    for (handler = channelSecurityHandlers; ++	    handler && size<MAX_SECURITY_TYPES; handler = handler->next) { ++	buffer[size] = handler->type; ++	size++; ++    } ++    buffer[0] = (unsigned char)size-1; ++ ++    if (rfbWriteExact(cl, (char *)buffer, size) < 0) { ++	rfbLogPerror("rfbSendSecurityTypeList: write"); ++	rfbCloseClient(cl); ++	return; ++    } +  ++    /* Dispatch client input to rfbProcessClientChannelSecurityType. */ ++    cl->state = RFB_CHANNEL_SECURITY_TYPE; ++} +  +  + /* +@@ -297,18 +374,19 @@ rfbSendSecurityType(rfbClientPtr cl, int32_t securityType) + void + rfbAuthNewClient(rfbClientPtr cl) + { +-    int32_t securityType = rfbSecTypeInvalid; ++    int32_t securityType; +  +-    if (!cl->screen->authPasswdData || cl->reverseConnection) { +-	/* chk if this condition is valid or not. */ +-	securityType = rfbSecTypeNone; +-    } else if (cl->screen->authPasswdData) { +- 	    securityType = rfbSecTypeVncAuth; +-    } ++    securityType = determinePrimarySecurityType(cl); +  +     if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion < 7) +     { + 	/* Make sure we use only RFB 3.3 compatible security types. */ ++	if (channelSecurityHandlers) { ++	    rfbLog("VNC channel security enabled - RFB 3.3 client rejected\n"); ++	    rfbClientConnFailed(cl, "Your viewer cannot hnadler required " ++				"security methods"); ++	    return; ++	} + 	if (securityType == rfbSecTypeInvalid) { + 	    rfbLog("VNC authentication disabled - RFB 3.3 client rejected\n"); + 	    rfbClientConnFailed(cl, "Your viewer cannot handle required " +@@ -316,9 +394,13 @@ rfbAuthNewClient(rfbClientPtr cl) + 	    return; + 	} + 	rfbSendSecurityType(cl, securityType); ++    } else if (channelSecurityHandlers) { ++	rfbLog("Send channel security type list\n"); ++	rfbSendChannelSecurityTypeList(cl); +     } else { + 	/* Here it's ok when securityType is set to rfbSecTypeInvalid. */ +-	rfbSendSecurityTypeList(cl, securityType); ++	rfbLog("Send channel security type 'none'\n"); ++	rfbSendSecurityTypeList(cl, RFB_SECURITY_TAG_NONE); +     } + } +  +@@ -332,6 +414,7 @@ rfbProcessClientSecurityType(rfbClientPtr cl) +     int n; +     uint8_t chosenType; +     rfbSecurityHandler* handler; ++    rfbSecurityHandler* handlerListHead; +      +     /* Read the security type. */ +     n = rfbReadExact(cl, (char *)&chosenType, 1); +@@ -344,8 +427,17 @@ rfbProcessClientSecurityType(rfbClientPtr cl) + 	return; +     } +  ++    switch (cl->state) { ++    case RFB_CHANNEL_SECURITY_TYPE: ++        handlerListHead = channelSecurityHandlers; ++        break; ++    case RFB_SECURITY_TYPE: ++        handlerListHead = securityHandlers; ++        break; ++    } ++ +     /* Make sure it was present in the list sent by the server. */ +-    for (handler = securityHandlers; handler; handler = handler->next) { ++    for (handler = handlerListHead; handler; handler = handler->next) { + 	if (chosenType == handler->type) { + 	      rfbLog("rfbProcessClientSecurityType: executing handler for type %d\n", chosenType); + 	      handler->handler(cl); +diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c +index 72e9ba79..48eada64 100644 +--- a/libvncserver/rfbserver.c ++++ b/libvncserver/rfbserver.c +@@ -652,6 +652,7 @@ rfbProcessClientMessage(rfbClientPtr cl) +     case RFB_PROTOCOL_VERSION: +         rfbProcessClientProtocolVersion(cl); +         return; ++    case RFB_CHANNEL_SECURITY_TYPE: +     case RFB_SECURITY_TYPE: +         rfbProcessClientSecurityType(cl); +         return; +diff --git a/rfb/rfb.h b/rfb/rfb.h +index 3c0b25a3..d136f884 100644 +--- a/rfb/rfb.h ++++ b/rfb/rfb.h +@@ -144,6 +144,11 @@ typedef struct { +   } data; /**< there have to be count*3 entries */ + } rfbColourMap; +  ++enum rfbSecurityTag { ++    RFB_SECURITY_TAG_NONE = 0, ++    RFB_SECURITY_TAG_CHANNEL = 1 << 0 ++}; ++ + /** +  * Security handling (RFB protocol version 3.7) +  */ +@@ -152,6 +157,7 @@ typedef struct _rfbSecurity { + 	uint8_t type; + 	void (*handler)(struct _rfbClientRec* cl); + 	struct _rfbSecurity* next; ++	enum rfbSecurityTag securityTags; + } rfbSecurityHandler; +  + /** +@@ -480,7 +486,7 @@ typedef struct _rfbClientRec { +                                 /** Possible client states: */ +     enum { +         RFB_PROTOCOL_VERSION,   /**< establishing protocol version */ +-	RFB_SECURITY_TYPE,      /**< negotiating security (RFB v.3.7) */ ++        RFB_SECURITY_TYPE,      /**< negotiating security (RFB v.3.7) */ +         RFB_AUTHENTICATION,     /**< authenticating */ +         RFB_INITIALISATION,     /**< sending initialisation messages */ +         RFB_NORMAL,             /**< normal protocol messages */ +@@ -488,7 +494,9 @@ typedef struct _rfbClientRec { +         /* Ephemeral internal-use states that will never be seen by software +          * using LibVNCServer to provide services: */ +  +-        RFB_INITIALISATION_SHARED /**< sending initialisation messages with implicit shared-flag already true */ ++        RFB_INITIALISATION_SHARED, /**< sending initialisation messages with implicit shared-flag already true */ ++ ++        RFB_CHANNEL_SECURITY_TYPE, /**< negotiating security (RFB v.3.7) */ +     } state; +  +     rfbBool reverseConnection; +@@ -840,6 +848,9 @@ extern void rfbProcessClientSecurityType(rfbClientPtr cl); + extern void rfbAuthProcessClientMessage(rfbClientPtr cl); + extern void rfbRegisterSecurityHandler(rfbSecurityHandler* handler); + extern void rfbUnregisterSecurityHandler(rfbSecurityHandler* handler); ++extern void rfbRegisterChannelSecurityHandler(rfbSecurityHandler* handler); ++extern void rfbUnregisterChannelSecurityHandler(rfbSecurityHandler* handler); ++extern void rfbSendSecurityTypeList(rfbClientPtr cl, enum rfbSecurityTag exclude); +  + /* rre.c */ +  +--  +2.28.0 + diff --git a/0003-libvncserver-auth-don-t-keep-security-handlers-from-.patch b/0003-libvncserver-auth-don-t-keep-security-handlers-from-.patch new file mode 100644 index 0000000..2f736d0 --- /dev/null +++ b/0003-libvncserver-auth-don-t-keep-security-handlers-from-.patch @@ -0,0 +1,32 @@ +From 2a77dd86a97fa5f4735f678599cea839ba09009c Mon Sep 17 00:00:00 2001 +From: Christian Beier <info@christianbeier.net> +Date: Sun, 9 Aug 2020 20:11:26 +0200 +Subject: [PATCH 3/4] libvncserver/auth: don't keep security handlers from + previous runs + +Whyohsoever security handlers are stored in a variable global to the +application, not in the rfbScreen struct. This meant that security +handlers registered once would stick around forever before this commit. +--- + libvncserver/auth.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libvncserver/auth.c b/libvncserver/auth.c +index 55e0b3c9..fc74c800 100644 +--- a/libvncserver/auth.c ++++ b/libvncserver/auth.c +@@ -264,9 +264,11 @@ rfbSendSecurityTypeList(rfbClientPtr cl, +     primaryType = determinePrimarySecurityType(cl); +     switch (primaryType) { +     case rfbSecTypeNone: ++	rfbUnregisterSecurityHandler(&VncSecurityHandlerVncAuth); +         rfbRegisterSecurityHandler(&VncSecurityHandlerNone); +         break; +     case rfbSecTypeVncAuth: ++	rfbUnregisterSecurityHandler(&VncSecurityHandlerNone); +         rfbRegisterSecurityHandler(&VncSecurityHandlerVncAuth); +         break; +     } +--  +2.28.0 + diff --git a/0004-zlib-Clear-buffer-pointers-on-cleanup-444.patch b/0004-zlib-Clear-buffer-pointers-on-cleanup-444.patch new file mode 100644 index 0000000..d45dfeb --- /dev/null +++ b/0004-zlib-Clear-buffer-pointers-on-cleanup-444.patch @@ -0,0 +1,45 @@ +From 641610b961a732bb68f111536ebf8c42be20f05b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Wed, 16 Sep 2020 17:35:49 +0200 +Subject: [PATCH 4/4] zlib: Clear buffer pointers on cleanup (#444) + +The pointers to the buffers were freed, and the size fields were set to +0, but the buffer pointers themsef was not set to NULL, when shutting +down, meaning the next time used, NULL checks would not tell whether the +pointer is valid. This caused crashes ending with + +  #0  0x00007ffff73729e5 in raise () from /lib64/libc.so.6 +  #1  0x00007ffff735b895 in abort () from /lib64/libc.so.6 +  #2  0x00007ffff73b6857 in __libc_message () from /lib64/libc.so.6 +  #3  0x00007ffff73bdd7c in malloc_printerr () from /lib64/libc.so.6 +  #4  0x00007ffff73c2f1a in realloc () from /lib64/libc.so.6 +  #5  0x00007ffff78b558e in rfbSendOneRectEncodingZlib (cl=0x4a4b80, x=0, y=0, w=800, h=40) at /home/jonas/Dev/gnome/libvncserver/libvncserver/zlib.c:106 +  #6  0x00007ffff78b5dec in rfbSendRectEncodingZlib (cl=0x4a4b80, x=0, y=0, w=800, h=600) at /home/jonas/Dev/gnome/libvncserver/libvncserver/zlib.c:308 +  #7  0x00007ffff7899453 in rfbSendFramebufferUpdate (cl=0x4a4b80, givenUpdateRegion=0x49ef70) at /home/jonas/Dev/gnome/libvncserver/libvncserver/rfbserver.c:3264 +  #8  0x00007ffff789079d in rfbUpdateClient (cl=0x4a4b80) at /home/jonas/Dev/gnome/libvncserver/libvncserver/main.c:1275 +  #9  0x00007ffff78905f5 in rfbProcessEvents (screen=0x4d5790, usec=0) at /home/jonas/Dev/gnome/libvncserver/libvncserver/main.c:1251 +--- + libvncserver/zlib.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libvncserver/zlib.c b/libvncserver/zlib.c +index d24d7d15..5c3a8236 100644 +--- a/libvncserver/zlib.c ++++ b/libvncserver/zlib.c +@@ -64,11 +64,13 @@ void rfbZlibCleanup(rfbScreenInfoPtr screen) + { +   if (zlibBeforeBufSize) { +     free(zlibBeforeBuf); ++    zlibBeforeBuf = NULL; +     zlibBeforeBufSize=0; +   } +   if (zlibAfterBufSize) { +     zlibAfterBufSize=0; +     free(zlibAfterBuf); ++    zlibAfterBuf = NULL; +   } + } +  +--  +2.28.0 + diff --git a/gnome-remote-desktop.spec b/gnome-remote-desktop.spec new file mode 100644 index 0000000..2913277 --- /dev/null +++ b/gnome-remote-desktop.spec @@ -0,0 +1,312 @@ +%global systemd_unit gnome-remote-desktop.service + +%global tarball_version %%(echo %{version} | tr '~' '.') + +%if 0%{?rhel} >= 9 +%global bundle_libvncserver 1 +%global enable_rdp 0 +%else +%global bundle_libvncserver 0 +%global enable_rdp 1 +%endif + +%global libvncserver_name LibVNCServer +%global libvncserver_version 0.9.13 + +Name:           gnome-remote-desktop +Version:        40.0 +Release:        7%{?dist} +Summary:        GNOME Remote Desktop screen share service + +License:        GPLv2+ +URL:            https://gitlab.gnome.org/jadahl/gnome-remote-desktop +Source0:        https://download.gnome.org/sources/gnome-remote-desktop/40/%{name}-%{tarball_version}.tar.xz +Source1:        https://github.com/LibVNC/libvncserver/archive/refs/tags/%{libvncserver_name}-%{libvncserver_version}.tar.gz + +### gnome-remote-desktop patches +# Adds encryption support (requires patched LibVNCServer) +Patch0:         gnutls-anontls.patch + +# Backport upstream leak fix (rhbz#1951129) +Patch1:         0001-pipewire-stream-Don-t-leak-GSource-s.patch + +## LibVNCServer patches required for bundling +Patch100:       0001-build-Set-rpath-on-executable.patch + +### LibVNCServer patches +## TLS security type enablement patches +# https://github.com/LibVNC/libvncserver/pull/234 +Patch1000: 0001-libvncserver-Add-API-to-add-custom-I-O-entry-points.patch +Patch1001: 0002-libvncserver-Add-channel-security-handlers.patch +# https://github.com/LibVNC/libvncserver/commit/87c52ee0551b7c4e76855d270d475b9e3039fe08 +Patch1002: 0003-libvncserver-auth-don-t-keep-security-handlers-from-.patch +# Fix crash on all runs after the first +# https://github.com/LibVNC/libvncserver/pull/444 +# https://bugzilla.redhat.com/show_bug.cgi?id=1882718 +Patch1003: 0004-zlib-Clear-buffer-pointers-on-cleanup-444.patch +# Fix another crasher +# https://gitlab.gnome.org/GNOME/gnome-remote-desktop/-/issues/45 +# https://bugzilla.redhat.com/show_bug.cgi?id=1882718 +Patch1004: 0001-libvncserver-don-t-NULL-out-internal-of-the-default-.patch + +## downstream patches +Patch2000: libvncserver-LibVNCServer-0.9.13-system-crypto-policy.patch + +## Don't compile SHA1 support +Patch2100: 0001-crypto-Don-t-compile-SHA1-support-when-Websockets-ar.patch + + +BuildRequires:  git +BuildRequires:  gcc +BuildRequires:  meson >= 0.36.0 +BuildRequires:  pkgconfig +BuildRequires:  pkgconfig(cairo) +BuildRequires:  pkgconfig(glib-2.0) >= 2.32 +BuildRequires:  pkgconfig(gio-unix-2.0) >= 2.32 +BuildRequires:  pkgconfig(libpipewire-0.3) >= 0.3.0 +%if 0%{?enable_rdp} +BuildRequires:  pkgconfig(freerdp2) +BuildRequires:  pkgconfig(winpr2) +BuildRequires:  pkgconfig(fuse3) +%endif +BuildRequires:  pkgconfig(xkbcommon) +BuildRequires:  pkgconfig(libsecret-1) +BuildRequires:  pkgconfig(libnotify) +BuildRequires:  pkgconfig(gnutls) +%if 0%{?bundle_libvncserver} +BuildRequires:  cmake +BuildRequires:  lzo-devel +BuildRequires:  lzo-minilzo +%else +BuildRequires:  pkgconfig(libvncserver) >= 0.9.11-7 +%endif + +%{?systemd_requires} +BuildRequires:  systemd + +Requires:       pipewire >= 0.3.0 + +Obsoletes:      vino < 3.22.0-21 +%if 0%{?bundle_libvncserver} +Provides:       bundled(libvncserver) = %{libvncserver_version} +%endif + +%description +GNOME Remote Desktop is a remote desktop and screen sharing service for the +GNOME desktop environment. + + +%prep + +## Setup libvncserver + +%if 0%{?bundle_libvncserver} +%setup -b 1 -n libvncserver-%{libvncserver_name}-%{libvncserver_version} +%patch1000 -p1 -b .tls-1 +%patch1001 -p1 -b .tls-2 +%patch1002 -p1 -b .handlers +%patch1003 -p1 -b .pointers +%patch1004 -p1 -b .cursor_null +%patch2000 -p1 -b .crypto_policy + +# Nuke bundled minilzo +rm -fv common/lzodefs.h common/lzoconf.h commmon/minilzo.h common/minilzo.c + +# Fix encoding +for file in ChangeLog ; do +    mv ${file} ${file}.OLD && \ +    iconv -f ISO_8859-1 -t UTF8 ${file}.OLD > ${file} && \ +    touch --reference ${file}.OLD $file +done +%endif + +## Setup gnome-remote-desktop + +%setup -n %{name}-%{tarball_version} +%patch0 -p1 +%patch1 -p1 +%if 0%{?bundle_libvncserver} +%patch100 -p1 +%endif + + +%build + +## Build libvncserver + +%if 0%{?bundle_libvncserver} +pushd ../libvncserver-%{libvncserver_name}-%{libvncserver_version} +mkdir -p %{_builddir}/libvncserver/ +%global libvncserver_install_dir %{buildroot}%{_builddir}/libvncserver +%cmake \ +  -DCMAKE_INSTALL_PREFIX=%{libvncserver_install_dir} \ +  -DINCLUDE_INSTALL_DIR=%{libvncserver_install_dir}/include \ +  -DLIB_INSTALL_DIR:PATH=%{libvncserver_install_dir}/%{_lib} \ +  -DSYSCONF_INSTALL_DIR=%{libvncserver_install_dir}/etc \ +  -DWITH_FFMPEG=OFF -DWITH_GTK=OFF -DWITH_OPENSSL=OFF -DWITH_GNUTLS=ON \ +  -DWITH_SDL=OFF -DWITH_X11=OFF -DWITH_WEBSOCKETS=OFF \ +  -DLIBVNCSERVER_WITH_WEBSOCKETS=OFF +%cmake_build +%__cmake --install "%{__cmake_builddir}" +popd +%endif + +## Build gnome-remote-desktop + +%if 0%{?bundle_libvncserver} +%global pkg_config_path_override --pkg-config-path %{buildroot}/%{_builddir}/libvncserver/%{_lib}/pkgconfig +%endif + +%if 0%{?enable_rdp} +%global rdp_configuration -Drdp=true +%else +%global rdp_configuration -Drdp=false +%endif + +%meson %{?pkg_config_path_override} %{rdp_configuration} +%meson_build + + +%install +%meson_install + +%if 0%{?bundle_libvncserver} +pushd ../libvncserver-%{libvncserver_name}-%{libvncserver_version} +mkdir -p %{buildroot}/%{_libdir}/gnome-remote-desktop/ +cp %{__cmake_builddir}/libvncserver.so.1 %{buildroot}/%{_libdir}/gnome-remote-desktop/ +cp COPYING %{_builddir}/%{name}-%{tarball_version}/COPYING.libvncserver +popd +%endif + + +%post +%systemd_user_post %{systemd_unit} + + +%preun +%systemd_user_preun %{systemd_unit} + + +%postun +%systemd_user_postun_with_restart %{systemd_unit} + + +%files +%license COPYING +%if 0%{?bundle_libvncserver} +%license COPYING.libvncserver +%endif +%doc README +%{_libexecdir}/gnome-remote-desktop-daemon +%if 0%{?bundle_libvncserver} +%{_libdir}/gnome-remote-desktop/libvncserver.so.1 +%endif +%{_userunitdir}/gnome-remote-desktop.service +%{_datadir}/glib-2.0/schemas/org.gnome.desktop.remote-desktop.gschema.xml +%{_datadir}/glib-2.0/schemas/org.gnome.desktop.remote-desktop.enums.xml + + +%changelog +* Mon Oct 25 2021 Jonas Ã…dahl <jadahl@redhat.com> - 40.0-7 +- Don't compile in SHA1 support +  Resolves: #1936594 + +* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 40.0-6 +- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags +  Related: rhbz#1991688 + +* Tue Jun 15 2021 Jonas Ã…dahl <jadahl@redhat.com> - 40.0-5 +- Backport leak fix +  Resolves: #1951129 + +* Mon May 17 2021 Ondrej Holy <oholy@redhat.com> - 40.0-4 +- Rebuild for updated FreeRDP (#1951123). + +* Thu Apr 22 2021 Jonas Ã…dahl <jadahl@redhat.com> - 40.0-3 +- Bundle libvncserver +- Disable RDP support + +* Thu Apr 15 2021 Mohan Boddu <mboddu@redhat.com> - 40.0-2 +- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 + +* Mon Mar 22 2021 Kalev Lember <klember@redhat.com> - 40.0-1 +- Update to 40.0 + +* Thu Mar 18 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 40.0~rc-2 +- Add Obsoletes: vino + +* Mon Mar 15 2021 Kalev Lember <klember@redhat.com> - 40.0~rc-1 +- Update to 40.rc + +* Thu Mar 04 2021 Jonas Ã…dahl <jadahl@redhat.com> - 40.0~beta-1 +- Bump to 40.beta + +* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 0.1.9-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Mon Sep 14 2020 Jonas Ã…dahl <jadahl@redhat.com> - 0.1.9-2 +- Copy using the right destination stride + +* Mon Sep 14 2020 Jonas Ã…dahl <jadahl@redhat.com> - 0.1.9-1 +- Update to 0.1.9 +- Backport race condition crash fix +- Rebase anon-tls patches + +* Thu Aug 27 2020 Ray Strode <rstrode@redhat.com> - 0.1.8-3 +- Fix crash +  Related: #1844993 + +* Mon Jun 1 2020 Felipe Borges <feborges@redhat.com> - 0.1.8-2 +- Fix black screen issue in remote connections on Wayland + +* Wed Mar 11 2020 Jonas Ã…dahl <jadahl@redhat.com> - 0.1.8-1 +- Update to 0.1.8 + +* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 0.1.7-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.1.7-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Mon Mar 4 2019 Jonas Ã…dahl <jadahl@redhat.com> - 0.1.7-1 +- Update to 0.1.7 + +* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.1.6-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Tue Oct 2 2018 Jonas Ã…dahl <jadahl@redhat.com> - 0.1.6-2 +- Don't crash when PipeWire disconnects (rhbz#1632781) + +* Tue Aug 7 2018 Jonas Ã…dahl <jadahl@redhat.com> - 0.1.6 +- Update to 0.1.6 +- Apply ANON-TLS patch +- Depend on pipewire 0.2.2 + +* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.1.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Wed May 30 2018 Jonas Ã…dahl <jadahl@redhat.com> - 0.1.4-1 +- Update to new version + +* Fri Feb 09 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 0.1.2-5 +- Escape macros in %%changelog + +* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.1.2-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Tue Aug 29 2017 Jonas Ã…dahl <jadahl@redhat.com> - 0.1.2-3 +- Use %%autosetup +- Install licence file + +* Tue Aug 22 2017 Jonas Ã…dahl <jadahl@redhat.com> - 0.1.2-2 +- Remove gschema compilation step as that had been deprecated + +* Mon Aug 21 2017 Jonas Ã…dahl <jadahl@redhat.com> - 0.1.2-1 +- Update to 0.1.2 +- Changed tabs to spaces +- Added systemd user macros +- Install to correct systemd user unit directory +- Compile gsettings schemas after install and uninstall + +* Mon Aug 21 2017 Jonas Ã…dahl <jadahl@redhat.com> - 0.1.1-1 +- First packaged version diff --git a/gnutls-anontls.patch b/gnutls-anontls.patch new file mode 100644 index 0000000..bd05eac --- /dev/null +++ b/gnutls-anontls.patch @@ -0,0 +1,1544 @@ +From 8676ef6c32557234d08acb13d7524df5fa1f4bb2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Thu, 14 Jun 2018 12:21:37 +0200 +Subject: [PATCH 1/7] vnc: Add anonymous TLS encryption support + +Add support for encrypting the VNC connection using anonymous TLS. In +effect this means that the channel is encrypted using TLS but that no +authentication of the peers are done. This means the connection is still +vulnerable to man-in-the-middle attacks where an attacker proxies the +VNC connection. +--- + meson.build                                   |   1 + + src/grd-enums.h                               |   6 + + src/grd-session-vnc.c                         | 120 ++++- + src/grd-session-vnc.h                         |  17 + + src/grd-settings.c                            |  28 ++ + src/grd-settings.h                            |   2 + + src/grd-vnc-server.c                          |  45 ++ + src/grd-vnc-tls.c                             | 444 ++++++++++++++++++ + src/grd-vnc-tls.h                             |  28 ++ + src/meson.build                               |   3 + + ...nome.desktop.remote-desktop.gschema.xml.in |  10 + + 11 files changed, 678 insertions(+), 26 deletions(-) + create mode 100644 src/grd-vnc-tls.c + create mode 100644 src/grd-vnc-tls.h + +diff --git a/meson.build b/meson.build +index 5e9ad04..9bbd5fc 100644 +--- a/meson.build ++++ b/meson.build +@@ -40,6 +40,7 @@ endif + if have_vnc +   libvncserver_dep = dependency('libvncserver') +   libvncclient_dep = dependency('libvncclient') ++  gnutls_dep = dependency('gnutls') + endif +  + cdata = configuration_data() +diff --git a/src/grd-enums.h b/src/grd-enums.h +index ffab821..4333863 100644 +--- a/src/grd-enums.h ++++ b/src/grd-enums.h +@@ -27,4 +27,10 @@ typedef enum +   GRD_VNC_AUTH_METHOD_PASSWORD + } GrdVncAuthMethod; +  ++typedef enum ++{ ++  GRD_VNC_ENCRYPTION_NONE = 1 << 0, ++  GRD_VNC_ENCRYPTION_TLS_ANON = 1 << 1, ++} GrdVncEncryption; ++ + #endif /* GRD_ENUMS_H */ +diff --git a/src/grd-session-vnc.c b/src/grd-session-vnc.c +index 0e520dc..0c189fd 100644 +--- a/src/grd-session-vnc.c ++++ b/src/grd-session-vnc.c +@@ -45,7 +45,9 @@ struct _GrdSessionVnc + { +   GrdSession parent; +  ++  GrdVncServer *vnc_server; +   GSocketConnection *connection; ++  GList *socket_grabs; +   GSource *source; +   rfbScreenInfoPtr rfb_screen; +   rfbClientPtr rfb_client; +@@ -540,6 +542,12 @@ check_rfb_password (rfbClientPtr  rfb_client, +     } + } +  ++int ++grd_session_vnc_get_fd (GrdSessionVnc *session_vnc) ++{ ++  return session_vnc->rfb_screen->inetdSock; ++} ++ + int + grd_session_vnc_get_stride_for_width (GrdSessionVnc *session_vnc, +                                       int            width) +@@ -547,6 +555,18 @@ grd_session_vnc_get_stride_for_width (GrdSessionVnc *session_vnc, +   return width * BGRX_BYTES_PER_PIXEL; + } +  ++rfbClientPtr ++grd_session_vnc_get_rfb_client (GrdSessionVnc *session_vnc) ++{ ++  return session_vnc->rfb_client; ++} ++ ++GrdVncServer * ++grd_session_vnc_get_vnc_server (GrdSessionVnc *session_vnc) ++{ ++  return session_vnc->vnc_server; ++} ++ + static void + init_vnc_session (GrdSessionVnc *session_vnc) + { +@@ -590,44 +610,85 @@ init_vnc_session (GrdSessionVnc *session_vnc) +   rfbProcessEvents (rfb_screen, 0); + } +  ++void ++grd_session_vnc_grab_socket (GrdSessionVnc        *session_vnc, ++                             GrdVncSocketGrabFunc  grab_func) ++{ ++  session_vnc->socket_grabs = g_list_prepend (session_vnc->socket_grabs, ++                                              grab_func); ++} ++ ++void ++grd_session_vnc_ungrab_socket (GrdSessionVnc        *session_vnc, ++                               GrdVncSocketGrabFunc  grab_func) ++{ ++  session_vnc->socket_grabs = g_list_remove (session_vnc->socket_grabs, ++                                             grab_func); ++} ++ ++static gboolean ++vnc_socket_grab_func (GrdSessionVnc  *session_vnc, ++                      GError        **error) ++{ ++  if (rfbIsActive (session_vnc->rfb_screen)) ++    { ++      rfbProcessEvents (session_vnc->rfb_screen, 0); ++ ++      if (session_vnc->pending_framebuffer_resize && ++          session_vnc->rfb_client->preferredEncoding != -1) ++        { ++          resize_vnc_framebuffer (session_vnc, ++                                  session_vnc->pending_framebuffer_width, ++                                  session_vnc->pending_framebuffer_height); ++          session_vnc->pending_framebuffer_resize = FALSE; ++ ++          /** ++           * This is a workaround. libvncserver is unable to handle clipboard ++           * changes early and either disconnects the client or crashes g-r-d ++           * if it receives rfbSendServerCutText too early altough the ++           * authentification process is already done. ++           * Doing this after resizing the framebuffer, seems to work fine, ++           * so enable the clipboard here and not when the remote desktop ++           * session proxy is acquired. ++           */ ++          grd_clipboard_vnc_maybe_enable_clipboard (session_vnc->clipboard_vnc); ++        } ++    } ++ ++  return TRUE; ++} ++ + static gboolean + handle_socket_data (GSocket *socket, +                     GIOCondition condition, +                     gpointer user_data) + { +-  GrdSessionVnc *session_vnc = user_data; ++  GrdSessionVnc *session_vnc = GRD_SESSION_VNC (user_data); ++  GrdSession *session = GRD_SESSION (session_vnc); +  +-  if (condition & G_IO_IN) ++  if (condition & (G_IO_ERR | G_IO_HUP)) ++    { ++      g_warning ("Client disconnected"); ++ ++      grd_session_stop (session); ++    } ++  else if (condition & G_IO_IN) +     { +-      if (rfbIsActive (session_vnc->rfb_screen)) ++      GrdVncSocketGrabFunc grab_func; ++      g_autoptr (GError) error = NULL; ++ ++      grab_func = g_list_first (session_vnc->socket_grabs)->data; ++      if (!grab_func (session_vnc, &error)) +         { +-          rfbProcessEvents (session_vnc->rfb_screen, 0); ++          g_warning ("Error when reading socket: %s", error->message); +  +-          if (session_vnc->pending_framebuffer_resize && +-              session_vnc->rfb_client->preferredEncoding != -1) +-            { +-              resize_vnc_framebuffer (session_vnc, +-                                      session_vnc->pending_framebuffer_width, +-                                      session_vnc->pending_framebuffer_height); +-              session_vnc->pending_framebuffer_resize = FALSE; +- +-              /** +-               * This is a workaround. libvncserver is unable to handle clipboard +-               * changes early and either disconnects the client or crashes g-r-d +-               * if it receives rfbSendServerCutText too early altough the +-               * authentification process is already done. +-               * Doing this after resizing the framebuffer, seems to work fine, +-               * so enable the clipboard here and not when the remote desktop +-               * session proxy is acquired. +-               */ +-              grd_clipboard_vnc_maybe_enable_clipboard (session_vnc->clipboard_vnc); +-            } ++          grd_session_stop (session); +         } +     } +   else +     { +-      g_debug ("Unhandled socket condition %d\n", condition); +-      return G_SOURCE_REMOVE; ++      g_warning ("Unhandled socket condition %d\n", condition); ++      g_assert_not_reached (); +     } +  +   return G_SOURCE_CONTINUE; +@@ -640,7 +701,10 @@ grd_session_vnc_attach_source (GrdSessionVnc *session_vnc) +  +   socket = g_socket_connection_get_socket (session_vnc->connection); +   session_vnc->source = g_socket_create_source (socket, +-                                                G_IO_IN | G_IO_PRI, ++                                                (G_IO_IN | ++                                                 G_IO_PRI | ++                                                 G_IO_ERR | ++                                                 G_IO_HUP), +                                                 NULL); +   g_source_set_callback (session_vnc->source, +                          (GSourceFunc) handle_socket_data, +@@ -666,8 +730,10 @@ grd_session_vnc_new (GrdVncServer      *vnc_server, +                               "context", context, +                               NULL); +  ++  session_vnc->vnc_server = vnc_server; +   session_vnc->connection = g_object_ref (connection); +  ++  grd_session_vnc_grab_socket (session_vnc, vnc_socket_grab_func); +   grd_session_vnc_attach_source (session_vnc); +  +   init_vnc_session (session_vnc); +@@ -682,6 +748,8 @@ grd_session_vnc_dispose (GObject *object) +  +   g_assert (!session_vnc->rfb_screen); +  ++  g_clear_pointer (&session_vnc->socket_grabs, g_list_free); ++ +   g_clear_pointer (&session_vnc->pressed_keys, g_hash_table_unref); +  +   G_OBJECT_CLASS (grd_session_vnc_parent_class)->dispose (object); +diff --git a/src/grd-session-vnc.h b/src/grd-session-vnc.h +index a532567..4e7b33d 100644 +--- a/src/grd-session-vnc.h ++++ b/src/grd-session-vnc.h +@@ -36,6 +36,9 @@ G_DECLARE_FINAL_TYPE (GrdSessionVnc, +                       GRD, SESSION_VNC, +                       GrdSession); +  ++typedef gboolean (* GrdVncSocketGrabFunc) (GrdSessionVnc  *session_vnc, ++                                           GError        **error); ++ + GrdSessionVnc *grd_session_vnc_new (GrdVncServer      *vnc_server, +                                     GSocketConnection *connection); +  +@@ -62,6 +65,20 @@ void grd_session_vnc_set_client_clipboard_text (GrdSessionVnc *session_vnc, + int grd_session_vnc_get_stride_for_width (GrdSessionVnc *session_vnc, +                                           int            width); +  ++int grd_session_vnc_get_fd (GrdSessionVnc *session_vnc); ++ ++int grd_session_vnc_get_framebuffer_stride (GrdSessionVnc *session_vnc); ++ + gboolean grd_session_vnc_is_client_gone (GrdSessionVnc *session_vnc); +  ++rfbClientPtr grd_session_vnc_get_rfb_client (GrdSessionVnc *session_vnc); ++ ++void grd_session_vnc_grab_socket (GrdSessionVnc        *session_vnc, ++                                  GrdVncSocketGrabFunc  grab_func); ++ ++void grd_session_vnc_ungrab_socket (GrdSessionVnc        *session_vnc, ++                                    GrdVncSocketGrabFunc  grab_func); ++ ++GrdVncServer * grd_session_vnc_get_vnc_server (GrdSessionVnc *session_vnc); ++ + #endif /* GRD_SESSION_VNC_H */ +diff --git a/src/grd-settings.c b/src/grd-settings.c +index d2f31d2..12d8693 100644 +--- a/src/grd-settings.c ++++ b/src/grd-settings.c +@@ -60,6 +60,7 @@ struct _GrdSettings +     gboolean view_only; +     GrdVncAuthMethod auth_method; +     int port; ++    GrdVncEncryption encryption; +   } vnc; + }; +  +@@ -242,6 +243,12 @@ grd_settings_get_vnc_auth_method (GrdSettings *settings) +     return settings->vnc.auth_method; + } +  ++GrdVncEncryption ++grd_settings_get_vnc_encryption (GrdSettings *settings) ++{ ++  return settings->vnc.encryption; ++} ++ + static void + update_rdp_tls_cert (GrdSettings *settings) + { +@@ -277,6 +284,13 @@ update_vnc_auth_method (GrdSettings *settings) +                                                    "auth-method"); + } +  ++static void ++update_vnc_encryption (GrdSettings *settings) ++{ ++  settings->vnc.encryption = g_settings_get_flags (settings->vnc.settings, ++                                                   "encryption"); ++} ++ + static void + on_rdp_settings_changed (GSettings   *rdp_settings, +                          const char  *key, +@@ -314,6 +328,11 @@ on_vnc_settings_changed (GSettings   *vnc_settings, +       update_vnc_auth_method (settings); +       g_signal_emit (settings, signals[VNC_AUTH_METHOD_CHANGED], 0); +     } ++  else if (strcmp (key, "encryption") == 0) ++    { ++      update_vnc_encryption (settings); ++      g_signal_emit (settings, signals[VNC_ENCRYPTION_CHANGED], 0); ++    } + } +  + static void +@@ -345,6 +364,8 @@ grd_settings_init (GrdSettings *settings) +  +   settings->rdp.port = GRD_RDP_SERVER_PORT; +   settings->vnc.port = GRD_VNC_SERVER_PORT; ++ ++  update_vnc_encryption (settings); + } +  + static void +@@ -389,4 +410,11 @@ grd_settings_class_init (GrdSettingsClass *klass) +                   0, +                   NULL, NULL, NULL, +                   G_TYPE_NONE, 0); ++  signals[VNC_ENCRYPTION_CHANGED] = ++    g_signal_new ("vnc-encryption-changed", ++                  G_TYPE_FROM_CLASS (klass), ++                  G_SIGNAL_RUN_LAST, ++                  0, ++                  NULL, NULL, NULL, ++                  G_TYPE_NONE, 0); + } +diff --git a/src/grd-settings.h b/src/grd-settings.h +index e12e47e..b940fdb 100644 +--- a/src/grd-settings.h ++++ b/src/grd-settings.h +@@ -64,4 +64,6 @@ gboolean grd_settings_get_vnc_view_only (GrdSettings *settings); +  + GrdVncAuthMethod grd_settings_get_vnc_auth_method (GrdSettings *settings); +  ++GrdVncEncryption grd_settings_get_vnc_encryption (GrdSettings *settings); ++ + #endif /* GRD_SETTINGS_H */ +diff --git a/src/grd-vnc-server.c b/src/grd-vnc-server.c +index a6d95cb..f9c68db 100644 +--- a/src/grd-vnc-server.c ++++ b/src/grd-vnc-server.c +@@ -24,11 +24,13 @@ +  + #include "grd-vnc-server.h" +  ++#include <rfb/rfb.h> + #include <gio/gio.h> + #include <rfb/rfb.h> +  + #include "grd-context.h" + #include "grd-session-vnc.h" ++#include "grd-vnc-tls.h" +  +  + enum +@@ -130,6 +132,43 @@ on_incoming (GSocketService    *service, +   return TRUE; + } +  ++static void ++sync_encryption_settings (GrdVncServer *vnc_server) ++{ ++  GrdSettings *settings = grd_context_get_settings (vnc_server->context); ++  rfbSecurityHandler *tls_security_handler; ++  GrdVncEncryption encryption; ++ ++  tls_security_handler = grd_vnc_tls_get_security_handler (); ++  encryption = grd_settings_get_vnc_encryption (settings); ++ ++  if (encryption == (GRD_VNC_ENCRYPTION_NONE | GRD_VNC_ENCRYPTION_TLS_ANON)) ++    { ++      rfbRegisterSecurityHandler (tls_security_handler); ++      rfbUnregisterChannelSecurityHandler (tls_security_handler); ++    } ++  else if (encryption == GRD_VNC_ENCRYPTION_NONE) ++    { ++      rfbUnregisterSecurityHandler (tls_security_handler); ++      rfbUnregisterChannelSecurityHandler (tls_security_handler); ++    } ++  else ++    { ++      if (encryption != GRD_VNC_ENCRYPTION_TLS_ANON) ++        g_warning ("Invalid VNC encryption setting, falling back to TLS-ANON"); ++ ++      rfbRegisterChannelSecurityHandler (tls_security_handler); ++      rfbUnregisterSecurityHandler (tls_security_handler); ++    } ++} ++ ++static void ++on_vnc_encryption_changed (GrdSettings  *settings, ++                           GrdVncServer *vnc_server) ++{ ++  sync_encryption_settings (vnc_server); ++} ++ + gboolean + grd_vnc_server_start (GrdVncServer  *vnc_server, +                       GError       **error) +@@ -220,12 +259,18 @@ static void + grd_vnc_server_constructed (GObject *object) + { +   GrdVncServer *vnc_server = GRD_VNC_SERVER (object); ++  GrdSettings *settings = grd_context_get_settings (vnc_server->context); +  +   if (grd_context_get_debug_flags (vnc_server->context) & GRD_DEBUG_VNC) +     rfbLogEnable (1); +   else +     rfbLogEnable (0); +  ++  g_signal_connect (settings, "vnc-encryption-changed", ++                    G_CALLBACK (on_vnc_encryption_changed), ++                    vnc_server); ++  sync_encryption_settings (vnc_server); ++ +   G_OBJECT_CLASS (grd_vnc_server_parent_class)->constructed (object); + } +  +diff --git a/src/grd-vnc-tls.c b/src/grd-vnc-tls.c +new file mode 100644 +index 0000000..ec4758e +--- /dev/null ++++ b/src/grd-vnc-tls.c +@@ -0,0 +1,444 @@ ++/* ++ * Copyright (C) 2018 Red Hat Inc. ++ * ++ * 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, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA ++ * 02111-1307, USA. ++ * ++ */ ++ ++#include "grd-vnc-tls.h" ++ ++#include <errno.h> ++#include <glib.h> ++#include <gnutls/gnutls.h> ++#include <rfb/rfb.h> ++ ++#include "grd-session-vnc.h" ++#include "grd-vnc-server.h" ++ ++typedef struct _GrdVncTlsContext ++{ ++  gnutls_anon_server_credentials_t anon_credentials; ++  gnutls_dh_params_t dh_params; ++} GrdVncTlsContext; ++ ++typedef enum _GrdTlsHandshakeState ++{ ++  GRD_TLS_HANDSHAKE_STATE_INIT, ++  GRD_TLS_HANDSHAKE_STATE_DURING, ++  GRD_TLS_HANDSHAKE_STATE_FINISHED ++} GrdTlsHandshakeState; ++ ++typedef struct _GrdVncTlsSession ++{ ++  GrdVncTlsContext *tls_context; ++ ++  int fd; ++ ++  gnutls_session_t tls_session; ++  GrdTlsHandshakeState handshake_state; ++ ++  char *peek_buffer; ++  int peek_buffer_size; ++  int peek_buffer_len; ++} GrdVncTlsSession; ++ ++static gboolean ++tls_handshake_grab_func (GrdSessionVnc  *session_vnc, ++                         GError        **error); ++ ++static GrdVncTlsContext * ++grd_vnc_tls_context_new (void) ++{ ++  GrdVncTlsContext *tls_context; ++  const unsigned int dh_bits = 1024; ++ ++  tls_context = g_new0 (GrdVncTlsContext, 1); ++ ++  gnutls_global_init (); ++ ++  gnutls_anon_allocate_server_credentials (&tls_context->anon_credentials); ++ ++  gnutls_dh_params_init (&tls_context->dh_params); ++  gnutls_dh_params_generate2 (tls_context->dh_params, dh_bits); ++ ++  gnutls_anon_set_server_dh_params (tls_context->anon_credentials, ++                                    tls_context->dh_params); ++ ++  return tls_context; ++} ++ ++static void ++grd_vnc_tls_context_free (GrdVncTlsContext *tls_context) ++{ ++  gnutls_dh_params_deinit (tls_context->dh_params); ++  gnutls_anon_free_server_credentials (tls_context->anon_credentials); ++  gnutls_global_deinit (); ++} ++ ++GrdVncTlsContext * ++ensure_tls_context (GrdVncServer *vnc_server) ++{ ++  GrdVncTlsContext *tls_context; ++ ++  tls_context = g_object_get_data (G_OBJECT (vnc_server), "vnc-tls-context"); ++  if (!tls_context) ++    { ++      tls_context = grd_vnc_tls_context_new (); ++      g_object_set_data_full (G_OBJECT (vnc_server), "vnc-tls-context", ++                              tls_context, ++                              (GDestroyNotify) grd_vnc_tls_context_free); ++    } ++ ++  return tls_context; ++} ++ ++static gboolean ++perform_anon_tls_handshake (GrdVncTlsSession  *tls_session, ++                            GError           **error) ++{ ++  GrdVncTlsContext *tls_context = tls_session->tls_context; ++  const char kx_priority[] = "NORMAL:+ANON-DH"; ++  int ret; ++ ++  gnutls_init (&tls_session->tls_session, GNUTLS_SERVER | GNUTLS_NO_SIGNAL); ++ ++  gnutls_set_default_priority (tls_session->tls_session); ++  gnutls_priority_set_direct (tls_session->tls_session, kx_priority, NULL); ++ ++  gnutls_credentials_set (tls_session->tls_session, ++                          GNUTLS_CRD_ANON, ++                          tls_context->anon_credentials); ++  gnutls_transport_set_ptr (tls_session->tls_session, ++                            GINT_TO_POINTER (tls_session->fd)); ++ ++  ret = gnutls_handshake (tls_session->tls_session); ++  if (ret != GNUTLS_E_SUCCESS && !gnutls_error_is_fatal (ret)) ++    { ++      tls_session->handshake_state = GRD_TLS_HANDSHAKE_STATE_DURING; ++      return TRUE; ++    } ++ ++  if (ret != GNUTLS_E_SUCCESS) ++    { ++      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++                   "%s", gnutls_strerror (ret)); ++      gnutls_deinit (tls_session->tls_session); ++      tls_session->tls_session = NULL; ++      return FALSE; ++    } ++ ++  tls_session->handshake_state = GRD_TLS_HANDSHAKE_STATE_FINISHED; ++  return TRUE; ++} ++ ++static gboolean ++continue_tls_handshake (GrdVncTlsSession  *tls_session, ++                        GError           **error) ++{ ++  int ret; ++ ++  ret = gnutls_handshake (tls_session->tls_session); ++  if (ret != GNUTLS_E_SUCCESS && !gnutls_error_is_fatal (ret)) ++    return TRUE; ++ ++  if (ret != GNUTLS_E_SUCCESS) ++    { ++      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++                   "%s", gnutls_strerror (ret)); ++      gnutls_deinit (tls_session->tls_session); ++      tls_session->tls_session = NULL; ++      return FALSE; ++    } ++ ++  tls_session->handshake_state = GRD_TLS_HANDSHAKE_STATE_FINISHED; ++  return TRUE; ++} ++ ++static void ++grd_vnc_tls_session_free (GrdVncTlsSession *tls_session) ++{ ++  g_clear_pointer (&tls_session->peek_buffer, g_free); ++  g_clear_pointer (&tls_session->tls_session, gnutls_deinit); ++  g_free (tls_session); ++} ++ ++static GrdVncTlsSession * ++grd_vnc_tls_session_from_vnc_session (GrdSessionVnc *session_vnc) ++{ ++  return g_object_get_data (G_OBJECT (session_vnc), "vnc-tls-session"); ++} ++ ++static int ++do_read (GrdVncTlsSession *tls_session, ++         char             *buf, ++         int               len) ++{ ++  do ++    { ++      int ret; ++ ++      ret = gnutls_record_recv (tls_session->tls_session, buf, len); ++      if (ret == GNUTLS_E_AGAIN || ++          ret == GNUTLS_E_INTERRUPTED) ++        { ++          continue; ++        } ++      else if (ret < 0) ++        { ++          g_debug ("gnutls_record_recv failed: %s", gnutls_strerror (ret)); ++          errno = EIO; ++          return -1; ++        } ++      else ++        { ++          return ret; ++        } ++    } ++  while (TRUE); ++} ++ ++static int ++grd_vnc_tls_read_from_socket (rfbClientPtr  rfb_client, ++                              char         *buf, ++                              int           len) ++{ ++  GrdSessionVnc *session_vnc = rfb_client->screen->screenData; ++  GrdVncTlsSession *tls_session = ++    grd_vnc_tls_session_from_vnc_session (session_vnc); ++  int to_read = len; ++  int len_read = 0; ++ ++  if (to_read < tls_session->peek_buffer_len) ++    { ++      memcpy (buf, tls_session->peek_buffer, to_read); ++      memmove (buf, ++               tls_session->peek_buffer + to_read, ++               tls_session->peek_buffer_len - to_read); ++      len_read = to_read; ++      to_read = 0; ++    } ++  else ++    { ++      memcpy (buf, ++              tls_session->peek_buffer, ++              tls_session->peek_buffer_len); ++      to_read -= tls_session->peek_buffer_len; ++      len_read = tls_session->peek_buffer_len; ++ ++      g_clear_pointer (&tls_session->peek_buffer, ++                       g_free); ++      tls_session->peek_buffer_len = 0; ++      tls_session->peek_buffer_size = 0; ++    } ++ ++  if (to_read > 0) ++    { ++      int ret; ++ ++      ret = do_read (tls_session, buf + len_read, to_read); ++      if (ret == -1) ++        return -1; ++ ++      len_read += ret; ++    } ++ ++  return len_read; ++} ++ ++static int ++grd_vnc_tls_peek_at_socket (rfbClientPtr  rfb_client, ++                            char         *buf, ++                            int           len) ++{ ++  GrdSessionVnc *session_vnc = rfb_client->screen->screenData; ++  GrdVncTlsSession *tls_session = ++    grd_vnc_tls_session_from_vnc_session (session_vnc); ++  int peekable_len; ++ ++  if (tls_session->peek_buffer_len < len) ++    { ++      int ret; ++ ++      if (len > tls_session->peek_buffer_size) ++        { ++          tls_session->peek_buffer = g_renew (char, ++                                              tls_session->peek_buffer, ++                                              len); ++          tls_session->peek_buffer_size = len; ++        } ++ ++      ret = do_read (tls_session, ++                     tls_session->peek_buffer + tls_session->peek_buffer_len, ++                     len - tls_session->peek_buffer_len); ++      if (ret == -1) ++        return -1; ++ ++      tls_session->peek_buffer_len += ret; ++    } ++ ++  peekable_len = MIN (len, tls_session->peek_buffer_len); ++  memcpy (buf, tls_session->peek_buffer, peekable_len); ++ ++  return peekable_len; ++} ++ ++static rfbBool ++grd_vnc_tls_has_pending_on_socket (rfbClientPtr rfb_client) ++{ ++  GrdSessionVnc *session_vnc = rfb_client->screen->screenData; ++  GrdVncTlsSession *tls_session = ++    grd_vnc_tls_session_from_vnc_session (session_vnc); ++ ++  if (tls_session->peek_buffer_len > 0) ++    return TRUE; ++ ++  if (gnutls_record_check_pending (tls_session->tls_session) > 0) ++    return TRUE; ++ ++  return FALSE; ++} ++ ++static int ++grd_vnc_tls_write_to_socket (rfbClientPtr  rfb_client, ++                             const char   *buf, ++                             int           len) ++{ ++  GrdSessionVnc *session_vnc = rfb_client->screen->screenData; ++  GrdVncTlsSession *tls_session = ++    grd_vnc_tls_session_from_vnc_session (session_vnc); ++ ++  do ++    { ++      int ret; ++ ++      ret = gnutls_record_send (tls_session->tls_session, buf, len); ++      if (ret == GNUTLS_E_AGAIN || ++          ret == GNUTLS_E_INTERRUPTED) ++        { ++          continue; ++        } ++      else if (ret < 0) ++        { ++          g_debug ("gnutls_record_send failed: %s", gnutls_strerror (ret)); ++          errno = EIO; ++          return -1; ++        } ++      else ++        { ++          return ret; ++        } ++    } ++  while (TRUE); ++} ++ ++static gboolean ++perform_handshake (GrdSessionVnc  *session_vnc, ++                   GError        **error) ++{ ++  GrdVncTlsSession *tls_session = ++    grd_vnc_tls_session_from_vnc_session (session_vnc); ++ ++  switch (tls_session->handshake_state) ++    { ++    case GRD_TLS_HANDSHAKE_STATE_INIT: ++      if (!perform_anon_tls_handshake (tls_session, error)) ++        return FALSE; ++      break; ++    case GRD_TLS_HANDSHAKE_STATE_DURING: ++      if (!continue_tls_handshake (tls_session, error)) ++        return FALSE; ++      break; ++    case GRD_TLS_HANDSHAKE_STATE_FINISHED: ++      break; ++    } ++ ++  switch (tls_session->handshake_state) ++    { ++    case GRD_TLS_HANDSHAKE_STATE_INIT: ++      break; ++    case GRD_TLS_HANDSHAKE_STATE_DURING: ++      break; ++    case GRD_TLS_HANDSHAKE_STATE_FINISHED: ++      grd_session_vnc_ungrab_socket (session_vnc, tls_handshake_grab_func); ++      rfbSendSecurityTypeList (grd_session_vnc_get_rfb_client (session_vnc), ++                               RFB_SECURITY_TAG_CHANNEL); ++      break; ++    } ++ ++  return TRUE; ++} ++ ++static gboolean ++tls_handshake_grab_func (GrdSessionVnc  *session_vnc, ++                         GError        **error) ++{ ++  g_autoptr (GError) handshake_error = NULL; ++ ++  if (!perform_handshake (session_vnc, &handshake_error)) ++    { ++      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++                   "TLS handshake failed: %s", handshake_error->message); ++      return FALSE; ++    } ++ ++  return TRUE; ++} ++ ++static void ++rfb_tls_security_handler (rfbClientPtr rfb_client) ++{ ++  GrdSessionVnc *session_vnc = rfb_client->screen->screenData; ++  GrdVncTlsSession *tls_session; ++  g_autoptr(GError) error = NULL; ++ ++  tls_session = grd_vnc_tls_session_from_vnc_session (session_vnc); ++  if (!tls_session) ++    { ++      GrdVncServer *vnc_server = grd_session_vnc_get_vnc_server (session_vnc); ++ ++      tls_session = g_new0 (GrdVncTlsSession, 1); ++      tls_session->fd = grd_session_vnc_get_fd (session_vnc); ++      tls_session->tls_context = ensure_tls_context (vnc_server); ++      g_object_set_data_full (G_OBJECT (session_vnc), "vnc-tls-session", ++                              tls_session, ++                              (GDestroyNotify) grd_vnc_tls_session_free); ++ ++      rfb_client->readFromSocket = grd_vnc_tls_read_from_socket; ++      rfb_client->peekAtSocket = grd_vnc_tls_peek_at_socket; ++      rfb_client->hasPendingOnSocket = grd_vnc_tls_has_pending_on_socket; ++      rfb_client->writeToSocket = grd_vnc_tls_write_to_socket; ++ ++      grd_session_vnc_grab_socket (session_vnc, tls_handshake_grab_func); ++    } ++ ++  if (!perform_handshake (session_vnc, &error)) ++    { ++      g_warning ("TLS handshake failed: %s", error->message); ++      rfbCloseClient (rfb_client); ++    } ++} ++ ++static rfbSecurityHandler anon_tls_security_handler = { ++  .type = rfbTLS, ++  .handler = rfb_tls_security_handler, ++  .securityTags = RFB_SECURITY_TAG_CHANNEL, ++}; ++ ++rfbSecurityHandler * ++grd_vnc_tls_get_security_handler (void) ++{ ++  return &anon_tls_security_handler; ++} +diff --git a/src/grd-vnc-tls.h b/src/grd-vnc-tls.h +new file mode 100644 +index 0000000..135ef8c +--- /dev/null ++++ b/src/grd-vnc-tls.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2018 Red Hat Inc. ++ * ++ * 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, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA ++ * 02111-1307, USA. ++ * ++ */ ++ ++#ifndef GRD_VNC_TLS_H ++#define GRD_VNC_TLS_H ++ ++#include <rfb/rfb.h> ++ ++rfbSecurityHandler * grd_vnc_tls_get_security_handler (void); ++ ++#endif /* GRD_VNC_TLS_H */ +diff --git a/src/meson.build b/src/meson.build +index 843746d..133cc60 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -72,10 +72,13 @@ if have_vnc +     'grd-vnc-pipewire-stream.h', +     'grd-vnc-server.c', +     'grd-vnc-server.h', ++    'grd-vnc-tls.c', ++    'grd-vnc-tls.h', +   ]) +  +   deps += [ +     libvncserver_dep, ++    gnutls_dep, +   ] + endif +  +diff --git a/src/org.gnome.desktop.remote-desktop.gschema.xml.in b/src/org.gnome.desktop.remote-desktop.gschema.xml.in +index 4b6e593..0086d99 100644 +--- a/src/org.gnome.desktop.remote-desktop.gschema.xml.in ++++ b/src/org.gnome.desktop.remote-desktop.gschema.xml.in +@@ -49,5 +49,15 @@ + 	 * password - by requiring the remote client to provide a known password +       </description> +     </key> ++    <key name='encryption' flags='org.gnome.desktop.remote-desktop.GrdVncEncryption'> ++      <default>['tls-anon']</default> ++      <summary>Allowed encryption method to use</summary> ++      <description> ++	Allowed encryption methods. Includes the following: ++ ++	 * none     - no encryption ++	 * tls-anon - anonymous (unauthenticated) TLS ++      </description> ++    </key> +   </schema> + </schemalist> +--  +2.29.2 + + +From 552e9c9add722e953a8da22bd54ba0fef7a9d6af Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Wed, 27 Nov 2019 11:02:09 +0100 +Subject: [PATCH 2/7] session-vnc: Add paused/resumed signals + +Paused is when the socket sourec is detached, and resumed when attached. +Meant to be used by the TLS channel security to a attach/detach +out-of-socket source. +--- + src/grd-session-vnc.c | 72 ++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 65 insertions(+), 7 deletions(-) + +diff --git a/src/grd-session-vnc.c b/src/grd-session-vnc.c +index 0c189fd..596896d 100644 +--- a/src/grd-session-vnc.c ++++ b/src/grd-session-vnc.c +@@ -41,14 +41,27 @@ + #define BGRX_SAMPLES_PER_PIXEL 3 + #define BGRX_BYTES_PER_PIXEL 4 +  ++enum ++{ ++  PAUSED, ++  RESUMED, ++ ++  N_SIGNALS ++}; ++ ++static guint signals[N_SIGNALS]; ++ + struct _GrdSessionVnc + { +   GrdSession parent; +  +   GrdVncServer *vnc_server; +   GSocketConnection *connection; ++ +   GList *socket_grabs; +   GSource *source; ++  gboolean is_paused; ++ +   rfbScreenInfoPtr rfb_screen; +   rfbClientPtr rfb_client; +  +@@ -76,7 +89,7 @@ struct _GrdSessionVnc + G_DEFINE_TYPE (GrdSessionVnc, grd_session_vnc, GRD_TYPE_SESSION); +  + static void +-grd_session_vnc_detach_source (GrdSessionVnc *session_vnc); ++grd_session_vnc_pause (GrdSessionVnc *session_vnc); +  + static gboolean + close_session_idle (gpointer user_data); +@@ -235,7 +248,8 @@ handle_client_gone (rfbClientPtr rfb_client) +  +   g_debug ("VNC client gone"); +  +-  grd_session_vnc_detach_source (session_vnc); ++  grd_session_vnc_pause (session_vnc); ++ +   maybe_queue_close_session_idle (session_vnc); +   session_vnc->rfb_client = NULL; + } +@@ -304,7 +318,7 @@ handle_new_client (rfbClientPtr rfb_client) +                               session_vnc->prompt_cancellable, +                               prompt_response_callback, +                               session_vnc); +-      grd_session_vnc_detach_source (session_vnc); ++      grd_session_vnc_pause (session_vnc); +       return RFB_CLIENT_ON_HOLD; +     case GRD_VNC_AUTH_METHOD_PASSWORD: +       session_vnc->rfb_screen->passwordCheck = check_rfb_password; +@@ -533,7 +547,7 @@ check_rfb_password (rfbClientPtr  rfb_client, +   if (memcmp (challenge_encrypted, response_encrypted, len) == 0) +     { +       grd_session_start (GRD_SESSION (session_vnc)); +-      grd_session_vnc_detach_source (session_vnc); ++      grd_session_vnc_pause (session_vnc); +       return TRUE; +     } +   else +@@ -718,6 +732,36 @@ grd_session_vnc_detach_source (GrdSessionVnc *session_vnc) +   g_clear_pointer (&session_vnc->source, g_source_destroy); + } +  ++gboolean ++grd_session_vnc_is_paused (GrdSessionVnc *session_vnc) ++{ ++  return session_vnc->is_paused; ++} ++ ++static void ++grd_session_vnc_pause (GrdSessionVnc *session_vnc) ++{ ++  if (grd_session_vnc_is_paused (session_vnc)) ++    return; ++ ++  session_vnc->is_paused = TRUE; ++ ++  grd_session_vnc_detach_source (session_vnc); ++  g_signal_emit (session_vnc, signals[PAUSED], 0); ++} ++ ++static void ++grd_session_vnc_resume (GrdSessionVnc *session_vnc) ++{ ++  if (!grd_session_vnc_is_paused (session_vnc)) ++    return; ++ ++  session_vnc->is_paused = FALSE; ++ ++  grd_session_vnc_attach_source (session_vnc); ++  g_signal_emit (session_vnc, signals[RESUMED], 0); ++} ++ + GrdSessionVnc * + grd_session_vnc_new (GrdVncServer      *vnc_server, +                      GSocketConnection *connection) +@@ -735,6 +779,7 @@ grd_session_vnc_new (GrdVncServer      *vnc_server, +  +   grd_session_vnc_grab_socket (session_vnc, vnc_socket_grab_func); +   grd_session_vnc_attach_source (session_vnc); ++  session_vnc->is_paused = FALSE; +  +   init_vnc_session (session_vnc); +  +@@ -764,7 +809,7 @@ grd_session_vnc_stop (GrdSession *session) +  +   g_clear_object (&session_vnc->pipewire_stream); +  +-  grd_session_vnc_detach_source (session_vnc); ++  grd_session_vnc_pause (session_vnc); +  +   g_clear_object (&session_vnc->connection); +   g_clear_object (&session_vnc->clipboard_vnc); +@@ -817,8 +862,8 @@ grd_session_vnc_stream_ready (GrdSession *session, +                     G_CALLBACK (on_pipewire_stream_closed), +                     session_vnc); +  +-  if (!session_vnc->source) +-    grd_session_vnc_attach_source (session_vnc); ++  if (grd_session_vnc_is_paused (session_vnc)) ++    grd_session_vnc_resume (session_vnc); + } +  + static void +@@ -837,4 +882,17 @@ grd_session_vnc_class_init (GrdSessionVncClass *klass) +  +   session_class->stop = grd_session_vnc_stop; +   session_class->stream_ready = grd_session_vnc_stream_ready; ++ ++  signals[PAUSED] = g_signal_new ("paused", ++                                  G_TYPE_FROM_CLASS (klass), ++                                  G_SIGNAL_RUN_LAST, ++                                  0, ++                                  NULL, NULL, NULL, ++                                  G_TYPE_NONE, 0); ++  signals[RESUMED] = g_signal_new ("resumed", ++                                   G_TYPE_FROM_CLASS (klass), ++                                   G_SIGNAL_RUN_LAST, ++                                   0, ++                                   NULL, NULL, NULL, ++                                   G_TYPE_NONE, 0); + } +--  +2.29.2 + + +From 3b33524046d299111cc150cc8d6d100f1e516485 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Wed, 27 Nov 2019 11:03:46 +0100 +Subject: [PATCH 3/7] session-vnc: Add grd_session_vnc_dispatch() helper + +To be used by the TLS channel security to dispatch when there is data +available that is not visible to the socket source. +--- + src/grd-session-vnc.c | 26 ++++++++++++++++---------- + src/grd-session-vnc.h |  2 ++ + 2 files changed, 18 insertions(+), 10 deletions(-) + +diff --git a/src/grd-session-vnc.c b/src/grd-session-vnc.c +index 596896d..06b2cf7 100644 +--- a/src/grd-session-vnc.c ++++ b/src/grd-session-vnc.c +@@ -672,6 +672,21 @@ vnc_socket_grab_func (GrdSessionVnc  *session_vnc, +   return TRUE; + } +  ++void ++grd_session_vnc_dispatch (GrdSessionVnc *session_vnc) ++{ ++  GrdVncSocketGrabFunc grab_func; ++  g_autoptr (GError) error = NULL; ++ ++  grab_func = g_list_first (session_vnc->socket_grabs)->data; ++  if (!grab_func (session_vnc, &error)) ++    { ++      g_warning ("Error when reading socket: %s", error->message); ++ ++      grd_session_stop (GRD_SESSION (session_vnc)); ++    } ++} ++ + static gboolean + handle_socket_data (GSocket *socket, +                     GIOCondition condition, +@@ -688,16 +703,7 @@ handle_socket_data (GSocket *socket, +     } +   else if (condition & G_IO_IN) +     { +-      GrdVncSocketGrabFunc grab_func; +-      g_autoptr (GError) error = NULL; +- +-      grab_func = g_list_first (session_vnc->socket_grabs)->data; +-      if (!grab_func (session_vnc, &error)) +-        { +-          g_warning ("Error when reading socket: %s", error->message); +- +-          grd_session_stop (session); +-        } ++      grd_session_vnc_dispatch (session_vnc); +     } +   else +     { +diff --git a/src/grd-session-vnc.h b/src/grd-session-vnc.h +index 4e7b33d..cf275af 100644 +--- a/src/grd-session-vnc.h ++++ b/src/grd-session-vnc.h +@@ -79,6 +79,8 @@ void grd_session_vnc_grab_socket (GrdSessionVnc        *session_vnc, + void grd_session_vnc_ungrab_socket (GrdSessionVnc        *session_vnc, +                                     GrdVncSocketGrabFunc  grab_func); +  ++void grd_session_vnc_dispatch (GrdSessionVnc *session_vnc); ++ + GrdVncServer * grd_session_vnc_get_vnc_server (GrdSessionVnc *session_vnc); +  + #endif /* GRD_SESSION_VNC_H */ +--  +2.29.2 + + +From 3945af78cea858033d954bb1b071269687bdea85 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Wed, 27 Nov 2019 11:05:13 +0100 +Subject: [PATCH 4/7] vnc/tls: Add some logging + +Uses the log utility from libvncserver as it is related to the RFB +protocol rather than the session itself. +--- + src/grd-vnc-tls.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/grd-vnc-tls.c b/src/grd-vnc-tls.c +index ec4758e..ac6c35f 100644 +--- a/src/grd-vnc-tls.c ++++ b/src/grd-vnc-tls.c +@@ -67,6 +67,7 @@ grd_vnc_tls_context_new (void) +  +   tls_context = g_new0 (GrdVncTlsContext, 1); +  ++  rfbLog ("TLS: Initializing gnutls context\n"); +   gnutls_global_init (); +  +   gnutls_anon_allocate_server_credentials (&tls_context->anon_credentials); +@@ -127,6 +128,7 @@ perform_anon_tls_handshake (GrdVncTlsSession  *tls_session, +   ret = gnutls_handshake (tls_session->tls_session); +   if (ret != GNUTLS_E_SUCCESS && !gnutls_error_is_fatal (ret)) +     { ++      rfbLog ("TLS: More handshake pending\n"); +       tls_session->handshake_state = GRD_TLS_HANDSHAKE_STATE_DURING; +       return TRUE; +     } +@@ -140,6 +142,8 @@ perform_anon_tls_handshake (GrdVncTlsSession  *tls_session, +       return FALSE; +     } +  ++  rfbLog ("TLS: Handshake finished"); ++ +   tls_session->handshake_state = GRD_TLS_HANDSHAKE_STATE_FINISHED; +   return TRUE; + } +@@ -373,6 +377,7 @@ perform_handshake (GrdSessionVnc  *session_vnc, +       break; +     case GRD_TLS_HANDSHAKE_STATE_FINISHED: +       grd_session_vnc_ungrab_socket (session_vnc, tls_handshake_grab_func); ++      rfbLog ("TLS: Sending post-channel security security list\n"); +       rfbSendSecurityTypeList (grd_session_vnc_get_rfb_client (session_vnc), +                                RFB_SECURITY_TAG_CHANNEL); +       break; +@@ -387,6 +392,7 @@ tls_handshake_grab_func (GrdSessionVnc  *session_vnc, + { +   g_autoptr (GError) handshake_error = NULL; +  ++  rfbLog ("TLS: Continuing handshake\n"); +   if (!perform_handshake (session_vnc, &handshake_error)) +     { +       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, +@@ -404,6 +410,8 @@ rfb_tls_security_handler (rfbClientPtr rfb_client) +   GrdVncTlsSession *tls_session; +   g_autoptr(GError) error = NULL; +  ++  rfbLog ("TLS: Setting up rfbClient for gnutls encrypted traffic\n"); ++ +   tls_session = grd_vnc_tls_session_from_vnc_session (session_vnc); +   if (!tls_session) +     { +@@ -424,6 +432,7 @@ rfb_tls_security_handler (rfbClientPtr rfb_client) +       grd_session_vnc_grab_socket (session_vnc, tls_handshake_grab_func); +     } +  ++  rfbLog ("TLS: Performing handshake\n"); +   if (!perform_handshake (session_vnc, &error)) +     { +       g_warning ("TLS handshake failed: %s", error->message); +--  +2.29.2 + + +From f5330797678f4c4db4a3fa19cebd30dd4d6bbb8c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Wed, 27 Nov 2019 11:07:40 +0100 +Subject: [PATCH 5/7] vnc/tls: Dispatch also when data is pending outside of + the socket + +gnutls may have data available in its buffers, and we have our own peek +buffer temporarly storing data later to be processed. This would missed +by the socket source, as it wouldn't get any notification about it from +epoll(). Deal with this by adding a custom source that dispatches as +long as there is data to read in those buffers. +--- + src/grd-session-vnc.h |  2 + + src/grd-vnc-tls.c     | 90 ++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 86 insertions(+), 6 deletions(-) + +diff --git a/src/grd-session-vnc.h b/src/grd-session-vnc.h +index cf275af..efc0038 100644 +--- a/src/grd-session-vnc.h ++++ b/src/grd-session-vnc.h +@@ -79,6 +79,8 @@ void grd_session_vnc_grab_socket (GrdSessionVnc        *session_vnc, + void grd_session_vnc_ungrab_socket (GrdSessionVnc        *session_vnc, +                                     GrdVncSocketGrabFunc  grab_func); +  ++gboolean grd_session_vnc_is_paused (GrdSessionVnc *session_vnc); ++ + void grd_session_vnc_dispatch (GrdSessionVnc *session_vnc); +  + GrdVncServer * grd_session_vnc_get_vnc_server (GrdSessionVnc *session_vnc); +diff --git a/src/grd-vnc-tls.c b/src/grd-vnc-tls.c +index ac6c35f..312b6b9 100644 +--- a/src/grd-vnc-tls.c ++++ b/src/grd-vnc-tls.c +@@ -41,6 +41,12 @@ typedef enum _GrdTlsHandshakeState +   GRD_TLS_HANDSHAKE_STATE_FINISHED + } GrdTlsHandshakeState; +  ++typedef struct _PeekBufferSource ++{ ++  GSource parent; ++  GrdSessionVnc *session_vnc; ++} PeekBufferSource; ++ + typedef struct _GrdVncTlsSession + { +   GrdVncTlsContext *tls_context; +@@ -53,6 +59,8 @@ typedef struct _GrdVncTlsSession +   char *peek_buffer; +   int peek_buffer_size; +   int peek_buffer_len; ++ ++  GSource *peek_buffer_source; + } GrdVncTlsSession; +  + static gboolean +@@ -299,13 +307,9 @@ grd_vnc_tls_peek_at_socket (rfbClientPtr  rfb_client, +   return peekable_len; + } +  +-static rfbBool +-grd_vnc_tls_has_pending_on_socket (rfbClientPtr rfb_client) ++static gboolean ++grd_vnc_tls_session_has_pending_data (GrdVncTlsSession *tls_session) + { +-  GrdSessionVnc *session_vnc = rfb_client->screen->screenData; +-  GrdVncTlsSession *tls_session = +-    grd_vnc_tls_session_from_vnc_session (session_vnc); +- +   if (tls_session->peek_buffer_len > 0) +     return TRUE; +  +@@ -315,6 +319,16 @@ grd_vnc_tls_has_pending_on_socket (rfbClientPtr rfb_client) +   return FALSE; + } +  ++static rfbBool ++grd_vnc_tls_has_pending_on_socket (rfbClientPtr rfb_client) ++{ ++  GrdSessionVnc *session_vnc = rfb_client->screen->screenData; ++  GrdVncTlsSession *tls_session = ++    grd_vnc_tls_session_from_vnc_session (session_vnc); ++ ++  return grd_vnc_tls_session_has_pending_data (tls_session); ++} ++ + static int + grd_vnc_tls_write_to_socket (rfbClientPtr  rfb_client, +                              const char   *buf, +@@ -403,6 +417,62 @@ tls_handshake_grab_func (GrdSessionVnc  *session_vnc, +   return TRUE; + } +  ++static gboolean ++peek_buffer_source_prepare (GSource *source, ++                            int     *timeout) ++{ ++  PeekBufferSource *psource = (PeekBufferSource *) source; ++  GrdSessionVnc *session_vnc = psource->session_vnc; ++  GrdVncTlsSession *tls_session = ++    grd_vnc_tls_session_from_vnc_session (session_vnc); ++ ++  return grd_vnc_tls_session_has_pending_data (tls_session); ++} ++ ++static gboolean ++peek_buffer_source_dispatch (GSource     *source, ++                             GSourceFunc  callback, ++                             gpointer     user_data) ++{ ++  PeekBufferSource *psource = (PeekBufferSource *) source; ++  GrdSessionVnc *session_vnc = psource->session_vnc; ++ ++  grd_session_vnc_dispatch (session_vnc); ++ ++  return G_SOURCE_CONTINUE; ++} ++ ++static GSourceFuncs peek_buffer_source_funcs = { ++  .prepare = peek_buffer_source_prepare, ++  .dispatch = peek_buffer_source_dispatch, ++}; ++ ++static void ++attach_peek_buffer_source (GrdSessionVnc *session_vnc) ++{ ++  GrdVncTlsSession *tls_session; ++ ++  tls_session = grd_vnc_tls_session_from_vnc_session (session_vnc); ++  tls_session->peek_buffer_source = g_source_new (&peek_buffer_source_funcs, ++                                                  sizeof (PeekBufferSource)); ++  ((PeekBufferSource *) tls_session->peek_buffer_source)->session_vnc = ++    session_vnc; ++  g_source_set_priority (tls_session->peek_buffer_source, ++                         G_PRIORITY_DEFAULT + 1); ++ ++  g_source_attach (tls_session->peek_buffer_source, NULL); ++} ++ ++static void ++detach_peek_buffer_source (GrdSessionVnc *session_vnc) ++{ ++  GrdVncTlsSession *tls_session; ++ ++  tls_session = grd_vnc_tls_session_from_vnc_session (session_vnc); ++ ++  g_clear_pointer (&tls_session->peek_buffer_source, g_source_destroy); ++} ++ + static void + rfb_tls_security_handler (rfbClientPtr rfb_client) + { +@@ -429,6 +499,14 @@ rfb_tls_security_handler (rfbClientPtr rfb_client) +       rfb_client->hasPendingOnSocket = grd_vnc_tls_has_pending_on_socket; +       rfb_client->writeToSocket = grd_vnc_tls_write_to_socket; +  ++      if (!grd_session_vnc_is_paused (session_vnc)) ++        attach_peek_buffer_source (session_vnc); ++ ++      g_signal_connect (session_vnc, "paused", ++                        G_CALLBACK (detach_peek_buffer_source), NULL); ++      g_signal_connect (session_vnc, "resumed", ++                        G_CALLBACK (attach_peek_buffer_source), NULL); ++ +       grd_session_vnc_grab_socket (session_vnc, tls_handshake_grab_func); +     } +  +--  +2.29.2 + + +From fae9653965ddcc3d5684a056d9bdf46ef439d649 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Wed, 27 Nov 2019 16:48:00 +0100 +Subject: [PATCH 6/7] session-vnc: Set our own password handling function up + front + +libvncserver decides whether to register a auth security handler +depending on whether the password data is set or not. When we use the +prompt auth method, we don't want to ask for password, so set the +password data to NULL. + +Also, to be a bit more in control of the password mechanism, always set +the password function up front, instead of just when the client uses the +password prompt. +--- + src/grd-session-vnc.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/src/grd-session-vnc.c b/src/grd-session-vnc.c +index 06b2cf7..7a4c6b3 100644 +--- a/src/grd-session-vnc.c ++++ b/src/grd-session-vnc.c +@@ -94,11 +94,6 @@ grd_session_vnc_pause (GrdSessionVnc *session_vnc); + static gboolean + close_session_idle (gpointer user_data); +  +-static rfbBool +-check_rfb_password (rfbClientPtr  rfb_client, +-                    const char   *response_encrypted, +-                    int           len); +- + static void + swap_uint8 (uint8_t *a, +             uint8_t *b) +@@ -321,7 +316,6 @@ handle_new_client (rfbClientPtr rfb_client) +       grd_session_vnc_pause (session_vnc); +       return RFB_CLIENT_ON_HOLD; +     case GRD_VNC_AUTH_METHOD_PASSWORD: +-      session_vnc->rfb_screen->passwordCheck = check_rfb_password; +       /* +        * authPasswdData needs to be non NULL in libvncserver to trigger +        * password authentication. +@@ -620,6 +614,8 @@ init_vnc_session (GrdSessionVnc *session_vnc) +   rfb_screen->frameBuffer = g_malloc0 (screen_width * screen_height * 4); +   memset (rfb_screen->frameBuffer, 0x1f, screen_width * screen_height * 4); +  ++  rfb_screen->passwordCheck = check_rfb_password; ++ +   rfbInitServer (rfb_screen); +   rfbProcessEvents (rfb_screen, 0); + } +--  +2.29.2 + + +From 1ae1286b2cc868045f93c02b7a990638ca94b26d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> +Date: Mon, 12 Oct 2020 17:34:30 +0200 +Subject: [PATCH 7/7] vnc: Copy pixels using the right destination stride + +We're copying the pixels in a separate thread managed by PipeWire, and +in this thread, accessing the VNC framebuffer dimension and stride is +racy. Instead of fetching the dimension directly, pass the expected +width and get the stride it will eventually have. + +Already before this patch, when the copied pixel end up on the main +thread and the dimension still doesn't match up, the frame will be +dropped. +--- + src/grd-session-vnc.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/grd-session-vnc.h b/src/grd-session-vnc.h +index efc0038..f3a6314 100644 +--- a/src/grd-session-vnc.h ++++ b/src/grd-session-vnc.h +@@ -67,7 +67,8 @@ int grd_session_vnc_get_stride_for_width (GrdSessionVnc *session_vnc, +  + int grd_session_vnc_get_fd (GrdSessionVnc *session_vnc); +  +-int grd_session_vnc_get_framebuffer_stride (GrdSessionVnc *session_vnc); ++int grd_session_vnc_get_stride_for_width (GrdSessionVnc *session_vnc, ++                                          int            width); +  + gboolean grd_session_vnc_is_client_gone (GrdSessionVnc *session_vnc); +  +--  +2.29.2 + diff --git a/libvncserver-LibVNCServer-0.9.13-system-crypto-policy.patch b/libvncserver-LibVNCServer-0.9.13-system-crypto-policy.patch new file mode 100644 index 0000000..493617f --- /dev/null +++ b/libvncserver-LibVNCServer-0.9.13-system-crypto-policy.patch @@ -0,0 +1,15 @@ +diff -up libvncserver-LibVNCServer-0.9.13/libvncclient/tls_gnutls.c.crypto_policy libvncserver-LibVNCServer-0.9.13/libvncclient/tls_gnutls.c +--- libvncserver-LibVNCServer-0.9.13/libvncclient/tls_gnutls.c.crypto_policy	2020-06-13 13:49:53.000000000 -0500 ++++ libvncserver-LibVNCServer-0.9.13/libvncclient/tls_gnutls.c	2020-07-02 08:00:54.304902893 -0500 +@@ -29,8 +29,8 @@ + #include "tls.h" +  +  +-static const char *rfbTLSPriority = "NORMAL:+DHE-DSS:+RSA:+DHE-RSA:+SRP"; +-static const char *rfbAnonTLSPriority= "NORMAL:+ANON-DH"; ++static const char *rfbTLSPriority = "@SYSTEM"; ++static const char *rfbAnonTLSPriority= "@SYSTEM:+ANON-DH"; +  + #define DH_BITS 1024 + static gnutls_dh_params_t rfbDHParams; +diff -up libvncserver-LibVNCServer-0.9.13/libvncserver/rfbssl_gnutls.c.crypto_policy libvncserver-LibVNCServer-0.9.13/libvncserver/rfbssl_gnutls.c @@ -0,0 +1,2 @@ +503b5527b93dce77e8b6a45f273f6e39  LibVNCServer-0.9.13.tar.gz +1c269b3b0f30116f27cce0ca63af9eb0  gnome-remote-desktop-40.0.tar.xz  | 
