diff options
author | Andrew Bartlett <abartlet@samba.org> | 2005-06-22 02:12:26 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:18:41 -0500 |
commit | 8a68f96f8cea2c53c8babf2ec826dfc6ef1cc199 (patch) | |
tree | ae8dc487623d695ce74f7d7f639f23823908031b | |
parent | cc98a92bb0396845ec1dcb75ac412df9db9652d9 (diff) | |
download | samba-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)
-rw-r--r-- | source4/auth/gensec/gensec.h | 5 | ||||
-rw-r--r-- | source4/auth/gensec/gensec_gssapi.c | 59 | ||||
-rw-r--r-- | source4/auth/gensec/gensec_krb5.c | 25 | ||||
-rw-r--r-- | source4/auth/gensec/spnego.c | 23 | ||||
-rw-r--r-- | source4/auth/kerberos/clikrb5.c | 11 | ||||
-rw-r--r-- | source4/auth/kerberos/gssapi_parse.c | 21 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos.h | 10 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_util.c | 163 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_verify.c | 115 | ||||
-rw-r--r-- | source4/auth/ntlmssp/ntlmssp.c | 11 | ||||
-rw-r--r-- | source4/lib/basic.mk | 1 | ||||
-rw-r--r-- | source4/lib/server_mutex.c | 58 | ||||
-rw-r--r-- | source4/passdb/secrets.c | 51 |
13 files changed, 322 insertions, 231 deletions
diff --git a/source4/auth/gensec/gensec.h b/source4/auth/gensec/gensec.h index 2951e13dd9..20f0b1c642 100644 --- a/source4/auth/gensec/gensec.h +++ b/source4/auth/gensec/gensec.h @@ -57,6 +57,11 @@ struct gensec_security_ops { const char **oid; /* NULL if not offered by SPNEGO */ NTSTATUS (*client_start)(struct gensec_security *gensec_security); NTSTATUS (*server_start)(struct gensec_security *gensec_security); + /** + Determine if a packet has the right 'magic' for this mechanism + */ + NTSTATUS (*magic)(struct gensec_security *gensec_security, + const DATA_BLOB *first_packet); NTSTATUS (*update)(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, const DATA_BLOB in, DATA_BLOB *out); NTSTATUS (*seal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx, diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index c6a16cdf33..1542441e27 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -46,6 +46,7 @@ struct gensec_gssapi_state { struct smb_krb5_context *smb_krb5_context; krb5_ccache ccache; const char *ccache_name; + krb5_keytab keytab; gss_cred_id_t cred; }; @@ -170,6 +171,7 @@ static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_securi { NTSTATUS nt_status; struct gensec_gssapi_state *gensec_gssapi_state; + struct cli_credentials *machine_account; nt_status = gensec_gssapi_start(gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { @@ -178,7 +180,30 @@ static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_securi gensec_gssapi_state = gensec_security->private_data; + machine_account = cli_credentials_init(gensec_gssapi_state); + cli_credentials_set_conf(machine_account); + nt_status = cli_credentials_set_machine_account(machine_account); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(3, ("Could not obtain machine account credentials from the local database\n")); + talloc_free(machine_account); + return nt_status; + } else { + nt_status = create_memory_keytab(gensec_gssapi_state, + machine_account, + gensec_gssapi_state->smb_krb5_context, + &gensec_gssapi_state->keytab); + talloc_free(machine_account); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(3, ("Could not create memory keytab!\n")); + talloc_free(machine_account); + return nt_status; + } + } + + gsskrb5_register_acceptor_keytab(gensec_gssapi_state->keytab); return NT_STATUS_OK; + } static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security) @@ -236,7 +261,6 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi return nt_status; } -#ifdef HAVE_GSS_KRB5_CCACHE_NAME /* FIXME, we need an alternate function */ maj_stat = gss_krb5_ccache_name(&min_stat, gensec_gssapi_state->ccache_name, NULL); @@ -246,7 +270,6 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat))); return NT_STATUS_UNSUCCESSFUL; } -#endif maj_stat = gss_acquire_cred(&min_stat, gensec_gssapi_state->client_name, @@ -266,6 +289,25 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi } +/** + * Check if the packet is one for this mechansim + * + * @param gensec_security GENSEC state + * @param in The request, as a DATA_BLOB + * @return Error, INVALID_PARAMETER if it's not a packet for us + * or NT_STATUS_OK if the packet is ok. + */ + +static NTSTATUS gensec_gssapi_magic(struct gensec_security *gensec_security, + const DATA_BLOB *in) +{ + if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) { + return NT_STATUS_OK; + } else { + return NT_STATUS_INVALID_PARAMETER; + } +} + /** * Next state function for the GSSAPI GENSEC mechanism @@ -294,8 +336,18 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, switch (gensec_security->gensec_role) { case GENSEC_CLIENT: { + maj_stat = gss_krb5_ccache_name(&min_stat, + gensec_gssapi_state->ccache_name, + NULL); + if (maj_stat) { + DEBUG(1, ("GSS krb5 ccache set %s failed: %s\n", + gensec_gssapi_state->ccache_name, + gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat))); + return NT_STATUS_UNSUCCESSFUL; + } + maj_stat = gss_init_sec_context(&min_stat, - GSS_C_NO_CREDENTIAL, + gensec_gssapi_state->cred, &gensec_gssapi_state->gssapi_context, gensec_gssapi_state->server_name, discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid), @@ -756,6 +808,7 @@ static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = { .oid = gensec_krb5_oids, .client_start = gensec_gssapi_client_start, .server_start = gensec_gssapi_server_start, + .magic = gensec_gssapi_magic, .update = gensec_gssapi_update, .session_key = gensec_gssapi_session_key, .session_info = gensec_gssapi_session_info, diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c index d633794e1c..348a75b535 100644 --- a/source4/auth/gensec/gensec_krb5.c +++ b/source4/auth/gensec/gensec_krb5.c @@ -400,6 +400,26 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security /** + * Check if the packet is one for this mechansim + * + * @param gensec_security GENSEC state + * @param in The request, as a DATA_BLOB + * @return Error, INVALID_PARAMETER if it's not a packet for us + * or NT_STATUS_OK if the packet is ok. + */ + +static NTSTATUS gensec_krb5_magic(struct gensec_security *gensec_security, + const DATA_BLOB *in) +{ + if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) { + return NT_STATUS_OK; + } else { + return NT_STATUS_INVALID_PARAMETER; + } +} + + +/** * Next state function for the Krb5 GENSEC mechanism * * @param gensec_krb5_state KRB5 State @@ -494,7 +514,7 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, /* Parse the GSSAPI wrapping, if it's there... (win2k3 allows it to be omited) */ if (!gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) { nt_status = ads_verify_ticket(out_mem_ctx, - gensec_krb5_state->smb_krb5_context->krb5_context, + gensec_krb5_state->smb_krb5_context, gensec_krb5_state->auth_context, lp_realm(), gensec_get_target_service(gensec_security), &in, @@ -503,7 +523,7 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, } else { /* TODO: check the tok_id */ nt_status = ads_verify_ticket(out_mem_ctx, - gensec_krb5_state->smb_krb5_context->krb5_context, + gensec_krb5_state->smb_krb5_context, gensec_krb5_state->auth_context, lp_realm(), gensec_get_target_service(gensec_security), @@ -669,6 +689,7 @@ static const struct gensec_security_ops gensec_krb5_security_ops = { .oid = gensec_krb5_oids, .client_start = gensec_krb5_client_start, .server_start = gensec_krb5_server_start, + .magic = gensec_krb5_magic, .update = gensec_krb5_update, .session_key = gensec_krb5_session_key, .session_info = gensec_krb5_session_info, diff --git a/source4/auth/gensec/spnego.c b/source4/auth/gensec/spnego.c index f5d1dd2238..e3d335b71b 100644 --- a/source4/auth/gensec/spnego.c +++ b/source4/auth/gensec/spnego.c @@ -269,9 +269,21 @@ static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec continue; } + if (!all_ops[i]->magic) { + continue; + } + + nt_status = all_ops[i]->magic(gensec_security, &in); + if (!NT_STATUS_IS_OK(nt_status)) { + continue; + } + + spnego_state->state_position = SPNEGO_FALLBACK; + nt_status = gensec_subcontext_start(spnego_state, gensec_security, &spnego_state->sub_sec_security); + if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } @@ -279,18 +291,11 @@ static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security, all_ops[i]); if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; - continue; + return nt_status; } nt_status = gensec_update(spnego_state->sub_sec_security, out_mem_ctx, in, out); - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - spnego_state->state_position = SPNEGO_FALLBACK; - return nt_status; - } - talloc_free(spnego_state->sub_sec_security); - spnego_state->sub_sec_security = NULL; + return nt_status; } DEBUG(1, ("Failed to parse SPNEGO request\n")); return NT_STATUS_INVALID_PARAMETER; 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; diff --git a/source4/auth/ntlmssp/ntlmssp.c b/source4/auth/ntlmssp/ntlmssp.c index 26e9d66e6f..1fd7ac6756 100644 --- a/source4/auth/ntlmssp/ntlmssp.c +++ b/source4/auth/ntlmssp/ntlmssp.c @@ -89,6 +89,16 @@ void debug_ntlmssp_flags(uint32_t neg_flags) DEBUGADD(4, (" NTLMSSP_NEGOTIATE_KEY_EXCH\n")); } +static NTSTATUS gensec_ntlmssp_magic(struct gensec_security *gensec_security, + const DATA_BLOB *first_packet) +{ + if (first_packet->length > 8 && memcmp("NTLMSSP\0", first_packet->data, 8) == 0) { + return NT_STATUS_OK; + } else { + return NT_STATUS_INVALID_PARAMETER; + } +} + /** * Next state function for the wrapped NTLMSSP state machine * @@ -337,6 +347,7 @@ static const struct gensec_security_ops gensec_ntlmssp_security_ops = { .oid = gensec_ntlmssp_oids, .client_start = gensec_ntlmssp_client_start, .server_start = gensec_ntlmssp_server_start, + .magic = gensec_ntlmssp_magic, .update = gensec_ntlmssp_update, .sig_size = gensec_ntlmssp_sig_size, .sign_packet = gensec_ntlmssp_sign_packet, diff --git a/source4/lib/basic.mk b/source4/lib/basic.mk index 6a463b8ec6..58cbca0198 100644 --- a/source4/lib/basic.mk +++ b/source4/lib/basic.mk @@ -73,7 +73,6 @@ ADD_OBJ_FILES = \ lib/ms_fnmatch.o \ lib/select.o \ lib/mutex.o \ - lib/server_mutex.o \ lib/idtree.o \ lib/unix_privs.o \ lib/db_wrap.o \ diff --git a/source4/lib/server_mutex.c b/source4/lib/server_mutex.c deleted file mode 100644 index 878e5497d8..0000000000 --- a/source4/lib/server_mutex.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Authenticate against a remote domain - Copyright (C) Andrew Tridgell 1992-2002 - Copyright (C) Andrew Bartlett 2002 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -/* For reasons known only to MS, many of their NT/Win2k versions - need serialised access only. Two connections at the same time - may (in certain situations) cause connections to be reset, - or access to be denied. - - This locking allows smbd's mutlithread architecture to look - like the single-connection that NT makes. */ - -static char *mutex_server_name; -/* FIXME. ref_count should be allocated per name... JRA. */ -size_t ref_count; - -BOOL grab_server_mutex(const char *name) -{ - mutex_server_name = strdup(name); - if (!mutex_server_name) { - DEBUG(0,("grab_server_mutex: malloc failed for %s\n", name)); - return False; - } - if (!secrets_named_mutex(mutex_server_name, 10, &ref_count)) { - DEBUG(10,("grab_server_mutex: failed for %s\n", name)); - SAFE_FREE(mutex_server_name); - return False; - } - - return True; -} - -void release_server_mutex(void) -{ - if (mutex_server_name) { - secrets_named_mutex_release(mutex_server_name, &ref_count); - SAFE_FREE(mutex_server_name); - } -} diff --git a/source4/passdb/secrets.c b/source4/passdb/secrets.c index 81e92b4da0..44f9fe9311 100644 --- a/source4/passdb/secrets.c +++ b/source4/passdb/secrets.c @@ -123,57 +123,6 @@ char *secrets_fetch_machine_password(const char *domain) } - -/******************************************************************************* - Lock the secrets tdb based on a string - this is used as a primitive form of mutex - between smbd instances. -*******************************************************************************/ - -BOOL secrets_named_mutex(const char *name, uint_t timeout, size_t *p_ref_count) -{ - size_t ref_count = *p_ref_count; - int ret = 0; - - secrets_init(); - if (!tdb) - return False; - - if (ref_count == 0) { - ret = tdb_lock_bystring(tdb->tdb, name); - if (ret == 0) - DEBUG(10,("secrets_named_mutex: got mutex for %s\n", name )); - } - - if (ret == 0) { - *p_ref_count = ++ref_count; - DEBUG(10,("secrets_named_mutex: ref_count for mutex %s = %u\n", name, (uint_t)ref_count )); - } - return (ret == 0); -} - -/******************************************************************************* - Unlock a named mutex. -*******************************************************************************/ - -void secrets_named_mutex_release(const char *name, size_t *p_ref_count) -{ - size_t ref_count = *p_ref_count; - - SMB_ASSERT(ref_count != 0); - - secrets_init(); - if (!tdb) - return; - - if (ref_count == 1) { - tdb_unlock_bystring(tdb->tdb, name); - DEBUG(10,("secrets_named_mutex: released mutex for %s\n", name )); - } - - *p_ref_count = --ref_count; - DEBUG(10,("secrets_named_mutex_release: ref_count for mutex %s = %u\n", name, (uint_t)ref_count )); -} - /* connect to the schannel ldb */ |