diff options
-rw-r--r-- | source3/configure.in | 24 | ||||
-rw-r--r-- | source3/libads/kerberos.c | 52 | ||||
-rw-r--r-- | source3/libsmb/cliconnect.c | 50 |
3 files changed, 118 insertions, 8 deletions
diff --git a/source3/configure.in b/source3/configure.in index 7272ae4d9a..ac60b6f645 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -4221,6 +4221,30 @@ if test x"$with_ads_support" != x"no"; then fi fi + AC_CACHE_CHECK([for krb5_principal_get_realm], + samba_cv_HAVE_KRB5_PRINCIPAL_GET_REALM,[ + AC_TRY_LINK([#include <krb5.h>], + [krb5_context ctx = NULL; krb5_principal princ = NULL; const char *str = krb5_principal_get_realm(ctx, princ);], + samba_cv_HAVE_KRB5_PRINCIPAL_GET_REALM=yes, + samba_cv_HAVE_KRB5_PRINCIPAL_GET_REALM=no)]) + + if test x"$samba_cv_HAVE_KRB5_PRINCIPAL_GET_REALM" = x"yes"; then + AC_DEFINE(HAVE_KRB5_PRINCIPAL_GET_REALM,1, + [Whether the function krb5_principal_get_realm is defined]) + fi + + AC_CACHE_CHECK([for krb5_princ_realm], + samba_cv_HAVE_KRB5_PRINC_REALM,[ + AC_TRY_LINK([#include <krb5.h>], + [krb5_context ctx = NULL; krb5_principal princ = NULL; const char *str = krb5_princ_realm(ctx, princ)->data;], + samba_cv_HAVE_KRB5_PRINC_REALM=yes, + samba_cv_HAVE_KRB5_PRINC_REALM=no)]) + + if test x"$samba_cv_HAVE_KRB5_PRINC_REALM" = x"yes"; then + AC_DEFINE(HAVE_KRB5_PRINC_REALM,1, + [Whether the macro krb5_princ_realm is defined]) + fi + # # # Now the decisions whether we can support krb5 diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c index 29e5661d3c..02e14f468d 100644 --- a/source3/libads/kerberos.c +++ b/source3/libads/kerberos.c @@ -487,6 +487,58 @@ char* kerberos_secrets_fetch_des_salt( void ) return salt; } +/************************************************************************ + Routine to get the default realm from the kerberos credentials cache. + Caller must free if the return value is not NULL. +************************************************************************/ + +char *kerberos_get_default_realm_from_ccache( void ) +{ + 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(0,("kerberos_get_default_realm_from_ccache: " + "failed to read default cache\n")); + goto out; + } + if (krb5_cc_get_principal(ctx, cc, &princ)) { + DEBUG(0,("kerberos_get_default_realm_from_ccache: " + "failed to get default principal\n")); + goto done; + } + +#if defined(HAVE_KRB5_PRINCIPAL_GET_REALM) + realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ)); +#elif defined(HAVE_KRB5_PRINC_REALM) + realm = SMB_STRDUP(krb5_princ_realm(ctx, princ)->data); +#endif + + out: + + if (princ) { + krb5_free_principal(ctx, princ); + } + if (cc) { + krb5_cc_close(ctx, cc); + } + if (ctx) { + krb5_free_context(ctx); + } +done: + return realm; +} + /************************************************************************ Routine to get the salting principal for this service. This is diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 45c202090e..52ff69953e 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -37,6 +37,8 @@ static const struct { {-1,NULL} }; +static const char *star_smbserver_name = "*SMBSERVER"; + /** * Set the user session key for a connection * @param cli The cli structure to add it too @@ -858,10 +860,42 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, } } - rc = cli_session_setup_kerberos(cli, principal, domain); - if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) { + /* If we get a bad principal, try to guess it if + we have a valid host NetBIOS name. + */ + if (strequal(principal, + "not_defined_in_RFC4178@please_ignore")) { SAFE_FREE(principal); - return rc; + } + + if (principal == NULL && + !is_ipaddress(cli->desthost) && + !strequal(star_smbserver_name, + cli->desthost)) { + char *realm = NULL; + DEBUG(3,("cli_session_setup_spnego: got a " + "bad server principal, trying to guess ...\n")); + + realm = kerberos_get_default_realm_from_ccache(); + if (realm && *realm) { + if (asprintf(&principal, "%s$@%s", + cli->desthost, realm) < 0) { + SAFE_FREE(realm); + return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + } + DEBUG(3,("cli_session_setup_spnego: guessed " + "server principal=%s\n", + principal ? principal : "<null>")); + } + SAFE_FREE(realm); + } + + if (principal) { + rc = cli_session_setup_kerberos(cli, principal, domain); + if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) { + SAFE_FREE(principal); + return rc; + } } } #endif @@ -1432,7 +1466,7 @@ NTSTATUS cli_connect(struct cli_state *cli, /* reasonable default hostname */ if (!host) { - host = "*SMBSERVER"; + host = star_smbserver_name; } fstrcpy(cli->desthost, host); @@ -1580,8 +1614,8 @@ again: *p = 0; goto again; } - if (strcmp(called.name, "*SMBSERVER")) { - make_nmb_name(&called , "*SMBSERVER", 0x20); + if (strcmp(called.name, star_smbserver_name)) { + make_nmb_name(&called , star_smbserver_name, 0x20); goto again; } return NT_STATUS_BAD_NETWORK_NAME; @@ -1706,7 +1740,7 @@ bool attempt_netbios_session_request(struct cli_state **ppcli, const char *srcho */ if(is_ipaddress(desthost)) { - make_nmb_name(&called, "*SMBSERVER", 0x20); + make_nmb_name(&called, star_smbserver_name, 0x20); } else { make_nmb_name(&called, desthost, 0x20); } @@ -1715,7 +1749,7 @@ bool attempt_netbios_session_request(struct cli_state **ppcli, const char *srcho NTSTATUS status; struct nmb_name smbservername; - make_nmb_name(&smbservername , "*SMBSERVER", 0x20); + make_nmb_name(&smbservername, star_smbserver_name, 0x20); /* * If the name wasn't *SMBSERVER then |