[Spice-devel] [spice-gtk] spice-channel: support SASL GSSAPI

Fabiano FidĂȘncio fidencio at redhat.com
Mon Jun 6 12:51:23 UTC 2016


From: Alexander Bokovoy <abokovoy at redhat.com>

Support SASL GSSAPI Kerberos by discovering default credential from
default Kerberos credentials cache.

If default Kerberos credential is missing, fallback to standard method
with password and username.

Signed-of-by: Alexander Bokovoy <abokovoy at redhat.com>
---
 src/spice-channel.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 57 insertions(+), 4 deletions(-)

diff --git a/src/spice-channel.c b/src/spice-channel.c
index c6e548d..af49d8a 100644
--- a/src/spice-channel.c
+++ b/src/spice-channel.c
@@ -1358,17 +1358,32 @@ static gchar *addr_to_string(GSocketAddress *addr)
 
 static gboolean
 spice_channel_gather_sasl_credentials(SpiceChannel *channel,
-				       sasl_interact_t *interact)
+				      sasl_interact_t *interact,
+				      sasl_conn_t *sasl_conn)
 {
     SpiceChannelPrivate *c;
-    int ninteract;
+    int ninteract, rc;
     gboolean ret = TRUE;
+    const char *mechname = NULL;
+    gboolean is_gssapi = FALSE;
+    krb5_context krbctx = NULL;
+    krb5_ccache ccache = NULL;
+    krb5_principal defprinc = NULL;
+    krb5_error_code krberr = 0;
+    char *username = NULL;
 
     g_return_val_if_fail(channel != NULL, FALSE);
     g_return_val_if_fail(channel->priv != NULL, FALSE);
 
     c = channel->priv;
 
+    if (sasl_conn != NULL) {
+        rc = sasl_getprop(sasl_conn, SASL_MECHNAME, (const void**) &mechname);
+        if (rc == SASL_OK && g_strcmp0(mechname, "GSSAPI") == 0) {
+            is_gssapi = TRUE;
+        }
+    }
+
     /* FIXME: we could keep connection open and ask connection details if missing */
 
     for (ninteract = 0 ; interact[ninteract].id != 0 ; ninteract++) {
@@ -1387,6 +1402,44 @@ spice_channel_gather_sasl_credentials(SpiceChannel *channel,
         switch (interact[ninteract].id) {
         case SASL_CB_AUTHNAME:
         case SASL_CB_USER:
+            /* For SASL GSSAPI derive user name from the default Kerberos credential */
+            if (is_gssapi && spice_session_get_username(c->session) == NULL) {
+                krberr = krb5_init_context(&krbctx);
+                if (krberr) {
+                    g_critical("Cannot initialize Kerberos context while using SASL GSSAPI");
+                    return FALSE;
+                }
+                krberr = krb5_cc_default(krbctx, &ccache);
+                if (krberr) {
+                    krb5_free_context(krbctx);
+                    g_critical("Default Kerberos credential cache not found. Need username and password to initialize");
+                    return FALSE;
+                }
+                krberr = krb5_cc_get_principal(krbctx, ccache, &defprinc);
+                if (krberr) {
+                    krb5_cc_close(krbctx, ccache);
+                    krb5_free_context(krbctx);
+                    g_critical("Kerberos user principal not found. Need username and password to initialize");
+                    return FALSE;
+                }
+
+                krberr = krb5_unparse_name_flags(krbctx, defprinc, KRB5_PRINCIPAL_UNPARSE_SHORT, &username);
+                if (krberr) {
+                    krb5_free_principal(krbctx, defprinc);
+                    krb5_cc_close(krbctx, ccache);
+                    krb5_free_context(krbctx);
+                    g_critical("Kerberos user principal cannot be parsed. Need username and password to initialize");
+                    return FALSE;
+                }
+
+                g_object_set(c->session, "username", username, NULL);
+
+                krb5_free_unparsed_name(krbctx, username);
+                krb5_free_principal(krbctx, defprinc);
+                krb5_cc_close(krbctx, ccache);
+                krb5_free_context(krbctx);
+            }
+
             if (spice_session_get_username(c->session) == NULL)
                 return FALSE;
 
@@ -1595,7 +1648,7 @@ restart:
 
     /* Need to gather some credentials from the client */
     if (err == SASL_INTERACT) {
-        if (!spice_channel_gather_sasl_credentials(channel, interact)) {
+        if (!spice_channel_gather_sasl_credentials(channel, interact, saslconn)) {
             CHANNEL_DEBUG(channel, "Failed to collect auth credentials");
             goto error;
         }
@@ -1679,7 +1732,7 @@ restart:
         /* Need to gather some credentials from the client */
         if (err == SASL_INTERACT) {
             if (!spice_channel_gather_sasl_credentials(channel,
-                                                       interact)) {
+                                                       interact, saslconn)) {
                 CHANNEL_DEBUG(channel, "%s", "Failed to collect auth credentials");
                 goto error;
             }
-- 
2.7.4



More information about the Spice-devel mailing list