diff options
Diffstat (limited to 'source4/auth')
-rw-r--r-- | source4/auth/gensec/gensec_gssapi.c | 19 | ||||
-rw-r--r-- | source4/auth/gensec/gensec_krb5.c | 148 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos.h | 9 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_util.c | 59 | ||||
-rw-r--r-- | source4/auth/ntlmssp/ntlmssp_client.c | 55 |
5 files changed, 121 insertions, 169 deletions
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index 64a6f8be77..26494f0222 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -208,6 +208,8 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi { struct gensec_gssapi_state *gensec_gssapi_state; struct cli_credentials *creds = gensec_get_credentials(gensec_security); + struct ccache_container *ccache; + krb5_error_code ret; NTSTATUS nt_status; gss_buffer_desc name_token; OM_uint32 maj_stat, min_stat; @@ -245,6 +247,13 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi return NT_STATUS_INVALID_PARAMETER; } + ret = cli_credentials_get_ccache(creds, + &ccache); + if (ret) { + DEBUG(1, ("Failed to get CCACHE for gensec_gssapi: %s\n", error_message(ret))); + return NT_STATUS_UNSUCCESSFUL; + } + name_token.value = cli_credentials_get_principal(creds, gensec_gssapi_state); name_token.length = strlen(name_token.value); @@ -260,16 +269,8 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi return NT_STATUS_UNSUCCESSFUL; } - nt_status = kinit_to_ccache(gensec_gssapi_state, - creds, - gensec_gssapi_state->smb_krb5_context, - &gensec_gssapi_state->ccache, &gensec_gssapi_state->ccache_name); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - maj_stat = gsskrb5_acquire_cred(&min_stat, - NULL, gensec_gssapi_state->ccache, + NULL, ccache->ccache, gensec_gssapi_state->client_name, GSS_C_INDEFINITE, GSS_C_NULL_OID_SET, diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c index a89f46a411..09722af10b 100644 --- a/source4/auth/gensec/gensec_krb5.c +++ b/source4/auth/gensec/gensec_krb5.c @@ -45,7 +45,6 @@ struct gensec_krb5_state { enum GENSEC_KRB5_STATE state_position; struct smb_krb5_context *smb_krb5_context; krb5_auth_context auth_context; - krb5_ccache ccache; krb5_data ticket; krb5_keyblock *keyblock; char *peer_principal; @@ -75,7 +74,6 @@ static int gensec_krb5_destory(void *ptr) static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security) { struct gensec_krb5_state *gensec_krb5_state; - krb5_error_code ret = 0; gensec_krb5_state = talloc(gensec_security, struct gensec_krb5_state); if (!gensec_krb5_state) { @@ -85,7 +83,6 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security) gensec_security->private_data = gensec_krb5_state; gensec_krb5_state->auth_context = NULL; - gensec_krb5_state->ccache = NULL; ZERO_STRUCT(gensec_krb5_state->ticket); ZERO_STRUCT(gensec_krb5_state->keyblock); gensec_krb5_state->session_key = data_blob(NULL, 0); @@ -93,34 +90,29 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security) talloc_set_destructor(gensec_krb5_state, gensec_krb5_destory); - ret = smb_krb5_init_context(gensec_krb5_state, - &gensec_krb5_state->smb_krb5_context); - if (ret) { - DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n", - error_message(ret))); - return NT_STATUS_INTERNAL_ERROR; - } - - ret = krb5_auth_con_init(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context); - if (ret) { - DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", - smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, - ret, gensec_krb5_state))); - return NT_STATUS_INTERNAL_ERROR; - } - return NT_STATUS_OK; } static NTSTATUS gensec_krb5_server_start(struct gensec_security *gensec_security) { NTSTATUS nt_status; + krb5_error_code ret = 0; struct gensec_krb5_state *gensec_krb5_state; nt_status = gensec_krb5_start(gensec_security); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } + + gensec_krb5_state = gensec_security->private_data; + + ret = smb_krb5_init_context(gensec_krb5_state, + &gensec_krb5_state->smb_krb5_context); + if (ret) { + DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n", + error_message(ret))); + return NT_STATUS_INTERNAL_ERROR; + } gensec_krb5_state = gensec_security->private_data; gensec_krb5_state->state_position = GENSEC_KRB5_SERVER_START; @@ -133,7 +125,7 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security struct gensec_krb5_state *gensec_krb5_state; krb5_error_code ret; NTSTATUS nt_status; - const char *ccache_name; + struct ccache_container *ccache_container; const char *hostname = gensec_get_target_hostname(gensec_security); if (!hostname) { @@ -154,72 +146,68 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security gensec_krb5_state = gensec_security->private_data; gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_START; - /* TODO: This is effecivly a static/global variable... - - TODO: If the user set a username, we should use an in-memory CCACHE (see below) - */ - ret = krb5_cc_default(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->ccache); + ret = cli_credentials_get_ccache(gensec_security->credentials, &ccache_container); if (ret) { - DEBUG(1,("krb5_cc_default failed (%s)\n", - smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); - return NT_STATUS_INTERNAL_ERROR; + DEBUG(1,("gensec_krb5_start: cli_credentials_get_ccache failed: %s\n", + error_message(ret))); + return NT_STATUS_UNSUCCESSFUL; } - - while (1) { - { - krb5_data in_data; - in_data.length = 0; - - ret = krb5_mk_req(gensec_krb5_state->smb_krb5_context->krb5_context, - &gensec_krb5_state->auth_context, - AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED, - gensec_get_target_service(gensec_security), - hostname, - &in_data, gensec_krb5_state->ccache, - &gensec_krb5_state->ticket); - - } - switch (ret) { - case 0: - return NT_STATUS_OK; - case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: - DEBUG(3, ("Server [%s] is not registered with our KDC: %s\n", - hostname, smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); - return NT_STATUS_ACCESS_DENIED; - case KRB5KDC_ERR_PREAUTH_FAILED: - case KRB5KRB_AP_ERR_TKT_EXPIRED: - case KRB5_CC_END: - /* Too much clock skew - we will need to kinit to re-skew the clock */ - case KRB5KRB_AP_ERR_SKEW: - case KRB5_KDCREP_SKEW: - { - DEBUG(3, ("kerberos (mk_req) failed: %s\n", - smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); - /* fall down to remaining code */ - } + gensec_krb5_state->smb_krb5_context = talloc_reference(gensec_krb5_state, ccache_container->smb_krb5_context); - /* just don't print a message for these really ordinary messages */ - case KRB5_FCC_NOFILE: - case KRB5_CC_NOTFOUND: - case ENOENT: - - nt_status = kinit_to_ccache(gensec_krb5_state, - gensec_security->credentials, - gensec_krb5_state->smb_krb5_context, - &gensec_krb5_state->ccache, - &ccache_name); + ret = krb5_auth_con_init(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context); + if (ret) { + DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", + smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, + ret, gensec_krb5_state))); + return NT_STATUS_INTERNAL_ERROR; + } + + if (!ret) { + krb5_data in_data; + in_data.length = 0; - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } + ret = krb5_mk_req(gensec_krb5_state->smb_krb5_context->krb5_context, + &gensec_krb5_state->auth_context, + AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED, + gensec_get_target_service(gensec_security), + hostname, + &in_data, ccache_container->ccache, + &gensec_krb5_state->ticket); + + } + switch (ret) { + case 0: + return NT_STATUS_OK; + case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: + DEBUG(3, ("Server [%s] is not registered with our KDC: %s\n", + hostname, smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); + return NT_STATUS_ACCESS_DENIED; + case KRB5KDC_ERR_PREAUTH_FAILED: + case KRB5KRB_AP_ERR_TKT_EXPIRED: + case KRB5_CC_END: + /* Too much clock skew - we will need to kinit to re-skew the clock */ + case KRB5KRB_AP_ERR_SKEW: + case KRB5_KDCREP_SKEW: + { + DEBUG(3, ("kerberos (mk_req) failed: %s\n", + smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); + /* fall down to remaining code */ + } + + + /* just don't print a message for these really ordinary messages */ + case KRB5_FCC_NOFILE: + case KRB5_CC_NOTFOUND: + case ENOENT: + + return NT_STATUS_UNSUCCESSFUL; break; - - default: - DEBUG(0, ("kerberos: %s\n", - smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); - return NT_STATUS_UNSUCCESSFUL; - } + + default: + DEBUG(0, ("kerberos: %s\n", + smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state))); + return NT_STATUS_UNSUCCESSFUL; } } diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h index 954ac7dc57..8cc8e561ac 100644 --- a/source4/auth/kerberos/kerberos.h +++ b/source4/auth/kerberos/kerberos.h @@ -34,6 +34,10 @@ struct smb_krb5_context { #endif }; +struct ccache_container { + struct smb_krb5_context *smb_krb5_context; + krb5_ccache ccache; +}; /* not really ASN.1, but RFC 1964 */ #define TOK_ID_KRB_AP_REQ "\x01\x00" @@ -111,11 +115,10 @@ BOOL kerberos_compatible_enctypes(krb5_context context, krb5_enctype enctype1, k void kerberos_free_data_contents(krb5_context context, krb5_data *pdata); krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry); char *smb_get_krb5_error_message(krb5_context context, krb5_error_code code, TALLOC_CTX *mem_ctx); -NTSTATUS kinit_to_ccache(TALLOC_CTX *parent_ctx, + krb5_error_code kinit_to_ccache(TALLOC_CTX *parent_ctx, struct cli_credentials *credentials, struct smb_krb5_context *smb_krb5_context, - krb5_ccache *ccache, - const char **ccache_name); + krb5_ccache ccache); 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, diff --git a/source4/auth/kerberos/kerberos_util.c b/source4/auth/kerberos/kerberos_util.c index d455dac572..9dc8621b0e 100644 --- a/source4/auth/kerberos/kerberos_util.c +++ b/source4/auth/kerberos/kerberos_util.c @@ -33,11 +33,6 @@ struct principal_container { krb5_principal principal; }; -struct ccache_container { - struct smb_krb5_context *smb_krb5_context; - krb5_ccache ccache; -}; - struct keytab_container { struct smb_krb5_context *smb_krb5_context; krb5_keytab keytab; @@ -65,7 +60,7 @@ krb5_error_code salt_principal_from_credentials(TALLOC_CTX *parent_ctx, return ENOMEM; } - machine_username = talloc_strdup(mem_ctx, cli_credentials_get_username(machine_account)); + machine_username = talloc_strdup(mem_ctx, cli_credentials_get_username(machine_account, mem_ctx)); if (!machine_username) { talloc_free(mem_ctx); @@ -100,58 +95,30 @@ krb5_error_code salt_principal_from_credentials(TALLOC_CTX *parent_ctx, return ret; } -static int free_ccache(void *ptr) { - struct ccache_container *ccc = ptr; - /* current heimdal - 0.6.3, which we need anyway, fixes segfaults here */ - krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache); - - return 0; -} - /** * Return a freshly allocated ccache (destroyed by destructor on child * of parent_ctx), for a given set of client credentials */ - NTSTATUS kinit_to_ccache(TALLOC_CTX *parent_ctx, + krb5_error_code kinit_to_ccache(TALLOC_CTX *parent_ctx, struct cli_credentials *credentials, struct smb_krb5_context *smb_krb5_context, - krb5_ccache *ccache, - const char **ccache_name) + krb5_ccache ccache) { krb5_error_code ret; const char *password; - char *ccache_string; time_t kdc_time = 0; - struct ccache_container *mem_ctx = talloc(parent_ctx, struct ccache_container); + + TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); if (!mem_ctx) { - return NT_STATUS_NO_MEMORY; + return ENOMEM; } password = cli_credentials_get_password(credentials); - /* this string should be unique */ - ccache_string = talloc_asprintf(mem_ctx, "MEMORY:%s_%s", - cli_credentials_get_principal(credentials, mem_ctx), - generate_random_str(mem_ctx, 16)); - - ret = krb5_cc_resolve(smb_krb5_context->krb5_context, ccache_string, ccache); - if (ret) { - DEBUG(1,("failed to generate a new krb5 ccache (%s): %s\n", - ccache_string, - 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->ccache = *ccache; - - talloc_set_destructor(mem_ctx, free_ccache); - if (password) { - ret = kerberos_kinit_password_cc(smb_krb5_context->krb5_context, *ccache, + ret = kerberos_kinit_password_cc(smb_krb5_context->krb5_context, ccache, cli_credentials_get_principal(credentials, mem_ctx), password, NULL, &kdc_time); } else { @@ -163,7 +130,7 @@ static int free_ccache(void *ptr) { if (!mach_pwd) { talloc_free(mem_ctx); DEBUG(1, ("kinit_to_ccache: No password available for kinit\n")); - return NT_STATUS_WRONG_PASSWORD; + return EINVAL; } ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, @@ -171,7 +138,7 @@ static int free_ccache(void *ptr) { &keyblock); if (ret == 0) { - ret = kerberos_kinit_keyblock_cc(smb_krb5_context->krb5_context, *ccache, + ret = kerberos_kinit_keyblock_cc(smb_krb5_context->krb5_context, ccache, cli_credentials_get_principal(credentials, mem_ctx), &keyblock, NULL, &kdc_time); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &keyblock); @@ -192,7 +159,7 @@ static int free_ccache(void *ptr) { smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); - return NT_STATUS_TIME_DIFFERENCE_AT_DC; + return ret; } if (ret) { DEBUG(1,("kinit for %s failed (%s)\n", @@ -200,11 +167,9 @@ static int free_ccache(void *ptr) { smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); - return NT_STATUS_WRONG_PASSWORD; + return ret; } - *ccache_name = ccache_string; - - return NT_STATUS_OK; + return 0; } static int free_keytab(void *ptr) { diff --git a/source4/auth/ntlmssp/ntlmssp_client.c b/source4/auth/ntlmssp/ntlmssp_client.c index add774f84e..feee14a857 100644 --- a/source4/auth/ntlmssp/ntlmssp_client.c +++ b/source4/auth/ntlmssp/ntlmssp_client.c @@ -164,20 +164,10 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, return NT_STATUS_INVALID_PARAMETER; } - /* Correctly handle username in the original form of user@REALM, which is valid */ - if (gensec_security->credentials->realm_obtained - > gensec_security->credentials->domain_obtained) { - user = talloc_asprintf(out_mem_ctx, "%s@%s", - cli_credentials_get_username(gensec_security->credentials), - cli_credentials_get_realm(gensec_security->credentials)); - domain = NULL; - } else { - user = cli_credentials_get_username(gensec_security->credentials); - domain = cli_credentials_get_domain(gensec_security->credentials); - } + user = cli_credentials_get_username(gensec_security->credentials, out_mem_ctx); + domain = cli_credentials_get_domain(gensec_security->credentials); nt_hash = cli_credentials_get_nt_hash(gensec_security->credentials, out_mem_ctx); - password = cli_credentials_get_password(gensec_security->credentials); if (!nt_hash) { static const uint8_t zeros[16]; @@ -265,24 +255,29 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, } /* lanman auth is insecure, it may be disabled. We may also not have a password */ - if (lp_client_lanman_auth() && password) { - lm_response = data_blob_talloc(gensec_ntlmssp_state, NULL, 24); - if (!SMBencrypt(password,challenge_blob.data, - lm_response.data)) { - /* If the LM password was too long (and therefore the LM hash being - of the first 14 chars only), don't send it */ - data_blob_free(&lm_response); - - /* LM Key is incompatible with 'long' passwords */ - gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; + if (lp_client_lanman_auth()) { + password = cli_credentials_get_password(gensec_security->credentials); + if (!password) { + lm_response = nt_response; } else { - E_deshash(password, lm_hash); - lm_session_key = data_blob_talloc(gensec_ntlmssp_state, NULL, 16); - memcpy(lm_session_key.data, lm_hash, 8); - memset(&lm_session_key.data[8], '\0', 8); - - if (!gensec_ntlmssp_state->use_nt_response) { + lm_response = data_blob_talloc(gensec_ntlmssp_state, NULL, 24); + if (!SMBencrypt(password,challenge_blob.data, + lm_response.data)) { + /* If the LM password was too long (and therefore the LM hash being + of the first 14 chars only), don't send it */ + data_blob_free(&lm_response); + + /* LM Key is incompatible with 'long' passwords */ + gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; + } else { + E_deshash(password, lm_hash); + lm_session_key = data_blob_talloc(gensec_ntlmssp_state, NULL, 16); + memcpy(lm_session_key.data, lm_hash, 8); + memset(&lm_session_key.data[8], '\0', 8); + + if (!gensec_ntlmssp_state->use_nt_response) { session_key = lm_session_key; + } } } } else { @@ -353,7 +348,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, gensec_ntlmssp_state->expected_state = NTLMSSP_DONE; - if (gensec_security->want_features & GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL) { + if (gensec_security->want_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL)) { nt_status = ntlmssp_sign_init(gensec_ntlmssp_state); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", @@ -362,7 +357,7 @@ NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, } } - return nt_status; + return NT_STATUS_OK; } NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security) |