[Spice-devel] [v3: PATCH 3/3] Add support to handle username when connecting with SASL

Fabiano Fidêncio fidencio at redhat.com
Tue Oct 7 07:21:04 PDT 2014


Based on a patch from Dietmar Maurer <dietmar at proxmox.com>
http://lists.freedesktop.org/archives/spice-devel/2013-October/015138.html
---
Changes since v2:
Adapt the patch according to the changes made in the previous one
---
 gtk/spice-channel-priv.h |  1 +
 gtk/spice-channel.c      | 45 ++++++++++++++++++++++++++++++++++++++++-----
 po/POTFILES.in           |  1 +
 3 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index 03eed38..6067abc 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -136,6 +136,7 @@ struct _SpiceChannelPrivate {
     GSList                      *flushing;
 
     gboolean                    disable_channel_msg;
+    gboolean                    auth_needs_username_and_password;
     GError                      *error;
 };
 
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index a8b4e35..0086679 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -26,6 +26,8 @@
 #include "spice-marshal.h"
 #include "bio-gio.h"
 
+#include <glib/gi18n.h>
+
 #include <openssl/rsa.h>
 #include <openssl/evp.h>
 #include <openssl/x509.h>
@@ -118,6 +120,7 @@ static void spice_channel_init(SpiceChannel *channel)
     c->out_serial = 1;
     c->in_serial = 1;
     c->fd = -1;
+    c->auth_needs_username_and_password = FALSE;
     strcpy(c->name, "?");
     c->caps = g_array_new(FALSE, TRUE, sizeof(guint32));
     c->common_caps = g_array_new(FALSE, TRUE, sizeof(guint32));
@@ -1253,6 +1256,7 @@ spice_channel_gather_sasl_credentials(SpiceChannel *channel,
 {
     SpiceChannelPrivate *c;
     int ninteract;
+    gboolean ret = TRUE;
 
     g_return_val_if_fail(channel != NULL, FALSE);
     g_return_val_if_fail(channel->priv != NULL, FALSE);
@@ -1265,12 +1269,22 @@ spice_channel_gather_sasl_credentials(SpiceChannel *channel,
         switch (interact[ninteract].id) {
         case SASL_CB_AUTHNAME:
         case SASL_CB_USER:
-            g_warn_if_reached();
+            c->auth_needs_username_and_password = TRUE;
+            if (spice_session_get_username(c->session) == NULL)
+                return FALSE;
+
+            interact[ninteract].result =  spice_session_get_username(c->session);
+            interact[ninteract].len = strlen(interact[ninteract].result);
             break;
 
         case SASL_CB_PASS:
-            if (spice_session_get_password(c->session) == NULL)
-                return FALSE;
+            if (spice_session_get_password(c->session) == NULL) {
+                /* Even if we reach this point, we have to continue looking for
+                 * SASL_CB_AUTHNAME|SASL_CB_USER, otherwise we would return a
+                 * wrong error to the applications */
+                ret = FALSE;
+                continue;
+            }
 
             interact[ninteract].result =  spice_session_get_password(c->session);
             interact[ninteract].len = strlen(interact[ninteract].result);
@@ -1280,7 +1294,7 @@ spice_channel_gather_sasl_credentials(SpiceChannel *channel,
 
     CHANNEL_DEBUG(channel, "Filled SASL interact");
 
-    return TRUE;
+    return ret;
 }
 
 /*
@@ -1319,6 +1333,22 @@ spice_channel_gather_sasl_credentials(SpiceChannel *channel,
 #define SASL_MAX_MECHNAME_LEN 100
 #define SASL_MAX_DATA_LEN (1024 * 1024)
 
+static void spice_channel_set_detailed_authentication_error(SpiceChannel *channel)
+{
+    SpiceChannelPrivate *c = channel->priv;
+
+    if (c->auth_needs_username_and_password)
+        g_set_error_literal(&c->error,
+                            SPICE_CHANNEL_ERROR,
+                            SPICE_CHANNEL_ERROR_AUTH_NEEDS_PASSWORD_AND_USERNAME,
+                            _("Authentication failed: password and username are required"));
+    else
+        g_set_error_literal(&c->error,
+                            SPICE_CHANNEL_ERROR,
+                            SPICE_CHANNEL_ERROR_AUTH_NEEDS_PASSWORD,
+                            _("Authentication failed: password is required"));
+}
+
 /* Perform the SASL authentication process
  */
 static gboolean spice_channel_perform_auth_sasl(SpiceChannel *channel)
@@ -1334,6 +1364,8 @@ static gboolean spice_channel_perform_auth_sasl(SpiceChannel *channel)
     const void *val;
     sasl_ssf_t ssf;
     static const sasl_callback_t saslcb[] = {
+        { .id = SASL_CB_USER },
+        { .id = SASL_CB_AUTHNAME },
         { .id = SASL_CB_PASS },
         { .id = 0 },
     };
@@ -1635,8 +1667,10 @@ restart:
 complete:
     CHANNEL_DEBUG(channel, "%s", "SASL authentication complete");
     spice_channel_read(channel, &len, sizeof(len));
-    if (len != SPICE_LINK_ERR_OK)
+    if (len != SPICE_LINK_ERR_OK) {
+        spice_channel_set_detailed_authentication_error(channel);
         g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_AUTH);
+    }
     ret = len == SPICE_LINK_ERR_OK;
     /* This must come *after* check-auth-result, because the former
      * is defined to be sent unencrypted, and setting saslconn turns
@@ -1647,6 +1681,7 @@ complete:
 error:
     if (saslconn)
         sasl_dispose(&saslconn);
+    spice_channel_set_detailed_authentication_error(channel);
     g_coroutine_signal_emit(channel, signals[SPICE_CHANNEL_EVENT], 0, SPICE_CHANNEL_ERROR_AUTH);
     c->has_error = TRUE; /* force disconnect */
     ret = FALSE;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8809121..3375ab5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -2,6 +2,7 @@ data/spice-mime.xml.in
 data/spicy.desktop.in.in
 gtk/channel-usbredir.c
 gtk/desktop-integration.c
+gtk/spice-channel.c
 gtk/spice-cmdline.c
 gtk/spice-option.c
 gtk/spicy-screenshot.c
-- 
2.1.0



More information about the Spice-devel mailing list