diff options
author | Isaac Boukris <iboukris@gmail.com> | 2018-10-15 18:33:15 +0300 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2018-10-23 16:44:02 -0400 |
commit | 0b872730081f01d0d2b6f78675bb5c74604cef62 (patch) | |
tree | e6bea7500dc8c5581e68cbfaad1087b1e1186845 | |
parent | a7020d32cf4c7692aec1903e7818d779713ecd43 (diff) | |
download | krb5-0b872730081f01d0d2b6f78675bb5c74604cef62.zip krb5-0b872730081f01d0d2b6f78675bb5c74604cef62.tar.gz krb5-0b872730081f01d0d2b6f78675bb5c74604cef62.tar.bz2 |
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.
[ghudson@mit.edu: added Windows export entry; adjusted comments and
test code; edited commit message]
ticket: 8756 (new)
-rw-r--r-- | doc/appdev/gssapi.rst | 6 | ||||
-rw-r--r-- | src/lib/gssapi/krb5/gssapi_krb5.c | 3 | ||||
-rw-r--r-- | src/lib/gssapi/krb5/gssapi_krb5.h | 5 | ||||
-rw-r--r-- | src/lib/gssapi/krb5/import_name.c | 8 | ||||
-rw-r--r-- | src/lib/gssapi/libgssapi_krb5.exports | 1 | ||||
-rw-r--r-- | src/lib/gssapi32.def | 2 | ||||
-rw-r--r-- | src/plugins/kdb/test/kdb_test.c | 3 | ||||
-rw-r--r-- | src/tests/gssapi/Makefile.in | 1 | ||||
-rw-r--r-- | src/tests/gssapi/common.c | 4 | ||||
-rw-r--r-- | src/tests/gssapi/t_imp_name.c | 44 | ||||
-rw-r--r-- | src/tests/gssapi/t_oid.c | 3 | ||||
-rwxr-xr-x | 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 = "host@dcl.mit.edu"; 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:user@MIT.EDU"); + test_import_name("e:enterprise@mit.edu@MIT.EDU"); + test_import_name("h:HOST@dc1.mit.edu"); 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() |