From 3b2a6997b43dcfe37adf67c84e564a4fbff5b108 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 2 Nov 2005 00:31:22 +0000 Subject: r11452: Update Heimdal to current lorikeet, including removing the ccache side of the gsskrb5_acquire_cred hack. Add support for delegated credentials into the auth and credentials subsystem, and specifically into gensec_gssapi. Add the CIFS NTVFS handler as a consumer of delegated credentials, when no user/domain/password is specified. Andrew Bartlett (This used to be commit 55b89899adb692d90e63873ccdf80b9f94a6b448) --- source4/auth/auth.h | 1 + source4/auth/auth_util.c | 2 + source4/auth/credentials/credentials.c | 1 + source4/auth/credentials/credentials.h | 2 + source4/auth/credentials/credentials_krb5.c | 113 +++++++++++++++++++++++++++- source4/auth/gensec/gensec_gssapi.c | 101 +++++++++++++------------ source4/auth/kerberos/kerberos.h | 10 +++ 7 files changed, 178 insertions(+), 52 deletions(-) (limited to 'source4/auth') diff --git a/source4/auth/auth.h b/source4/auth/auth.h index 9f2e0b6a07..58f72aa8af 100644 --- a/source4/auth/auth.h +++ b/source4/auth/auth.h @@ -118,6 +118,7 @@ struct auth_session_info { struct security_token *security_token; struct auth_serversupplied_info *server_info; DATA_BLOB session_key; + struct cli_credentials *credentials; }; struct auth_method_context; diff --git a/source4/auth/auth_util.c b/source4/auth/auth_util.c index 753f680fb1..df4e510c2f 100644 --- a/source4/auth/auth_util.c +++ b/source4/auth/auth_util.c @@ -526,6 +526,8 @@ NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx, &session_info->security_token); NT_STATUS_NOT_OK_RETURN(nt_status); + session_info->credentials = NULL; + *_session_info = session_info; return NT_STATUS_OK; } diff --git a/source4/auth/credentials/credentials.c b/source4/auth/credentials/credentials.c index 5d2c5c553e..86a3df0077 100644 --- a/source4/auth/credentials/credentials.c +++ b/source4/auth/credentials/credentials.c @@ -46,6 +46,7 @@ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx) cred->domain_obtained = CRED_UNINITIALISED; cred->realm_obtained = CRED_UNINITIALISED; cred->ccache_obtained = CRED_UNINITIALISED; + cred->gss_creds_obtained = CRED_UNINITIALISED; cred->keytab_obtained = CRED_UNINITIALISED; cred->principal_obtained = CRED_UNINITIALISED; diff --git a/source4/auth/credentials/credentials.h b/source4/auth/credentials/credentials.h index b85337bd18..3e84db52a5 100644 --- a/source4/auth/credentials/credentials.h +++ b/source4/auth/credentials/credentials.h @@ -47,6 +47,7 @@ struct cli_credentials { enum credentials_obtained domain_obtained; enum credentials_obtained realm_obtained; enum credentials_obtained ccache_obtained; + enum credentials_obtained gss_creds_obtained; enum credentials_obtained principal_obtained; enum credentials_obtained keytab_obtained; @@ -62,6 +63,7 @@ struct cli_credentials { struct samr_Password *nt_hash; struct ccache_container *ccache; + struct gssapi_creds_container *gssapi_creds; struct keytab_container *keytab; const char *(*workstation_cb) (struct cli_credentials *); diff --git a/source4/auth/credentials/credentials_krb5.c b/source4/auth/credentials/credentials_krb5.c index abb8418748..a3761e8359 100644 --- a/source4/auth/credentials/credentials_krb5.c +++ b/source4/auth/credentials/credentials_krb5.c @@ -85,7 +85,7 @@ int cli_credentials_set_from_ccache(struct cli_credentials *cred, return 0; } - +/* Free a memory ccache */ static int free_mccache(void *ptr) { struct ccache_container *ccc = ptr; krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache); @@ -93,6 +93,7 @@ static int free_mccache(void *ptr) { return 0; } +/* Free a disk-based ccache */ static int free_dccache(void *ptr) { struct ccache_container *ccc = ptr; krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache); @@ -163,7 +164,7 @@ int cli_credentials_set_ccache(struct cli_credentials *cred, } -int cli_credentials_new_ccache(struct cli_credentials *cred) +int cli_credentials_new_ccache(struct cli_credentials *cred, struct ccache_container **_ccc) { krb5_error_code ret; char *rand_string; @@ -211,6 +212,10 @@ int cli_credentials_new_ccache(struct cli_credentials *cred) talloc_steal(cred, ccc); talloc_free(ccache_name); + if (_ccc) { + *_ccc = ccc; + } + return ret; } @@ -228,7 +233,7 @@ int cli_credentials_get_ccache(struct cli_credentials *cred, return EINVAL; } - ret = cli_credentials_new_ccache(cred); + ret = cli_credentials_new_ccache(cred, NULL); if (ret) { return ret; } @@ -245,6 +250,108 @@ int cli_credentials_get_ccache(struct cli_credentials *cred, return ret; } +static int free_gssapi_creds(void *ptr) { + OM_uint32 min_stat, maj_stat; + struct gssapi_creds_container *gcc = ptr; + maj_stat = gss_release_cred(&min_stat, + &gcc->creds); + return 0; +} + +int cli_credentials_get_client_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 ccache_container *ccache; + if (cred->gss_creds_obtained >= (MAX(cred->ccache_obtained, + MAX(cred->principal_obtained, + cred->username_obtained)))) { + *_gcc = cred->gssapi_creds; + return 0; + } + ret = cli_credentials_get_ccache(cred, + &ccache); + if (ret) { + DEBUG(1, ("Failed to get CCACHE for GSSAPI client: %s\n", error_message(ret))); + return ret; + } + + gcc = talloc(cred, struct gssapi_creds_container); + if (!gcc) { + return ENOMEM; + } + + maj_stat = gss_krb5_import_ccache(&min_stat, ccache->ccache, + &gcc->creds); + if (maj_stat) { + if (min_stat) { + ret = min_stat; + } else { + ret = EINVAL; + } + } + if (ret == 0) { + cred->gss_creds_obtained = cred->ccache_obtained; + talloc_set_destructor(gcc, free_gssapi_creds); + cred->gssapi_creds = gcc; + *_gcc = gcc; + } + return ret; +} + +/** + Set a gssapi cred_id_t into the credentails system. + + 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. + + On sucess, the caller must not free gssapi_cred, as it now belongs + to the credentials system. +*/ + + int cli_credentials_set_client_gss_creds(struct cli_credentials *cred, + gss_cred_id_t gssapi_cred, + enum credentials_obtained obtained) +{ + int ret; + OM_uint32 maj_stat, min_stat; + struct ccache_container *ccc; + struct gssapi_creds_container *gcc = talloc(cred, struct gssapi_creds_container); + if (!gcc) { + return ENOMEM; + } + + ret = cli_credentials_new_ccache(cred, &ccc); + if (ret != 0) { + return ret; + } + + maj_stat = gss_krb5_copy_ccache(&min_stat, + gssapi_cred, ccc->ccache); + if (maj_stat) { + if (min_stat) { + ret = min_stat; + } else { + ret = EINVAL; + } + } + + if (ret == 0) { + ret = cli_credentials_set_from_ccache(cred, obtained); + } + if (ret == 0) { + gcc->creds = gssapi_cred; + talloc_set_destructor(gcc, free_gssapi_creds); + + cred->gss_creds_obtained = obtained; + cred->gssapi_creds = gcc; + } + return ret; +} + int cli_credentials_get_keytab(struct cli_credentials *cred, struct keytab_container **_ktc) { diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index d59d19c636..4608b62db5 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -44,8 +44,10 @@ struct gensec_gssapi_state { krb5_ccache ccache; const char *ccache_name; struct keytab_container *keytab; + struct gssapi_creds_container *client_cred; gss_cred_id_t cred; + gss_cred_id_t delegated_cred_handle; }; static char *gssapi_error_string(TALLOC_CTX *mem_ctx, @@ -83,6 +85,10 @@ static int gensec_gssapi_destory(void *ptr) maj_stat = gss_release_cred(&min_stat, &gensec_gssapi_state->cred); } + if (gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) { + maj_stat = gss_release_cred(&min_stat, + &gensec_gssapi_state->delegated_cred_handle); + } if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) { maj_stat = gss_delete_sec_context (&min_stat, @@ -118,13 +124,14 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security) /* TODO: Fill in channel bindings */ gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS; - gensec_gssapi_state->want_flags = GSS_C_MUTUAL_FLAG; + gensec_gssapi_state->want_flags = GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG; gensec_gssapi_state->got_flags = 0; gensec_gssapi_state->session_key = data_blob(NULL, 0); gensec_gssapi_state->pac = data_blob(NULL, 0); gensec_gssapi_state->cred = GSS_C_NO_CREDENTIAL; + gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL; talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory); @@ -205,7 +212,7 @@ static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_securi } maj_stat = gsskrb5_acquire_cred(&min_stat, - gensec_gssapi_state->keytab->keytab, NULL, + gensec_gssapi_state->keytab->keytab, gensec_gssapi_state->server_name, GSS_C_INDEFINITE, GSS_C_NULL_OID_SET, @@ -227,7 +234,6 @@ 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; @@ -235,6 +241,7 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi OM_uint32 maj_stat, min_stat; const char *hostname = gensec_get_target_hostname(gensec_security); const char *principal; + struct gssapi_creds_container *gcc; if (!hostname) { DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n")); @@ -256,29 +263,6 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi gensec_gssapi_state = gensec_security->private_data; - 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; - } - - principal = cli_credentials_get_principal(creds, - gensec_gssapi_state); - name_token.value = discard_const_p(uint8_t, principal); - name_token.length = strlen(principal); - - maj_stat = gss_import_name (&min_stat, - &name_token, - GSS_C_NT_USER_NAME, - &gensec_gssapi_state->client_name); - if (maj_stat) { - DEBUG(2, ("GSS Import name of %s failed: %s\n", - (char *)name_token.value, - gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat))); - return NT_STATUS_INVALID_PARAMETER; - } - principal = gensec_get_target_principal(gensec_security); if (principal && lp_client_use_spnego_principal()) { name_token.value = discard_const_p(uint8_t, principal); @@ -307,28 +291,20 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi return NT_STATUS_INVALID_PARAMETER; } - maj_stat = gsskrb5_acquire_cred(&min_stat, - NULL, ccache->ccache, - gensec_gssapi_state->client_name, - GSS_C_INDEFINITE, - GSS_C_NULL_OID_SET, - GSS_C_INITIATE, - &gensec_gssapi_state->cred, - NULL, - NULL); - if (maj_stat) { - switch (min_stat) { - case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: - DEBUG(3, ("Server [%s] is not registered with our KDC: %s\n", - hostname, gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat))); - return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */ - default: - DEBUG(1, ("Aquiring initiator credentails failed: %s\n", - gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat))); - return NT_STATUS_UNSUCCESSFUL; - } + ret = cli_credentials_get_client_gss_creds(creds, &gcc); + switch (ret) { + case 0: + break; + case KRB5_KDC_UNREACH: + DEBUG(3, ("Cannot reach a KDC we require\n")); + return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */ + default: + DEBUG(1, ("Aquiring initiator credentails failed\n")); + return NT_STATUS_UNSUCCESSFUL; } + gensec_gssapi_state->client_cred = gcc; + return NT_STATUS_OK; } @@ -369,7 +345,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, const DATA_BLOB in, DATA_BLOB *out) { struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data; - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; OM_uint32 maj_stat, min_stat; OM_uint32 min_stat2; gss_buffer_desc input_token, output_token; @@ -381,7 +357,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, case GENSEC_CLIENT: { maj_stat = gss_init_sec_context(&min_stat, - gensec_gssapi_state->cred, + gensec_gssapi_state->client_cred->creds, &gensec_gssapi_state->gssapi_context, gensec_gssapi_state->server_name, discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid), @@ -407,7 +383,7 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, &output_token, &gensec_gssapi_state->got_flags, NULL, - NULL); + &gensec_gssapi_state->delegated_cred_handle); gensec_gssapi_state->gss_oid = gss_oid_p; break; } @@ -420,6 +396,12 @@ static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length); gss_release_buffer(&min_stat2, &output_token); + if (gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG) { + DEBUG(5, ("gensec_gssapi: credentials were delegated\n")); + } else { + DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n")); + } + return NT_STATUS_OK; } else if (maj_stat == GSS_S_CONTINUE_NEEDED) { *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length); @@ -941,6 +923,27 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key); NT_STATUS_NOT_OK_RETURN(nt_status); + if (!(gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG)) { + DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client")); + } else { + krb5_error_code ret; + DEBUG(10, ("gensec_gssapi: delegated credentials supplied by client\n")); + session_info->credentials = cli_credentials_init(session_info); + if (!session_info->credentials) { + return NT_STATUS_NO_MEMORY; + } + + cli_credentials_set_conf(session_info->credentials); + + ret = cli_credentials_set_client_gss_creds(session_info->credentials, + gensec_gssapi_state->delegated_cred_handle, + CRED_SPECIFIED); + if (ret) { + return NT_STATUS_NO_MEMORY; + } + /* It has been taken from this place... */ + gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL; + } *_session_info = session_info; return NT_STATUS_OK; diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h index 070293df68..9813290650 100644 --- a/source4/auth/kerberos/kerberos.h +++ b/source4/auth/kerberos/kerberos.h @@ -29,6 +29,11 @@ struct ccache_container { }; +struct gssapi_creds_container { + gss_cred_id_t creds; +}; + + struct keytab_container { struct smb_krb5_context *smb_krb5_context; krb5_keytab keytab; @@ -155,5 +160,10 @@ NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, krb5_principal client_principal, time_t tgs_authtime, DATA_BLOB *pac); + + int cli_credentials_set_client_gss_creds(struct cli_credentials *cred, + gss_cred_id_t gssapi_cred, + enum credentials_obtained obtained); + #endif /* HAVE_KRB5 */ -- cgit