components/krb5/patches/024-smb-compat.patch
author Will Fiveash <will.fiveash@oracle.com>
Wed, 24 Feb 2016 10:43:57 -0600
changeset 5490 9bf0bc57423a
child 5562 880dc66054d5
permissions -rw-r--r--
PSARC/2015/144 Kerberos 1.13 Delivery to Userland 19153034 Add MIT Kerberos to the Userland Consolidation

#
# This patch allows for better interop with MS Windows clients accessing Solaris
# SMB services.  It fixes a few memory leaks and double frees found during SMB
# stress testing.  The CRs in order:
#
# 15580724 SUNBT6868908 Solaris acceptors should have returned KRB5KRB_AP_...
# 15648322 SUNBT6959251 coredump in gss_release_name+0x36
# 20416772 spnego_gss_accept_sec_context issue with incorrect KRB OID
# 16005842 Should retry SMB authentication upgrade to account for network...
# 15579598 SUNBT6867208 Windows client cannot recover from KRB5KRB_AP_ERR_SKEW..
#
# Note: MIT tickets will subsequently be filed, but the solution may differ from
# what we currently offer in Solaris, because they may want the changes as the
# default behavior therefore removing the dependency on the MS_INTEROP
# environment variable.
# Patch source: in-house
#
diff -pur old/src/lib/gssapi/krb5/accept_sec_context.c new/src/lib/gssapi/krb5/accept_sec_context.c
--- old/src/lib/gssapi/krb5/accept_sec_context.c	2015-03-30 23:53:08.814324223 -0600
+++ new/src/lib/gssapi/krb5/accept_sec_context.c	2015-04-02 00:05:08.243563972 -0600
@@ -1226,6 +1226,35 @@ fail:
          */
         memset(&krb_error_data, 0, sizeof(krb_error_data));
 
+        /*
+         * 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)
+            && getenv("MS_INTEROP")) {
+            code = KRB5KRB_AP_ERR_MODIFIED;
+            major_status = GSS_S_CONTINUE_NEEDED;
+        }
+
+        /*
+         * Set e-data to Windows constant (verified by MSFT).
+         *
+         * This facilitates the Windows CIFS client clock skew
+         * recovery feature.
+         */
+        if (code == KRB5KRB_AP_ERR_SKEW && getenv("MS_INTEROP")) {
+            char *ms_e_data = "\x30\x05\xa1\x03\x02\x01\x02";
+            int len = strlen(ms_e_data);
+
+            krb_error_data.e_data.data = malloc(len);
+            if (krb_error_data.e_data.data) {
+                (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 > KRB_ERR_MAX)
             code = 60 /* KRB_ERR_GENERIC */;
diff -pur old/src/lib/gssapi/spnego/spnego_mech.c new/src/lib/gssapi/spnego/spnego_mech.c
--- old/src/lib/gssapi/spnego/spnego_mech.c	2015-03-30 23:53:08.816648991 -0600
+++ new/src/lib/gssapi/spnego/spnego_mech.c	2015-04-15 18:52:40.053965732 -0600
@@ -190,6 +190,13 @@ static const gss_OID_set_desc spnego_oid
 };
 const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0;
 
+/* encoded OID octet string for NTLMSSP security mechanism */
+#define GSS_MECH_NTLMSSP_OID_LENGTH 10
+#define GSS_MECH_NTLMSSP_OID "\053\006\001\004\001\202\067\002\002\012"
+static gss_OID_desc ntlmssp_oid = {
+	GSS_MECH_NTLMSSP_OID_LENGTH, GSS_MECH_NTLMSSP_OID
+};
+
 static int make_NegHints(OM_uint32 *, spnego_gss_cred_id_t, gss_buffer_t *);
 static int put_neg_hints(unsigned char **, gss_buffer_t, unsigned int);
 static OM_uint32
@@ -1243,7 +1250,7 @@ make_NegHints(OM_uint32 *minor_status,
 					&hintNameBuf,
 					&hintNameType);
 	if (major_status != GSS_S_COMPLETE) {
-		gss_release_name(&minor, &hintName);
+		gss_release_name(&minor, &hintKerberosName);
 		return (major_status);
 	}
 	gss_release_name(&minor, &hintKerberosName);
@@ -1386,6 +1393,7 @@ acc_ctx_new(OM_uint32 *minor_status,
 	gss_buffer_desc der_mechTypes;
 	gss_OID mech_wanted;
 	spnego_gss_ctx_id_t sc = NULL;
+	unsigned int i;
 
 	ret = GSS_S_DEFECTIVE_TOKEN;
 	der_mechTypes.length = 0;
@@ -1409,6 +1417,24 @@ acc_ctx_new(OM_uint32 *minor_status,
 		goto cleanup;
 	}
 	/*
+	 * We add KRB5_WRONG here so that old MS clients can negotiate this
+	 * mechanism, which allows extensions in Kerberos (clock skew
+	 * adjustment, refresh ccache).
+	 */
+	for (i = 0; i < supported_mechSet->count; i++) {
+		if (is_kerb_mech(&supported_mechSet->elements[i])) {
+			extern gss_OID_desc * const gss_mech_krb5_wrong;
+			ret = gss_add_oid_set_member(minor_status,
+			    			     gss_mech_krb5_wrong,
+						     &supported_mechSet);
+			if (ret != GSS_S_COMPLETE) {
+				*return_token = NO_TOKEN_SEND;
+				goto cleanup;
+			}
+			break;
+		}
+        }
+	/*
 	 * Select the best match between the list of mechs
 	 * that the initiator requested and the list that
 	 * the acceptor will support.
@@ -2989,6 +3015,7 @@ get_available_mechs(OM_uint32 *minor_sta
 	int		found = 0;
 	OM_uint32 major_status = GSS_S_COMPLETE, tmpmin;
 	gss_OID_set mechs, goodmechs;
+	char *msinterop = getenv("MS_INTEROP");
 
 	major_status = gss_indicate_mechs(minor_status, &mechs);
 
@@ -3003,6 +3030,15 @@ get_available_mechs(OM_uint32 *minor_sta
 		return (major_status);
 	}
 
+	/*
+	 * If the required keytab entries for Kerberized SMB service are
+	 * missing due to an SMB authentication upgrade failure, SMB daemon
+	 * will set MS_INTEROP environmment variable to 1 to ensure only
+	 * NTLMSSP security mech is used for negotiation.
+	 */
+	if ((msinterop != NULL) && (!strcmp(msinterop, "1")))
+		goto ntlmssp;
+
 	for (i = 0; i < mechs->count && major_status == GSS_S_COMPLETE; i++) {
 		if ((mechs->elements[i].length
 		    != spnego_mechanism.mech_type.length) ||
@@ -3018,6 +3054,25 @@ get_available_mechs(OM_uint32 *minor_sta
 		}
 	}
 
+ntlmssp:
+	/*
+	 * Add NTLMSSP OID to the mech OID set only if MS_INTEROP env var has
+	 * been set to:
+	 * - "1" (NTLMSSP only) or
+	 * - "2" (both Krb5 and NTLMSSP)
+	 *
+	 * This is a requirement until NTLMSSP is implemented as a GSS-API
+	 * plugin.
+	 */
+	if ((msinterop != NULL) &&
+	    (!strcmp(msinterop, "1") || !strcmp(msinterop, "2"))) {
+		major_status = gss_add_oid_set_member(minor_status,
+		    &ntlmssp_oid, rmechs);
+
+		if (major_status == GSS_S_COMPLETE)
+			found++;
+	}
+
 	/*
 	 * If the caller wanted a list of creds returned,
 	 * trim the list of mechanisms down to only those
@@ -3593,9 +3648,17 @@ negotiate_mech(gss_OID_set supported, gs
 	for (i = 0; i < received->count; i++) {
 		gss_OID mech_oid = &received->elements[i];
 
+		/*
+		 * 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 (g_OID_equal(mech_oid, &gss_mech_krb5_wrong_oid))
 			mech_oid = (gss_OID)&gss_mech_krb5_oid;
+#endif
 
 		for (j = 0; j < supported->count; j++) {
 			if (g_OID_equal(mech_oid, &supported->elements[j])) {