[gtk+/gtk-3-8] broadway: Add support for password authentication



commit 1045dca1486e9eed13a1361b1317b9742bf03dd0
Author: Alexander Larsson <alexl redhat com>
Date:   Thu Mar 28 22:57:33 2013 +0100

    broadway: Add support for password authentication

 docs/reference/gtk/broadwayd.xml |    9 +++
 gdk/broadway/Makefile.am         |    2 +-
 gdk/broadway/broadway-output.c   |   25 +++++++
 gdk/broadway/broadway-output.h   |    5 ++
 gdk/broadway/broadway-protocol.h |    3 +
 gdk/broadway/broadway-server.c   |  138 ++++++++++++++++++++++++++++----------
 gdk/broadway/broadway.js         |   70 ++++++++++++++++---
 7 files changed, 202 insertions(+), 50 deletions(-)
---
diff --git a/docs/reference/gtk/broadwayd.xml b/docs/reference/gtk/broadwayd.xml
index be41c1a..14f7064 100644
--- a/docs/reference/gtk/broadwayd.xml
+++ b/docs/reference/gtk/broadwayd.xml
@@ -54,6 +54,15 @@ Start your applications like this:
 BROADWAY_DISPLAY=:5 gtk3-demo
 </programlisting>
 
+You can add password protection for your session by creating a file in
+<filename>$XDG_CONFIG_HOME/broadway.passwd</filename> or <filename>$HOME/.config/broadway.passwd</filename>
+with a crypt(3) style password hash.
+
+A simple way to generate it is with openssl:
+<programlisting>
+openssl passwd -1  > ~/.config/broadway.passwd
+</programlisting>
+
 </para>
 </refsect1>
 
diff --git a/gdk/broadway/Makefile.am b/gdk/broadway/Makefile.am
index a062240..dd4b189 100644
--- a/gdk/broadway/Makefile.am
+++ b/gdk/broadway/Makefile.am
@@ -83,7 +83,7 @@ broadwayd_SOURCES = \
        broadway-output.h               \
        broadway-output.c
 
-broadwayd_LDADD = $(GDK_DEP_LIBS) -lrt
+broadwayd_LDADD = $(GDK_DEP_LIBS) -lrt -lcrypt
 
 MAINTAINERCLEANFILES = $(broadway_built_sources)
 EXTRA_DIST += $(broadway_built_sources)
diff --git a/gdk/broadway/broadway-output.c b/gdk/broadway/broadway-output.c
index 3e1fb1e..774cca3 100644
--- a/gdk/broadway/broadway-output.c
+++ b/gdk/broadway/broadway-output.c
@@ -317,6 +317,13 @@ broadway_output_get_next_serial (BroadwayOutput *output)
   return output->serial;
 }
 
+void
+broadway_output_set_next_serial (BroadwayOutput *output,
+                                guint32 serial)
+{
+  output->serial = serial;
+}
+
 
 /************************************************************************
  *                     Core rendering operations                        *
@@ -472,6 +479,24 @@ broadway_output_new_surface(BroadwayOutput *output,
 }
 
 void
+broadway_output_request_auth (BroadwayOutput *output)
+{
+  write_header (output, BROADWAY_OP_REQUEST_AUTH);
+}
+
+void
+broadway_output_auth_ok (BroadwayOutput *output)
+{
+  write_header (output, BROADWAY_OP_AUTH_OK);
+}
+
+void
+broadway_output_disconnected (BroadwayOutput *output)
+{
+  write_header (output, BROADWAY_OP_DISCONNECTED);
+}
+
+void
 broadway_output_show_surface(BroadwayOutput *output,  int id)
 {
   write_header (output, BROADWAY_OP_SHOW_SURFACE);
diff --git a/gdk/broadway/broadway-output.h b/gdk/broadway/broadway-output.h
index 02436f4..ea57c7e 100644
--- a/gdk/broadway/broadway-output.h
+++ b/gdk/broadway/broadway-output.h
@@ -23,6 +23,8 @@ BroadwayOutput *broadway_output_new             (GOutputStream  *out,
 void            broadway_output_free            (BroadwayOutput *output);
 int             broadway_output_flush           (BroadwayOutput *output);
 int             broadway_output_has_error       (BroadwayOutput *output);
+void            broadway_output_set_next_serial (BroadwayOutput *output,
+                                                guint32         serial);
 guint32         broadway_output_get_next_serial (BroadwayOutput *output);
 void            broadway_output_new_surface     (BroadwayOutput *output,
                                                 int             id,
@@ -31,6 +33,9 @@ void            broadway_output_new_surface     (BroadwayOutput *output,
                                                 int             w,
                                                 int             h,
                                                 gboolean        is_temp);
+void            broadway_output_request_auth    (BroadwayOutput *output);
+void            broadway_output_auth_ok         (BroadwayOutput *output);
+void            broadway_output_disconnected    (BroadwayOutput *output);
 void            broadway_output_show_surface    (BroadwayOutput *output,
                                                 int             id);
 void            broadway_output_hide_surface    (BroadwayOutput *output,
diff --git a/gdk/broadway/broadway-protocol.h b/gdk/broadway/broadway-protocol.h
index c098fdf..fe7a8a4 100644
--- a/gdk/broadway/broadway-protocol.h
+++ b/gdk/broadway/broadway-protocol.h
@@ -36,6 +36,9 @@ typedef enum {
   BROADWAY_OP_SET_TRANSIENT_FOR = 'p',
   BROADWAY_OP_PUT_RGB = 'i',
   BROADWAY_OP_FLUSH = 'f',
+  BROADWAY_OP_REQUEST_AUTH = 'l',
+  BROADWAY_OP_AUTH_OK = 'L',
+  BROADWAY_OP_DISCONNECTED = 'D',
 } BroadwayOpType;
 
 typedef struct {
diff --git a/gdk/broadway/broadway-server.c b/gdk/broadway/broadway-server.c
index 77dd894..5b6bb96 100644
--- a/gdk/broadway/broadway-server.c
+++ b/gdk/broadway/broadway-server.c
@@ -2,6 +2,8 @@
 
 #include "broadway-output.h"
 
+#define _XOPEN_SOURCE /* for crypt */
+
 #include <glib.h>
 #include <glib/gprintf.h>
 #include "gdktypes.h"
@@ -9,6 +11,7 @@
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#include <crypt.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -19,6 +22,7 @@ typedef struct BroadwayWindow BroadwayWindow;
 struct _BroadwayServer {
   GObject parent_instance;
 
+  char *password;
   char *address;
   int port;
   GSocketService *service;
@@ -69,6 +73,7 @@ typedef struct HttpRequest {
 
 struct BroadwayInput {
   BroadwayServer *server;
+  BroadwayOutput *output;
   GSocketConnection *connection;
   GByteArray *buffer;
   GSource *source;
@@ -76,6 +81,7 @@ struct BroadwayInput {
   gint64 time_base;
   gboolean proto_v7_plus;
   gboolean binary;
+  gboolean active;
 };
 
 struct BroadwayWindow {
@@ -100,6 +106,8 @@ static void
 broadway_server_init (BroadwayServer *server)
 {
   BroadwayWindow *root;
+  char *passwd_file;
+  char *password, *p;
 
   server->service = g_socket_service_new ();
   server->pointer_grab_window_id = -1;
@@ -108,6 +116,22 @@ broadway_server_init (BroadwayServer *server)
   server->id_ht = g_hash_table_new (NULL, NULL);
   server->id_counter = 0;
 
+  passwd_file = g_build_filename (g_get_user_config_dir (),
+                                 "broadway.passwd", NULL);
+
+  if (g_file_get_contents (passwd_file,
+                          &password, NULL, NULL))
+    {
+      p = strchr (password, '\n');
+      if (p)
+       *p = 0;
+      g_strstrip (password);
+      if (strlen (password) > 3)
+       server->password = password;
+      else
+       g_free (password);
+    }
+
   root = g_new0 (BroadwayWindow, 1);
   root->id = server->id_counter++;
   root->width = 1024;
@@ -139,7 +163,7 @@ broadway_server_class_init (BroadwayServerClass * class)
   object_class->finalize = broadway_server_finalize;
 }
 
-static void start_output (HttpRequest *request, gboolean proto_v7_plus, gboolean binary);
+static void start (BroadwayInput *input);
 
 static void
 http_request_free (HttpRequest *request)
@@ -349,6 +373,14 @@ update_future_pointer_info (BroadwayServer *server, BroadwayInputPointerMsg *dat
   server->future_mouse_in_toplevel = data->mouse_window_id;
 }
 
+static gboolean
+verify_password (BroadwayServer *server, const char *password)
+{
+  char *hash;
+  hash = crypt (password, server->password);
+  return strcmp (hash, server->password) == 0;
+}
+
 static void
 parse_input_message (BroadwayInput *input, const char *message)
 {
@@ -357,6 +389,22 @@ parse_input_message (BroadwayInput *input, const char *message)
   char *p;
   gint64 time_;
 
+  if (!input->active)
+    {
+      /* The input has not been activated yet, handle auth/start */
+
+      if (message[0] != 'l' ||
+         !verify_password (server, message+1))
+       {
+         broadway_output_request_auth (input->output);
+         broadway_output_flush (input->output);
+       }
+      else
+       start (input);
+
+      return;
+    }
+
   memset (&msg, 0, sizeof (msg));
 
   p = (char *)message;
@@ -570,7 +618,7 @@ parse_input (BroadwayInput *input)
              }
            break;
          case BROADWAY_WS_CNX_PING:
-           broadway_output_pong (server->output);
+           broadway_output_pong (input->output);
            break;
          case BROADWAY_WS_CNX_PONG:
            break; /* we never send pings, but tolerate pongs */
@@ -596,7 +644,8 @@ parse_input (BroadwayInput *input)
 
       if (buf[0] != 0)
        {
-         server->input = NULL;
+         if (server->input == input)
+           server->input = NULL;
          broadway_input_free (input);
          return;
        }
@@ -613,7 +662,8 @@ parse_input (BroadwayInput *input)
 
          if (len > 0 && buf[0] != 0)
            {
-             server->input = NULL;
+             if (server->input == input)
+               server->input = NULL;
              broadway_input_free (input);
              break;
            }
@@ -640,19 +690,16 @@ queue_process_input_at_idle (BroadwayServer *server)
 }
 
 static void
-broadway_server_read_all_input_nonblocking (BroadwayServer *server)
+broadway_server_read_all_input_nonblocking (BroadwayInput *input)
 {
   GInputStream *in;
   gssize res;
   guint8 buffer[1024];
   GError *error;
-  BroadwayInput *input;
 
-  if (server->input == NULL)
+  if (input == NULL)
     return;
 
-  input = server->input;
-
   in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
 
   error = NULL;
@@ -668,7 +715,8 @@ broadway_server_read_all_input_nonblocking (BroadwayServer *server)
          return;
        }
 
-      server->input = NULL;
+      if (input->server->input == input)
+       input->server->input = NULL;
       broadway_input_free (input);
       if (res < 0)
        {
@@ -686,7 +734,7 @@ broadway_server_read_all_input_nonblocking (BroadwayServer *server)
 static void
 broadway_server_consume_all_input (BroadwayServer *server)
 {
-  broadway_server_read_all_input_nonblocking (server);
+  broadway_server_read_all_input_nonblocking (server->input);
 
   /* Since we're parsing input but not processing the resulting messages
      we might not get a readable callback on the stream, so queue an idle to
@@ -701,9 +749,10 @@ input_data_cb (GObject  *stream,
 {
   BroadwayServer *server = input->server;
 
-  broadway_server_read_all_input_nonblocking (server);
+  broadway_server_read_all_input_nonblocking (input);
 
-  process_input_messages (server);
+  if (input->active)
+    process_input_messages (server);
 
   return TRUE;
 }
@@ -878,15 +927,14 @@ start_input (HttpRequest *request, gboolean binary)
   gsize len;
   GChecksum *checksum;
   char *origin, *host;
-  BroadwayServer *server;
   BroadwayInput *input;
   const void *data_buffer;
   gsize data_buffer_size;
   GInputStream *in;
   char *key_v7;
   gboolean proto_v7_plus;
-
-  server = request->server;
+  GSocket *socket;
+  int flag = 1;
 
 #ifdef DEBUG_WEBSOCKETS
   g_print ("incoming request:\n%s\n", request->request->str);
@@ -1033,15 +1081,11 @@ start_input (HttpRequest *request, gboolean binary)
       proto_v7_plus = FALSE;
     }
 
-
-  if (server->input != NULL)
-    {
-      broadway_input_free (server->input);
-      server->input = NULL;
-    }
+  socket = g_socket_connection_get_socket (request->connection);
+  setsockopt (g_socket_get_fd (socket), IPPROTO_TCP,
+             TCP_NODELAY, (char *) &flag, sizeof(int));
 
   input = g_new0 (BroadwayInput, 1);
-
   input->server = request->server;
   input->connection = g_object_ref (request->connection);
   input->proto_v7_plus = proto_v7_plus;
@@ -1051,9 +1095,9 @@ start_input (HttpRequest *request, gboolean binary)
   input->buffer = g_byte_array_sized_new (data_buffer_size);
   g_byte_array_append (input->buffer, data_buffer, data_buffer_size);
 
-  server->input = input;
-
-  start_output (request, proto_v7_plus, binary);
+  input->output =
+    broadway_output_new (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
+                        0, proto_v7_plus, binary);
 
   /* This will free and close the data input stream, but we got all the buffered content already */
   http_request_free (request);
@@ -1063,35 +1107,53 @@ start_input (HttpRequest *request, gboolean binary)
   g_source_set_callback (input->source, (GSourceFunc)input_data_cb, input, NULL);
   g_source_attach (input->source, NULL);
 
+  if (input->server->password)
+    {
+      broadway_output_request_auth (input->output);
+      broadway_output_flush (input->output);
+    }
+  else
+    start (input);
+
   /* Process any data in the pipe already */
   parse_input (input);
-  process_input_messages (server);
 
   g_strfreev (lines);
 }
 
 static void
-start_output (HttpRequest *request, gboolean proto_v7_plus, gboolean binary)
+start (BroadwayInput *input)
 {
-  GSocket *socket;
   BroadwayServer *server;
-  int flag = 1;
 
-  socket = g_socket_connection_get_socket (request->connection);
-  setsockopt(g_socket_get_fd (socket), IPPROTO_TCP,
-            TCP_NODELAY, (char *) &flag, sizeof(int));
+  input->active = TRUE;
+
+  server = BROADWAY_SERVER (input->server);
+
+  if (server->output)
+    {
+      broadway_output_disconnected (server->output);
+      broadway_output_flush (server->output);
+    }
+
+  if (server->input != NULL)
+    {
+      broadway_input_free (server->input);
+      server->input = NULL;
+    }
 
-  server = BROADWAY_SERVER (request->server);
+  server->input = input;
 
   if (server->output)
     {
       server->saved_serial = broadway_output_get_next_serial (server->output);
       broadway_output_free (server->output);
     }
+  server->output = input->output;
 
-  server->output =
-    broadway_output_new (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
-                        server->saved_serial, proto_v7_plus, binary);
+  broadway_output_set_next_serial (server->output, server->saved_serial);
+  broadway_output_auth_ok (server->output);
+  broadway_output_flush (server->output);
 
   broadway_server_resync_windows (server);
 
@@ -1099,6 +1161,8 @@ start_output (HttpRequest *request, gboolean proto_v7_plus, gboolean binary)
     broadway_output_grab_pointer (server->output,
                                  server->pointer_grab_window_id,
                                  server->pointer_grab_owner_events);
+
+  process_input_messages (server);
 }
 
 static void
diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js
index fb4cffe..3f51e65 100644
--- a/gdk/broadway/broadway.js
+++ b/gdk/broadway/broadway.js
@@ -537,6 +537,21 @@ function handleCommands(cmd)
        var command = cmd.get_char();
        lastSerial = cmd.get_32();
        switch (command) {
+       case 'l':
+           login ();
+           break;
+
+       case 'L':
+           if (loginDiv != null)
+               loginDiv.parentNode.removeChild(loginDiv);
+           start ();
+           break;
+
+       case 'D':
+           alert ("disconnected");
+           inputSocket = null;
+           break;
+
        case 's': // create new surface
            id = cmd.get_16();
            x = cmd.get_16s();
@@ -2625,6 +2640,47 @@ function newWS(loc) {
     return ws;
 }
 
+function start()
+{
+    setupDocument(document);
+
+    var w, h;
+    w = window.innerWidth;
+    h = window.innerHeight;
+    window.onresize = function(ev) {
+       var w, h;
+       w = window.innerWidth;
+       h = window.innerHeight;
+       sendInput ("d", [w, h]);
+    };
+    sendInput ("d", [w, h]);
+}
+
+var loginDiv = null;
+function login()
+{
+    if (loginDiv == null) {
+       var div = document.createElement('div');
+       document.body.appendChild(div);
+       div.innerHTML = "Please enter password<br>";
+       div.style.marginTop = "40px";
+       div.style.textAlign = "center";
+
+       var input = document.createElement("input");
+       input.setAttribute("type", "password");
+       div.appendChild(input);
+       input.onkeyup = function(e) {
+           if (e.keyCode === 13) {
+               inputSocket.send ("l" + input.value);
+           }
+       }
+       input.focus ();
+       loginDiv = div;
+    } else {
+       alert ("Wrong password");
+    }
+}
+
 function connect()
 {
     var url = window.location.toString();
@@ -2646,23 +2702,13 @@ function connect()
 
     ws.onopen = function() {
        inputSocket = ws;
-       var w, h;
-       w = window.innerWidth;
-       h = window.innerHeight;
-       window.onresize = function(ev) {
-           var w, h;
-           w = window.innerWidth;
-           h = window.innerHeight;
-           sendInput ("d", [w, h]);
-       };
-       sendInput ("d", [w, h]);
     };
     ws.onclose = function() {
+       if (inputSocket != null)
+           alert ("disconnected");
        inputSocket = null;
     };
     ws.onmessage = function(event) {
        handleMessage(event.data);
     };
-
-    setupDocument(document);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]