From 860ad734ba77238d187520f72afcbdc1c73d94ef Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 4 Jan 2012 11:39:38 +1100 Subject: s3-libads Factor out a new routine kerberos_get_principal_from_service_hostname() This is now used in the GSE GSSAPI client, so that when we connect to a target server at the CIFS level, we use the same name to connect at the DCE/RPC level. Andrew Bartlett Signed-off-by: Stefan Metzmacher --- source3/libads/kerberos.c | 50 +++++++++++++++++++++++++++++++++++------ source3/libads/kerberos_proto.h | 7 ++++-- source3/librpc/crypto/gse.c | 14 +++++++++--- source3/libsmb/cliconnect.c | 46 +++++++++---------------------------- 4 files changed, 69 insertions(+), 48 deletions(-) diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c index 76ca0c0cf3..f260dcaaf0 100644 --- a/source3/libads/kerberos.c +++ b/source3/libads/kerberos.c @@ -428,7 +428,7 @@ char* kerberos_secrets_fetch_des_salt( void ) Caller must free if the return value is not NULL. ************************************************************************/ -char *kerberos_get_default_realm_from_ccache( void ) +char *kerberos_get_default_realm_from_ccache(TALLOC_CTX *mem_ctx) { char *realm = NULL; krb5_context ctx = NULL; @@ -455,11 +455,11 @@ char *kerberos_get_default_realm_from_ccache( void ) } #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM) - realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ)); + 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 = SMB_STRNDUP(realm_data->data, realm_data->length); + realm = talloc_strndup(mem_ctx, realm_data->data, realm_data->length); } #endif @@ -479,11 +479,10 @@ char *kerberos_get_default_realm_from_ccache( void ) } /************************************************************************ - Routine to get the realm from a given DNS name. Returns malloc'ed memory. - Caller must free() if the return value is not NULL. + Routine to get the realm from a given DNS name. ************************************************************************/ -char *kerberos_get_realm_from_hostname(const char *hostname) +char *kerberos_get_realm_from_hostname(TALLOC_CTX *mem_ctx, const char *hostname) { #if defined(HAVE_KRB5_GET_HOST_REALM) && defined(HAVE_KRB5_FREE_HOST_REALM) #if defined(HAVE_KRB5_REALM_TYPE) @@ -512,7 +511,7 @@ char *kerberos_get_realm_from_hostname(const char *hostname) } if (realm_list && realm_list[0]) { - realm = SMB_STRDUP(realm_list[0]); + realm = talloc_strdup(mem_ctx, realm_list[0]); } out: @@ -531,6 +530,43 @@ char *kerberos_get_realm_from_hostname(const char *hostname) #endif } +char *kerberos_get_principal_from_service_hostname(TALLOC_CTX *mem_ctx, + const char *service, + const char *remote_name) +{ + char *realm = NULL; + char *host = NULL; + char *principal; + host = strchr_m(remote_name, '.'); + if (host) { + /* DNS name. */ + realm = kerberos_get_realm_from_hostname(talloc_tos(), remote_name); + } else { + /* NetBIOS name - use our realm. */ + realm = kerberos_get_default_realm_from_ccache(talloc_tos()); + } + + if (realm == NULL || *realm == '\0') { + realm = talloc_strdup(talloc_tos(), lp_realm()); + if (!realm) { + return NULL; + } + DEBUG(3,("kerberos_get_principal_from_service_hostname: " + "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; +} + /************************************************************************ Routine to get the salting principal for this service. This is maintained for backwards compatibilty with releases prior to 3.0.24. diff --git a/source3/libads/kerberos_proto.h b/source3/libads/kerberos_proto.h index ff1082a59b..094f38dca2 100644 --- a/source3/libads/kerberos_proto.h +++ b/source3/libads/kerberos_proto.h @@ -62,8 +62,11 @@ int ads_kdestroy(const char *cc_name); char* kerberos_standard_des_salt( void ); bool kerberos_secrets_store_des_salt( const char* salt ); char* kerberos_secrets_fetch_des_salt( void ); -char *kerberos_get_default_realm_from_ccache( void ); -char *kerberos_get_realm_from_hostname(const char *hostname); +char *kerberos_get_default_realm_from_ccache(TALLOC_CTX *mem_ctx); +char *kerberos_get_realm_from_hostname(TALLOC_CTX *mem_ctx, const char *hostname); +char *kerberos_get_principal_from_service_hostname(TALLOC_CTX *mem_ctx, + const char *service, + const char *remote_name); bool kerberos_secrets_store_salting_principal(const char *service, int enctype, diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c index b4e59da475..0f97978256 100644 --- a/source3/librpc/crypto/gse.c +++ b/source3/librpc/crypto/gse.c @@ -21,6 +21,7 @@ #include "includes.h" #include "gse.h" +#include "libads/kerberos_proto.h" #if defined(HAVE_KRB5) && defined(HAVE_GSS_WRAP_IOV) @@ -247,15 +248,22 @@ NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx, return NT_STATUS_NO_MEMORY; } - name_buffer.value = talloc_asprintf(gse_ctx, - "%s@%s", service, server); + /* 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 = kerberos_get_principal_from_service_hostname(gse_ctx, + service, server); 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_HOSTBASED_SERVICE, + GSS_C_NT_USER_NAME, &gse_ctx->server_name); if (gss_maj) { DEBUG(0, ("gss_import_name failed for %s, with [%s]\n", diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 4f98f5c5e9..76e32565e4 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -1931,56 +1931,30 @@ static ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, !is_ipaddress(remote_name) && !strequal(STAR_SMBSERVER, remote_name)) { - char *realm = NULL; - char *host = NULL; DEBUG(3,("cli_session_setup_spnego: using target " "hostname not SPNEGO principal\n")); - host = strchr_m(remote_name, '.'); if (dest_realm) { - realm = SMB_STRDUP(dest_realm); - if (!realm) { - return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + char *realm = strupper_talloc(talloc_tos(), dest_realm); + if (realm) { + principal = talloc_asprintf(talloc_tos(), + "cifs/%s@%s", + remote_name, + realm); + TALLOC_FREE(realm); } - strupper_m(realm); } else { - if (host) { - /* DNS name. */ - realm = kerberos_get_realm_from_hostname(remote_name); - } else { - /* NetBIOS name - use our realm. */ - realm = kerberos_get_default_realm_from_ccache(); - } + principal = kerberos_get_principal_from_service_hostname(talloc_tos(), + "cifs", + remote_name); } - if (realm == NULL || *realm == '\0') { - realm = SMB_STRDUP(lp_realm()); - if (!realm) { - return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); - } - strupper_m(realm); - DEBUG(3,("cli_session_setup_spnego: cannot " - "get realm from dest_realm %s, " - "desthost %s. Using default " - "smb.conf realm %s\n", - dest_realm ? dest_realm : "", - remote_name, - realm)); - } - - principal = talloc_asprintf(talloc_tos(), - "cifs/%s@%s", - remote_name, - realm); if (!principal) { - SAFE_FREE(realm); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } DEBUG(3,("cli_session_setup_spnego: guessed " "server principal=%s\n", principal ? principal : "")); - - SAFE_FREE(realm); } if (principal) { -- cgit