summaryrefslogtreecommitdiff
path: root/source4/auth/kerberos
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2005-06-22 02:12:26 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:18:41 -0500
commit8a68f96f8cea2c53c8babf2ec826dfc6ef1cc199 (patch)
treeae8dc487623d695ce74f7d7f639f23823908031b /source4/auth/kerberos
parentcc98a92bb0396845ec1dcb75ac412df9db9652d9 (diff)
downloadsamba-8a68f96f8cea2c53c8babf2ec826dfc6ef1cc199.tar.gz
samba-8a68f96f8cea2c53c8babf2ec826dfc6ef1cc199.tar.bz2
samba-8a68f96f8cea2c53c8babf2ec826dfc6ef1cc199.zip
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)
Diffstat (limited to 'source4/auth/kerberos')
-rw-r--r--source4/auth/kerberos/clikrb5.c11
-rw-r--r--source4/auth/kerberos/gssapi_parse.c21
-rw-r--r--source4/auth/kerberos/kerberos.h10
-rw-r--r--source4/auth/kerberos/kerberos_util.c163
-rw-r--r--source4/auth/kerberos/kerberos_verify.c115
5 files changed, 213 insertions, 107 deletions
diff --git a/source4/auth/kerberos/clikrb5.c b/source4/auth/kerberos/clikrb5.c
index ed075f9633..0fede8b2cd 100644
--- a/source4/auth/kerberos/clikrb5.c
+++ b/source4/auth/kerberos/clikrb5.c
@@ -440,17 +440,6 @@ cleanup_princ:
return retval;
}
-#if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING) && !defined(HAVE_KRB5_PRINC_COMPONENT)
- const krb5_data *krb5_princ_component(krb5_context context, krb5_principal principal, int i )
-{
- static krb5_data kdata;
-
- kdata.data = discard_const(krb5_principal_get_comp_string(context, principal, i));
- kdata.length = strlen(kdata.data);
- return &kdata;
-}
-#endif
-
krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry)
{
#if defined(HAVE_KRB5_KT_FREE_ENTRY)
diff --git a/source4/auth/kerberos/gssapi_parse.c b/source4/auth/kerberos/gssapi_parse.c
index 2c2c4e17e5..048eb8204e 100644
--- a/source4/auth/kerberos/gssapi_parse.c
+++ b/source4/auth/kerberos/gssapi_parse.c
@@ -93,3 +93,24 @@ BOOL gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, D
}
+/*
+ check a GSS-API wrapper packet givin an expected OID
+*/
+BOOL gensec_gssapi_check_oid(const DATA_BLOB *blob, const char *oid)
+{
+ BOOL ret;
+ struct asn1_data data;
+ int data_remaining;
+
+ asn1_load(&data, *blob);
+ asn1_start_tag(&data, ASN1_APPLICATION(0));
+ asn1_check_OID(&data, GENSEC_OID_KERBEROS5);
+
+ ret = !data.has_error;
+
+ asn1_free(&data);
+
+ return ret;
+}
+
+
diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h
index a3aff73c87..0f8fd28155 100644
--- a/source4/auth/kerberos/kerberos.h
+++ b/source4/auth/kerberos/kerberos.h
@@ -91,7 +91,7 @@ DATA_BLOB get_auth_data_from_tkt(TALLOC_CTX *mem_ctx,
krb5_ticket *tkt);
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
- krb5_context context,
+ struct smb_krb5_context *smb_krb5_context,
krb5_auth_context auth_context,
const char *realm, const char *service,
const DATA_BLOB *ticket,
@@ -116,5 +116,13 @@ NTSTATUS kinit_to_ccache(TALLOC_CTX *parent_ctx,
const char **ccache_name);
krb5_error_code smb_krb5_init_context(TALLOC_CTX *parent_ctx,
struct smb_krb5_context **smb_krb5_context);
+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);
+NTSTATUS create_memory_keytab(TALLOC_CTX *parent_ctx,
+ struct cli_credentials *machine_account,
+ struct smb_krb5_context *smb_krb5_context,
+ krb5_keytab *keytab);
#endif /* HAVE_KRB5 */
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;
+}
diff --git a/source4/auth/kerberos/kerberos_verify.c b/source4/auth/kerberos/kerberos_verify.c
index f85819aa36..f269012ae3 100644
--- a/source4/auth/kerberos/kerberos_verify.c
+++ b/source4/auth/kerberos/kerberos_verify.c
@@ -34,9 +34,6 @@
#ifdef HAVE_KRB5
-#if !defined(HAVE_KRB5_PRINC_COMPONENT)
-const krb5_data *krb5_princ_component(krb5_context, krb5_principal, int );
-#endif
static DATA_BLOB unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data)
{
DATA_BLOB out;
@@ -308,7 +305,7 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx,
***********************************************************************************/
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
- krb5_context context,
+ struct smb_krb5_context *smb_krb5_context,
krb5_auth_context auth_context,
const char *realm, const char *service,
const DATA_BLOB *ticket,
@@ -319,15 +316,10 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx,
NTSTATUS sret = NT_STATUS_LOGON_FAILURE;
krb5_data packet;
krb5_ticket *tkt = NULL;
- krb5_rcache rcache = NULL;
+ krb5_principal salt_princ;
int ret;
- BOOL got_replay_mutex = False;
-
char *malloc_principal;
- char *machine_username;
- krb5_principal salt_princ = NULL;
- char *salt_princ_string;
NTSTATUS creds_nt_status;
struct cli_credentials *machine_account;
@@ -342,100 +334,45 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx,
if (!NT_STATUS_IS_OK(creds_nt_status)) {
DEBUG(3, ("Could not obtain machine account credentials from the local database\n"));
-
- /* This just becomes a locking key, if we don't have creds, we must be using the keytab */
- salt_princ_string = talloc_asprintf(mem_ctx, "host/%s@%s", lp_netbios_name(), lp_realm());
- if (!salt_princ_string) {
- ret = ENOMEM;
- } else {
- ret = krb5_parse_name(context, salt_princ_string, &salt_princ);
- }
+ talloc_free(machine_account);
+ machine_account = NULL;
} else {
-
- machine_username = talloc_strdup(mem_ctx, cli_credentials_get_username(machine_account));
-
- if (!machine_username) {
- ret = ENOMEM;
- } else {
- char *salt_body;
- char *lower_realm = strlower_talloc(mem_ctx, cli_credentials_get_realm(machine_account));;
- if (machine_username[strlen(machine_username)-1] == '$') {
- machine_username[strlen(machine_username)-1] = '\0';
- }
- if (!lower_realm) {
- ret = ENOMEM;
- } else {
- salt_body = talloc_asprintf(mem_ctx, "%s.%s", machine_username,
- lower_realm);
- if (!salt_body) {
- ret = ENOMEM;
- } else {
- salt_princ_string = talloc_asprintf(mem_ctx, "host/%s@%s", salt_body, cli_credentials_get_realm(machine_account));
- if (!salt_princ_string) {
- ret = ENOMEM;
- } else {
- ret = krb5_parse_name(context, salt_princ_string, &salt_princ);
- }
- }
- }
+ ret = salt_principal_from_credentials(mem_ctx, machine_account,
+ smb_krb5_context,
+ &salt_princ);
+ if (ret) {
+ DEBUG(1,("ads_verify_ticket: maksing salt principal failed (%s)\n",
+ error_message(ret)));
+ return NT_STATUS_INTERNAL_ERROR;
}
}
- if (ret) {
- DEBUG(1,("ads_verify_ticket: maksing salt principal failed (%s)\n",
- error_message(ret)));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
/* This whole process is far more complex than I would
like. We have to go through all this to allow us to store
the secret internally, instead of using /etc/krb5.keytab */
- /* Lock a mutex surrounding the replay as there is no locking in the MIT krb5
- * code surrounding the replay cache... */
-
- if (!grab_server_mutex("replay cache mutex")) {
- DEBUG(1,("ads_verify_ticket: unable to protect replay cache with mutex.\n"));
- goto out;
- }
-
- got_replay_mutex = True;
-
/*
- * JRA. We must set the rcache here. This will prevent replay attacks.
+ * TODO: Actually hook in the replay cache in Heimdal, then
+ * re-add calls to setup a replay cache here, in our private
+ * directory. This will eventually prevent replay attacks
*/
- ret = krb5_get_server_rcache(context, krb5_princ_component(context, salt_princ, 0), &rcache);
- if (ret) {
- DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache failed (%s)\n", error_message(ret)));
- goto out;
- }
-
- ret = krb5_auth_con_setrcache(context, auth_context, rcache);
- if (ret) {
- DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache failed (%s)\n", error_message(ret)));
- goto out;
- }
-
- ret = ads_keytab_verify_ticket(mem_ctx, context, auth_context,
+ ret = ads_keytab_verify_ticket(mem_ctx, smb_krb5_context->krb5_context, auth_context,
service, ticket, &packet, &tkt, keyblock);
- if (ret) {
- ret = ads_secrets_verify_ticket(mem_ctx, machine_account, context, auth_context,
+ if (ret && machine_account) {
+ ret = ads_secrets_verify_ticket(mem_ctx, machine_account, smb_krb5_context->krb5_context, auth_context,
salt_princ, ticket,
&packet, &tkt, keyblock);
}
- release_server_mutex();
- got_replay_mutex = False;
-
if (ret) {
goto out;
}
- ret = krb5_mk_rep(context, auth_context, &packet);
+ ret = krb5_mk_rep(smb_krb5_context->krb5_context, auth_context, &packet);
if (ret) {
DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n",
- smb_get_krb5_error_message(context, ret, mem_ctx)));
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
goto out;
}
@@ -459,10 +396,10 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx,
}
#endif
- if ((ret = krb5_unparse_name(context, get_principal_from_tkt(tkt),
+ if ((ret = krb5_unparse_name(smb_krb5_context->krb5_context, get_principal_from_tkt(tkt),
&malloc_principal))) {
DEBUG(3,("ads_verify_ticket: krb5_unparse_name failed (%s)\n",
- smb_get_krb5_error_message(context, ret, mem_ctx)));
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
sret = NT_STATUS_LOGON_FAILURE;
goto out;
}
@@ -479,10 +416,6 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx,
out:
- if (got_replay_mutex) {
- release_server_mutex();
- }
-
if (!NT_STATUS_IS_OK(sret)) {
data_blob_free(auth_data);
}
@@ -492,11 +425,7 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx,
}
if (tkt != NULL) {
- krb5_free_ticket(context, tkt);
- }
-
- if (salt_princ != NULL) {
- krb5_free_principal(context, salt_princ);
+ krb5_free_ticket(smb_krb5_context->krb5_context, tkt);
}
return sret;