
EXTERNAL authentication changes to make it work across UID namespaces

Copyright (C) Espial Limited 2015 Company Confidential - All Rights Reserved 

The gdbus implementation has the same problem that dbus does with regards to the UID
namespaces: it serialises the container's own idea of the UID into the AUTH EXTERNAL
message and sends the SCM_CREDENTIALS via the kernel too.  The kernel translates the
credentials across namespace boundaries, leaving it different from the message.  The
change here is the same as that for dbus itself: don't supply the UID in the initial
message, and respond with an empty DATA message when the server asks for the missing
data.  Note there is either a parsing bug in the general message parser (it fails if
the DATA isn't followed by a space!) or the server should be sending the space - I'm
fixing it here)

NOTE: the gdbusauth.c change is a bug fix to fix a latent bug exposed by the changes
in gdbusauthmechanismexternal.c.  The bug has been reported in the GNOME Bugzilla as
a fault, with my fix, and thus may not be necessary in future releases of GLib, when
(if) the fix is incorporated.  See https://bugzilla.gnome.org/show_bug.cgi?id=756569

diff -pruN glib-2.44.1.orig/gio/gdbusauth.c glib-2.44.1/gio/gdbusauth.c
--- glib-2.44.1.orig/gio/gdbusauth.c	2014-12-19 21:49:48.000000000 +0000
+++ glib-2.44.1/gio/gdbusauth.c	2015-10-14 13:21:18.150713452 +0100
@@ -810,13 +810,13 @@ _g_dbus_auth_run_client (GDBusAuth     *
           if (line == NULL)
             goto out;
           debug_print ("CLIENT: WaitingForData, read='%s'", line);
-          if (g_str_has_prefix (line, "DATA "))
+          if (g_str_has_prefix (line, "DATA") && (line[4] == 0 || g_ascii_isspace (line[4])))
             {
               gchar *encoded;
               gchar *decoded_data;
               gsize decoded_data_len = 0;
 
-              encoded = g_strdup (line + 5);
+              encoded = g_strdup (line + (line[4] == 0 ? 4 : 5));
               g_free (line);
               g_strstrip (encoded);
               decoded_data = hexdecode (encoded, &decoded_data_len, error);
@@ -1255,13 +1255,13 @@ _g_dbus_auth_run_server (GDBusAuth
           debug_print ("SERVER: WaitingForData, read '%s'", line);
           if (line == NULL)
             goto out;
-          if (g_str_has_prefix (line, "DATA "))
+          if (g_str_has_prefix (line, "DATA") && (line[4] == 0 || g_ascii_isspace (line[4])))
             {
               gchar *encoded;
               gchar *decoded_data;
               gsize decoded_data_len = 0;
 
-              encoded = g_strdup (line + 5);
+              encoded = g_strdup (line + (line[4] == 0 ? 4 : 5));
               g_free (line);
               g_strstrip (encoded);
               decoded_data = hexdecode (encoded, &decoded_data_len, error);
diff -pruN glib-2.44.1.orig/gio/gdbusauthmechanismexternal.c glib-2.44.1/gio/gdbusauthmechanismexternal.c
--- glib-2.44.1.orig/gio/gdbusauthmechanismexternal.c	2014-12-19 21:49:48.000000000 +0000
+++ glib-2.44.1/gio/gdbusauthmechanismexternal.c	2015-10-13 14:58:35.545875597 +0100
@@ -330,7 +330,7 @@ mechanism_client_initiate (GDBusAuthMech
   g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL);
 
   m->priv->is_client = TRUE;
-  m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
+  m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
 
   *out_initial_response_len = -1;
 
@@ -339,7 +339,6 @@ mechanism_client_initiate (GDBusAuthMech
 
   /* return the uid */
 #if defined(G_OS_UNIX)
-  initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) g_credentials_get_unix_user (credentials, NULL));
 #elif defined(G_OS_WIN32)
 #ifdef __GNUC__
 #warning Dont know how to send credentials on this OS. The EXTERNAL D-Bus authentication mechanism will not work.
@@ -360,8 +359,7 @@ mechanism_client_data_receive (GDBusAuth
   g_return_if_fail (m->priv->is_client && !m->priv->is_server);
   g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA);
 
-  /* can never end up here because we are never in the WAITING_FOR_DATA state */
-  g_assert_not_reached ();
+  m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
 }
 
 static gchar *
@@ -374,10 +372,9 @@ mechanism_client_data_send (GDBusAuthMec
   g_return_val_if_fail (m->priv->is_client && !m->priv->is_server, NULL);
   g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL);
 
-  /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
-  g_assert_not_reached ();
+  m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED;
 
-  return NULL;
+  return g_strdup ("");
 }
 
 static void
