diff options
Diffstat (limited to 'source4/auth/credentials')
-rw-r--r-- | source4/auth/credentials/credentials.c | 20 | ||||
-rw-r--r-- | source4/auth/credentials/credentials_krb5.c | 75 | ||||
-rw-r--r-- | source4/auth/credentials/credentials_krb5.h | 6 |
3 files changed, 81 insertions, 20 deletions
diff --git a/source4/auth/credentials/credentials.c b/source4/auth/credentials/credentials.c index 5f2658d5bd..6f7630a206 100644 --- a/source4/auth/credentials/credentials.c +++ b/source4/auth/credentials/credentials.c @@ -222,7 +222,7 @@ _PUBLIC_ const char *cli_credentials_get_bind_dn(struct cli_credentials *cred) * @retval The username set on this context. * @note Return value will never be NULL except by programmer error. */ -_PUBLIC_ const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx) +const char *cli_credentials_get_principal_and_obtained(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, enum credentials_obtained *obtained) { if (cred->machine_account_pending) { cli_credentials_set_machine_account(cred, @@ -238,20 +238,36 @@ _PUBLIC_ const char *cli_credentials_get_principal(struct cli_credentials *cred, cli_credentials_invalidate_ccache(cred, cred->principal_obtained); } - if (cred->principal_obtained < cred->username_obtained) { + if (cred->principal_obtained < cred->username_obtained + || cred->principal_obtained < MAX(cred->domain_obtained, cred->realm_obtained)) { if (cred->domain_obtained > cred->realm_obtained) { + *obtained = MIN(cred->domain_obtained, cred->username_obtained); return talloc_asprintf(mem_ctx, "%s@%s", cli_credentials_get_username(cred), cli_credentials_get_domain(cred)); } else { + *obtained = MIN(cred->domain_obtained, cred->username_obtained); return talloc_asprintf(mem_ctx, "%s@%s", cli_credentials_get_username(cred), cli_credentials_get_realm(cred)); } } + *obtained = cred->principal_obtained; return talloc_reference(mem_ctx, cred->principal); } +/** + * Obtain the client principal for this credentials context. + * @param cred credentials context + * @retval The username set on this context. + * @note Return value will never be NULL except by programmer error. + */ +_PUBLIC_ const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx) +{ + enum credentials_obtained obtained; + return cli_credentials_get_principal_and_obtained(cred, mem_ctx, &obtained); +} + bool cli_credentials_set_principal(struct cli_credentials *cred, const char *val, enum credentials_obtained obtained) diff --git a/source4/auth/credentials/credentials_krb5.c b/source4/auth/credentials/credentials_krb5.c index d76073093b..12bf610bf8 100644 --- a/source4/auth/credentials/credentials_krb5.c +++ b/source4/auth/credentials/credentials_krb5.c @@ -27,6 +27,7 @@ #include "auth/credentials/credentials.h" #include "auth/credentials/credentials_proto.h" #include "auth/credentials/credentials_krb5.h" +#include "auth/kerberos/kerberos_credentials.h" #include "param/param.h" _PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred, @@ -282,6 +283,7 @@ _PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred, const char **error_string) { krb5_error_code ret; + enum credentials_obtained obtained; if (cred->machine_account_pending) { cli_credentials_set_machine_account(cred, lp_ctx); @@ -302,15 +304,13 @@ _PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred, return ret; } - ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, (*ccc)->ccache, error_string); + ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, (*ccc)->ccache, &obtained, error_string); if (ret) { return ret; } ret = cli_credentials_set_from_ccache(cred, *ccc, - (MAX(MAX(cred->principal_obtained, - cred->username_obtained), - cred->password_obtained)), error_string); + obtained, error_string); cred->ccache = *ccc; cred->ccache_obtained = cred->principal_obtained; @@ -330,6 +330,16 @@ _PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred, return cli_credentials_get_named_ccache(cred, event_ctx, lp_ctx, NULL, ccc, error_string); } +/* We have good reason to think the ccache in these credentials is invalid - blow it away */ +static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials *cred) +{ + if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) { + talloc_unlink(cred, cred->client_gss_creds); + cred->client_gss_creds = NULL; + } + cred->client_gss_creds_obtained = CRED_UNINITIALISED; +} + void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred, enum credentials_obtained obtained) { @@ -351,6 +361,18 @@ void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred, } } +/* We have good reason to think this CCACHE is invalid. Blow it away */ +static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials *cred) +{ + if (cred->ccache_obtained > CRED_UNINITIALISED) { + talloc_unlink(cred, cred->ccache); + cred->ccache = NULL; + } + cred->ccache_obtained = CRED_UNINITIALISED; + + cli_credentials_unconditionally_invalidate_client_gss_creds(cred); +} + _PUBLIC_ void cli_credentials_invalidate_ccache(struct cli_credentials *cred, enum credentials_obtained obtained) { @@ -416,6 +438,23 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, &gcc->creds); + if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) { + /* This CCACHE is no good. Ensure we don't use it again */ + cli_credentials_unconditionally_invalidate_ccache(cred); + + /* Now try again to get a ccache */ + ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx, + &ccache, error_string); + if (ret) { + DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret))); + return ret; + } + + maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, + &gcc->creds); + + } + if (maj_stat) { talloc_free(gcc); if (min_stat) { @@ -698,12 +737,11 @@ _PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred, TALLOC_CTX *mem_ctx; krb5_principal princ; const char *error_string; + enum credentials_obtained obtained; - if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, - MAX(cred->principal_obtained, - cred->username_obtained)))) { - *_gcc = cred->server_gss_creds; - return 0; + mem_ctx = talloc_new(cred); + if (!mem_ctx) { + return ENOMEM; } ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, &smb_krb5_context); @@ -711,22 +749,23 @@ _PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred, return ret; } - ret = cli_credentials_get_keytab(cred, event_ctx, lp_ctx, &ktc); + ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &obtained, &error_string); if (ret) { - DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret))); + DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n", + error_string)); + talloc_free(mem_ctx); return ret; } - mem_ctx = talloc_new(cred); - if (!mem_ctx) { - return ENOMEM; + if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, obtained))) { + talloc_free(mem_ctx); + *_gcc = cred->server_gss_creds; + return 0; } - ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &error_string); + ret = cli_credentials_get_keytab(cred, event_ctx, lp_ctx, &ktc); if (ret) { - DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n", - error_string)); - talloc_free(mem_ctx); + DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret))); return ret; } diff --git a/source4/auth/credentials/credentials_krb5.h b/source4/auth/credentials/credentials_krb5.h index 72a4373609..3a614ff30e 100644 --- a/source4/auth/credentials/credentials_krb5.h +++ b/source4/auth/credentials/credentials_krb5.h @@ -44,6 +44,12 @@ krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx, struct cli_credentials *credentials, struct smb_krb5_context *smb_krb5_context, krb5_principal *princ, + enum credentials_obtained *obtained, const char **error_string); +krb5_error_code impersonate_principal_from_credentials(TALLOC_CTX *parent_ctx, + struct cli_credentials *credentials, + struct smb_krb5_context *smb_krb5_context, + krb5_principal *princ, + const char **error_string); #endif /* __CREDENTIALS_KRB5_H__ */ |