Go to great lengths to avoid accidentally appending the default Kerberos realm
authorLuke Howard <lukeh@padl.com>
Fri, 18 Mar 2011 05:16:20 +0000 (16:16 +1100)
committerLuke Howard <lukeh@padl.com>
Fri, 18 Mar 2011 05:18:48 +0000 (16:18 +1100)
util_krb.c
util_name.c

index 2176d9b..abc9e61 100644 (file)
@@ -70,9 +70,11 @@ initKrbContext(krb5_context *pKrbContext)
     krb5_appdefault_string(krbContext, "eap_gss",
                            NULL, "default_realm", "", &defaultRealm);
 
-    code = krb5_set_default_realm(krbContext, defaultRealm);
-    if (code != 0)
-        goto cleanup;
+    if (defaultRealm != NULL && defaultRealm[0] != '\0') {
+        code = krb5_set_default_realm(krbContext, defaultRealm);
+        if (code != 0)
+            goto cleanup;
+    }
 
     *pKrbContext = krbContext;
 
index af34d67..4add1fe 100644 (file)
@@ -149,6 +149,17 @@ krbPrincipalToName(OM_uint32 *minor,
     return GSS_S_COMPLETE;
 }
 
+static krb5_error_code
+gssEapGetDefaultRealm(krb5_context krbContext, char **defaultRealm)
+{
+    *defaultRealm = NULL;
+
+    krb5_appdefault_string(krbContext, "eap_gss",
+                           NULL, "default_realm", "", defaultRealm);
+
+    return (*defaultRealm != NULL) ? 0 : KRB5_CONFIG_NODEFREALM;
+}
+
 static OM_uint32
 importServiceName(OM_uint32 *minor,
                   const gss_buffer_t nameBuffer,
@@ -172,7 +183,7 @@ importServiceName(OM_uint32 *minor,
         host++;
     }
 
-    krb5_get_default_realm(krbContext, &realm);
+    gssEapGetDefaultRealm(krbContext, &realm);
 
     code = krb5_build_principal(krbContext,
                                 &krbPrinc,
@@ -182,9 +193,6 @@ importServiceName(OM_uint32 *minor,
                                 host,
                                 NULL);
 
-    if (realm != NULL)
-        krb5_free_default_realm(krbContext, realm);
-
     if (code == 0) {
         KRB_PRINC_TYPE(krbPrinc) = KRB5_NT_SRV_HST;
 
@@ -196,6 +204,8 @@ importServiceName(OM_uint32 *minor,
         *minor = GSSEAP_BAD_SERVICE_NAME;
     }
 
+    if (realm != NULL)
+        GSSEAP_FREE(realm);
     GSSEAP_FREE(service);
 
     return major;
@@ -208,42 +218,67 @@ importUserName(OM_uint32 *minor,
 {
     OM_uint32 major;
     krb5_context krbContext;
-    krb5_principal krbPrinc;
-    char *nameString, *realm = NULL;
-    int flags = 0;
+    krb5_principal krbPrinc = NULL;
     krb5_error_code code;
 
     GSSEAP_KRB_INIT(&krbContext);
 
-    code = krb5_get_default_realm(krbContext, &realm);
-    if (code != 0 || realm == NULL)
-        flags |= KRB5_PRINCIPAL_PARSE_REQUIRE_REALM;
-    else
-        krb5_free_default_realm(krbContext, realm);
-
     if (nameBuffer == GSS_C_NO_BUFFER) {
-        *minor = krb5_copy_principal(krbContext,
-                                     krbAnonymousPrincipal(), &krbPrinc);
-        if (*minor != 0)
+        code = krb5_copy_principal(krbContext,
+                                   krbAnonymousPrincipal(), &krbPrinc);
+        if (code != 0) {
+            *minor = code;
             return GSS_S_FAILURE;
+        }
     } else {
+        char *nameString;
+
         major = bufferToString(minor, nameBuffer, &nameString);
         if (GSS_ERROR(major))
             return major;
 
-        *minor = krb5_parse_name_flags(krbContext, nameString, flags, &krbPrinc);
-        if (*minor != 0) {
-            GSSEAP_FREE(nameString);
+        /*
+         * First, attempt to parse the name on the assumption that it includes
+         * a qualifying realm.
+         */
+        code = krb5_parse_name_flags(krbContext, nameString,
+                                     KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &krbPrinc);
+        if (code == KRB5_PARSE_MALFORMED) {
+            char *defaultRealm = NULL;
+            int flags = 0;
+
+            /*
+             * We need an explicit appdefaults check because, at least with MIT
+             * Kerberos, setting the context realm to NULL will reset it to the
+             * default Kerberos realm after the second call to get_default_realm.
+             * We want to make sure that the default Kerberos realm does not end
+             * up accidentally appended to an unqualified name.
+             */
+            gssEapGetDefaultRealm(krbContext, &defaultRealm);
+
+            if (defaultRealm == NULL || defaultRealm[0] == '\0')
+                flags |= KRB5_PRINCIPAL_PARSE_NO_REALM;
+
+            code = krb5_parse_name_flags(krbContext, nameString, flags, &krbPrinc);
+
+            if (defaultRealm != NULL)
+                GSSEAP_FREE(defaultRealm);
+        }
+
+        GSSEAP_FREE(nameString);
+
+        if (code != 0) {
+            *minor = code;
             return GSS_S_FAILURE;
         }
     }
 
+    assert(krbPrinc != NULL);
+
     major = krbPrincipalToName(minor, &krbPrinc, pName);
-    if (GSS_ERROR(major)) {
+    if (GSS_ERROR(major))
         krb5_free_principal(krbContext, krbPrinc);
-    }
 
-    GSSEAP_FREE(nameString);
     return major;
 }