summaryrefslogtreecommitdiff
path: root/source3/librpc/crypto
diff options
context:
space:
mode:
authorAndreas Schneider <asn@samba.org>2017-03-09 07:54:29 +0100
committerAndreas Schneider <asn@cryptomilk.org>2017-03-10 11:37:22 +0100
commita3d95ed9037fb8b14a451da02dcadf011485ae34 (patch)
tree986a199e2641af7f1c52dbee77381e697dbfef85 /source3/librpc/crypto
parent2dd4887648bf006a577e03fc027e881738ca04ab (diff)
downloadsamba-a3d95ed9037fb8b14a451da02dcadf011485ae34.tar.gz
s3:gse: Use smb_krb5_get_realm_from_hostname()
With credentials for administrator@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@FOREST1.EXAMPLE.COM to ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM Typically ldap/dc2.forest2.example.com@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@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@FOREST1.EXAMPLE.COM. In the case of an external trust the client can still ask explicitly for krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM and the KDC of FOREST1.EXAMPLE.COM will generate it. From there the client can use the krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM ticket and ask a KDC of FOREST2.EXAMPLE.COM for a service ticket for ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM. With Heimdal we'll get the fallback on S_PRINCIPAL_UNKNOWN behavior when we pass ldap/dc2.forest2.example.com@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@samba.org> Signed-off-by: Andreas Schneider <asn@samba.org> Signed-off-by: Stefan Metzmacher <metze@samba.org>
Diffstat (limited to 'source3/librpc/crypto')
-rw-r--r--source3/librpc/crypto/gse.c93
1 files changed, 68 insertions, 25 deletions
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index a111320e829..cc62849b7b2 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,11 +251,12 @@ 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);
#endif
+ char *server_principal = NULL;
+ char *server_realm = NULL;
NTSTATUS status;
if (!server || !service) {
@@ -223,30 +272,24 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
/* 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;
+ server_realm = smb_krb5_get_realm_from_hostname(mem_ctx,
+ server,
+ realm);
+ if (server_realm == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
- 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;
+
+ status = gse_setup_server_principal(mem_ctx,
+ NULL,
+ service,
+ server,
+ server_realm,
+ &server_principal,
+ &gse_ctx->server_name);
+ TALLOC_FREE(server_realm);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
/* TODO: get krb5 ticket using username/password, if no valid
@@ -300,11 +343,11 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
#endif
*_gse_ctx = gse_ctx;
- TALLOC_FREE(name_buffer.value);
+ TALLOC_FREE(server_principal);
return NT_STATUS_OK;
err_out:
- TALLOC_FREE(name_buffer.value);
+ TALLOC_FREE(server_principal);
TALLOC_FREE(gse_ctx);
return status;
}