[SCM] Samba Shared Repository - branch master updated

Andreas Schneider asn at samba.org
Fri Mar 10 14:35:02 UTC 2017


The branch, master has been updated
       via  49c9ef64 objectclass_attrs: Remove schema copy shallow from attr_handler2
       via  3314bf5 s4:kdc: disable principal based autodetected referral detection
       via  209886e HEIMDAL:kdc: make it possible to disable the principal based referral detection
       via  b8bca7d s3:gse: Correctly handle external trusts with MIT
       via  ada31d6 s3:gse: Check if we have a target_princpal set we should use
       via  3ba1ad1 s3:gse: Move setup of service_principal to update function
       via  e6b1e58 s3:gse: Pass down the gensec_security pointer
       via  804e828 krb5_wrap: Remove obsolete smb_krb5_get_principal_from_service_hostname()
       via  a3d95ed s3:gse: Use smb_krb5_get_realm_from_hostname()
       via  2dd4887 s4:gensec_gssapi: Correctly handle external trusts with MIT
       via  3781eb2 s4:gensec_gssapi: Use smb_krb5_get_realm_from_hostname()
       via  bf6358b s4:gensec_gssapi: Move setup of service_principal to update function
       via  8f7c452 s4:gensec-gssapi: Create a helper function to setup server_principal
       via  339a2ec krb5_wrap: Make smb_krb5_get_realm_from_hostname() public
       via  f0c4fca krb5_wrap: pass client_realm to smb_krb5_get_realm_from_hostname()
       via  6522892 krb5_wrap: Try to guess the correct realm from the service hostname
       via  946f9dd krb5_wrap: Do not return an empty realm from smb_krb5_get_realm_from_hostname()
       via  42bd003 testprogs: Add kinit_trusts tests with smbclient4
       via  9b3ff90 testprogs: Use smbclient by default in test_kinit_trusts
      from  7142a88 waf: disable-python - don't include python.h in test_headers.c

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 49c9ef641d82fd09faa6a7ce405e5b8aa1aeda69
Author: Garming Sam <garming at catalyst.net.nz>
Date:   Thu Mar 9 12:22:13 2017 +1300

    objectclass_attrs: Remove schema copy shallow from attr_handler2
    
    This appears quite expensive (particularly in provision), and also
    unnecessary.
    
    Signed-off-by: Garming Sam <garming at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>
    
    Autobuild-User(master): Andreas Schneider <asn at cryptomilk.org>
    Autobuild-Date(master): Fri Mar 10 15:34:39 CET 2017 on sn-devel-144

commit 3314bf52aaef60ef5cc1110587b53064df7c475d
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sun Jan 29 17:20:09 2017 +0100

    s4:kdc: disable principal based autodetected referral detection
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>

commit 209886e95c3afe1e4e50bacc30b40a543856a7a0
Author: Stefan Metzmacher <metze at samba.org>
Date:   Sun Jan 29 17:19:14 2017 +0100

    HEIMDAL:kdc: make it possible to disable the principal based referral detection
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>

commit b8bca7d08fe05758e536767b1146cdcdd8b9fee3
Author: Andreas Schneider <asn at samba.org>
Date:   Thu Mar 9 08:18:27 2017 +0100

    s3:gse: Correctly handle external trusts with MIT
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit ada31d65d6c5929d2fbddfea5611a5f5fe5a0d74
Author: Andreas Schneider <asn at samba.org>
Date:   Thu Mar 9 08:11:07 2017 +0100

    s3:gse: Check if we have a target_princpal set we should use
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit 3ba1ad1f8c7871070d0ecbe5d49c5c44afe98bbf
Author: Andreas Schneider <asn at samba.org>
Date:   Thu Mar 9 08:05:26 2017 +0100

    s3:gse: Move setup of service_principal to update function
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit e6b1e58874de30d094f9bce474479cfddb39d3fc
Author: Andreas Schneider <asn at samba.org>
Date:   Mon Mar 6 08:16:11 2017 +0100

    s3:gse: Pass down the gensec_security pointer
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit 804e828d52ec922f3970e847652ab1ee5538b9b0
Author: Andreas Schneider <asn at samba.org>
Date:   Thu Mar 9 09:10:12 2017 +0100

    krb5_wrap: Remove obsolete smb_krb5_get_principal_from_service_hostname()
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit a3d95ed9037fb8b14a451da02dcadf011485ae34
Author: Andreas Schneider <asn at samba.org>
Date:   Thu Mar 9 07:54:29 2017 +0100

    s3:gse: Use smb_krb5_get_realm_from_hostname()
    
    With credentials for administrator at FOREST1.EXAMPLE.COM
    this patch changes the target_principal for
    the ldap service of host dc2.forest2.example.com
    from
    
      ldap/dc2.forest2.example.com at FOREST1.EXAMPLE.COM
    
    to
    
      ldap/dc2.forest2.example.com at FOREST2.EXAMPLE.COM
    
    Typically ldap/dc2.forest2.example.com at FOREST1.EXAMPLE.COM
    should be used in order to allow the KDC of FOREST1.EXAMPLE.COM
    to generate a referral ticket for
    krbtgt/FOREST2.EXAMPLE.COM at FOREST1.EXAMPLE.COM.
    
    The problem is that KDCs only return such referral tickets
    if there's a forest trust between FOREST1.EXAMPLE.COM
    and FOREST2.EXAMPLE.COM. If there's only an external domain
    trust between FOREST1.EXAMPLE.COM and FOREST2.EXAMPLE.COM
    the KDC of FOREST1.EXAMPLE.COM will respond with S_PRINCIPAL_UNKNOWN
    when being asked for ldap/dc2.forest2.example.com at FOREST1.EXAMPLE.COM.
    
    In the case of an external trust the client can still ask
    explicitly for krbtgt/FOREST2.EXAMPLE.COM at FOREST1.EXAMPLE.COM
    and the KDC of FOREST1.EXAMPLE.COM will generate it.
    
    From there the client can use the
    krbtgt/FOREST2.EXAMPLE.COM at FOREST1.EXAMPLE.COM
    ticket and ask a KDC of FOREST2.EXAMPLE.COM for a
    service ticket for ldap/dc2.forest2.example.com at FOREST2.EXAMPLE.COM.
    
    With Heimdal we'll get the fallback on S_PRINCIPAL_UNKNOWN behavior
    when we pass ldap/dc2.forest2.example.com at FOREST2.EXAMPLE.COM as
    target principal. As _krb5_get_cred_kdc_any() first calls
    get_cred_kdc_referral() (which always starts with the client realm)
    and falls back to get_cred_kdc_capath() (which starts with the given realm).
    
    MIT krb5 only tries the given realm of the target principal,
    if we want to autodetect support for transitive forest trusts,
    we'll have to do the fallback ourself.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit 2dd4887648bf006a577e03fc027e881738ca04ab
Author: Andreas Schneider <asn at samba.org>
Date:   Wed Mar 8 13:10:05 2017 +0100

    s4:gensec_gssapi: Correctly handle external trusts with MIT
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit 3781eb250173981a8890b82d1ff9358f144034cd
Author: Andreas Schneider <asn at samba.org>
Date:   Wed Mar 8 11:03:17 2017 +0100

    s4:gensec_gssapi: Use smb_krb5_get_realm_from_hostname()
    
    With credentials for administrator at FOREST1.EXAMPLE.COM
    this patch changes the target_principal for
    the ldap service of host dc2.forest2.example.com
    from
    
      ldap/dc2.forest2.example.com at FOREST1.EXAMPLE.COM
    
    to
    
      ldap/dc2.forest2.example.com at FOREST2.EXAMPLE.COM
    
    Typically ldap/dc2.forest2.example.com at FOREST1.EXAMPLE.COM
    should be used in order to allow the KDC of FOREST1.EXAMPLE.COM
    to generate a referral ticket for
    krbtgt/FOREST2.EXAMPLE.COM at FOREST1.EXAMPLE.COM.
    
    The problem is that KDCs only return such referral tickets
    if there's a forest trust between FOREST1.EXAMPLE.COM
    and FOREST2.EXAMPLE.COM. If there's only an external domain
    trust between FOREST1.EXAMPLE.COM and FOREST2.EXAMPLE.COM
    the KDC of FOREST1.EXAMPLE.COM will respond with S_PRINCIPAL_UNKNOWN
    when being asked for ldap/dc2.forest2.example.com at FOREST1.EXAMPLE.COM.
    
    In the case of an external trust the client can still ask
    explicitly for krbtgt/FOREST2.EXAMPLE.COM at FOREST1.EXAMPLE.COM
    and the KDC of FOREST1.EXAMPLE.COM will generate it.
    
    From there the client can use the
    krbtgt/FOREST2.EXAMPLE.COM at FOREST1.EXAMPLE.COM
    ticket and ask a KDC of FOREST2.EXAMPLE.COM for a
    service ticket for ldap/dc2.forest2.example.com at FOREST2.EXAMPLE.COM.
    
    With Heimdal we'll get the fallback on S_PRINCIPAL_UNKNOWN behavior
    when we pass ldap/dc2.forest2.example.com at FOREST2.EXAMPLE.COM as
    target principal. As _krb5_get_cred_kdc_any() first calls
    get_cred_kdc_referral() (which always starts with the client realm)
    and falls back to get_cred_kdc_capath() (which starts with the given realm).
    
    MIT krb5 only tries the given realm of the target principal,
    if we want to autodetect support for transitive forest trusts,
    we'll have to do the fallback ourself.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit bf6358bf035e7ad48bd15cc2164afab2a19e7ad6
Author: Andreas Schneider <asn at samba.org>
Date:   Wed Mar 8 12:34:59 2017 +0100

    s4:gensec_gssapi: Move setup of service_principal to update function
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit 8f7c4529420316b553c80cd3d19b6996525b029a
Author: Andreas Schneider <asn at samba.org>
Date:   Mon Mar 6 09:19:13 2017 +0100

    s4:gensec-gssapi: Create a helper function to setup server_principal
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit 339a2ecb3f05d0c9e860a5dd59b8bdbc51d4ffa7
Author: Andreas Schneider <asn at samba.org>
Date:   Wed Mar 8 11:56:30 2017 +0100

    krb5_wrap: Make smb_krb5_get_realm_from_hostname() public
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit f0c4fcace586197d5c170f6a9dcc175df23e3802
Author: Andreas Schneider <asn at samba.org>
Date:   Wed Mar 8 11:56:30 2017 +0100

    krb5_wrap: pass client_realm to smb_krb5_get_realm_from_hostname()
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit 65228925ab3c4da4ae299f77cae219fc7d37cc68
Author: Andreas Schneider <asn at samba.org>
Date:   Wed Mar 8 10:48:52 2017 +0100

    krb5_wrap: Try to guess the correct realm from the service hostname
    
    If we do not get a realm mapping from the krb5.conf or from the Kerberos
    library try to guess it from the service hostname. The guessing of the
    realm from the service hostname is already implemented in Heimdal. This
    makes the behavior of smb_krb5_get_realm_from_hostname() consistent
    with both MIT and Heimdal.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit 946f9dd1170be63b91e31ce825ea123f3c07329b
Author: Andreas Schneider <asn at samba.org>
Date:   Wed Mar 8 10:40:08 2017 +0100

    krb5_wrap: Do not return an empty realm from smb_krb5_get_realm_from_hostname()
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Pair-Programmed-With: Stefan Metzmacher <metze at samba.org>
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>

commit 42bd003f468ab95b6ac97c774e2cd217d06c05ed
Author: Andreas Schneider <asn at samba.org>
Date:   Mon Mar 6 09:15:45 2017 +0100

    testprogs: Add kinit_trusts tests with smbclient4
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit 9b3ff90dbc5cc1017dfc89831a1081272e6c2356
Author: Andreas Schneider <asn at samba.org>
Date:   Mon Mar 6 09:13:09 2017 +0100

    testprogs: Use smbclient by default in test_kinit_trusts
    
    This is the tool we use by default and we should test with it.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12554
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 lib/krb5_wrap/krb5_samba.c                         | 164 +++++----------
 lib/krb5_wrap/krb5_samba.h                         |   7 +-
 source3/librpc/crypto/gse.c                        | 224 +++++++++++++++++----
 source4/auth/gensec/gensec_gssapi.c                | 212 ++++++++++++++++---
 source4/auth/gensec/gensec_gssapi.h                |   2 +-
 source4/dsdb/samdb/ldb_modules/objectclass_attrs.c |  14 +-
 source4/dsdb/schema/schema_init.c                  |  22 +-
 source4/heimdal/kdc/default_config.c               |   1 +
 source4/heimdal/kdc/kdc.h                          |   2 +
 source4/heimdal/kdc/krb5tgs.c                      |   4 +-
 source4/kdc/kdc-heimdal.c                          |   2 +
 testprogs/blackbox/test_kinit_trusts_heimdal.sh    |  10 +-
 12 files changed, 450 insertions(+), 214 deletions(-)


Changeset truncated at 500 lines:

diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c
index 8ebf601..6fa0d82 100644
--- a/lib/krb5_wrap/krb5_samba.c
+++ b/lib/krb5_wrap/krb5_samba.c
@@ -2628,67 +2628,27 @@ krb5_error_code smb_krb5_principal_set_realm(krb5_context context,
 }
 
 
-/************************************************************************
- Routine to get the default realm from the kerberos credentials cache.
- Caller must free if the return value is not NULL.
-************************************************************************/
-
-static char *smb_krb5_get_default_realm_from_ccache(TALLOC_CTX *mem_ctx)
-{
-	char *realm = NULL;
-	krb5_context ctx = NULL;
-	krb5_ccache cc = NULL;
-	krb5_principal princ = NULL;
-
-	initialize_krb5_error_table();
-	if (krb5_init_context(&ctx)) {
-		return NULL;
-	}
-
-	DEBUG(5,("kerberos_get_default_realm_from_ccache: "
-		"Trying to read krb5 cache: %s\n",
-		krb5_cc_default_name(ctx)));
-	if (krb5_cc_default(ctx, &cc)) {
-		DEBUG(5,("kerberos_get_default_realm_from_ccache: "
-			"failed to read default cache\n"));
-		goto out;
-	}
-	if (krb5_cc_get_principal(ctx, cc, &princ)) {
-		DEBUG(5,("kerberos_get_default_realm_from_ccache: "
-			"failed to get default principal\n"));
-		goto out;
-	}
-
-#if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
-	realm = talloc_strdup(mem_ctx, krb5_principal_get_realm(ctx, princ));
-#elif defined(HAVE_KRB5_PRINC_REALM)
-	{
-		krb5_data *realm_data = krb5_princ_realm(ctx, princ);
-		realm = talloc_strndup(mem_ctx, realm_data->data, realm_data->length);
-	}
-#endif
-
-  out:
-
-	if (ctx) {
-		if (princ) {
-			krb5_free_principal(ctx, princ);
-		}
-		if (cc) {
-			krb5_cc_close(ctx, cc);
-		}
-		krb5_free_context(ctx);
-	}
-
-	return realm;
-}
-
-/************************************************************************
- Routine to get the realm from a given DNS name.
-************************************************************************/
-
-static char *smb_krb5_get_realm_from_hostname(TALLOC_CTX *mem_ctx,
-						const char *hostname)
+/**
+ * @brief Get the realm from the service hostname.
+ *
+ * This function will look for a domain realm mapping in the [domain_realm]
+ * section of the krb5.conf first and fallback to extract the realm from
+ * the provided service hostname. As a last resort it will return the
+ * provided client_realm.
+ *
+ * @param[in]  mem_ctx     The talloc context
+ *
+ * @param[in]  hostname    The service hostname
+ *
+ * @param[in]  client_realm  If we can not find a mapping, fall back to
+ *                           this realm.
+ *
+ * @return The realm to use for the service hostname, NULL if a fatal error
+ *         occured.
+ */
+char *smb_krb5_get_realm_from_hostname(TALLOC_CTX *mem_ctx,
+				       const char *hostname,
+				       const char *client_realm)
 {
 #if defined(HAVE_KRB5_REALM_TYPE)
 	/* Heimdal. */
@@ -2715,8 +2675,33 @@ static char *smb_krb5_get_realm_from_hostname(TALLOC_CTX *mem_ctx,
 		goto out;
 	}
 
-	if (realm_list && realm_list[0]) {
+	if (realm_list != NULL &&
+	    realm_list[0] != NULL &&
+	    realm_list[0][0] != '\0') {
 		realm = talloc_strdup(mem_ctx, realm_list[0]);
+		if (realm == NULL) {
+			goto out;
+		}
+	} else {
+		const char *p = NULL;
+
+		/*
+		 * "dc6.samba2003.example.com"
+		 * returns a realm of "SAMBA2003.EXAMPLE.COM"
+		 *
+		 * "dc6." returns realm as NULL
+		 */
+		p = strchr_m(hostname, '.');
+		if (p != NULL && p[1] != '\0') {
+			realm = talloc_strdup_upper(mem_ctx, p + 1);
+			if (realm == NULL) {
+				goto out;
+			}
+		}
+	}
+
+	if (realm == NULL) {
+		realm = talloc_strdup(mem_ctx, client_realm);
 	}
 
   out:
@@ -2733,61 +2718,6 @@ static char *smb_krb5_get_realm_from_hostname(TALLOC_CTX *mem_ctx,
 }
 
 /**
- * @brief Get the principal as a string from the service hostname.
- *
- * @param[in]  mem_ctx  The talloc context
- *
- * @param[in]  service  The service name
- *
- * @param[in]  remote_name The remote name
- *
- * @param[in]  default_realm The default_realm if we cannot get it from the
- *                           hostname or netbios name.
- *
- * @return A talloc'ed principal string or NULL if an error occurred.
- *
- * The caller needs to free the principal with talloc_free() if it isn't needed
- * anymore.
- */
-char *smb_krb5_get_principal_from_service_hostname(TALLOC_CTX *mem_ctx,
-						   const char *service,
-						   const char *remote_name,
-						   const char *default_realm)
-{
-	char *realm = NULL;
-	char *host = NULL;
-	char *principal;
-	host = strchr_m(remote_name, '.');
-	if (host) {
-		/* DNS name. */
-		realm = smb_krb5_get_realm_from_hostname(talloc_tos(),
-							 remote_name);
-	} else {
-		/* NetBIOS name - use our realm. */
-		realm = smb_krb5_get_default_realm_from_ccache(talloc_tos());
-	}
-
-	if (realm == NULL || *realm == '\0') {
-		realm = talloc_strdup(talloc_tos(), default_realm);
-		if (!realm) {
-			return NULL;
-		}
-		DEBUG(3,("Cannot get realm from, "
-			 "desthost %s or default ccache. Using default "
-			 "smb.conf realm %s\n",
-			 remote_name,
-			 realm));
-	}
-
-	principal = talloc_asprintf(mem_ctx,
-				    "%s/%s@%s",
-				    service, remote_name,
-				    realm);
-	TALLOC_FREE(realm);
-	return principal;
-}
-
-/**
  * @brief Get an error string from a Kerberos error code.
  *
  * @param[in]  context  The library context.
diff --git a/lib/krb5_wrap/krb5_samba.h b/lib/krb5_wrap/krb5_samba.h
index 71e81ea..c921538 100644
--- a/lib/krb5_wrap/krb5_samba.h
+++ b/lib/krb5_wrap/krb5_samba.h
@@ -314,10 +314,9 @@ krb5_error_code smb_krb5_principal_set_realm(krb5_context context,
 					     krb5_principal principal,
 					     const char *realm);
 
-char *smb_krb5_get_principal_from_service_hostname(TALLOC_CTX *mem_ctx,
-						   const char *service,
-						   const char *remote_name,
-						   const char *default_realm);
+char *smb_krb5_get_realm_from_hostname(TALLOC_CTX *mem_ctx,
+				       const char *hostname,
+				       const char *client_realm);
 
 char *smb_get_krb5_error_message(krb5_context context,
 				 krb5_error_code code,
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index a111320..1d9e8dc 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -120,6 +120,54 @@ static int gse_context_destructor(void *ptr)
 	return 0;
 }
 
+static NTSTATUS gse_setup_server_principal(TALLOC_CTX *mem_ctx,
+					   const char *target_principal,
+					   const char *service,
+					   const char *hostname,
+					   const char *realm,
+					   char **pserver_principal,
+					   gss_name_t *pserver_name)
+{
+	char *server_principal = NULL;
+	gss_buffer_desc name_token;
+	gss_OID name_type;
+	OM_uint32 maj_stat, min_stat = 0;
+
+	if (target_principal != NULL) {
+		server_principal = talloc_strdup(mem_ctx, target_principal);
+		name_type = GSS_C_NULL_OID;
+	} else {
+		server_principal = talloc_asprintf(mem_ctx,
+						   "%s/%s@%s",
+						   service,
+						   hostname,
+						   realm);
+		name_type = GSS_C_NT_USER_NAME;
+	}
+	if (server_principal == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	name_token.value = (uint8_t *)server_principal;
+	name_token.length = strlen(server_principal);
+
+	maj_stat = gss_import_name(&min_stat,
+				   &name_token,
+				   name_type,
+				   pserver_name);
+	if (maj_stat) {
+		DBG_WARNING("GSS Import name of %s failed: %s\n",
+			    server_principal,
+			    gse_errstr(mem_ctx, maj_stat, min_stat));
+		TALLOC_FREE(server_principal);
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	*pserver_principal = server_principal;
+
+	return NT_STATUS_OK;
+}
+
 static NTSTATUS gse_context_init(TALLOC_CTX *mem_ctx,
 				 bool do_sign, bool do_seal,
 				 const char *ccache_name,
@@ -203,7 +251,6 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
 {
 	struct gse_context *gse_ctx;
 	OM_uint32 gss_maj, gss_min;
-	gss_buffer_desc name_buffer = GSS_C_EMPTY_BUFFER;
 #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
 	gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
 	gss_OID oid = discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X);
@@ -221,34 +268,6 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	/* Guess the realm based on the supplied service, and avoid the GSS libs
-	   doing DNS lookups which may fail.
-
-	   TODO: Loop with the KDC on some more combinations (local
-	   realm in particular), possibly falling back to
-	   GSS_C_NT_HOSTBASED_SERVICE
-	*/
-	name_buffer.value =
-		smb_krb5_get_principal_from_service_hostname(gse_ctx,
-							     service,
-							     server,
-							     realm);
-	if (!name_buffer.value) {
-		status = NT_STATUS_NO_MEMORY;
-		goto err_out;
-	}
-	name_buffer.length = strlen((char *)name_buffer.value);
-	gss_maj = gss_import_name(&gss_min, &name_buffer,
-				  GSS_C_NT_USER_NAME,
-				  &gse_ctx->server_name);
-	if (gss_maj) {
-		DEBUG(5, ("gss_import_name failed for %s, with [%s]\n",
-			  (char *)name_buffer.value,
-			  gse_errstr(gse_ctx, gss_maj, gss_min)));
-		status = NT_STATUS_INTERNAL_ERROR;
-		goto err_out;
-	}
-
 	/* TODO: get krb5 ticket using username/password, if no valid
 	 * one already available in ccache */
 
@@ -300,20 +319,21 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
 #endif
 
 	*_gse_ctx = gse_ctx;
-	TALLOC_FREE(name_buffer.value);
 	return NT_STATUS_OK;
 
 err_out:
-	TALLOC_FREE(name_buffer.value);
 	TALLOC_FREE(gse_ctx);
 	return status;
 }
 
 static NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
-					  struct gse_context *gse_ctx,
+					  struct gensec_security *gensec_security,
 					  const DATA_BLOB *token_in,
 					  DATA_BLOB *token_out)
 {
+	struct gse_context *gse_ctx =
+		talloc_get_type_abort(gensec_security->private_data,
+				      struct gse_context);
 	OM_uint32 gss_maj, gss_min;
 	gss_buffer_desc in_data;
 	gss_buffer_desc out_data;
@@ -321,10 +341,132 @@ static NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
 	NTSTATUS status;
 	OM_uint32 time_rec = 0;
 	struct timeval tv;
+	struct cli_credentials *cli_creds = gensec_get_credentials(gensec_security);
+	const char *target_principal = gensec_get_target_principal(gensec_security);
+	const char *hostname = gensec_get_target_hostname(gensec_security);
+	const char *service = gensec_get_target_service(gensec_security);
+	const char *client_realm = cli_credentials_get_realm(cli_creds);
+	char *server_principal = NULL;
+	char *server_realm = NULL;
+	bool fallback = false;
 
 	in_data.value = token_in->data;
 	in_data.length = token_in->length;
 
+	/*
+	 * With credentials for administrator at FOREST1.EXAMPLE.COM this patch
+	 * changes the target_principal for the ldap service of host
+	 * dc2.forest2.example.com from
+	 *
+	 *   ldap/dc2.forest2.example.com at FOREST1.EXAMPLE.COM
+	 *
+	 * to
+	 *
+	 *   ldap/dc2.forest2.example.com at FOREST2.EXAMPLE.COM
+	 *
+	 * Typically ldap/dc2.forest2.example.com at FOREST1.EXAMPLE.COM should be
+	 * used in order to allow the KDC of FOREST1.EXAMPLE.COM to generate a
+	 * referral ticket for krbtgt/FOREST2.EXAMPLE.COM at FOREST1.EXAMPLE.COM.
+	 *
+	 * The problem is that KDCs only return such referral tickets if
+	 * there's a forest trust between FOREST1.EXAMPLE.COM and
+	 * FOREST2.EXAMPLE.COM. If there's only an external domain trust
+	 * between FOREST1.EXAMPLE.COM and FOREST2.EXAMPLE.COM the KDC of
+	 * FOREST1.EXAMPLE.COM will respond with S_PRINCIPAL_UNKNOWN when being
+	 * asked for ldap/dc2.forest2.example.com at FOREST1.EXAMPLE.COM.
+	 *
+	 * In the case of an external trust the client can still ask explicitly
+	 * for krbtgt/FOREST2.EXAMPLE.COM at FOREST1.EXAMPLE.COM and the KDC of
+	 * FOREST1.EXAMPLE.COM will generate it.
+	 *
+	 * From there the client can use the
+	 * krbtgt/FOREST2.EXAMPLE.COM at FOREST1.EXAMPLE.COM ticket and ask a KDC
+	 * of FOREST2.EXAMPLE.COM for a service ticket for
+	 * ldap/dc2.forest2.example.com at FOREST2.EXAMPLE.COM.
+	 *
+	 * With Heimdal we'll get the fallback on S_PRINCIPAL_UNKNOWN behavior
+	 * when we pass ldap/dc2.forest2.example.com at FOREST2.EXAMPLE.COM as
+	 * target principal. As _krb5_get_cred_kdc_any() first calls
+	 * get_cred_kdc_referral() (which always starts with the client realm)
+	 * and falls back to get_cred_kdc_capath() (which starts with the given
+	 * realm).
+	 *
+	 * MIT krb5 only tries the given realm of the target principal, if we
+	 * want to autodetect support for transitive forest trusts, would have
+	 * to do the fallback ourself.
+	 */
+#ifndef SAMBA4_USES_HEIMDAL
+	if (gse_ctx->server_name == NULL) {
+		OM_uint32 gss_min2 = 0;
+
+		status = gse_setup_server_principal(mem_ctx,
+						    target_principal,
+						    service,
+						    hostname,
+						    client_realm,
+						    &server_principal,
+						    &gse_ctx->server_name);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+
+		gss_maj = gss_init_sec_context(&gss_min,
+					       gse_ctx->creds,
+					       &gse_ctx->gssapi_context,
+					       gse_ctx->server_name,
+					       &gse_ctx->gss_mech,
+					       gse_ctx->gss_want_flags,
+					       0,
+					       GSS_C_NO_CHANNEL_BINDINGS,
+					       &in_data,
+					       NULL,
+					       &out_data,
+					       &gse_ctx->gss_got_flags,
+					       &time_rec);
+		if (gss_maj != GSS_S_FAILURE) {
+			goto init_sec_context_done;
+		}
+		if (gss_min != (OM_uint32)KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
+			goto init_sec_context_done;
+		}
+		if (target_principal != NULL) {
+			goto init_sec_context_done;
+		}
+
+		fallback = true;
+		TALLOC_FREE(server_principal);
+		gss_release_name(&gss_min2, &gse_ctx->server_name);
+	}
+#endif /* !SAMBA4_USES_HEIMDAL */
+
+	if (gse_ctx->server_name == NULL) {
+		server_realm = smb_krb5_get_realm_from_hostname(mem_ctx,
+								hostname,
+								client_realm);
+		if (server_realm == NULL) {
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		if (fallback &&
+		    strequal(client_realm, server_realm)) {
+			goto init_sec_context_done;
+		}
+
+		status = gse_setup_server_principal(mem_ctx,
+						    target_principal,
+						    service,
+						    hostname,
+						    server_realm,
+						    &server_principal,
+						    &gse_ctx->server_name);
+		TALLOC_FREE(server_realm);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+
+		TALLOC_FREE(server_principal);
+	}
+
 	gss_maj = gss_init_sec_context(&gss_min,
 					gse_ctx->creds,
 					&gse_ctx->gssapi_context,
@@ -334,6 +476,10 @@ static NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
 					0, GSS_C_NO_CHANNEL_BINDINGS,
 					&in_data, NULL, &out_data,
 					&gse_ctx->gss_got_flags, &time_rec);
+	goto init_sec_context_done;
+	/* JUMP! */
+init_sec_context_done:
+
 	switch (gss_maj) {
 	case GSS_S_COMPLETE:
 		/* we are done with it */
@@ -454,10 +600,13 @@ done:
 }
 
 static NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
-					  struct gse_context *gse_ctx,
+					  struct gensec_security *gensec_security,
 					  const DATA_BLOB *token_in,
 					  DATA_BLOB *token_out)
 {
+	struct gse_context *gse_ctx =
+		talloc_get_type_abort(gensec_security->private_data,
+				      struct gse_context);
 	OM_uint32 gss_maj, gss_min;
 	gss_buffer_desc in_data;
 	gss_buffer_desc out_data;
@@ -674,17 +823,16 @@ static NTSTATUS gensec_gse_update(struct gensec_security *gensec_security,
 				  const DATA_BLOB in, DATA_BLOB *out)
 {
 	NTSTATUS status;
-	struct gse_context *gse_ctx =
-		talloc_get_type_abort(gensec_security->private_data,


-- 
Samba Shared Repository



More information about the samba-cvs mailing list