summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorShawn Emery <Shawn.Emery@Sun.COM>2009-11-12 17:40:34 -0700
committerShawn Emery <Shawn.Emery@Sun.COM>2009-11-12 17:40:34 -0700
commit72f0806acd90f56fb47a8087c33cfeaec527fdda (patch)
treef12af7094149cec193c6329636b95ccc410ceb09 /usr/src
parent56e7e6c6e6c82bcc8d19a12a3bd8f9fd529ba5b4 (diff)
downloadillumos-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.sh50
-rw-r--r--usr/src/cmd/krb5/kadmin/kclient/ksetpw.c2
-rw-r--r--usr/src/lib/gss_mechs/mech_krb5/krb5/keytab/kt_file.c22
-rw-r--r--usr/src/lib/gss_mechs/mech_krb5/krb5/krb/princ_comp.c35
-rw-r--r--usr/src/lib/gss_mechs/mech_krb5/mapfile-vers1
-rw-r--r--usr/src/lib/gss_mechs/mech_krb5/mech/accept_sec_context.c47
-rw-r--r--usr/src/lib/gss_mechs/mech_krb5/mech/krb5_gss_glue.c16
-rw-r--r--usr/src/lib/gss_mechs/mech_spnego/mech/spnego_mech.c25
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)