summaryrefslogtreecommitdiff
path: root/source4/auth/credentials/credentials_krb5.c
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2005-12-01 05:20:39 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:46:56 -0500
commit9c6b7f2d62e134a4bc15efc04e05be25e4a53dc7 (patch)
tree8ef389a528fdc2caca79f279c086b4f8bea7afeb /source4/auth/credentials/credentials_krb5.c
parent22f1de0998ee34be4c032b16e4a6d30c9f8e6b85 (diff)
downloadsamba-9c6b7f2d62e134a4bc15efc04e05be25e4a53dc7.tar.gz
samba-9c6b7f2d62e134a4bc15efc04e05be25e4a53dc7.tar.bz2
samba-9c6b7f2d62e134a4bc15efc04e05be25e4a53dc7.zip
r11995: A big kerberos-related update.
This merges Samba4 up to current lorikeet-heimdal, which includes a replacement for some Samba-specific hacks. In particular, the credentials system now supplies GSS client and server credentials. These are imported into GSS with gss_krb5_import_creds(). Unfortunetly this can't take an MEMORY keytab, so we now create a FILE based keytab as provision and join time. Because the keytab is now created in advance, we don't spend .4s at negprot doing sha1 s2k calls. Also, because the keytab is read in real time, any change in the server key will be correctly picked up by the the krb5 code. To mark entries in the secrets which should be exported to a keytab, there is a new kerberosSecret objectClass. The new routine cli_credentials_update_all_keytabs() searches for these, and updates the keytabs. This is called in the provision.js via the ejs wrapper credentials_update_all_keytabs(). We can now (in theory) use a system-provided /etc/krb5.keytab, if krb5Keytab: FILE:/etc/krb5.keytab is added to the secrets.ldb record. By default the attribute privateKeytab: secrets.keytab is set, pointing to allow the whole private directory to be moved without breaking the internal links. (This used to be commit 6b75573df49c6210e1b9d71e108a9490976bd41d)
Diffstat (limited to 'source4/auth/credentials/credentials_krb5.c')
-rw-r--r--source4/auth/credentials/credentials_krb5.c211
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);
}
+
+