summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2024-08-02 07:10:58 +0000
committerCoprDistGit <infra@openeuler.org>2024-08-02 07:10:58 +0000
commit4e17ce57fa4b190b82a065fc8aa6fa6143651ecd (patch)
tree513a6d740ae342f31f6b89b089b736bf6c2ba6a4
parent55e88a20b37ca9b6f9738a9f423b19beed17e9bb (diff)
automatic import of gnome-remote-desktopopeneuler24.03_LTSopeneuler23.09
-rw-r--r--.gitignore2
-rw-r--r--0001-build-Set-rpath-on-executable.patch50
-rw-r--r--0001-crypto-Don-t-compile-SHA1-support-when-Websockets-ar.patch92
-rw-r--r--0001-libvncserver-Add-API-to-add-custom-I-O-entry-points.patch241
-rw-r--r--0001-libvncserver-don-t-NULL-out-internal-of-the-default-.patch28
-rw-r--r--0001-pipewire-stream-Don-t-leak-GSource-s.patch53
-rw-r--r--0002-libvncserver-Add-channel-security-handlers.patch368
-rw-r--r--0003-libvncserver-auth-don-t-keep-security-handlers-from-.patch32
-rw-r--r--0004-zlib-Clear-buffer-pointers-on-cleanup-444.patch45
-rw-r--r--gnome-remote-desktop.spec312
-rw-r--r--gnutls-anontls.patch1544
-rw-r--r--libvncserver-LibVNCServer-0.9.13-system-crypto-policy.patch15
-rw-r--r--sources2
13 files changed, 2784 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..029799e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/sources b/sources
new file mode 100644
index 0000000..c97a5f7
--- /dev/null
+++ b/sources
@@ -0,0 +1,2 @@
+503b5527b93dce77e8b6a45f273f6e39 LibVNCServer-0.9.13.tar.gz
+1c269b3b0f30116f27cce0ca63af9eb0 gnome-remote-desktop-40.0.tar.xz