Blame SOURCES/anon-tls-support.patch

359730
From 10843a1f3edffbb475c01835451d39ebe6153e44 Mon Sep 17 00:00:00 2001
78005c
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
78005c
Date: Thu, 14 Jun 2018 12:21:37 +0200
359730
Subject: [PATCH 1/7] vnc: Add anonymous TLS encryption support
78005c
78005c
Add support for encrypting the VNC connection using anonymous TLS. In
78005c
effect this means that the channel is encrypted using TLS but that no
78005c
authentication of the peers are done. This means the connection is still
78005c
vulnerable to man-in-the-middle attacks where an attacker proxies the
78005c
VNC connection.
78005c
---
78005c
 meson.build                                   |   1 +
78005c
 src/grd-enums.h                               |   6 +
78005c
 src/grd-session-vnc.c                         |  98 +++-
359730
 src/grd-session-vnc.h                         |  15 +
359730
 src/grd-settings.c                            |  28 ++
78005c
 src/grd-settings.h                            |   2 +
78005c
 src/grd-vnc-server.c                          |  45 ++
78005c
 src/grd-vnc-tls.c                             | 444 ++++++++++++++++++
78005c
 src/grd-vnc-tls.h                             |  28 ++
78005c
 src/meson.build                               |   5 +-
359730
 ...nome.desktop.remote-desktop.gschema.xml.in |  10 +
78005c
 11 files changed, 666 insertions(+), 16 deletions(-)
78005c
 create mode 100644 src/grd-vnc-tls.c
78005c
 create mode 100644 src/grd-vnc-tls.h
78005c
78005c
diff --git a/meson.build b/meson.build
359730
index 1c96849..a24acfd 100644
78005c
--- a/meson.build
78005c
+++ b/meson.build
359730
@@ -15,6 +15,7 @@ libvncserver_dep = dependency('libvncserver')
359730
 libvncclient_dep = dependency('libvncclient')
78005c
 libsecret_dep = dependency('libsecret-1')
78005c
 libnotify_dep = dependency('libnotify')
78005c
+gnutls_dep = dependency('gnutls')
78005c
 
78005c
 cdata = configuration_data()
78005c
 cdata.set_quoted('GETTEXT_PACKAGE', 'gnome-remote-desktop')
78005c
diff --git a/src/grd-enums.h b/src/grd-enums.h
78005c
index ffab821..4333863 100644
78005c
--- a/src/grd-enums.h
78005c
+++ b/src/grd-enums.h
78005c
@@ -27,4 +27,10 @@ typedef enum
78005c
   GRD_VNC_AUTH_METHOD_PASSWORD
78005c
 } GrdVncAuthMethod;
78005c
 
78005c
+typedef enum
78005c
+{
78005c
+  GRD_VNC_ENCRYPTION_NONE = 1 << 0,
78005c
+  GRD_VNC_ENCRYPTION_TLS_ANON = 1 << 1,
78005c
+} GrdVncEncryption;
78005c
+
78005c
 #endif /* GRD_ENUMS_H */
78005c
diff --git a/src/grd-session-vnc.c b/src/grd-session-vnc.c
359730
index 1f3f0e2..0cc2ea2 100644
78005c
--- a/src/grd-session-vnc.c
78005c
+++ b/src/grd-session-vnc.c
78005c
@@ -44,7 +44,9 @@ struct _GrdSessionVnc
78005c
 {
78005c
   GrdSession parent;
78005c
 
78005c
+  GrdVncServer *vnc_server;
78005c
   GSocketConnection *connection;
78005c
+  GList *socket_grabs;
78005c
   GSource *source;
78005c
   rfbScreenInfoPtr rfb_screen;
78005c
   rfbClientPtr rfb_client;
359730
@@ -505,12 +507,30 @@ check_rfb_password (rfbClientPtr  rfb_client,
78005c
     }
78005c
 }
78005c
 
78005c
+int
78005c
+grd_session_vnc_get_fd (GrdSessionVnc *session_vnc)
78005c
+{
78005c
+  return session_vnc->rfb_screen->inetdSock;
78005c
+}
78005c
+
78005c
 int
78005c
 grd_session_vnc_get_framebuffer_stride (GrdSessionVnc *session_vnc)
78005c
 {
78005c
   return session_vnc->rfb_screen->paddedWidthInBytes;
78005c
 }
78005c
 
78005c
+rfbClientPtr
78005c
+grd_session_vnc_get_rfb_client (GrdSessionVnc *session_vnc)
78005c
+{
78005c
+  return session_vnc->rfb_client;
78005c
+}
78005c
+
78005c
+GrdVncServer *
78005c
+grd_session_vnc_get_vnc_server (GrdSessionVnc *session_vnc)
78005c
+{
78005c
+  return session_vnc->vnc_server;
78005c
+}
78005c
+
78005c
 static void
78005c
 init_vnc_session (GrdSessionVnc *session_vnc)
78005c
 {
359730
@@ -551,33 +571,74 @@ init_vnc_session (GrdSessionVnc *session_vnc)
78005c
   rfbProcessEvents (rfb_screen, 0);
78005c
 }
78005c
 
78005c
+void
78005c
+grd_session_vnc_grab_socket (GrdSessionVnc        *session_vnc,
78005c
+                             GrdVncSocketGrabFunc  grab_func)
78005c
+{
78005c
+  session_vnc->socket_grabs = g_list_prepend (session_vnc->socket_grabs,
78005c
+                                              grab_func);
78005c
+}
78005c
+
78005c
+void
78005c
+grd_session_vnc_ungrab_socket (GrdSessionVnc        *session_vnc,
78005c
+                               GrdVncSocketGrabFunc  grab_func)
78005c
+{
78005c
+  session_vnc->socket_grabs = g_list_remove (session_vnc->socket_grabs,
78005c
+                                             grab_func);
78005c
+}
78005c
+
78005c
+static gboolean
78005c
+vnc_socket_grab_func (GrdSessionVnc  *session_vnc,
78005c
+                      GError        **error)
78005c
+{
78005c
+  if (rfbIsActive (session_vnc->rfb_screen))
78005c
+    {
78005c
+      rfbProcessEvents (session_vnc->rfb_screen, 0);
78005c
+
78005c
+      if (session_vnc->pending_framebuffer_resize &&
78005c
+          session_vnc->rfb_client->preferredEncoding != -1)
78005c
+        {
78005c
+          resize_vnc_framebuffer (session_vnc,
78005c
+                                  session_vnc->pending_framebuffer_width,
78005c
+                                  session_vnc->pending_framebuffer_height);
78005c
+          session_vnc->pending_framebuffer_resize = FALSE;
78005c
+        }
78005c
+    }
78005c
+
78005c
+  return TRUE;
78005c
+}
78005c
+
78005c
 static gboolean
78005c
 handle_socket_data (GSocket *socket,
78005c
                     GIOCondition condition,
78005c
                     gpointer user_data)
78005c
 {
78005c
-  GrdSessionVnc *session_vnc = user_data;
78005c
+  GrdSessionVnc *session_vnc = GRD_SESSION_VNC (user_data);
78005c
+  GrdSession *session = GRD_SESSION (session_vnc);
78005c
 
78005c
-  if (condition & G_IO_IN)
78005c
+  if (condition & (G_IO_ERR | G_IO_HUP))
78005c
+    {
78005c
+      g_warning ("Client disconnected");
78005c
+
78005c
+      grd_session_stop (session);
78005c
+    }
78005c
+  else if (condition & G_IO_IN)
78005c
     {
78005c
-      if (rfbIsActive (session_vnc->rfb_screen))
78005c
+      GrdVncSocketGrabFunc grab_func;
78005c
+      g_autoptr (GError) error = NULL;
78005c
+
78005c
+      grab_func = g_list_first (session_vnc->socket_grabs)->data;
78005c
+      if (!grab_func (session_vnc, &error))
78005c
         {
78005c
-          rfbProcessEvents (session_vnc->rfb_screen, 0);
78005c
+          g_warning ("Error when reading socket: %s", error->message);
78005c
 
78005c
-          if (session_vnc->pending_framebuffer_resize &&
78005c
-              session_vnc->rfb_client->preferredEncoding != -1)
78005c
-            {
78005c
-              resize_vnc_framebuffer (session_vnc,
78005c
-                                      session_vnc->pending_framebuffer_width,
78005c
-                                      session_vnc->pending_framebuffer_height);
78005c
-              session_vnc->pending_framebuffer_resize = FALSE;
78005c
-            }
78005c
+          grd_session_stop (session);
78005c
         }
78005c
     }
78005c
   else
78005c
     {
78005c
-      g_debug ("Unhandled socket condition %d\n", condition);
78005c
-      return G_SOURCE_REMOVE;
78005c
+      g_warning ("Unhandled socket condition %d\n", condition);
78005c
+      g_assert_not_reached ();
78005c
     }
78005c
 
78005c
   return G_SOURCE_CONTINUE;
359730
@@ -590,7 +651,10 @@ grd_session_vnc_attach_source (GrdSessionVnc *session_vnc)
78005c
 
78005c
   socket = g_socket_connection_get_socket (session_vnc->connection);
78005c
   session_vnc->source = g_socket_create_source (socket,
78005c
-                                                G_IO_IN | G_IO_PRI,
78005c
+                                                (G_IO_IN |
78005c
+                                                 G_IO_PRI |
78005c
+                                                 G_IO_ERR |
78005c
+                                                 G_IO_HUP),
78005c
                                                 NULL);
78005c
   g_source_set_callback (session_vnc->source,
78005c
                          (GSourceFunc) handle_socket_data,
359730
@@ -616,8 +680,10 @@ grd_session_vnc_new (GrdVncServer      *vnc_server,
78005c
                               "context", context,
78005c
                               NULL);
78005c
 
78005c
+  session_vnc->vnc_server = vnc_server;
78005c
   session_vnc->connection = g_object_ref (connection);
78005c
 
78005c
+  grd_session_vnc_grab_socket (session_vnc, vnc_socket_grab_func);
78005c
   grd_session_vnc_attach_source (session_vnc);
78005c
 
78005c
   init_vnc_session (session_vnc);
359730
@@ -632,6 +698,8 @@ grd_session_vnc_dispose (GObject *object)
78005c
 
78005c
   g_assert (!session_vnc->rfb_screen);
78005c
 
78005c
+  g_clear_pointer (&session_vnc->socket_grabs, g_list_free);
78005c
+
78005c
   g_clear_pointer (&session_vnc->pressed_keys, g_hash_table_unref);
78005c
 
78005c
   G_OBJECT_CLASS (grd_session_vnc_parent_class)->dispose (object);
78005c
diff --git a/src/grd-session-vnc.h b/src/grd-session-vnc.h
359730
index 14b5d12..46a8579 100644
78005c
--- a/src/grd-session-vnc.h
78005c
+++ b/src/grd-session-vnc.h
359730
@@ -36,6 +36,9 @@ G_DECLARE_FINAL_TYPE (GrdSessionVnc,
78005c
                       GRD, SESSION_VNC,
78005c
                       GrdSession);
78005c
 
78005c
+typedef gboolean (* GrdVncSocketGrabFunc) (GrdSessionVnc  *session_vnc,
78005c
+                                           GError        **error);
78005c
+
78005c
 GrdSessionVnc *grd_session_vnc_new (GrdVncServer      *vnc_server,
78005c
                                     GSocketConnection *connection);
78005c
 
359730
@@ -53,6 +56,18 @@ void grd_session_vnc_move_cursor (GrdSessionVnc *session_vnc,
359730
                                   int            x,
359730
                                   int            y);
78005c
 
78005c
+int grd_session_vnc_get_fd (GrdSessionVnc *session_vnc);
78005c
+
78005c
 int grd_session_vnc_get_framebuffer_stride (GrdSessionVnc *session_vnc);
78005c
 
78005c
+rfbClientPtr grd_session_vnc_get_rfb_client (GrdSessionVnc *session_vnc);
78005c
+
78005c
+void grd_session_vnc_grab_socket (GrdSessionVnc        *session_vnc,
78005c
+                                  GrdVncSocketGrabFunc  grab_func);
78005c
+
78005c
+void grd_session_vnc_ungrab_socket (GrdSessionVnc        *session_vnc,
78005c
+                                    GrdVncSocketGrabFunc  grab_func);
78005c
+
78005c
+GrdVncServer * grd_session_vnc_get_vnc_server (GrdSessionVnc *session_vnc);
78005c
+
78005c
 #endif /* GRD_SESSION_VNC_H */
78005c
diff --git a/src/grd-settings.c b/src/grd-settings.c
359730
index bdf8211..7324310 100644
78005c
--- a/src/grd-settings.c
78005c
+++ b/src/grd-settings.c
359730
@@ -48,6 +48,7 @@ struct _GrdSettings
78005c
     gboolean view_only;
78005c
     GrdVncAuthMethod auth_method;
359730
     int port;
78005c
+    GrdVncEncryption encryption;
78005c
   } vnc;
78005c
 };
78005c
 
359730
@@ -120,6 +121,12 @@ grd_settings_get_vnc_auth_method (GrdSettings *settings)
359730
     return settings->vnc.auth_method;
78005c
 }
78005c
 
78005c
+GrdVncEncryption
78005c
+grd_settings_get_vnc_encryption (GrdSettings *settings)
78005c
+{
78005c
+  return settings->vnc.encryption;
78005c
+}
78005c
+
78005c
 static void
78005c
 update_vnc_view_only (GrdSettings *settings)
78005c
 {
359730
@@ -134,6 +141,13 @@ update_vnc_auth_method (GrdSettings *settings)
78005c
                                                    "auth-method");
78005c
 }
78005c
 
78005c
+static void
78005c
+update_vnc_encryption (GrdSettings *settings)
78005c
+{
78005c
+  settings->vnc.encryption = g_settings_get_flags (settings->vnc.settings,
78005c
+                                                   "encryption");
78005c
+}
78005c
+
78005c
 static void
78005c
 on_vnc_settings_changed (GSettings   *vnc_settings,
78005c
                          const char  *key,
359730
@@ -149,6 +163,11 @@ on_vnc_settings_changed (GSettings   *vnc_settings,
78005c
       update_vnc_auth_method (settings);
78005c
       g_signal_emit (settings, signals[VNC_AUTH_METHOD_CHANGED], 0);
78005c
     }
78005c
+  else if (strcmp (key, "encryption") == 0)
78005c
+    {
78005c
+      update_vnc_encryption (settings);
78005c
+      g_signal_emit (settings, signals[VNC_ENCRYPTION_CHANGED], 0);
78005c
+    }
78005c
 }
78005c
 
78005c
 static void
359730
@@ -172,6 +191,8 @@ grd_settings_init (GrdSettings *settings)
78005c
   update_vnc_auth_method (settings);
359730
 
359730
   settings->vnc.port = GRD_VNC_SERVER_PORT;
359730
+
78005c
+  update_vnc_encryption (settings);
78005c
 }
78005c
 
78005c
 static void
359730
@@ -195,4 +216,11 @@ grd_settings_class_init (GrdSettingsClass *klass)
78005c
                   0,
78005c
                   NULL, NULL, NULL,
78005c
                   G_TYPE_NONE, 0);
78005c
+  signals[VNC_ENCRYPTION_CHANGED] =
78005c
+    g_signal_new ("vnc-encryption-changed",
78005c
+                  G_TYPE_FROM_CLASS (klass),
78005c
+                  G_SIGNAL_RUN_LAST,
78005c
+                  0,
78005c
+                  NULL, NULL, NULL,
78005c
+                  G_TYPE_NONE, 0);
78005c
 }
78005c
diff --git a/src/grd-settings.h b/src/grd-settings.h
359730
index e4e0c09..0575ec1 100644
78005c
--- a/src/grd-settings.h
78005c
+++ b/src/grd-settings.h
359730
@@ -45,4 +45,6 @@ gboolean grd_settings_get_vnc_view_only (GrdSettings *settings);
78005c
 
78005c
 GrdVncAuthMethod grd_settings_get_vnc_auth_method (GrdSettings *settings);
78005c
 
78005c
+GrdVncEncryption grd_settings_get_vnc_encryption (GrdSettings *settings);
78005c
+
78005c
 #endif /* GRD_SETTINGS_H */
78005c
diff --git a/src/grd-vnc-server.c b/src/grd-vnc-server.c
359730
index a6d95cb..f9c68db 100644
78005c
--- a/src/grd-vnc-server.c
78005c
+++ b/src/grd-vnc-server.c
78005c
@@ -24,11 +24,13 @@
78005c
 
78005c
 #include "grd-vnc-server.h"
78005c
 
78005c
+#include <rfb/rfb.h>
78005c
 #include <gio/gio.h>
78005c
 #include <rfb/rfb.h>
78005c
 
78005c
 #include "grd-context.h"
78005c
 #include "grd-session-vnc.h"
78005c
+#include "grd-vnc-tls.h"
78005c
 
78005c
 
359730
 enum
359730
@@ -130,6 +132,43 @@ on_incoming (GSocketService    *service,
78005c
   return TRUE;
78005c
 }
78005c
 
78005c
+static void
78005c
+sync_encryption_settings (GrdVncServer *vnc_server)
78005c
+{
78005c
+  GrdSettings *settings = grd_context_get_settings (vnc_server->context);
78005c
+  rfbSecurityHandler *tls_security_handler;
78005c
+  GrdVncEncryption encryption;
78005c
+
78005c
+  tls_security_handler = grd_vnc_tls_get_security_handler ();
78005c
+  encryption = grd_settings_get_vnc_encryption (settings);
78005c
+
78005c
+  if (encryption == (GRD_VNC_ENCRYPTION_NONE | GRD_VNC_ENCRYPTION_TLS_ANON))
78005c
+    {
78005c
+      rfbRegisterSecurityHandler (tls_security_handler);
78005c
+      rfbUnregisterChannelSecurityHandler (tls_security_handler);
78005c
+    }
78005c
+  else if (encryption == GRD_VNC_ENCRYPTION_NONE)
78005c
+    {
78005c
+      rfbUnregisterSecurityHandler (tls_security_handler);
78005c
+      rfbUnregisterChannelSecurityHandler (tls_security_handler);
78005c
+    }
78005c
+  else
78005c
+    {
78005c
+      if (encryption != GRD_VNC_ENCRYPTION_TLS_ANON)
78005c
+        g_warning ("Invalid VNC encryption setting, falling back to TLS-ANON");
78005c
+
78005c
+      rfbRegisterChannelSecurityHandler (tls_security_handler);
78005c
+      rfbUnregisterSecurityHandler (tls_security_handler);
78005c
+    }
78005c
+}
78005c
+
78005c
+static void
78005c
+on_vnc_encryption_changed (GrdSettings  *settings,
78005c
+                           GrdVncServer *vnc_server)
78005c
+{
78005c
+  sync_encryption_settings (vnc_server);
78005c
+}
78005c
+
78005c
 gboolean
78005c
 grd_vnc_server_start (GrdVncServer  *vnc_server,
78005c
                       GError       **error)
359730
@@ -220,12 +259,18 @@ static void
78005c
 grd_vnc_server_constructed (GObject *object)
78005c
 {
78005c
   GrdVncServer *vnc_server = GRD_VNC_SERVER (object);
78005c
+  GrdSettings *settings = grd_context_get_settings (vnc_server->context);
78005c
 
78005c
   if (grd_context_get_debug_flags (vnc_server->context) & GRD_DEBUG_VNC)
78005c
     rfbLogEnable (1);
78005c
   else
78005c
     rfbLogEnable (0);
78005c
 
78005c
+  g_signal_connect (settings, "vnc-encryption-changed",
78005c
+                    G_CALLBACK (on_vnc_encryption_changed),
78005c
+                    vnc_server);
78005c
+  sync_encryption_settings (vnc_server);
78005c
+
78005c
   G_OBJECT_CLASS (grd_vnc_server_parent_class)->constructed (object);
78005c
 }
78005c
 
78005c
diff --git a/src/grd-vnc-tls.c b/src/grd-vnc-tls.c
78005c
new file mode 100644
359730
index 0000000..ec4758e
78005c
--- /dev/null
78005c
+++ b/src/grd-vnc-tls.c
78005c
@@ -0,0 +1,444 @@
78005c
+/*
78005c
+ * Copyright (C) 2018 Red Hat Inc.
78005c
+ *
78005c
+ * This program is free software; you can redistribute it and/or
78005c
+ * modify it under the terms of the GNU General Public License as
78005c
+ * published by the Free Software Foundation; either version 2 of the
78005c
+ * License, or (at your option) any later version.
78005c
+ *
78005c
+ * This program is distributed in the hope that it will be useful, but
78005c
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
78005c
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
78005c
+ * General Public License for more details.
78005c
+ *
78005c
+ * You should have received a copy of the GNU General Public License
78005c
+ * along with this program; if not, write to the Free Software
78005c
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
78005c
+ * 02111-1307, USA.
78005c
+ *
78005c
+ */
78005c
+
78005c
+#include "grd-vnc-tls.h"
78005c
+
78005c
+#include <errno.h>
78005c
+#include <glib.h>
78005c
+#include <gnutls/gnutls.h>
78005c
+#include <rfb/rfb.h>
78005c
+
78005c
+#include "grd-session-vnc.h"
78005c
+#include "grd-vnc-server.h"
78005c
+
78005c
+typedef struct _GrdVncTlsContext
78005c
+{
78005c
+  gnutls_anon_server_credentials_t anon_credentials;
78005c
+  gnutls_dh_params_t dh_params;
78005c
+} GrdVncTlsContext;
78005c
+
78005c
+typedef enum _GrdTlsHandshakeState
78005c
+{
78005c
+  GRD_TLS_HANDSHAKE_STATE_INIT,
78005c
+  GRD_TLS_HANDSHAKE_STATE_DURING,
78005c
+  GRD_TLS_HANDSHAKE_STATE_FINISHED
78005c
+} GrdTlsHandshakeState;
78005c
+
78005c
+typedef struct _GrdVncTlsSession
78005c
+{
78005c
+  GrdVncTlsContext *tls_context;
78005c
+
78005c
+  int fd;
78005c
+
78005c
+  gnutls_session_t tls_session;
78005c
+  GrdTlsHandshakeState handshake_state;
78005c
+
78005c
+  char *peek_buffer;
78005c
+  int peek_buffer_size;
78005c
+  int peek_buffer_len;
78005c
+} GrdVncTlsSession;
78005c
+
78005c
+static gboolean
78005c
+tls_handshake_grab_func (GrdSessionVnc  *session_vnc,
78005c
+                         GError        **error);
78005c
+
78005c
+static GrdVncTlsContext *
78005c
+grd_vnc_tls_context_new (void)
78005c
+{
78005c
+  GrdVncTlsContext *tls_context;
78005c
+  const unsigned int dh_bits = 1024;
78005c
+
78005c
+  tls_context = g_new0 (GrdVncTlsContext, 1);
78005c
+
78005c
+  gnutls_global_init ();
78005c
+
78005c
+  gnutls_anon_allocate_server_credentials (&tls_context->anon_credentials);
78005c
+
78005c
+  gnutls_dh_params_init (&tls_context->dh_params);
78005c
+  gnutls_dh_params_generate2 (tls_context->dh_params, dh_bits);
78005c
+
78005c
+  gnutls_anon_set_server_dh_params (tls_context->anon_credentials,
78005c
+                                    tls_context->dh_params);
78005c
+
78005c
+  return tls_context;
78005c
+}
78005c
+
78005c
+static void
78005c
+grd_vnc_tls_context_free (GrdVncTlsContext *tls_context)
78005c
+{
78005c
+  gnutls_dh_params_deinit (tls_context->dh_params);
78005c
+  gnutls_anon_free_server_credentials (tls_context->anon_credentials);
78005c
+  gnutls_global_deinit ();
78005c
+}
78005c
+
78005c
+GrdVncTlsContext *
78005c
+ensure_tls_context (GrdVncServer *vnc_server)
78005c
+{
78005c
+  GrdVncTlsContext *tls_context;
78005c
+
78005c
+  tls_context = g_object_get_data (G_OBJECT (vnc_server), "vnc-tls-context");
78005c
+  if (!tls_context)
78005c
+    {
78005c
+      tls_context = grd_vnc_tls_context_new ();
78005c
+      g_object_set_data_full (G_OBJECT (vnc_server), "vnc-tls-context",
78005c
+                              tls_context,
78005c
+                              (GDestroyNotify) grd_vnc_tls_context_free);
78005c
+    }
78005c
+
78005c
+  return tls_context;
78005c
+}
78005c
+
78005c
+static gboolean
78005c
+perform_anon_tls_handshake (GrdVncTlsSession  *tls_session,
78005c
+                            GError           **error)
78005c
+{
78005c
+  GrdVncTlsContext *tls_context = tls_session->tls_context;
78005c
+  const char kx_priority[] = "NORMAL:+ANON-DH";
78005c
+  int ret;
78005c
+
78005c
+  gnutls_init (&tls_session->tls_session, GNUTLS_SERVER | GNUTLS_NO_SIGNAL);
78005c
+
78005c
+  gnutls_set_default_priority (tls_session->tls_session);
78005c
+  gnutls_priority_set_direct (tls_session->tls_session, kx_priority, NULL);
78005c
+
78005c
+  gnutls_credentials_set (tls_session->tls_session,
78005c
+                          GNUTLS_CRD_ANON,
78005c
+                          tls_context->anon_credentials);
78005c
+  gnutls_transport_set_ptr (tls_session->tls_session,
78005c
+                            GINT_TO_POINTER (tls_session->fd));
78005c
+
78005c
+  ret = gnutls_handshake (tls_session->tls_session);
78005c
+  if (ret != GNUTLS_E_SUCCESS && !gnutls_error_is_fatal (ret))
78005c
+    {
78005c
+      tls_session->handshake_state = GRD_TLS_HANDSHAKE_STATE_DURING;
78005c
+      return TRUE;
78005c
+    }
78005c
+
78005c
+  if (ret != GNUTLS_E_SUCCESS)
78005c
+    {
78005c
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
78005c
+                   "%s", gnutls_strerror (ret));
78005c
+      gnutls_deinit (tls_session->tls_session);
78005c
+      tls_session->tls_session = NULL;
78005c
+      return FALSE;
78005c
+    }
78005c
+
78005c
+  tls_session->handshake_state = GRD_TLS_HANDSHAKE_STATE_FINISHED;
78005c
+  return TRUE;
78005c
+}
78005c
+
78005c
+static gboolean
78005c
+continue_tls_handshake (GrdVncTlsSession  *tls_session,
78005c
+                        GError           **error)
78005c
+{
78005c
+  int ret;
78005c
+
78005c
+  ret = gnutls_handshake (tls_session->tls_session);
78005c
+  if (ret != GNUTLS_E_SUCCESS && !gnutls_error_is_fatal (ret))
78005c
+    return TRUE;
78005c
+
78005c
+  if (ret != GNUTLS_E_SUCCESS)
78005c
+    {
78005c
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
78005c
+                   "%s", gnutls_strerror (ret));
78005c
+      gnutls_deinit (tls_session->tls_session);
78005c
+      tls_session->tls_session = NULL;
78005c
+      return FALSE;
78005c
+    }
78005c
+
78005c
+  tls_session->handshake_state = GRD_TLS_HANDSHAKE_STATE_FINISHED;
78005c
+  return TRUE;
78005c
+}
78005c
+
78005c
+static void
78005c
+grd_vnc_tls_session_free (GrdVncTlsSession *tls_session)
78005c
+{
78005c
+  g_clear_pointer (&tls_session->peek_buffer, g_free);
359730
+  g_clear_pointer (&tls_session->tls_session, gnutls_deinit);
78005c
+  g_free (tls_session);
78005c
+}
78005c
+
78005c
+static GrdVncTlsSession *
78005c
+grd_vnc_tls_session_from_vnc_session (GrdSessionVnc *session_vnc)
78005c
+{
78005c
+  return g_object_get_data (G_OBJECT (session_vnc), "vnc-tls-session");
78005c
+}
78005c
+
78005c
+static int
78005c
+do_read (GrdVncTlsSession *tls_session,
78005c
+         char             *buf,
78005c
+         int               len)
78005c
+{
78005c
+  do
78005c
+    {
78005c
+      int ret;
78005c
+
78005c
+      ret = gnutls_record_recv (tls_session->tls_session, buf, len);
78005c
+      if (ret == GNUTLS_E_AGAIN ||
78005c
+          ret == GNUTLS_E_INTERRUPTED)
78005c
+        {
78005c
+          continue;
78005c
+        }
78005c
+      else if (ret < 0)
78005c
+        {
78005c
+          g_debug ("gnutls_record_recv failed: %s", gnutls_strerror (ret));
78005c
+          errno = EIO;
78005c
+          return -1;
78005c
+        }
78005c
+      else
78005c
+        {
78005c
+          return ret;
78005c
+        }
78005c
+    }
78005c
+  while (TRUE);
78005c
+}
78005c
+
78005c
+static int
78005c
+grd_vnc_tls_read_from_socket (rfbClientPtr  rfb_client,
78005c
+                              char         *buf,
78005c
+                              int           len)
78005c
+{
78005c
+  GrdSessionVnc *session_vnc = rfb_client->screen->screenData;
78005c
+  GrdVncTlsSession *tls_session =
78005c
+    grd_vnc_tls_session_from_vnc_session (session_vnc);
78005c
+  int to_read = len;
78005c
+  int len_read = 0;
78005c
+
78005c
+  if (to_read < tls_session->peek_buffer_len)
78005c
+    {
78005c
+      memcpy (buf, tls_session->peek_buffer, to_read);
78005c
+      memmove (buf,
78005c
+               tls_session->peek_buffer + to_read,
78005c
+               tls_session->peek_buffer_len - to_read);
78005c
+      len_read = to_read;
78005c
+      to_read = 0;
78005c
+    }
78005c
+  else
78005c
+    {
78005c
+      memcpy (buf,
78005c
+              tls_session->peek_buffer,
78005c
+              tls_session->peek_buffer_len);
78005c
+      to_read -= tls_session->peek_buffer_len;
78005c
+      len_read = tls_session->peek_buffer_len;
78005c
+
78005c
+      g_clear_pointer (&tls_session->peek_buffer,
78005c
+                       g_free);
78005c
+      tls_session->peek_buffer_len = 0;
78005c
+      tls_session->peek_buffer_size = 0;
78005c
+    }
78005c
+
78005c
+  if (to_read > 0)
78005c
+    {
78005c
+      int ret;
78005c
+
78005c
+      ret = do_read (tls_session, buf + len_read, to_read);
78005c
+      if (ret == -1)
78005c
+        return -1;
78005c
+
78005c
+      len_read += ret;
78005c
+    }
78005c
+
78005c
+  return len_read;
78005c
+}
78005c
+
78005c
+static int
78005c
+grd_vnc_tls_peek_at_socket (rfbClientPtr  rfb_client,
78005c
+                            char         *buf,
78005c
+                            int           len)
78005c
+{
78005c
+  GrdSessionVnc *session_vnc = rfb_client->screen->screenData;
78005c
+  GrdVncTlsSession *tls_session =
78005c
+    grd_vnc_tls_session_from_vnc_session (session_vnc);
78005c
+  int peekable_len;
78005c
+
78005c
+  if (tls_session->peek_buffer_len < len)
78005c
+    {
78005c
+      int ret;
78005c
+
78005c
+      if (len > tls_session->peek_buffer_size)
78005c
+        {
78005c
+          tls_session->peek_buffer = g_renew (char,
78005c
+                                              tls_session->peek_buffer,
78005c
+                                              len);
78005c
+          tls_session->peek_buffer_size = len;
78005c
+        }
78005c
+
78005c
+      ret = do_read (tls_session,
78005c
+                     tls_session->peek_buffer + tls_session->peek_buffer_len,
78005c
+                     len - tls_session->peek_buffer_len);
78005c
+      if (ret == -1)
78005c
+        return -1;
78005c
+
78005c
+      tls_session->peek_buffer_len += ret;
78005c
+    }
78005c
+
78005c
+  peekable_len = MIN (len, tls_session->peek_buffer_len);
78005c
+  memcpy (buf, tls_session->peek_buffer, peekable_len);
78005c
+
78005c
+  return peekable_len;
78005c
+}
78005c
+
78005c
+static rfbBool
78005c
+grd_vnc_tls_has_pending_on_socket (rfbClientPtr rfb_client)
78005c
+{
78005c
+  GrdSessionVnc *session_vnc = rfb_client->screen->screenData;
78005c
+  GrdVncTlsSession *tls_session =
78005c
+    grd_vnc_tls_session_from_vnc_session (session_vnc);
78005c
+
78005c
+  if (tls_session->peek_buffer_len > 0)
78005c
+    return TRUE;
78005c
+
78005c
+  if (gnutls_record_check_pending (tls_session->tls_session) > 0)
78005c
+    return TRUE;
78005c
+
78005c
+  return FALSE;
78005c
+}
78005c
+
78005c
+static int
78005c
+grd_vnc_tls_write_to_socket (rfbClientPtr  rfb_client,
78005c
+                             const char   *buf,
78005c
+                             int           len)
78005c
+{
78005c
+  GrdSessionVnc *session_vnc = rfb_client->screen->screenData;
78005c
+  GrdVncTlsSession *tls_session =
78005c
+    grd_vnc_tls_session_from_vnc_session (session_vnc);
78005c
+
78005c
+  do
78005c
+    {
78005c
+      int ret;
78005c
+
78005c
+      ret = gnutls_record_send (tls_session->tls_session, buf, len);
78005c
+      if (ret == GNUTLS_E_AGAIN ||
78005c
+          ret == GNUTLS_E_INTERRUPTED)
78005c
+        {
78005c
+          continue;
78005c
+        }
78005c
+      else if (ret < 0)
78005c
+        {
78005c
+          g_debug ("gnutls_record_send failed: %s", gnutls_strerror (ret));
78005c
+          errno = EIO;
78005c
+          return -1;
78005c
+        }
78005c
+      else
78005c
+        {
78005c
+          return ret;
78005c
+        }
78005c
+    }
78005c
+  while (TRUE);
78005c
+}
78005c
+
78005c
+static gboolean
78005c
+perform_handshake (GrdSessionVnc  *session_vnc,
78005c
+                   GError        **error)
78005c
+{
78005c
+  GrdVncTlsSession *tls_session =
78005c
+    grd_vnc_tls_session_from_vnc_session (session_vnc);
78005c
+
78005c
+  switch (tls_session->handshake_state)
78005c
+    {
78005c
+    case GRD_TLS_HANDSHAKE_STATE_INIT:
78005c
+      if (!perform_anon_tls_handshake (tls_session, error))
78005c
+        return FALSE;
78005c
+      break;
78005c
+    case GRD_TLS_HANDSHAKE_STATE_DURING:
78005c
+      if (!continue_tls_handshake (tls_session, error))
78005c
+        return FALSE;
78005c
+      break;
78005c
+    case GRD_TLS_HANDSHAKE_STATE_FINISHED:
78005c
+      break;
78005c
+    }
78005c
+
78005c
+  switch (tls_session->handshake_state)
78005c
+    {
78005c
+    case GRD_TLS_HANDSHAKE_STATE_INIT:
78005c
+      break;
78005c
+    case GRD_TLS_HANDSHAKE_STATE_DURING:
78005c
+      break;
78005c
+    case GRD_TLS_HANDSHAKE_STATE_FINISHED:
78005c
+      grd_session_vnc_ungrab_socket (session_vnc, tls_handshake_grab_func);
78005c
+      rfbSendSecurityTypeList (grd_session_vnc_get_rfb_client (session_vnc),
78005c
+                               RFB_SECURITY_TAG_CHANNEL);
78005c
+      break;
78005c
+    }
78005c
+
78005c
+  return TRUE;
78005c
+}
78005c
+
78005c
+static gboolean
78005c
+tls_handshake_grab_func (GrdSessionVnc  *session_vnc,
78005c
+                         GError        **error)
78005c
+{
78005c
+  g_autoptr (GError) handshake_error = NULL;
78005c
+
78005c
+  if (!perform_handshake (session_vnc, &handshake_error))
78005c
+    {
78005c
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
78005c
+                   "TLS handshake failed: %s", handshake_error->message);
78005c
+      return FALSE;
78005c
+    }
78005c
+
78005c
+  return TRUE;
78005c
+}
78005c
+
78005c
+static void
78005c
+rfb_tls_security_handler (rfbClientPtr rfb_client)
78005c
+{
78005c
+  GrdSessionVnc *session_vnc = rfb_client->screen->screenData;
78005c
+  GrdVncTlsSession *tls_session;
78005c
+  g_autoptr(GError) error = NULL;
78005c
+
78005c
+  tls_session = grd_vnc_tls_session_from_vnc_session (session_vnc);
78005c
+  if (!tls_session)
78005c
+    {
78005c
+      GrdVncServer *vnc_server = grd_session_vnc_get_vnc_server (session_vnc);
78005c
+
78005c
+      tls_session = g_new0 (GrdVncTlsSession, 1);
78005c
+      tls_session->fd = grd_session_vnc_get_fd (session_vnc);
78005c
+      tls_session->tls_context = ensure_tls_context (vnc_server);
78005c
+      g_object_set_data_full (G_OBJECT (session_vnc), "vnc-tls-session",
78005c
+                              tls_session,
78005c
+                              (GDestroyNotify) grd_vnc_tls_session_free);
78005c
+
78005c
+      rfb_client->readFromSocket = grd_vnc_tls_read_from_socket;
78005c
+      rfb_client->peekAtSocket = grd_vnc_tls_peek_at_socket;
78005c
+      rfb_client->hasPendingOnSocket = grd_vnc_tls_has_pending_on_socket;
78005c
+      rfb_client->writeToSocket = grd_vnc_tls_write_to_socket;
78005c
+
78005c
+      grd_session_vnc_grab_socket (session_vnc, tls_handshake_grab_func);
78005c
+    }
78005c
+
78005c
+  if (!perform_handshake (session_vnc, &error))
78005c
+    {
78005c
+      g_warning ("TLS handshake failed: %s", error->message);
78005c
+      rfbCloseClient (rfb_client);
78005c
+    }
78005c
+}
78005c
+
78005c
+static rfbSecurityHandler anon_tls_security_handler = {
78005c
+  .type = rfbTLS,
78005c
+  .handler = rfb_tls_security_handler,
78005c
+  .securityTags = RFB_SECURITY_TAG_CHANNEL,
78005c
+};
78005c
+
78005c
+rfbSecurityHandler *
78005c
+grd_vnc_tls_get_security_handler (void)
78005c
+{
78005c
+  return &anon_tls_security_handler;
78005c
+}
78005c
diff --git a/src/grd-vnc-tls.h b/src/grd-vnc-tls.h
78005c
new file mode 100644
78005c
index 0000000..135ef8c
78005c
--- /dev/null
78005c
+++ b/src/grd-vnc-tls.h
78005c
@@ -0,0 +1,28 @@
78005c
+/*
78005c
+ * Copyright (C) 2018 Red Hat Inc.
78005c
+ *
78005c
+ * This program is free software; you can redistribute it and/or
78005c
+ * modify it under the terms of the GNU General Public License as
78005c
+ * published by the Free Software Foundation; either version 2 of the
78005c
+ * License, or (at your option) any later version.
78005c
+ *
78005c
+ * This program is distributed in the hope that it will be useful, but
78005c
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
78005c
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
78005c
+ * General Public License for more details.
78005c
+ *
78005c
+ * You should have received a copy of the GNU General Public License
78005c
+ * along with this program; if not, write to the Free Software
78005c
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
78005c
+ * 02111-1307, USA.
78005c
+ *
78005c
+ */
78005c
+
78005c
+#ifndef GRD_VNC_TLS_H
78005c
+#define GRD_VNC_TLS_H
78005c
+
78005c
+#include <rfb/rfb.h>
78005c
+
78005c
+rfbSecurityHandler * grd_vnc_tls_get_security_handler (void);
78005c
+
78005c
+#endif /* GRD_VNC_TLS_H */
78005c
diff --git a/src/meson.build b/src/meson.build
359730
index 0f76fab..9d2f1ce 100644
78005c
--- a/src/meson.build
78005c
+++ b/src/meson.build
359730
@@ -21,6 +21,8 @@ daemon_sources = files([
78005c
   'grd-vnc-pipewire-stream.h',
78005c
   'grd-vnc-server.c',
78005c
   'grd-vnc-server.h',
78005c
+  'grd-vnc-tls.c',
78005c
+  'grd-vnc-tls.h',
78005c
 ])
78005c
 
78005c
 gen_daemon_sources = []
359730
@@ -51,7 +53,8 @@ executable('gnome-remote-desktop-daemon',
78005c
                           pipewire_dep,
78005c
                           libvncserver_dep,
78005c
                           libsecret_dep,
78005c
-                          libnotify_dep],
78005c
+                          libnotify_dep,
78005c
+                          gnutls_dep],
78005c
            include_directories: [configinc],
78005c
            install: true,
78005c
            install_dir: libexecdir)
359730
diff --git a/src/org.gnome.desktop.remote-desktop.gschema.xml.in b/src/org.gnome.desktop.remote-desktop.gschema.xml.in
78005c
index a5c2022..846e65b 100644
359730
--- a/src/org.gnome.desktop.remote-desktop.gschema.xml.in
359730
+++ b/src/org.gnome.desktop.remote-desktop.gschema.xml.in
78005c
@@ -23,5 +23,15 @@
78005c
 	 * password - by requiring the remote client to provide a known password
78005c
       </description>
78005c
     </key>
78005c
+    <key name='encryption' flags='org.gnome.desktop.remote-desktop.GrdVncEncryption'>
78005c
+      <default>['tls-anon']</default>
78005c
+      <summary>Allowed encryption method to use</summary>
78005c
+      <description>
78005c
+	Allowed encryption methods. Includes the following:
78005c
+
78005c
+	 * none     - no encryption
78005c
+	 * tls-anon - anonymous (unauthenticated) TLS
78005c
+      </description>
78005c
+    </key>
78005c
   </schema>
78005c
 </schemalist>
78005c
-- 
359730
2.26.2
359730
359730
359730
From aa54aeb43938250a4d27a99e62eb5628d3b55076 Mon Sep 17 00:00:00 2001
359730
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
359730
Date: Wed, 27 Nov 2019 11:02:09 +0100
359730
Subject: [PATCH 2/7] session-vnc: Add paused/resumed signals
359730
359730
Paused is when the socket sourec is detached, and resumed when attached.
359730
Meant to be used by the TLS channel security to a attach/detach
359730
out-of-socket source.
359730
---
359730
 src/grd-session-vnc.c | 72 ++++++++++++++++++++++++++++++++++++++-----
359730
 1 file changed, 65 insertions(+), 7 deletions(-)
359730
359730
diff --git a/src/grd-session-vnc.c b/src/grd-session-vnc.c
359730
index 0cc2ea2..076e25f 100644
359730
--- a/src/grd-session-vnc.c
359730
+++ b/src/grd-session-vnc.c
359730
@@ -40,14 +40,27 @@
359730
 #define BGRX_SAMPLES_PER_PIXEL 3
359730
 #define BGRX_BYTES_PER_PIXEL 4
359730
 
359730
+enum
359730
+{
359730
+  PAUSED,
359730
+  RESUMED,
359730
+
359730
+  N_SIGNALS
359730
+};
359730
+
359730
+static guint signals[N_SIGNALS];
359730
+
359730
 struct _GrdSessionVnc
359730
 {
359730
   GrdSession parent;
359730
 
359730
   GrdVncServer *vnc_server;
359730
   GSocketConnection *connection;
359730
+
359730
   GList *socket_grabs;
359730
   GSource *source;
359730
+  gboolean is_paused;
359730
+
359730
   rfbScreenInfoPtr rfb_screen;
359730
   rfbClientPtr rfb_client;
359730
 
359730
@@ -73,7 +86,7 @@ struct _GrdSessionVnc
359730
 G_DEFINE_TYPE (GrdSessionVnc, grd_session_vnc, GRD_TYPE_SESSION);
359730
 
359730
 static void
359730
-grd_session_vnc_detach_source (GrdSessionVnc *session_vnc);
359730
+grd_session_vnc_pause (GrdSessionVnc *session_vnc);
359730
 
359730
 static gboolean
359730
 close_session_idle (gpointer user_data);
359730
@@ -212,7 +225,8 @@ handle_client_gone (rfbClientPtr rfb_client)
359730
 
359730
   g_debug ("VNC client gone");
359730
 
359730
-  grd_session_vnc_detach_source (session_vnc);
359730
+  grd_session_vnc_pause (session_vnc);
359730
+
359730
   maybe_queue_close_session_idle (session_vnc);
359730
 }
359730
 
359730
@@ -280,7 +294,7 @@ handle_new_client (rfbClientPtr rfb_client)
359730
                               session_vnc->prompt_cancellable,
359730
                               prompt_response_callback,
359730
                               session_vnc);
359730
-      grd_session_vnc_detach_source (session_vnc);
359730
+      grd_session_vnc_pause (session_vnc);
359730
       return RFB_CLIENT_ON_HOLD;
359730
     case GRD_VNC_AUTH_METHOD_PASSWORD:
359730
       session_vnc->rfb_screen->passwordCheck = check_rfb_password;
359730
@@ -498,7 +512,7 @@ check_rfb_password (rfbClientPtr  rfb_client,
359730
   if (memcmp (challenge_encrypted, response_encrypted, len) == 0)
359730
     {
359730
       grd_session_start (GRD_SESSION (session_vnc));
359730
-      grd_session_vnc_detach_source (session_vnc);
359730
+      grd_session_vnc_pause (session_vnc);
359730
       return TRUE;
359730
     }
359730
   else
359730
@@ -668,6 +682,36 @@ grd_session_vnc_detach_source (GrdSessionVnc *session_vnc)
359730
   g_clear_pointer (&session_vnc->source, g_source_destroy);
359730
 }
359730
 
359730
+gboolean
359730
+grd_session_vnc_is_paused (GrdSessionVnc *session_vnc)
359730
+{
359730
+  return session_vnc->is_paused;
359730
+}
359730
+
359730
+static void
359730
+grd_session_vnc_pause (GrdSessionVnc *session_vnc)
359730
+{
359730
+  if (grd_session_vnc_is_paused (session_vnc))
359730
+    return;
359730
+
359730
+  session_vnc->is_paused = TRUE;
359730
+
359730
+  grd_session_vnc_detach_source (session_vnc);
359730
+  g_signal_emit (session_vnc, signals[PAUSED], 0);
359730
+}
359730
+
359730
+static void
359730
+grd_session_vnc_resume (GrdSessionVnc *session_vnc)
359730
+{
359730
+  if (!grd_session_vnc_is_paused (session_vnc))
359730
+    return;
359730
+
359730
+  session_vnc->is_paused = FALSE;
359730
+
359730
+  grd_session_vnc_attach_source (session_vnc);
359730
+  g_signal_emit (session_vnc, signals[RESUMED], 0);
359730
+}
359730
+
359730
 GrdSessionVnc *
359730
 grd_session_vnc_new (GrdVncServer      *vnc_server,
359730
                      GSocketConnection *connection)
359730
@@ -685,6 +729,7 @@ grd_session_vnc_new (GrdVncServer      *vnc_server,
359730
 
359730
   grd_session_vnc_grab_socket (session_vnc, vnc_socket_grab_func);
359730
   grd_session_vnc_attach_source (session_vnc);
359730
+  session_vnc->is_paused = FALSE;
359730
 
359730
   init_vnc_session (session_vnc);
359730
 
359730
@@ -714,7 +759,7 @@ grd_session_vnc_stop (GrdSession *session)
359730
 
359730
   g_clear_object (&session_vnc->pipewire_stream);
359730
 
359730
-  grd_session_vnc_detach_source (session_vnc);
359730
+  grd_session_vnc_pause (session_vnc);
359730
 
359730
   g_clear_object (&session_vnc->connection);
359730
   g_clear_pointer (&session_vnc->rfb_screen->frameBuffer, g_free);
359730
@@ -770,8 +815,8 @@ grd_session_vnc_stream_ready (GrdSession *session,
359730
                     G_CALLBACK (on_pipwire_stream_closed),
359730
                     session_vnc);
359730
 
359730
-  if (!session_vnc->source)
359730
-    grd_session_vnc_attach_source (session_vnc);
359730
+  if (grd_session_vnc_is_paused (session_vnc))
359730
+    grd_session_vnc_resume (session_vnc);
359730
 }
359730
 
359730
 static void
359730
@@ -790,4 +835,17 @@ grd_session_vnc_class_init (GrdSessionVncClass *klass)
359730
 
359730
   session_class->stop = grd_session_vnc_stop;
359730
   session_class->stream_ready = grd_session_vnc_stream_ready;
359730
+
359730
+  signals[PAUSED] = g_signal_new ("paused",
359730
+                                  G_TYPE_FROM_CLASS (klass),
359730
+                                  G_SIGNAL_RUN_LAST,
359730
+                                  0,
359730
+                                  NULL, NULL, NULL,
359730
+                                  G_TYPE_NONE, 0);
359730
+  signals[RESUMED] = g_signal_new ("resumed",
359730
+                                   G_TYPE_FROM_CLASS (klass),
359730
+                                   G_SIGNAL_RUN_LAST,
359730
+                                   0,
359730
+                                   NULL, NULL, NULL,
359730
+                                   G_TYPE_NONE, 0);
359730
 }
359730
-- 
359730
2.26.2
359730
359730
359730
From ed3d72cb8d08192831397903f0ba92f439751988 Mon Sep 17 00:00:00 2001
359730
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
359730
Date: Wed, 27 Nov 2019 11:03:46 +0100
359730
Subject: [PATCH 3/7] session-vnc: Add grd_session_vnc_dispatch() helper
359730
359730
To be used by the TLS channel security to dispatch when there is data
359730
available that is not visible to the socket source.
359730
---
359730
 src/grd-session-vnc.c | 26 ++++++++++++++++----------
359730
 src/grd-session-vnc.h |  2 ++
359730
 2 files changed, 18 insertions(+), 10 deletions(-)
359730
359730
diff --git a/src/grd-session-vnc.c b/src/grd-session-vnc.c
359730
index 076e25f..8b8ce1b 100644
359730
--- a/src/grd-session-vnc.c
359730
+++ b/src/grd-session-vnc.c
359730
@@ -622,6 +622,21 @@ vnc_socket_grab_func (GrdSessionVnc  *session_vnc,
359730
   return TRUE;
359730
 }
359730
 
359730
+void
359730
+grd_session_vnc_dispatch (GrdSessionVnc *session_vnc)
359730
+{
359730
+  GrdVncSocketGrabFunc grab_func;
359730
+  g_autoptr (GError) error = NULL;
359730
+
359730
+  grab_func = g_list_first (session_vnc->socket_grabs)->data;
359730
+  if (!grab_func (session_vnc, &error))
359730
+    {
359730
+      g_warning ("Error when reading socket: %s", error->message);
359730
+
359730
+      grd_session_stop (GRD_SESSION (session_vnc));
359730
+    }
359730
+}
359730
+
359730
 static gboolean
359730
 handle_socket_data (GSocket *socket,
359730
                     GIOCondition condition,
359730
@@ -638,16 +653,7 @@ handle_socket_data (GSocket *socket,
359730
     }
359730
   else if (condition & G_IO_IN)
359730
     {
359730
-      GrdVncSocketGrabFunc grab_func;
359730
-      g_autoptr (GError) error = NULL;
359730
-
359730
-      grab_func = g_list_first (session_vnc->socket_grabs)->data;
359730
-      if (!grab_func (session_vnc, &error))
359730
-        {
359730
-          g_warning ("Error when reading socket: %s", error->message);
359730
-
359730
-          grd_session_stop (session);
359730
-        }
359730
+      grd_session_vnc_dispatch (session_vnc);
359730
     }
359730
   else
359730
     {
359730
diff --git a/src/grd-session-vnc.h b/src/grd-session-vnc.h
359730
index 46a8579..910b00c 100644
359730
--- a/src/grd-session-vnc.h
359730
+++ b/src/grd-session-vnc.h
359730
@@ -68,6 +68,8 @@ void grd_session_vnc_grab_socket (GrdSessionVnc        *session_vnc,
359730
 void grd_session_vnc_ungrab_socket (GrdSessionVnc        *session_vnc,
359730
                                     GrdVncSocketGrabFunc  grab_func);
359730
 
359730
+void grd_session_vnc_dispatch (GrdSessionVnc *session_vnc);
359730
+
359730
 GrdVncServer * grd_session_vnc_get_vnc_server (GrdSessionVnc *session_vnc);
359730
 
359730
 #endif /* GRD_SESSION_VNC_H */
359730
-- 
359730
2.26.2
359730
359730
359730
From 44e6bec84a86064a7b3abbcbbcd07ebb525aca9f Mon Sep 17 00:00:00 2001
359730
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
359730
Date: Wed, 27 Nov 2019 11:05:13 +0100
359730
Subject: [PATCH 4/7] vnc/tls: Add some logging
359730
359730
Uses the log utility from libvncserver as it is related to the RFB
359730
protocol rather than the session itself.
359730
---
359730
 src/grd-vnc-tls.c | 9 +++++++++
359730
 1 file changed, 9 insertions(+)
359730
359730
diff --git a/src/grd-vnc-tls.c b/src/grd-vnc-tls.c
359730
index ec4758e..ac6c35f 100644
359730
--- a/src/grd-vnc-tls.c
359730
+++ b/src/grd-vnc-tls.c
359730
@@ -67,6 +67,7 @@ grd_vnc_tls_context_new (void)
359730
 
359730
   tls_context = g_new0 (GrdVncTlsContext, 1);
359730
 
359730
+  rfbLog ("TLS: Initializing gnutls context\n");
359730
   gnutls_global_init ();
359730
 
359730
   gnutls_anon_allocate_server_credentials (&tls_context->anon_credentials);
359730
@@ -127,6 +128,7 @@ perform_anon_tls_handshake (GrdVncTlsSession  *tls_session,
359730
   ret = gnutls_handshake (tls_session->tls_session);
359730
   if (ret != GNUTLS_E_SUCCESS && !gnutls_error_is_fatal (ret))
359730
     {
359730
+      rfbLog ("TLS: More handshake pending\n");
359730
       tls_session->handshake_state = GRD_TLS_HANDSHAKE_STATE_DURING;
359730
       return TRUE;
359730
     }
359730
@@ -140,6 +142,8 @@ perform_anon_tls_handshake (GrdVncTlsSession  *tls_session,
359730
       return FALSE;
359730
     }
359730
 
359730
+  rfbLog ("TLS: Handshake finished");
359730
+
359730
   tls_session->handshake_state = GRD_TLS_HANDSHAKE_STATE_FINISHED;
359730
   return TRUE;
359730
 }
359730
@@ -373,6 +377,7 @@ perform_handshake (GrdSessionVnc  *session_vnc,
359730
       break;
359730
     case GRD_TLS_HANDSHAKE_STATE_FINISHED:
359730
       grd_session_vnc_ungrab_socket (session_vnc, tls_handshake_grab_func);
359730
+      rfbLog ("TLS: Sending post-channel security security list\n");
359730
       rfbSendSecurityTypeList (grd_session_vnc_get_rfb_client (session_vnc),
359730
                                RFB_SECURITY_TAG_CHANNEL);
359730
       break;
359730
@@ -387,6 +392,7 @@ tls_handshake_grab_func (GrdSessionVnc  *session_vnc,
359730
 {
359730
   g_autoptr (GError) handshake_error = NULL;
359730
 
359730
+  rfbLog ("TLS: Continuing handshake\n");
359730
   if (!perform_handshake (session_vnc, &handshake_error))
359730
     {
359730
       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
359730
@@ -404,6 +410,8 @@ rfb_tls_security_handler (rfbClientPtr rfb_client)
359730
   GrdVncTlsSession *tls_session;
359730
   g_autoptr(GError) error = NULL;
359730
 
359730
+  rfbLog ("TLS: Setting up rfbClient for gnutls encrypted traffic\n");
359730
+
359730
   tls_session = grd_vnc_tls_session_from_vnc_session (session_vnc);
359730
   if (!tls_session)
359730
     {
359730
@@ -424,6 +432,7 @@ rfb_tls_security_handler (rfbClientPtr rfb_client)
359730
       grd_session_vnc_grab_socket (session_vnc, tls_handshake_grab_func);
359730
     }
359730
 
359730
+  rfbLog ("TLS: Performing handshake\n");
359730
   if (!perform_handshake (session_vnc, &error))
359730
     {
359730
       g_warning ("TLS handshake failed: %s", error->message);
359730
-- 
359730
2.26.2
359730
359730
359730
From fc07db3b6fafec47e02ff81f0f893dcaf64ba988 Mon Sep 17 00:00:00 2001
359730
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
359730
Date: Wed, 27 Nov 2019 11:07:40 +0100
359730
Subject: [PATCH 5/7] vnc/tls: Dispatch also when data is pending outside of
359730
 the socket
359730
359730
gnutls may have data available in its buffers, and we have our own peek
359730
buffer temporarly storing data later to be processed. This would missed
359730
by the socket source, as it wouldn't get any notification about it from
359730
epoll(). Deal with this by adding a custom source that dispatches as
359730
long as there is data to read in those buffers.
359730
---
359730
 src/grd-session-vnc.h |  2 +
359730
 src/grd-vnc-tls.c     | 92 ++++++++++++++++++++++++++++++++++++++++---
359730
 2 files changed, 88 insertions(+), 6 deletions(-)
359730
359730
diff --git a/src/grd-session-vnc.h b/src/grd-session-vnc.h
359730
index 910b00c..294860e 100644
359730
--- a/src/grd-session-vnc.h
359730
+++ b/src/grd-session-vnc.h
359730
@@ -68,6 +68,8 @@ void grd_session_vnc_grab_socket (GrdSessionVnc        *session_vnc,
359730
 void grd_session_vnc_ungrab_socket (GrdSessionVnc        *session_vnc,
359730
                                     GrdVncSocketGrabFunc  grab_func);
359730
 
359730
+gboolean grd_session_vnc_is_paused (GrdSessionVnc *session_vnc);
359730
+
359730
 void grd_session_vnc_dispatch (GrdSessionVnc *session_vnc);
359730
 
359730
 GrdVncServer * grd_session_vnc_get_vnc_server (GrdSessionVnc *session_vnc);
359730
diff --git a/src/grd-vnc-tls.c b/src/grd-vnc-tls.c
359730
index ac6c35f..8f65225 100644
359730
--- a/src/grd-vnc-tls.c
359730
+++ b/src/grd-vnc-tls.c
359730
@@ -41,6 +41,12 @@ typedef enum _GrdTlsHandshakeState
359730
   GRD_TLS_HANDSHAKE_STATE_FINISHED
359730
 } GrdTlsHandshakeState;
359730
 
359730
+typedef struct _PeekBufferSource
359730
+{
359730
+  GSource parent;
359730
+  GrdSessionVnc *session_vnc;
359730
+} PeekBufferSource;
359730
+
359730
 typedef struct _GrdVncTlsSession
359730
 {
359730
   GrdVncTlsContext *tls_context;
359730
@@ -53,6 +59,8 @@ typedef struct _GrdVncTlsSession
359730
   char *peek_buffer;
359730
   int peek_buffer_size;
359730
   int peek_buffer_len;
359730
+
359730
+  GSource *peek_buffer_source;
359730
 } GrdVncTlsSession;
359730
 
359730
 static gboolean
359730
@@ -296,16 +304,14 @@ grd_vnc_tls_peek_at_socket (rfbClientPtr  rfb_client,
359730
   peekable_len = MIN (len, tls_session->peek_buffer_len);
359730
   memcpy (buf, tls_session->peek_buffer, peekable_len);
359730
 
359730
+  fprintf(stderr, ":::: %s:%d %s() - peeked %d bytes, can peek %d bytes\n", __FILE__, __LINE__, __func__,
359730
+          peekable_len, tls_session->peek_buffer_len);
359730
   return peekable_len;
359730
 }
359730
 
359730
-static rfbBool
359730
-grd_vnc_tls_has_pending_on_socket (rfbClientPtr rfb_client)
359730
+static gboolean
359730
+grd_vnc_tls_session_has_pending_data (GrdVncTlsSession *tls_session)
359730
 {
359730
-  GrdSessionVnc *session_vnc = rfb_client->screen->screenData;
359730
-  GrdVncTlsSession *tls_session =
359730
-    grd_vnc_tls_session_from_vnc_session (session_vnc);
359730
-
359730
   if (tls_session->peek_buffer_len > 0)
359730
     return TRUE;
359730
 
359730
@@ -315,6 +321,16 @@ grd_vnc_tls_has_pending_on_socket (rfbClientPtr rfb_client)
359730
   return FALSE;
359730
 }
359730
 
359730
+static rfbBool
359730
+grd_vnc_tls_has_pending_on_socket (rfbClientPtr rfb_client)
359730
+{
359730
+  GrdSessionVnc *session_vnc = rfb_client->screen->screenData;
359730
+  GrdVncTlsSession *tls_session =
359730
+    grd_vnc_tls_session_from_vnc_session (session_vnc);
359730
+
359730
+  return grd_vnc_tls_session_has_pending_data (tls_session);
359730
+}
359730
+
359730
 static int
359730
 grd_vnc_tls_write_to_socket (rfbClientPtr  rfb_client,
359730
                              const char   *buf,
359730
@@ -403,6 +419,62 @@ tls_handshake_grab_func (GrdSessionVnc  *session_vnc,
359730
   return TRUE;
359730
 }
359730
 
359730
+static gboolean
359730
+peek_buffer_source_prepare (GSource *source,
359730
+                            int     *timeout)
359730
+{
359730
+  PeekBufferSource *psource = (PeekBufferSource *) source;
359730
+  GrdSessionVnc *session_vnc = psource->session_vnc;
359730
+  GrdVncTlsSession *tls_session =
359730
+    grd_vnc_tls_session_from_vnc_session (session_vnc);
359730
+
359730
+  return grd_vnc_tls_session_has_pending_data (tls_session);
359730
+}
359730
+
359730
+static gboolean
359730
+peek_buffer_source_dispatch (GSource     *source,
359730
+                             GSourceFunc  callback,
359730
+                             gpointer     user_data)
359730
+{
359730
+  PeekBufferSource *psource = (PeekBufferSource *) source;
359730
+  GrdSessionVnc *session_vnc = psource->session_vnc;
359730
+
359730
+  grd_session_vnc_dispatch (session_vnc);
359730
+
359730
+  return G_SOURCE_CONTINUE;
359730
+}
359730
+
359730
+static GSourceFuncs peek_buffer_source_funcs = {
359730
+  .prepare = peek_buffer_source_prepare,
359730
+  .dispatch = peek_buffer_source_dispatch,
359730
+};
359730
+
359730
+static void
359730
+attach_peek_buffer_source (GrdSessionVnc *session_vnc)
359730
+{
359730
+  GrdVncTlsSession *tls_session;
359730
+
359730
+  tls_session = grd_vnc_tls_session_from_vnc_session (session_vnc);
359730
+  tls_session->peek_buffer_source = g_source_new (&peek_buffer_source_funcs,
359730
+                                                  sizeof (PeekBufferSource));
359730
+  ((PeekBufferSource *) tls_session->peek_buffer_source)->session_vnc =
359730
+    session_vnc;
359730
+  g_source_set_priority (tls_session->peek_buffer_source,
359730
+                         G_PRIORITY_DEFAULT + 1);
359730
+
359730
+  g_source_attach (tls_session->peek_buffer_source, NULL);
359730
+}
359730
+
359730
+static void
359730
+detach_peek_buffer_source (GrdSessionVnc *session_vnc)
359730
+{
359730
+  GrdVncTlsSession *tls_session;
359730
+
359730
+  tls_session = grd_vnc_tls_session_from_vnc_session (session_vnc);
359730
+
359730
+  g_clear_pointer (&tls_session->peek_buffer_source, g_source_destroy);
359730
+}
359730
+
359730
 static void
359730
 rfb_tls_security_handler (rfbClientPtr rfb_client)
359730
 {
359730
@@ -429,6 +501,14 @@ rfb_tls_security_handler (rfbClientPtr rfb_client)
359730
       rfb_client->hasPendingOnSocket = grd_vnc_tls_has_pending_on_socket;
359730
       rfb_client->writeToSocket = grd_vnc_tls_write_to_socket;
359730
 
359730
+      if (!grd_session_vnc_is_paused (session_vnc))
359730
+        attach_peek_buffer_source (session_vnc);
359730
+
359730
+      g_signal_connect (session_vnc, "paused",
359730
+                        G_CALLBACK (detach_peek_buffer_source), NULL);
359730
+      g_signal_connect (session_vnc, "resumed",
359730
+                        G_CALLBACK (attach_peek_buffer_source), NULL);
359730
+
359730
       grd_session_vnc_grab_socket (session_vnc, tls_handshake_grab_func);
359730
     }
359730
 
359730
-- 
359730
2.26.2
359730
359730
359730
From c582baab12c1e2dd2b512329da42880c40993df6 Mon Sep 17 00:00:00 2001
359730
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
359730
Date: Wed, 27 Nov 2019 16:48:00 +0100
359730
Subject: [PATCH 6/7] session-vnc: Set our own password handling function up
359730
 front
359730
359730
libvncserver decides whether to register a auth security handler
359730
depending on whether the password data is set or not. When we use the
359730
prompt auth method, we don't want to ask for password, so set the
359730
password data to NULL.
359730
359730
Also, to be a bit more in control of the password mechanism, always set
359730
the password function up front, instead of just when the client uses the
359730
password prompt.
359730
---
359730
 src/grd-session-vnc.c | 8 ++------
359730
 1 file changed, 2 insertions(+), 6 deletions(-)
359730
359730
diff --git a/src/grd-session-vnc.c b/src/grd-session-vnc.c
359730
index 8b8ce1b..a93a2e3 100644
359730
--- a/src/grd-session-vnc.c
359730
+++ b/src/grd-session-vnc.c
359730
@@ -91,11 +91,6 @@ grd_session_vnc_pause (GrdSessionVnc *session_vnc);
359730
 static gboolean
359730
 close_session_idle (gpointer user_data);
359730
 
359730
-static rfbBool
359730
-check_rfb_password (rfbClientPtr  rfb_client,
359730
-                    const char   *response_encrypted,
359730
-                    int           len);
359730
-
359730
 static void
359730
 swap_uint8 (uint8_t *a,
359730
             uint8_t *b)
359730
@@ -297,7 +292,6 @@ handle_new_client (rfbClientPtr rfb_client)
359730
       grd_session_vnc_pause (session_vnc);
359730
       return RFB_CLIENT_ON_HOLD;
359730
     case GRD_VNC_AUTH_METHOD_PASSWORD:
359730
-      session_vnc->rfb_screen->passwordCheck = check_rfb_password;
359730
       /*
359730
        * authPasswdData needs to be non NULL in libvncserver to trigger
359730
        * password authentication.
359730
@@ -581,6 +575,8 @@ init_vnc_session (GrdSessionVnc *session_vnc)
359730
   rfb_screen->frameBuffer = g_malloc0 (screen_width * screen_height * 4);
359730
   memset (rfb_screen->frameBuffer, 0x1f, screen_width * screen_height * 4);
359730
 
359730
+  rfb_screen->passwordCheck = check_rfb_password;
359730
+
359730
   rfbInitServer (rfb_screen);
359730
   rfbProcessEvents (rfb_screen, 0);
359730
 }
359730
-- 
359730
2.26.2
359730
359730
359730
From b7fc232ee5272b430f28c33ebaacd501ff63a4dc Mon Sep 17 00:00:00 2001
359730
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
359730
Date: Wed, 27 Nov 2019 16:53:42 +0100
359730
Subject: [PATCH 7/7] vnc: Unregister previously set security handlers on init
359730
359730
When we're starting a session, we're going to handle a new client
359730
connection. However, any previous client that was ever run on in a
359730
previous session would still have their "security handler" registered,
359730
as such is a global permanent change in libvncserver right now.
359730
359730
To work around this, unregister all primary security handler (i.e.
359730
'none' and 'password') when initializing the RFB screen. We'll set up
359730
the preferred one when handling the new client.
359730
---
359730
 src/grd-session-vnc.c | 6 ++++++
359730
 1 file changed, 6 insertions(+)
359730
359730
diff --git a/src/grd-session-vnc.c b/src/grd-session-vnc.c
359730
index a93a2e3..9fcbb69 100644
359730
--- a/src/grd-session-vnc.c
359730
+++ b/src/grd-session-vnc.c
359730
@@ -555,6 +555,12 @@ init_vnc_session (GrdSessionVnc *session_vnc)
359730
                              8, 3, 4);
359730
   session_vnc->rfb_screen = rfb_screen;
359730
 
359730
+  /*
359730
+   * Unregister whatever security handler was used the last time; we'll set
359730
+   * up new ones when authorizing the new client anyway.
359730
+   */
359730
+  rfbUnregisterPrimarySecurityHandlers ();
359730
+
359730
   update_server_format (session_vnc);
359730
 
359730
   socket = g_socket_connection_get_socket (session_vnc->connection);
359730
-- 
359730
2.26.2
78005c