krb5 commit: Add GSS_KRB5_NT_ENTERPRISE_NAME name type

Greg Hudson <[email protected]>
Newsgroups gmane.comp.encryption.kerberos.cvs
Message-ID <[email protected]>
https://github.com/krb5/krb5/commit/0b872730081f01d0d2b6f78675bb5c74604cef62
commit 0b872730081f01d0d2b6f78675bb5c74604cef62
Author: Isaac Boukris <[email protected]>
Date:   Mon Oct 15 18:33:15 2018 +0300

    Add GSS_KRB5_NT_ENTERPRISE_NAME name type
    
    Add a new name-type OID which causes a string to be imported as an
    enterprise name.  This is useful for authenticating and impersonating
    users with their UPN names.
    
    Resurrect t_imp_name test to exercise importing of the new name OID.
    Also add a test using the new name in cross-realm protocol transition,
    to exercise s4u_identify_user() with multiple realms.
    
    [[email protected]: added Windows export entry; adjusted comments and
    test code; edited commit message]
    
    ticket: 8756 (new)

 doc/appdev/gssapi.rst                 |    6 ++++
 src/lib/gssapi/krb5/gssapi_krb5.c     |    3 ++
 src/lib/gssapi/krb5/gssapi_krb5.h     |    5 +++
 src/lib/gssapi/krb5/import_name.c     |    8 ++++-
 src/lib/gssapi/libgssapi_krb5.exports |    1 +
 src/lib/gssapi32.def                  |    2 +
 src/plugins/kdb/test/kdb_test.c       |    3 +-
 src/tests/gssapi/Makefile.in          |    1 +
 src/tests/gssapi/common.c             |    4 ++-
 src/tests/gssapi/t_imp_name.c         |   44 +++++++++++++++++++++++++++++---
 src/tests/gssapi/t_oid.c              |    3 ++
 src/tests/gssapi/t_s4u.py             |   26 +++++++++++++++++--
 12 files changed, 94 insertions(+), 12 deletions(-)

diff --git a/doc/appdev/gssapi.rst b/doc/appdev/gssapi.rst
index a53094f..d26ac08 100644
--- a/doc/appdev/gssapi.rst
+++ b/doc/appdev/gssapi.rst
@@ -55,6 +55,12 @@ name types are supported by the krb5 mechanism:
 * **GSS_C_NT_EXPORT_NAME**: The value must be the result of a
   gss_export_name_ call.
 
+* **GSS_KRB5_NT_ENTERPRISE_NAME**: The value should be a krb5
+  enterprise name string (see :rfc:`6806` section 5), in the form
+  ``user@suffix``.  This name type is used to convey alias names, and
+  is defined in the ``<gssapi/gssapi_krb5.h>`` header.  (New in
+  release 1.17.)
+
 
 Initiator credentials
 ---------------------
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index 1eaf2bf..79b83e0 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -152,6 +152,8 @@ const gss_OID_desc krb5_gss_oid_array[] = {
     {NO_CI_FLAGS_X_OID_LENGTH, NO_CI_FLAGS_X_OID},
     /* this is an inquire cred OID */
     {GET_CRED_IMPERSONATOR_OID_LENGTH, GET_CRED_IMPERSONATOR_OID},
+    /* GSS_KRB5_NT_ENTERPRISE_NAME */
+    {10, "\052\206\110\206\367\022\001\002\002\006"},
     { 0, 0 }
 };
 
@@ -169,6 +171,7 @@ const gss_OID GSS_KRB5_NT_PRINCIPAL_NAME        = &kg_oids[5];
 
 const gss_OID GSS_KRB5_CRED_NO_CI_FLAGS_X       = &kg_oids[7];
 const gss_OID GSS_KRB5_GET_CRED_IMPERSONATOR    = &kg_oids[8];
+const gss_OID GSS_KRB5_NT_ENTERPRISE_NAME       = &kg_oids[9];
 
 static const gss_OID_set_desc oidsets[] = {
     {1, &kg_oids[0]}, /* RFC OID */
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.h b/src/lib/gssapi/krb5/gssapi_krb5.h
index e145eec..84b4159 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.h
+++ b/src/lib/gssapi/krb5/gssapi_krb5.h
@@ -73,6 +73,11 @@ GSS_DLLIMP extern const gss_OID GSS_KRB5_NT_PRINCIPAL_NAME;
  * generic(1) string_uid_name(3)}.  The recommended symbolic name for
  * this type is "GSS_KRB5_NT_STRING_UID_NAME". */
 
+/* Kerberos Enterprise Name Form (see RFC 6806 section 5): */
+GSS_DLLIMP extern const gss_OID GSS_KRB5_NT_ENTERPRISE_NAME;
+/* {iso(1) member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5-enterprise-name(6)}. */
+
 GSS_DLLIMP extern const gss_OID gss_mech_krb5;
 GSS_DLLIMP extern const gss_OID gss_mech_krb5_old;
 GSS_DLLIMP extern const gss_OID gss_mech_krb5_wrong;
diff --git a/src/lib/gssapi/krb5/import_name.c b/src/lib/gssapi/krb5/import_name.c
index 3f5492b..da2ab14 100644
--- a/src/lib/gssapi/krb5/import_name.c
+++ b/src/lib/gssapi/krb5/import_name.c
@@ -140,6 +140,7 @@ krb5_gss_import_name(minor_status, input_name_buffer,
     krb5_authdata_context ad_context = NULL;
     OM_uint32 status = GSS_S_FAILURE;
     krb5_gss_name_t name;
+    int flags = 0;
 
     *output_name = NULL;
     *minor_status = 0;
@@ -206,7 +207,10 @@ krb5_gss_import_name(minor_status, input_name_buffer,
         if ((input_name_type == GSS_C_NULL_OID) ||
             g_OID_equal(input_name_type, gss_nt_krb5_name) ||
             g_OID_equal(input_name_type, gss_nt_user_name)) {
-            stringrep = (char *) tmp;
+            stringrep = tmp;
+        } else if (g_OID_equal(input_name_type, GSS_KRB5_NT_ENTERPRISE_NAME)) {
+            stringrep = tmp;
+            flags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;
 #ifndef NO_PASSWORD
         } else if (g_OID_equal(input_name_type, gss_nt_machine_uid_name)) {
             uid = *(uid_t *) input_name_buffer->value;
@@ -296,7 +300,7 @@ krb5_gss_import_name(minor_status, input_name_buffer,
 
         /* At this point, stringrep is set, or if not, code is. */
         if (stringrep) {
-            code = krb5_parse_name(context, (char *)stringrep, &princ);
+            code = krb5_parse_name_flags(context, stringrep, flags, &princ);
             if (code)
                 goto cleanup;
         } else {
diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports
index b07f69f..c292cb1 100644
--- a/src/lib/gssapi/libgssapi_krb5.exports
+++ b/src/lib/gssapi/libgssapi_krb5.exports
@@ -9,6 +9,7 @@ GSS_C_NT_MACHINE_UID_NAME
 GSS_C_NT_STRING_UID_NAME
 GSS_C_NT_USER_NAME
 GSS_KRB5_NT_PRINCIPAL_NAME
+GSS_KRB5_NT_ENTERPRISE_NAME
 GSS_KRB5_CRED_NO_CI_FLAGS_X
 GSS_KRB5_GET_CRED_IMPERSONATOR
 GSS_C_MA_MECH_CONCRETE
diff --git a/src/lib/gssapi32.def b/src/lib/gssapi32.def
index 842f3d5..e6b1479 100644
--- a/src/lib/gssapi32.def
+++ b/src/lib/gssapi32.def
@@ -185,3 +185,5 @@ EXPORTS
 ; Added in 1.16
 	GSS_KRB5_GET_CRED_IMPERSONATOR			@148	DATA
 	GSS_C_SEC_CONTEXT_SASL_SSF			@149	DATA
+; Added in 1.17
+	GSS_KRB5_NT_ENTERPRISE_NAME			@150 	DATA
diff --git a/src/plugins/kdb/test/kdb_test.c b/src/plugins/kdb/test/kdb_test.c
index bc65bfb..6df2d58 100644
--- a/src/plugins/kdb/test/kdb_test.c
+++ b/src/plugins/kdb/test/kdb_test.c
@@ -334,7 +334,8 @@ test_get_principal(krb5_context context, krb5_const_principal search_for,
                                   &search_name));
     canon = get_string(h, "alias", search_name, NULL);
     if (canon != NULL) {
-        if (!(flags & KRB5_KDB_FLAG_ALIAS_OK)) {
+        if (!(flags & KRB5_KDB_FLAG_ALIAS_OK) &&
+            search_for->type != KRB5_NT_ENTERPRISE_PRINCIPAL) {
             ret = KRB5_KDB_NOENTRY;
             goto cleanup;
         }
diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in
index 2463c23..a7b8da4 100644
--- a/src/tests/gssapi/Makefile.in
+++ b/src/tests/gssapi/Makefile.in
@@ -40,6 +40,7 @@ check-unix: t_oid
 	$(RUN_TEST) ./t_invalid
 	$(RUN_TEST) ./t_oid
 	$(RUN_TEST) ./t_prf
+	$(RUN_TEST) ./t_imp_name
 
 check-pytests: ccinit ccrefresh t_accname t_add_cred t_ccselect t_ciflags \
 	t_credstore t_enctypes t_err t_export_cred t_export_name t_imp_cred \
diff --git a/src/tests/gssapi/common.c b/src/tests/gssapi/common.c
index 0de36d3..83e9d9b 100644
--- a/src/tests/gssapi/common.c
+++ b/src/tests/gssapi/common.c
@@ -97,10 +97,12 @@ import_name(const char *str)
         nametype = GSS_C_NT_USER_NAME;
     else if (*str == 'p')
         nametype = (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME;
+    else if (*str == 'e')
+        nametype = (gss_OID)GSS_KRB5_NT_ENTERPRISE_NAME;
     else if (*str == 'h')
         nametype = GSS_C_NT_HOSTBASED_SERVICE;
     if (nametype == NULL || str[1] != ':')
-        errout("names must begin with u: or p: or h:");
+        errout("names must begin with u: or p: or e: or h:");
     buf.value = (char *)str + 2;
     buf.length = strlen(str) - 2;
     major = gss_import_name(&minor, &buf, nametype, &name);
diff --git a/src/tests/gssapi/t_imp_name.c b/src/tests/gssapi/t_imp_name.c
index 4fcd61b..3d73dc8 100644
--- a/src/tests/gssapi/t_imp_name.c
+++ b/src/tests/gssapi/t_imp_name.c
@@ -29,13 +29,37 @@
  */
 
 #include <stdio.h>
+#include <string.h>
 
 #include "common.h"
 
-int
-main(int argc, char **argv)
+static const char *
+oid_str(char type)
+{
+    switch (type) {
+    case 'p': /* GSS_KRB5_NT_PRINCIPAL_NAME */
+        return "{ 1 2 840 113554 1 2 2 1 }";
+    case 'e': /* GSS_KRB5_NT_ENTERPRISE_NAME */
+        return "{ 1 2 840 113554 1 2 2 6 }";
+    case 'h': /* GSS_C_NT_HOSTBASED_SERVICE */
+        return "{ 1 2 840 113554 1 2 1 4 }";
+    }
+    return "no_oid";
+}
+
+/* Return true if buf has the same contents as str, plus a zero byte if
+ * indicated by buf_includes_nullterm. */
+static int
+buf_eq_str(gss_buffer_t buf, const char *str, int buf_includes_nullterm)
+{
+    size_t len = strlen(str) + (buf_includes_nullterm ? 1 : 0);
+
+    return (buf->length == len && memcmp(buf->value, str, len) == 0);
+}
+
+static void
+test_import_name(const char *name)
 {
-    const char *name = "[email protected]";
     OM_uint32 major, minor;
     gss_name_t gss_name;
     gss_buffer_desc buf;
@@ -45,14 +69,24 @@ main(int argc, char **argv)
 
     major = gss_display_name(&minor, gss_name, &buf, &name_oid);
     check_gsserr("gss_display_name", major, minor);
-    printf("name is: %.*s\n", (int)buf.length, (char *)buf.value);
+    if (!buf_eq_str(&buf, name + 2, 0))
+        errout("wrong name string");
     (void)gss_release_buffer(&minor, &buf);
 
     major = gss_oid_to_str(&minor, name_oid, &buf);
     check_gsserr("gss_oid_to_str", major, minor);
-    printf("name type is: %.*s\n", (int)buf.length, (char *)buf.value);
+    if (!buf_eq_str(&buf, oid_str(*name), 1))
+        errout("wrong name type");
     (void)gss_release_buffer(&minor, &buf);
     (void)gss_release_name(&minor, &gss_name);
+}
+
+int
+main(int argc, char **argv)
+{
+    test_import_name("p:[email protected]");
+    test_import_name("e:[email protected]@MIT.EDU");
+    test_import_name("h:[email protected]");
 
     return 0;
 }
diff --git a/src/tests/gssapi/t_oid.c b/src/tests/gssapi/t_oid.c
index 417f7b9..1c9d394 100644
--- a/src/tests/gssapi/t_oid.c
+++ b/src/tests/gssapi/t_oid.c
@@ -59,6 +59,9 @@ static struct {
     /* GSS_KRB5_NT_PRINCIPAL_NAME */
     { "{ 1 2 840 113554 1 2 2 1 }", " {01 2 840 113554 1 2 2 1  } ",
       { 10, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x01" } },
+    /* GSS_KRB5_NT_ENTERPRISE_NAME */
+    { "{ 1 2 840 113554 1 2 2 6 }", " {1.2.840.113554.1.2.2.6} ",
+      { 10, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x06" } },
     /* gss_krb5_nt_principal */
     { "{ 1 2 840 113554 1 2 2 2 }", "{1.2.840.113554.1.2.2.2}",
       { 10, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02" } },
diff --git a/src/tests/gssapi/t_s4u.py b/src/tests/gssapi/t_s4u.py
index eb9545d..fd29e1a 100755
--- a/src/tests/gssapi/t_s4u.py
+++ b/src/tests/gssapi/t_s4u.py
@@ -143,14 +143,16 @@ realm.stop()
 mark('cross-realm S4U2Self')
 testprincs = {'krbtgt/SREALM': {'keys': 'aes128-cts'},
               'krbtgt/UREALM': {'keys': 'aes128-cts'},
-              'user': {'keys': 'aes128-cts'}}
+              'user': {'keys': 'aes128-cts', 'flags': '+preauth'}}
 kdcconf1 = {'realms': {'$realm': {'database_module': 'test'}},
             'dbmodules': {'test': {'db_library': 'test',
-                                   'princs': testprincs }}}
+                                   'princs': testprincs,
+                                   'alias': {'enterprise@abc': '@UREALM'}}}}
 kdcconf2 = {'realms': {'$realm': {'database_module': 'test'}},
             'dbmodules': {'test': {'db_library': 'test',
                                    'princs': testprincs,
-                                   'alias': {'user@SREALM': '@SREALM'}}}}
+                                   'alias': {'user@SREALM': '@SREALM',
+                                             'enterprise@abc': 'user'}}}}
 r1, r2 = cross_realms(2, xtgts=(),
                       args=({'realm': 'SREALM', 'kdc_conf': kdcconf1},
                             {'realm': 'UREALM', 'kdc_conf': kdcconf2}),
@@ -175,6 +177,24 @@ msgs = ('Getting credentials user@UREALM -> user@SREALM',
 r1.run(['./t_s4u', 'p:' + r2.user_princ, '-', r1.keytab], env=no_default,
        expected_trace=msgs)
 
+# Test realm identification of enterprise principal names ([MS-S4U]
+# 3.1.5.1.1.1).  Attach a bogus realm to the enterprise name to verify
+# that we start at the server realm.
+mark('cross-realm S4U2Self with enterprise name')
+msgs = ('Getting initial credentials for enterprise\\@abc@SREALM',
+        'Processing preauth types: PA-FOR-X509-USER (130)',
+        'Sending unauthenticated request',
+        '/Realm not local to KDC',
+        'Following referral to realm UREALM',
+        'Processing preauth types: PA-FOR-X509-USER (130)',
+        'Sending unauthenticated request',
+        '/Additional pre-authentication required',
+        '/Generic preauthentication failure',
+        'Getting credentials enterprise\\@abc@UREALM -> user@SREALM',
+        'TGS reply is for enterprise\@abc@UREALM -> user@SREALM')
+r1.run(['./t_s4u', 'e:enterprise@abc@NOREALM', '-', r1.keytab],
+       expected_trace=msgs)
+
 r1.stop()
 r2.stop()
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.