From 8a68f96f8cea2c53c8babf2ec826dfc6ef1cc199 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 22 Jun 2005 02:12:26 +0000 Subject: r7827: Add in-memory keytab to Samba4, using the new MEMORY_WILDCARD keytab support in Heimdal. This removes the 'ext_keytab' step from my Samba4/WinXP client howto. In doing this work, I realised that the replay cache in Heimdal is currently a no-op, so I have removed the calls to it, and therefore the mutex calls from passdb/secrets.c. This patch also includes a replacement 'magic' mechanism detection, that does not issue extra error messages from deep inside the GSSAPI code. Andrew Bartlett (This used to be commit c19d5706f4fa760415b727b970bc99e7f1abd064) --- source4/auth/kerberos/kerberos_util.c | 163 +++++++++++++++++++++++++++++++++- 1 file changed, 161 insertions(+), 2 deletions(-) (limited to 'source4/auth/kerberos/kerberos_util.c') diff --git a/source4/auth/kerberos/kerberos_util.c b/source4/auth/kerberos/kerberos_util.c index 7945094be9..9f93ffe7b0 100644 --- a/source4/auth/kerberos/kerberos_util.c +++ b/source4/auth/kerberos/kerberos_util.c @@ -28,10 +28,77 @@ #include "auth/kerberos/kerberos.h" #include "auth/auth.h" +struct principal_container { + struct smb_krb5_context *smb_krb5_context; + krb5_principal principal; +}; + struct ccache_container { struct smb_krb5_context *smb_krb5_context; krb5_ccache ccache; -} ccache_container; +}; + +struct keytab_container { + struct smb_krb5_context *smb_krb5_context; + krb5_keytab keytab; +}; + +static int free_principal(void *ptr) { + struct principal_container *pc = ptr; + /* current heimdal - 0.6.3, which we need anyway, fixes segfaults here */ + krb5_free_principal(pc->smb_krb5_context->krb5_context, pc->principal); + + return 0; +} + +krb5_error_code salt_principal_from_credentials(TALLOC_CTX *parent_ctx, + struct cli_credentials *machine_account, + struct smb_krb5_context *smb_krb5_context, + krb5_principal *salt_princ) +{ + krb5_error_code ret; + char *machine_username; + char *salt_body; + char *lower_realm; + struct principal_container *mem_ctx = talloc(parent_ctx, struct principal_container); + if (!mem_ctx) { + return ENOMEM; + } + + machine_username = talloc_strdup(mem_ctx, cli_credentials_get_username(machine_account)); + + if (!machine_username) { + talloc_free(mem_ctx); + return ENOMEM; + } + + if (machine_username[strlen(machine_username)-1] == '$') { + machine_username[strlen(machine_username)-1] = '\0'; + } + lower_realm = strlower_talloc(mem_ctx, cli_credentials_get_realm(machine_account)); + if (!lower_realm) { + talloc_free(mem_ctx); + return ENOMEM; + } + + salt_body = talloc_asprintf(mem_ctx, "%s.%s", machine_username, + lower_realm); + if (!salt_body) { + talloc_free(mem_ctx); + return ENOMEM; + } + + ret = krb5_make_principal(smb_krb5_context->krb5_context, salt_princ, + cli_credentials_get_realm(machine_account), + "host", salt_body, NULL); + + if (ret != 0) { + mem_ctx->smb_krb5_context = talloc_reference(mem_ctx, smb_krb5_context); + mem_ctx->principal = *salt_princ; + talloc_set_destructor(mem_ctx, free_principal); + } + return ret; +} static int free_ccache(void *ptr) { struct ccache_container *ccc = ptr; @@ -71,7 +138,7 @@ static int free_ccache(void *ptr) { ret = krb5_cc_resolve(smb_krb5_context->krb5_context, ccache_string, ccache); if (ret) { - DEBUG(1,("failed to generate a new krb5 keytab (%s): %s\n", + DEBUG(1,("failed to generate a new krb5 ccache (%s): %s\n", ccache_string, error_message(ret))); talloc_free(mem_ctx); @@ -114,3 +181,95 @@ static int free_ccache(void *ptr) { return NT_STATUS_OK; } + +static int free_keytab(void *ptr) { + struct keytab_container *ktc = ptr; + krb5_kt_close(ktc->smb_krb5_context->krb5_context, ktc->keytab); + + return 0; +} + + NTSTATUS create_memory_keytab(TALLOC_CTX *parent_ctx, + struct cli_credentials *machine_account, + struct smb_krb5_context *smb_krb5_context, + krb5_keytab *keytab) +{ + krb5_error_code ret; + const char *password_s; + krb5_data password; + int i; + struct keytab_container *mem_ctx = talloc(parent_ctx, struct keytab_container); + krb5_enctype *enctypes; + krb5_principal salt_princ; + + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; + } + + password_s = talloc_strdup(mem_ctx, cli_credentials_get_password(machine_account)); + if (!password_s) { + DEBUG(1, ("create_memory_keytab: Could not obtain password for our local machine account!\n")); + talloc_free(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + password.data = password_s; + password.length = strlen(password_s); + + /* this string should be unique */ + + ret = krb5_kt_resolve(smb_krb5_context->krb5_context, "MEMORY_WILDCARD:", keytab); + if (ret) { + DEBUG(1,("failed to generate a new krb5 keytab: %s\n", + error_message(ret))); + talloc_free(mem_ctx); + return NT_STATUS_INTERNAL_ERROR; + } + + mem_ctx->smb_krb5_context = talloc_reference(mem_ctx, smb_krb5_context); + mem_ctx->keytab = *keytab; + + talloc_set_destructor(mem_ctx, free_keytab); + + ret = salt_principal_from_credentials(mem_ctx, machine_account, + smb_krb5_context, + &salt_princ); + if (ret) { + DEBUG(1,("create_memory_keytab: maksing salt principal failed (%s)\n", + error_message(ret))); + return NT_STATUS_INTERNAL_ERROR; + } + + ret = get_kerberos_allowed_etypes(smb_krb5_context->krb5_context, + &enctypes); + if (ret) { + DEBUG(1,("create_memory_keytab: getting encrption types failed (%s)\n", + error_message(ret))); + return NT_STATUS_INTERNAL_ERROR; + } + + for (i=0; enctypes[i]; i++) { + krb5_keytab_entry entry; + ret = create_kerberos_key_from_string(smb_krb5_context->krb5_context, + salt_princ, &password, &entry.keyblock, enctypes[i]); + if (ret) { + return NT_STATUS_INTERNAL_ERROR; + } + + entry.principal = salt_princ; + entry.vno = 0 /* replace with real kvno */; + ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, *keytab, &entry); + if (ret) { + DEBUG(1, ("Failed to add entry for %s to keytab: %s", + cli_credentials_get_principal(machine_account, mem_ctx), + smb_get_krb5_error_message(smb_krb5_context->krb5_context, + ret, mem_ctx))); + return NT_STATUS_INTERNAL_ERROR; + } + + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock); + } + + free_kerberos_etypes(smb_krb5_context->krb5_context, enctypes); + + return NT_STATUS_OK; +} -- cgit