diff options
author | Shawn Emery <Shawn.Emery@Sun.COM> | 2009-11-12 17:40:34 -0700 |
---|---|---|
committer | Shawn Emery <Shawn.Emery@Sun.COM> | 2009-11-12 17:40:34 -0700 |
commit | 72f0806acd90f56fb47a8087c33cfeaec527fdda (patch) | |
tree | f12af7094149cec193c6329636b95ccc410ceb09 /usr/src | |
parent | 56e7e6c6e6c82bcc8d19a12a3bd8f9fd529ba5b4 (diff) | |
download | illumos-gate-72f0806acd90f56fb47a8087c33cfeaec527fdda.tar.gz |
6885980 Need case-insensitive keytab lookups for MS interop
6885387 gsskrb5_extract_authz_data_from_sec_context() fails with service ticket sent by Windows 7 client
6858400 kclient cant join Windows AD domain if hostname is 20 characters or longer
6867203 Solaris acceptors fail in Windows 2000 environment
6868908 Solaris acceptors should have returned KRB5KRB_AP_ERR_MODIFIED for Microsoft interoperability
6867208 Windows client cannot recover from KRB5KRB_AP_ERR_SKEW error
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/krb5/kadmin/kclient/kclient.sh | 50 | ||||
-rw-r--r-- | usr/src/cmd/krb5/kadmin/kclient/ksetpw.c | 2 | ||||
-rw-r--r-- | usr/src/lib/gss_mechs/mech_krb5/krb5/keytab/kt_file.c | 22 | ||||
-rw-r--r-- | usr/src/lib/gss_mechs/mech_krb5/krb5/krb/princ_comp.c | 35 | ||||
-rw-r--r-- | usr/src/lib/gss_mechs/mech_krb5/mapfile-vers | 1 | ||||
-rw-r--r-- | usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c | 47 | ||||
-rw-r--r-- | usr/src/lib/gss_mechs/mech_krb5/mech/krb5_gss_glue.c | 16 | ||||
-rw-r--r-- | usr/src/lib/gss_mechs/mech_spnego/mech/spnego_mech.c | 25 |
8 files changed, 152 insertions, 46 deletions
diff --git a/usr/src/cmd/krb5/kadmin/kclient/kclient.sh b/usr/src/cmd/krb5/kadmin/kclient/kclient.sh index db87bfb79d..f205755f61 100644 --- a/usr/src/cmd/krb5/kadmin/kclient/kclient.sh +++ b/usr/src/cmd/krb5/kadmin/kclient/kclient.sh @@ -29,6 +29,7 @@ # be generated and local host's keytab file setup. The script # can also optionally setup the system to do kerberized nfs and # bringover a master krb5.conf copy from a specified location. +# function cleanup { @@ -1156,6 +1157,8 @@ function getKDCDC { function join_domain { typeset -u upcase_nodename + typeset -l locase_nodename + typeset -L15 string15 typeset netbios_nodename fqdn container=Computers @@ -1175,7 +1178,16 @@ function join_domain { dom=$domain realm=$domain - upcase_nodename=$hostname + + if [[ ${#hostname} -gt 15 ]]; then + string15=$hostname + upcase_nodename=$string15 + locase_nodename=$string15 + else + upcase_nodename=$hostname + locase_nodename=$hostname + fi + netbios_nodename="${upcase_nodename}\$" fqdn=$hostname.$domain upn=host/${fqdn}@${realm} @@ -1313,9 +1325,10 @@ function join_domain { fi fi + [[ -z $dn ]] && dn="CN=${upcase_nodename},${baseDN}" if $modify_existing; then cat > "$object" <<EOF -dn: CN=$upcase_nodename,$baseDN +dn: $dn changetype: modify replace: userPrincipalName userPrincipalName: $upn @@ -1333,12 +1346,13 @@ EOF printf "$(gettext "A machine account already exists; updating it").\n" ldapadd -h "$dc" $ldap_args -f "$object" > /dev/null 2>&1 if [[ $? -ne 0 ]]; then - printf "$(gettext "Failed to create the AD object via LDAP").\n" >&2 + printf "$(gettext "Failed to modify the AD object via LDAP").\n" >&2 error_message fi else + dn="CN=${upcase_nodename},${baseDN}" cat > "$object" <<EOF -dn: CN=$upcase_nodename,$baseDN +dn: $dn objectClass: computer cn: $upcase_nodename sAMAccountName: ${netbios_nodename} @@ -1446,7 +1460,7 @@ EOF # encryption type attributes. if [[ $level -gt 2 ]]; then cat > "$object" <<EOF -dn: CN=$upcase_nodename,$baseDN +dn: $dn changetype: modify replace: msDS-SupportedEncryptionTypes msDS-SupportedEncryptionTypes: $val @@ -1469,7 +1483,7 @@ EOF # and possibly UseDesOnly (2097152) (see above) # cat > "$object" <<EOF -dn: CN=$upcase_nodename,$baseDN +dn: $dn changetype: modify replace: userAccountControl userAccountControl: $userAccountControl @@ -1491,13 +1505,14 @@ EOF rm $new_keytab > /dev/null 2>&1 cat > "$object" <<EOF -dn: CN=$upcase_nodename,$baseDN +dn: $dn changetype: modify add: servicePrincipalName servicePrincipalName: nfs/${fqdn} servicePrincipalName: HTTP/${fqdn} servicePrincipalName: root/${fqdn} servicePrincipalName: cifs/${fqdn} +servicePrincipalName: host/${upcase_nodename} EOF ldapmodify -h "$dc" $ldap_args -f "$object" >/dev/null 2>&1 if [[ $? -ne 0 ]]; then @@ -1507,10 +1522,10 @@ EOF # # In Windows, unlike MIT based implementations we salt the keys with - # the UPN, which is based on the host/fqdn@realm elements, not with the - # individual SPN strings. + # the UPN, which is based on the host/string15@realm elements, not + # with the individual SPN strings. # - salt=host/${fqdn}@${realm} + salt=host/${locase_nodename}.${domain}@${realm} printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" host/${fqdn}@${realm} > /dev/null 2>&1 if [[ $? -ne 0 ]] @@ -1519,38 +1534,35 @@ EOF error_message fi - printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" HOST/${fqdn}@${realm} > /dev/null 2>&1 + printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" nfs/${fqdn}@${realm} > /dev/null 2>&1 if [[ $? -ne 0 ]] then printf "$(gettext "Failed to set account password").\n" >&2 error_message fi - # Could be setting ${netbios_nodename}@${realm}, but for now no one - # is requesting this. - - printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" nfs/${fqdn}@${realm} > /dev/null 2>&1 + printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" HTTP/${fqdn}@${realm} > /dev/null 2>&1 if [[ $? -ne 0 ]] then printf "$(gettext "Failed to set account password").\n" >&2 error_message fi - printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" HTTP/${fqdn}@${realm} > /dev/null 2>&1 + printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" root/${fqdn}@${realm} > /dev/null 2>&1 if [[ $? -ne 0 ]] then printf "$(gettext "Failed to set account password").\n" >&2 error_message fi - printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" root/${fqdn}@${realm} > /dev/null 2>&1 + printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" cifs/${fqdn}@${realm} > /dev/null 2>&1 if [[ $? -ne 0 ]] then printf "$(gettext "Failed to set account password").\n" >&2 error_message fi - printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" cifs/${fqdn}@${realm} > /dev/null 2>&1 + printf "%s" $newpw | $KSETPW -n -s $salt -v $kvno -k "$new_keytab" "${args[@]}" ${netbios_nodename}@${realm} > /dev/null 2>&1 if [[ $? -ne 0 ]] then printf "$(gettext "Failed to set account password").\n" >&2 @@ -1563,7 +1575,7 @@ EOF setSMB $dom $dc - printf -- "\n---------------------------------------------------\n" + printf -- "---------------------------------------------------\n" printf "$(gettext "Setup COMPLETE").\n\n" kdestroy -q 1>$TMP_FILE 2>&1 diff --git a/usr/src/cmd/krb5/kadmin/kclient/ksetpw.c b/usr/src/cmd/krb5/kadmin/kclient/ksetpw.c index e33ede92cd..cde7c4b23a 100644 --- a/usr/src/cmd/krb5/kadmin/kclient/ksetpw.c +++ b/usr/src/cmd/krb5/kadmin/kclient/ksetpw.c @@ -381,7 +381,7 @@ void usage() { (void) fprintf(stderr, gettext("Usage: %s [-c ccache] [-k keytab] " - "[-e enctype_list] [-n] princ\n"), whoami); + "[-e enctype_list] [-s salt_name] [-n] princ\n"), whoami); (void) fprintf(stderr, gettext("\t-n\tDon't set the principal's password\n")); (void) fprintf(stderr, gettext("\tenctype_list is a comma or whitespace" diff --git a/usr/src/lib/gss_mechs/mech_krb5/krb5/keytab/kt_file.c b/usr/src/lib/gss_mechs/mech_krb5/krb5/keytab/kt_file.c index 5677cd4496..3504bc69f6 100644 --- a/usr/src/lib/gss_mechs/mech_krb5/krb5/keytab/kt_file.c +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/keytab/kt_file.c @@ -1,9 +1,8 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - /* * lib/krb5/keytab/kt_file.c * @@ -77,6 +76,10 @@ typedef struct _krb5_ktfile_data { extern const struct _krb5_kt_ops krb5_ktf_ops; extern const struct _krb5_kt_ops krb5_ktf_writable_ops; +extern krb5_boolean KRB5_CALLCONV +__krb5_principal_compare_case_ins(krb5_context context, + krb5_const_principal princ1, krb5_const_principal princ2); + krb5_error_code KRB5_CALLCONV krb5_ktfile_resolve (krb5_context, const char *, @@ -291,7 +294,20 @@ krb5_ktfile_get_entry(krb5_context context, krb5_keytab id, /* if the principal isn't the one requested, free new_entry and continue to the next. */ - if (!krb5_principal_compare(context, principal, new_entry.principal)) { + /* + * Solaris Kerberos: MS Interop requires that case insensitive + * comparisons of service and host components are performed for key + * table lookup, etc. Only called if the private environment variable + * MS_INTEROP is defined. + */ + if (krb5_getenv("MS_INTEROP")) { + if (!__krb5_principal_compare_case_ins(context, principal, + new_entry.principal)) { + krb5_kt_free_entry(context, &new_entry); + continue; + } + } else if (!krb5_principal_compare(context, principal, + new_entry.principal)) { krb5_kt_free_entry(context, &new_entry); continue; } diff --git a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/princ_comp.c b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/princ_comp.c index c672a7c634..d2250efe25 100644 --- a/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/princ_comp.c +++ b/usr/src/lib/gss_mechs/mech_krb5/krb5/krb/princ_comp.c @@ -1,4 +1,3 @@ -#pragma ident "%Z%%M% %I% %E% SMI" /* * lib/krb5/krb/princ_comp.c * @@ -29,6 +28,11 @@ * not. */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + #include <k5-int.h> /*ARGSUSED*/ @@ -68,6 +72,35 @@ krb5_principal_compare(krb5_context context, krb5_const_principal princ1, krb5_c return TRUE; } +/* + * Solaris Kerberos: MS Interop requires that case insensitive comparisons of + * service and host components are performed for key table lookup, etc. Only + * called if the private environment variable MS_INTEROP is defined. + */ +krb5_boolean KRB5_CALLCONV +__krb5_principal_compare_case_ins(krb5_context context, + krb5_const_principal princ1, krb5_const_principal princ2) +{ + register int i; + krb5_int32 nelem; + + nelem = krb5_princ_size(context, princ1); + if (nelem != krb5_princ_size(context, princ2)) + return FALSE; + + if (! krb5_realm_compare(context, princ1, princ2)) + return FALSE; + + for (i = 0; i < (int) nelem; i++) { + register const krb5_data *p1 = krb5_princ_component(context, princ1, i); + register const krb5_data *p2 = krb5_princ_component(context, princ2, i); + if (p1->length != p2->length || + strncasecmp(p1->data, p2->data, p1->length)) + return FALSE; + } + return TRUE; +} + krb5_boolean KRB5_CALLCONV krb5_is_referral_realm(const krb5_data *r) { /* diff --git a/usr/src/lib/gss_mechs/mech_krb5/mapfile-vers b/usr/src/lib/gss_mechs/mech_krb5/mapfile-vers index 4e65288bde..2e1bf90aac 100644 --- a/usr/src/lib/gss_mechs/mech_krb5/mapfile-vers +++ b/usr/src/lib/gss_mechs/mech_krb5/mapfile-vers @@ -219,6 +219,7 @@ SUNWprivate_1.1 { gss_krb5_copy_ccache; gss_mech_krb5; gss_mech_krb5_old; + gss_mech_krb5_wrong; gss_mech_set_krb5; gss_mech_set_krb5_both; gss_mech_set_krb5_old; diff --git a/usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c b/usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c index d6b5bfcbbc..0bbec8814c 100644 --- a/usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c @@ -1,8 +1,4 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ -/* * Copyright 2000, 2004 by the Massachusetts Institute of Technology. * All Rights Reserved. * @@ -74,6 +70,11 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + #include "k5-int.h" #include "gssapiP_krb5.h" #ifdef HAVE_MEMORY_H @@ -381,6 +382,12 @@ krb5_gss_accept_sec_context(minor_status, context_handle, input_token->length, 1))) { mech_used = gss_mech_krb5; } else if ((code == G_WRONG_MECH) && + !(code = g_verify_token_header(gss_mech_krb5_wrong, + (uint32_t *)&(ap_req.length), + &ptr, KG_TOK_CTX_AP_REQ, + input_token->length, 1))) { + mech_used = gss_mech_krb5_wrong; + } else if ((code == G_WRONG_MECH) && !(code = g_verify_token_header(gss_mech_krb5_old, (uint32_t *)&(ap_req.length), &ptr, KG_TOK_CTX_AP_REQ, @@ -1169,16 +1176,17 @@ krb5_gss_accept_sec_context(minor_status, context_handle, */ memset(&krb_error_data, 0, sizeof(krb_error_data)); - code -= ERROR_TABLE_BASE_krb5; - if (code < 0 || code > 128) - code = 60 /* KRB_ERR_GENERIC */; - - krb_error_data.error = code; - (void) krb5_us_timeofday(context, &krb_error_data.stime, - &krb_error_data.susec); - krb_error_data.server = cred->princ; + /* + * Solaris Kerberos: We need to remap error conditions for buggy + * Windows clients if the MS_INTEROP env var has been set. + */ + if ((code == KRB5KRB_AP_ERR_BAD_INTEGRITY || + code == KRB5KRB_AP_ERR_NOKEY || code == KRB5KRB_AP_ERR_BADKEYVER) + && krb5_getenv("MS_INTEROP")) { + code = KRB5KRB_AP_ERR_MODIFIED; + major_status = GSS_S_CONTINUE_NEEDED; + } - if (code == KRB5KRB_AP_ERR_SKEW) { /* * SUNW17PACresync / Solaris Kerberos * Set e-data to Windows constant. @@ -1187,6 +1195,7 @@ krb5_gss_accept_sec_context(minor_status, context_handle, * This facilitates the Windows CIFS client clock skew * recovery feature. */ + if (code == KRB5KRB_AP_ERR_SKEW && krb5_getenv("MS_INTEROP")) { char *ms_e_data = "\x30\x05\xa1\x03\x02\x01\x02"; int len = strlen(ms_e_data); @@ -1195,7 +1204,17 @@ krb5_gss_accept_sec_context(minor_status, context_handle, (void) memcpy(krb_error_data.e_data.data, ms_e_data, len); krb_error_data.e_data.length = len; } - } + major_status = GSS_S_CONTINUE_NEEDED; + } + + code -= ERROR_TABLE_BASE_krb5; + if (code < 0 || code > 128) + code = 60 /* KRB_ERR_GENERIC */; + + krb_error_data.error = code; + (void) krb5_us_timeofday(context, &krb_error_data.stime, + &krb_error_data.susec); + krb_error_data.server = cred->princ; code = krb5_mk_error(context, &krb_error_data, &scratch); if (code) diff --git a/usr/src/lib/gss_mechs/mech_krb5/mech/krb5_gss_glue.c b/usr/src/lib/gss_mechs/mech_krb5/mech/krb5_gss_glue.c index d8d11b455a..d8e3beb5c9 100644 --- a/usr/src/lib/gss_mechs/mech_krb5/mech/krb5_gss_glue.c +++ b/usr/src/lib/gss_mechs/mech_krb5/mech/krb5_gss_glue.c @@ -1326,8 +1326,13 @@ gss_mechanism gss_mech_initialize(oid) const gss_OID oid; { + /* + * Solaris Kerberos: We also want to use the same functions for KRB5 as + * we do for the MS KRB5 (krb5_mechanism_wrong). So both are valid. + */ /* ensure that the requested oid matches our oid */ - if (oid == NULL || !g_OID_equal(oid, &krb5_mechanism.mech_type)) { + if (oid == NULL || (!g_OID_equal(oid, &krb5_mechanism.mech_type) && + !g_OID_equal(oid, &krb5_mechanism_wrong.mech_type))) { (void) syslog(LOG_INFO, "krb5mech: gss_mech_initialize: bad oid"); return (NULL); } @@ -1379,16 +1384,13 @@ gsskrb5_extract_authz_data_from_sec_context( return major_status; } - /* * SUNW17PACresync / Solaris Kerberos - * MIT17 expects just 1 but our testing with Win2008 shows - * it returns 2. So we now handle that and rewhack mem mgmt as appro. + * MIT17 allows only count==1 which is correct for pre-Win2008 but + * our testing with Win2008 shows count==2 and Win7 count==3. */ - if (data_set == GSS_C_NO_BUFFER_SET || - (data_set->count != 1 && data_set->count != 2)) { + if ((data_set == GSS_C_NO_BUFFER_SET) || (data_set->count == 0)) { gss_release_buffer_set(minor_status, &data_set); - return GSS_S_FAILURE; } diff --git a/usr/src/lib/gss_mechs/mech_spnego/mech/spnego_mech.c b/usr/src/lib/gss_mechs/mech_spnego/mech/spnego_mech.c index f3cc82e67e..9e1cac8e55 100644 --- a/usr/src/lib/gss_mechs/mech_spnego/mech/spnego_mech.c +++ b/usr/src/lib/gss_mechs/mech_spnego/mech/spnego_mech.c @@ -2598,6 +2598,21 @@ get_available_mechs(OM_uint32 *minor_status, memcmp(mechs->elements[i].elements, spnego_mechanism.mech_type.elements, spnego_mechanism.mech_type.length)) { + /* + * Solaris Kerberos: gss_indicate_mechs is stupid as + * it never inferences any of the related OIDs of the + * mechanisms configured, e.g. KRB5_OLD, KRB5_WRONG. + * We add KRB5_WRONG here so that old MS clients can + * negotiate this mechanism, which allows extensions + * in Kerberos (clock skew adjustment, refresh ccache). + */ + if (is_kerb_mech(&mechs->elements[i])) { + extern gss_OID_desc * const gss_mech_krb5_wrong; + + major_status = + gss_add_oid_set_member(minor_status, + gss_mech_krb5_wrong, rmechs); + } major_status = gss_add_oid_set_member(minor_status, &mechs->elements[i], @@ -3098,10 +3113,18 @@ negotiate_mech_type(OM_uint32 *minor_status, for (i = 0; i < mechset->count; i++) { gss_OID mech_oid = &mechset->elements[i]; + /* + * Solaris Kerberos: MIT compares against MS' wrong OID, but + * we actually want to select it if the client supports, as this + * will enable features on MS clients that allow credential + * refresh on rekeying and caching system times from servers. + */ +#if 0 /* Accept wrong mechanism OID from MS clients */ if (mech_oid->length == gss_mech_krb5_wrong_oid.length && memcmp(mech_oid->elements, gss_mech_krb5_wrong_oid.elements, mech_oid->length) == 0) - mech_oid = (gss_OID)&gss_mech_krb5_oid;; + mech_oid = (gss_OID)&gss_mech_krb5_oid; +#endif gss_test_oid_set_member(minor_status, mech_oid, supported_mechSet, &present); if (!present) |