diff options
Diffstat (limited to 'source4/auth/credentials/credentials_krb5.c')
-rw-r--r-- | source4/auth/credentials/credentials_krb5.c | 211 |
1 files changed, 198 insertions, 13 deletions
diff --git a/source4/auth/credentials/credentials_krb5.c b/source4/auth/credentials/credentials_krb5.c index a3761e8359..173739e9b8 100644 --- a/source4/auth/credentials/credentials_krb5.c +++ b/source4/auth/credentials/credentials_krb5.c @@ -52,6 +52,10 @@ int cli_credentials_set_from_ccache(struct cli_credentials *cred, char *name; char **realm; + if (cred->ccache_obtained > obtained) { + return 0; + } + ret = krb5_cc_get_principal(cred->ccache->smb_krb5_context->krb5_context, cred->ccache->ccache, &princ); @@ -107,7 +111,12 @@ int cli_credentials_set_ccache(struct cli_credentials *cred, { krb5_error_code ret; krb5_principal princ; - struct ccache_container *ccc = talloc(cred, struct ccache_container); + struct ccache_container *ccc; + if (cred->ccache_obtained > obtained) { + return 0; + } + + ccc = talloc(cred, struct ccache_container); if (!ccc) { return ENOMEM; } @@ -265,10 +274,10 @@ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, OM_uint32 maj_stat, min_stat; struct gssapi_creds_container *gcc; struct ccache_container *ccache; - if (cred->gss_creds_obtained >= (MAX(cred->ccache_obtained, + if (cred->client_gss_creds_obtained >= (MAX(cred->ccache_obtained, MAX(cred->principal_obtained, cred->username_obtained)))) { - *_gcc = cred->gssapi_creds; + *_gcc = cred->client_gss_creds; return 0; } ret = cli_credentials_get_ccache(cred, @@ -283,8 +292,8 @@ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, return ENOMEM; } - maj_stat = gss_krb5_import_ccache(&min_stat, ccache->ccache, - &gcc->creds); + maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, + &gcc->creds); if (maj_stat) { if (min_stat) { ret = min_stat; @@ -293,20 +302,20 @@ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, } } if (ret == 0) { - cred->gss_creds_obtained = cred->ccache_obtained; + cred->client_gss_creds_obtained = cred->ccache_obtained; talloc_set_destructor(gcc, free_gssapi_creds); - cred->gssapi_creds = gcc; + cred->client_gss_creds = gcc; *_gcc = gcc; } return ret; } /** - Set a gssapi cred_id_t into the credentails system. + Set a gssapi cred_id_t into the credentails system. (Client case) This grabs the credentials both 'intact' and getting the krb5 ccache out of it. This routine can be generalised in future for - the case where we deal with GSSAPI mechs other than krb5. + the case where we deal with GSSAPI mechs other than krb5. On sucess, the caller must not free gssapi_cred, as it now belongs to the credentials system. @@ -319,7 +328,12 @@ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, int ret; OM_uint32 maj_stat, min_stat; struct ccache_container *ccc; - struct gssapi_creds_container *gcc = talloc(cred, struct gssapi_creds_container); + struct gssapi_creds_container *gcc; + if (cred->client_gss_creds_obtained > obtained) { + return 0; + } + + gcc = talloc(cred, struct gssapi_creds_container); if (!gcc) { return ENOMEM; } @@ -346,18 +360,23 @@ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, gcc->creds = gssapi_cred; talloc_set_destructor(gcc, free_gssapi_creds); - cred->gss_creds_obtained = obtained; - cred->gssapi_creds = gcc; + cred->client_gss_creds_obtained = obtained; + cred->client_gss_creds = gcc; } return ret; } +/* Get the keytab (actually, a container containing the krb5_keytab) + * attached to this context. If this hasn't been done or set before, + * it will be generated from the password. + */ int cli_credentials_get_keytab(struct cli_credentials *cred, struct keytab_container **_ktc) { krb5_error_code ret; struct keytab_container *ktc; struct smb_krb5_context *smb_krb5_context; + TALLOC_CTX *mem_ctx; if (cred->keytab_obtained >= (MAX(cred->principal_obtained, cred->username_obtained))) { @@ -374,16 +393,180 @@ int cli_credentials_get_keytab(struct cli_credentials *cred, return ret; } - ret = create_memory_keytab(cred, cred, smb_krb5_context, &ktc); + mem_ctx = talloc_new(cred); + if (!mem_ctx) { + return ENOMEM; + } + + ret = create_memory_keytab(mem_ctx, cred, smb_krb5_context, &ktc); if (ret) { + talloc_free(mem_ctx); return ret; } cred->keytab_obtained = (MAX(cred->principal_obtained, cred->username_obtained)); + talloc_steal(cred, ktc); cred->keytab = ktc; *_ktc = cred->keytab; + talloc_free(mem_ctx); + return ret; +} + +/* Given the name of a keytab (presumably in the format + * FILE:/etc/krb5.keytab), open it and attach it */ + +int cli_credentials_set_keytab(struct cli_credentials *cred, + const char *keytab_name, + enum credentials_obtained obtained) +{ + krb5_error_code ret; + struct keytab_container *ktc; + struct smb_krb5_context *smb_krb5_context; + krb5_keytab keytab; + TALLOC_CTX *mem_ctx; + + if (cred->keytab_obtained >= obtained) { + return 0; + } + + ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context); + if (ret) { + return ret; + } + + mem_ctx = talloc_new(cred); + if (!mem_ctx) { + return ENOMEM; + } + + ret = krb5_kt_resolve(smb_krb5_context->krb5_context, keytab_name, &keytab); + if (ret) { + DEBUG(1,("failed to open krb5 keytab: %s\n", + smb_get_krb5_error_message(smb_krb5_context->krb5_context, + ret, mem_ctx))); + talloc_free(mem_ctx); + return ret; + } + + ktc = talloc(mem_ctx, struct keytab_container); + if (!ktc) { + talloc_free(mem_ctx); + return ENOMEM; + } + + ktc->smb_krb5_context = talloc_reference(ktc, smb_krb5_context); + ktc->keytab = keytab; + + cred->keytab_obtained = obtained; + + talloc_steal(cred, ktc); + cred->keytab = ktc; + talloc_free(mem_ctx); + + return ret; +} + +int cli_credentials_update_keytab(struct cli_credentials *cred) +{ + krb5_error_code ret; + struct keytab_container *ktc; + struct smb_krb5_context *smb_krb5_context; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(cred); + if (!mem_ctx) { + return ENOMEM; + } + + ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context); + if (ret) { + talloc_free(mem_ctx); + return ret; + } + + ret = cli_credentials_get_keytab(cred, &ktc); + if (ret != 0) { + talloc_free(mem_ctx); + return ret; + } + + ret = update_keytab(mem_ctx, cred, smb_krb5_context, ktc); + + talloc_free(mem_ctx); + return ret; +} + +/* Get server gss credentials (in gsskrb5, this means the keytab) */ + +int cli_credentials_get_server_gss_creds(struct cli_credentials *cred, + struct gssapi_creds_container **_gcc) +{ + int ret = 0; + OM_uint32 maj_stat, min_stat; + struct gssapi_creds_container *gcc; + struct keytab_container *ktc; + struct smb_krb5_context *smb_krb5_context; + TALLOC_CTX *mem_ctx; + krb5_principal princ; + + if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, + MAX(cred->principal_obtained, + cred->username_obtained)))) { + *_gcc = cred->server_gss_creds; + return 0; + } + + ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context); + if (ret) { + return ret; + } + + ret = cli_credentials_get_keytab(cred, + &ktc); + if (ret) { + DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret))); + return ret; + } + + mem_ctx = talloc_new(cred); + if (!mem_ctx) { + return ENOMEM; + } + + ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ); + if (ret) { + DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n", + smb_get_krb5_error_message(smb_krb5_context->krb5_context, + ret, mem_ctx))); + talloc_free(mem_ctx); + return ret; + } + + gcc = talloc(cred, struct gssapi_creds_container); + if (!gcc) { + talloc_free(mem_ctx); + return ENOMEM; + } + + /* This creates a GSSAPI cred_id_t with the principal and keytab set */ + maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab, + &gcc->creds); + if (maj_stat) { + if (min_stat) { + ret = min_stat; + } else { + ret = EINVAL; + } + } + if (ret == 0) { + cred->server_gss_creds_obtained = cred->keytab_obtained; + talloc_set_destructor(gcc, free_gssapi_creds); + cred->server_gss_creds = gcc; + *_gcc = gcc; + } + talloc_free(mem_ctx); return ret; } @@ -415,3 +598,5 @@ void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char { cred->salt_principal = talloc_strdup(cred, principal); } + + |