diff options
-rw-r--r-- | source4/auth/gensec/gensec_gssapi.c | 114 | ||||
-rw-r--r-- | source4/auth/gensec/gensec_krb5.c | 134 | ||||
-rw-r--r-- | source4/auth/kerberos/clikrb5.c | 10 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos.h | 49 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_pac.c | 96 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_verify.c | 216 | ||||
-rw-r--r-- | source4/heimdal/kdc/kerberos5.c | 31 | ||||
-rw-r--r-- | source4/heimdal/lib/gssapi/accept_sec_context.c | 667 | ||||
-rw-r--r-- | source4/heimdal/lib/gssapi/copy_ccache.c | 19 | ||||
-rw-r--r-- | source4/heimdal/lib/gssapi/gssapi.h | 4 | ||||
-rw-r--r-- | source4/heimdal/lib/gssapi/init_sec_context.c | 18 | ||||
-rw-r--r-- | source4/heimdal/lib/krb5/krb5-protos.h | 13 | ||||
-rw-r--r-- | source4/heimdal/lib/krb5/rd_rep.c | 146 | ||||
-rw-r--r-- | source4/heimdal/lib/krb5/rd_req.c | 20 | ||||
-rw-r--r-- | source4/heimdal/lib/roken/roken-common.h | 31 | ||||
-rw-r--r-- | source4/kdc/pac-glue.c | 11 | ||||
-rw-r--r-- | source4/torture/auth/pac.c | 143 |
17 files changed, 961 insertions, 761 deletions
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index 6316b52bad..c3f7c52085 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -118,7 +118,7 @@ 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 = 0; + gensec_gssapi_state->want_flags = GSS_C_MUTUAL_FLAG; gensec_gssapi_state->got_flags = 0; gensec_gssapi_state->session_key = data_blob(NULL, 0); @@ -388,12 +388,15 @@ 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 (maj_stat == GSS_S_COMPLETE) { + *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length); + gss_release_buffer(&min_stat2, &output_token); + 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); + gss_release_buffer(&min_stat2, &output_token); + return NT_STATUS_MORE_PROCESSING_REQUIRED; } else { if (maj_stat == GSS_S_FAILURE @@ -427,12 +430,12 @@ static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security, &conf_state, &output_token); if (GSS_ERROR(maj_stat)) { - DEBUG(1, ("GSS Wrap failed: %s\n", + DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n", gssapi_error_string(mem_ctx, maj_stat, min_stat))); return NT_STATUS_ACCESS_DENIED; } - *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length); + *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length); gss_release_buffer(&min_stat, &output_token); if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) @@ -462,12 +465,12 @@ static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security, &conf_state, &qop_state); if (GSS_ERROR(maj_stat)) { - DEBUG(1, ("GSS UnWrap failed: %s\n", + DEBUG(1, ("gensec_gssapi_unwrap: GSS UnWrap failed: %s\n", gssapi_error_string(mem_ctx, maj_stat, min_stat))); return NT_STATUS_ACCESS_DENIED; } - *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length); + *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length); gss_release_buffer(&min_stat, &output_token); if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) @@ -506,7 +509,7 @@ static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_securit &conf_state, &output_token); if (GSS_ERROR(maj_stat)) { - DEBUG(1, ("GSS Wrap failed: %s\n", + DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n", gssapi_error_string(mem_ctx, maj_stat, min_stat))); return NT_STATUS_ACCESS_DENIED; } @@ -546,7 +549,7 @@ static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_secur gss_qop_t qop_state; DATA_BLOB in; - dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length); + dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length); in = data_blob_talloc(mem_ctx, NULL, sig->length + length); @@ -563,7 +566,7 @@ static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_secur &conf_state, &qop_state); if (GSS_ERROR(maj_stat)) { - DEBUG(1, ("GSS UnWrap failed: %s\n", + DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n", gssapi_error_string(mem_ctx, maj_stat, min_stat))); return NT_STATUS_ACCESS_DENIED; } @@ -688,7 +691,7 @@ static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security, } } if (feature & GENSEC_FEATURE_DCE_STYLE) { - return True; + return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE; } if (feature & GENSEC_FEATURE_ASYNC_REPLIES) { return True; @@ -744,15 +747,21 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi struct auth_serversupplied_info *server_info = NULL; struct auth_session_info *session_info = NULL; struct PAC_LOGON_INFO *logon_info; - char *p; - char *principal; - const char *account_name; - const char *realm; OM_uint32 maj_stat, min_stat; gss_buffer_desc name_token; gss_buffer_desc pac; krb5_keyblock *keyblock; + time_t authtime; + krb5_principal principal; + char *principal_string; + if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length) + || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, + gensec_gssapi_state->gss_oid->length) != 0)) { + DEBUG(1, ("NO session info available for this mech\n")); + return NT_STATUS_INVALID_PARAMETER; + } + mem_ctx = talloc_named(gensec_gssapi_state, 0, "gensec_gssapi_session_info context"); NT_STATUS_HAVE_NO_MEMORY(mem_ctx); @@ -764,49 +773,56 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi return NT_STATUS_FOOBAR; } - principal = talloc_strndup(mem_ctx, name_token.value, name_token.length); + principal_string = talloc_strndup(mem_ctx, name_token.value, name_token.length); gss_release_buffer(&min_stat, &name_token); - if (!principal) { + if (!principal_string) { talloc_free(mem_ctx); return NT_STATUS_NO_MEMORY; } - p = strchr(principal, '@'); - if (p) { - *p = '\0'; - p++; - realm = p; - } else { - realm = lp_realm(); - } - account_name = principal; - maj_stat = gss_krb5_copy_service_keyblock(&min_stat, gensec_gssapi_state->gssapi_context, &keyblock); - maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat, - gensec_gssapi_state->gssapi_context, - KRB5_AUTHDATA_IF_RELEVANT, - &pac); + if (maj_stat == 0) { + maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat, + gensec_gssapi_state->gssapi_context, + &authtime); + } + + if (maj_stat == 0) { + maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat, + gensec_gssapi_state->gssapi_context, + KRB5_AUTHDATA_IF_RELEVANT, + &pac); + } if (maj_stat == 0) { + krb5_error_code ret; DATA_BLOB pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length); pac_blob = unwrap_pac(mem_ctx, &pac_blob); gss_release_buffer(&min_stat, &pac); + + ret = krb5_parse_name(gensec_gssapi_state->smb_krb5_context->krb5_context, + principal_string, &principal); + if (ret) { + talloc_free(mem_ctx); + return NT_STATUS_INVALID_PARAMETER; + } /* decode and verify the pac */ nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob, gensec_gssapi_state->smb_krb5_context->krb5_context, - NULL, keyblock); + NULL, keyblock, principal, authtime); + krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal); if (NT_STATUS_IS_OK(nt_status)) { union netr_Validation validation; validation.sam3 = &logon_info->info3; nt_status = make_server_info_netlogon_validation(gensec_gssapi_state, - account_name, + NULL, 3, &validation, &server_info); if (!NT_STATUS_IS_OK(nt_status)) { @@ -819,6 +835,9 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi } if (maj_stat) { + krb5_error_code ret; + DATA_BLOB user_sess_key = data_blob(NULL, 0); + DATA_BLOB lm_sess_key = data_blob(NULL, 0); /* IF we have the PAC - otherwise we need to get this * data from elsewere - local ldb, or (TODO) lookup of some * kind... @@ -827,12 +846,32 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi * no PAC present */ - DATA_BLOB user_sess_key = data_blob(NULL, 0); - DATA_BLOB lm_sess_key = data_blob(NULL, 0); - /* TODO: should we pass the krb5 session key in here? */ + char *account_name; + const char *realm; + ret = krb5_parse_name(gensec_gssapi_state->smb_krb5_context->krb5_context, + principal_string, &principal); + if (ret) { + talloc_free(mem_ctx); + return NT_STATUS_INVALID_PARAMETER; + } + + realm = krb5_principal_get_realm(gensec_gssapi_state->smb_krb5_context->krb5_context, + principal); + ret = krb5_unparse_name_norealm(gensec_gssapi_state->smb_krb5_context->krb5_context, + principal, &account_name); + if (ret) { + krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal); + talloc_free(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + + DEBUG(1, ("Unable to use PAC, resorting to local user lookup!\n")); nt_status = sam_get_server_info(mem_ctx, account_name, realm, user_sess_key, lm_sess_key, &server_info); + free(account_name); + krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal); + if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); return nt_status; @@ -841,6 +880,7 @@ static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_securi /* references the server_info into the session_info */ nt_status = auth_generate_session_info(gensec_gssapi_state, server_info, &session_info); + talloc_free(mem_ctx); talloc_free(server_info); NT_STATUS_NOT_OK_RETURN(nt_status); diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c index 09722af10b..d4147496fd 100644 --- a/source4/auth/gensec/gensec_krb5.c +++ b/source4/auth/gensec/gensec_krb5.c @@ -45,19 +45,25 @@ struct gensec_krb5_state { enum GENSEC_KRB5_STATE state_position; struct smb_krb5_context *smb_krb5_context; krb5_auth_context auth_context; - krb5_data ticket; + krb5_data enc_ticket; krb5_keyblock *keyblock; - char *peer_principal; + krb5_ticket *ticket; }; static int gensec_krb5_destory(void *ptr) { struct gensec_krb5_state *gensec_krb5_state = ptr; - if (gensec_krb5_state->ticket.length) { + if (gensec_krb5_state->enc_ticket.length) { kerberos_free_data_contents(gensec_krb5_state->smb_krb5_context->krb5_context, - &gensec_krb5_state->ticket); + &gensec_krb5_state->enc_ticket); } + + if (gensec_krb5_state->ticket) { + krb5_free_ticket(gensec_krb5_state->smb_krb5_context->krb5_context, + gensec_krb5_state->ticket); + } + /* ccache freed in a child destructor */ krb5_free_keyblock(gensec_krb5_state->smb_krb5_context->krb5_context, @@ -83,8 +89,9 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security) gensec_security->private_data = gensec_krb5_state; gensec_krb5_state->auth_context = NULL; - ZERO_STRUCT(gensec_krb5_state->ticket); - ZERO_STRUCT(gensec_krb5_state->keyblock); + gensec_krb5_state->ticket = NULL; + ZERO_STRUCT(gensec_krb5_state->enc_ticket); + gensec_krb5_state->keyblock = NULL; gensec_krb5_state->session_key = data_blob(NULL, 0); gensec_krb5_state->pac = data_blob(NULL, 0); @@ -114,6 +121,14 @@ static NTSTATUS gensec_krb5_server_start(struct gensec_security *gensec_security 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; + } + gensec_krb5_state = gensec_security->private_data; gensec_krb5_state->state_position = GENSEC_KRB5_SERVER_START; @@ -173,7 +188,7 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security gensec_get_target_service(gensec_security), hostname, &in_data, ccache_container->ccache, - &gensec_krb5_state->ticket); + &gensec_krb5_state->enc_ticket); } switch (ret) { @@ -249,31 +264,23 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, { struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data; krb5_error_code ret = 0; - DATA_BLOB pac; NTSTATUS nt_status; switch (gensec_krb5_state->state_position) { case GENSEC_KRB5_CLIENT_START: { - if (ret) { - DEBUG(1,("ads_krb5_mk_req (request ticket) failed (%s)\n", - smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, out_mem_ctx))); - nt_status = NT_STATUS_LOGON_FAILURE; - } else { - DATA_BLOB unwrapped_out; - + DATA_BLOB unwrapped_out; + #ifndef GENSEC_SEND_UNWRAPPED_KRB5 /* This should be a switch for the torture code to set */ - unwrapped_out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->ticket.data, gensec_krb5_state->ticket.length); - - /* wrap that up in a nice GSS-API wrapping */ - *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REQ); + unwrapped_out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->enc_ticket.data, gensec_krb5_state->enc_ticket.length); + + /* wrap that up in a nice GSS-API wrapping */ + *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REQ); #else - *out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->ticket.data, gensec_krb5_state->ticket.length); + *out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->ticket.data, gensec_krb5_state->ticket.length); #endif - gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_MUTUAL_AUTH; - nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; - } - + gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_MUTUAL_AUTH; + nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; return nt_status; } @@ -314,7 +321,6 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, case GENSEC_KRB5_SERVER_START: { - char *principal; DATA_BLOB unwrapped_in; DATA_BLOB unwrapped_out = data_blob(NULL, 0); uint8_t tok_id[2]; @@ -328,20 +334,20 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, 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, - gensec_krb5_state->auth_context, + &gensec_krb5_state->auth_context, lp_realm(), gensec_get_target_service(gensec_security), &in, - &principal, &pac, &unwrapped_out, + &gensec_krb5_state->ticket, &unwrapped_out, &gensec_krb5_state->keyblock); } else { /* TODO: check the tok_id */ nt_status = ads_verify_ticket(out_mem_ctx, gensec_krb5_state->smb_krb5_context, - gensec_krb5_state->auth_context, + &gensec_krb5_state->auth_context, lp_realm(), gensec_get_target_service(gensec_security), &unwrapped_in, - &principal, &pac, &unwrapped_out, + &gensec_krb5_state->ticket, &unwrapped_out, &gensec_krb5_state->keyblock); } @@ -349,10 +355,6 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, return nt_status; } - if (pac.data) { - gensec_krb5_state->pac = data_blob_talloc_reference(gensec_krb5_state, &pac); - } - if (NT_STATUS_IS_OK(nt_status)) { gensec_krb5_state->state_position = GENSEC_KRB5_DONE; /* wrap that up in a nice GSS-API wrapping */ @@ -361,7 +363,6 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, #else *out = unwrapped_out; #endif - gensec_krb5_state->peer_principal = talloc_steal(gensec_krb5_state, principal); } return nt_status; } @@ -418,28 +419,29 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security struct auth_serversupplied_info *server_info = NULL; struct auth_session_info *session_info = NULL; struct PAC_LOGON_INFO *logon_info; - char *p; - char *principal; - const char *account_name; - const char *realm; - - principal = talloc_strdup(gensec_krb5_state, gensec_krb5_state->peer_principal); - NT_STATUS_HAVE_NO_MEMORY(principal); - - p = strchr(principal, '@'); - if (p) { - *p = '\0'; - p++; - realm = p; - } else { - realm = lp_realm(); + + krb5_const_principal client_principal; + + DATA_BLOB pac_wrapped; + DATA_BLOB pac; + + TALLOC_CTX *mem_ctx = talloc_new(gensec_security); + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; } - account_name = principal; + + pac_wrapped = get_auth_data_from_tkt(mem_ctx, gensec_krb5_state->ticket); + + pac = unwrap_pac(mem_ctx, &pac_wrapped); + + client_principal = get_principal_from_tkt(gensec_krb5_state->ticket); /* decode and verify the pac */ - nt_status = kerberos_pac_logon_info(gensec_krb5_state, &logon_info, gensec_krb5_state->pac, + nt_status = kerberos_pac_logon_info(gensec_krb5_state, &logon_info, pac, gensec_krb5_state->smb_krb5_context->krb5_context, - NULL, gensec_krb5_state->keyblock); + NULL, gensec_krb5_state->keyblock, + client_principal, + gensec_krb5_state->ticket->ticket.authtime); /* IF we have the PAC - otherwise we need to get this * data from elsewere - local ldb, or (TODO) lookup of some @@ -453,25 +455,41 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security union netr_Validation validation; validation.sam3 = &logon_info->info3; nt_status = make_server_info_netlogon_validation(gensec_krb5_state, - account_name, + NULL, 3, &validation, &server_info); - talloc_free(principal); + talloc_free(mem_ctx); NT_STATUS_NOT_OK_RETURN(nt_status); } else { + krb5_error_code ret; DATA_BLOB user_sess_key = data_blob(NULL, 0); DATA_BLOB lm_sess_key = data_blob(NULL, 0); + + char *account_name; + const char *realm = krb5_principal_get_realm(gensec_krb5_state->smb_krb5_context->krb5_context, + get_principal_from_tkt(gensec_krb5_state->ticket)); + ret = krb5_unparse_name_norealm(gensec_krb5_state->smb_krb5_context->krb5_context, + get_principal_from_tkt(gensec_krb5_state->ticket), &account_name); + if (ret) { + return NT_STATUS_NO_MEMORY; + } + /* TODO: should we pass the krb5 session key in here? */ - nt_status = sam_get_server_info(gensec_krb5_state, account_name, realm, + nt_status = sam_get_server_info(mem_ctx, account_name, realm, user_sess_key, lm_sess_key, &server_info); - talloc_free(principal); - NT_STATUS_NOT_OK_RETURN(nt_status); + free(account_name); + + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(mem_ctx); + return nt_status; + } } /* references the server_info into the session_info */ nt_status = auth_generate_session_info(gensec_krb5_state, server_info, &session_info); - talloc_free(server_info); + talloc_free(mem_ctx); + NT_STATUS_NOT_OK_RETURN(nt_status); nt_status = gensec_krb5_session_key(gensec_security, &session_info->session_key); diff --git a/source4/auth/kerberos/clikrb5.c b/source4/auth/kerberos/clikrb5.c index 40c1e254f8..e3f2057b44 100644 --- a/source4/auth/kerberos/clikrb5.c +++ b/source4/auth/kerberos/clikrb5.c @@ -375,11 +375,13 @@ cleanup_princ: #if defined(HAVE_KRB5_GET_ERROR_STRING) && defined(HAVE_KRB5_FREE_ERROR_STRING) char *context_error = krb5_get_error_string(context); - ret = talloc_asprintf(mem_ctx, "%s: %s", error_message(code), context_error); - krb5_free_error_string(context, context_error); -#else - ret = talloc_strdup(mem_ctx, error_message(code)); + if (context_error) { + ret = talloc_asprintf(mem_ctx, "%s: %s", error_message(code), context_error); + krb5_free_error_string(context, context_error); + return ret; + } #endif + ret = talloc_strdup(mem_ctx, error_message(code)); return ret; } diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h index 39bba5f46f..9535094e2b 100644 --- a/source4/auth/kerberos/kerberos.h +++ b/source4/auth/kerberos/kerberos.h @@ -92,13 +92,12 @@ krb5_error_code ads_krb5_mk_req(krb5_context context, krb5_data *outbuf); DATA_BLOB get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, krb5_ticket *tkt); - NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, - krb5_auth_context auth_context, + krb5_auth_context *auth_context, const char *realm, const char *service, - const DATA_BLOB *ticket, - char **principal, DATA_BLOB *auth_data, + const DATA_BLOB *enc_ticket, + krb5_ticket **tkt, DATA_BLOB *ap_rep, krb5_keyblock **keyblock); int kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc, @@ -125,6 +124,10 @@ 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 principal_from_credentials(TALLOC_CTX *parent_ctx, + struct cli_credentials *credentials, + struct smb_krb5_context *smb_krb5_context, + krb5_principal *princ); NTSTATUS create_memory_keytab(TALLOC_CTX *parent_ctx, struct cli_credentials *machine_account, struct smb_krb5_context *smb_krb5_context, @@ -134,26 +137,30 @@ NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, DATA_BLOB blob, krb5_context context, krb5_keyblock *krbtgt_keyblock, - krb5_keyblock *service_keyblock); -NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx, - struct PAC_LOGON_INFO **logon_info, - DATA_BLOB blob, - krb5_context context, - krb5_keyblock *krbtgt_keyblock, - krb5_keyblock *service_keyblock); -krb5_error_code kerberos_create_pac(TALLOC_CTX *mem_ctx, - struct auth_serversupplied_info *server_info, - krb5_context context, - krb5_keyblock *krbtgt_keyblock, - krb5_keyblock *server_keyblock, - time_t tgs_authtime, - DATA_BLOB *pac); - -krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx, + krb5_keyblock *service_keyblock, + krb5_const_principal client_principal, + time_t tgs_authtime); + NTSTATUS kerberos_pac_logon_info(TALLOC_CTX *mem_ctx, + struct PAC_LOGON_INFO **logon_info, + DATA_BLOB blob, + krb5_context context, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock, + krb5_const_principal client_principal, + time_t tgs_authtime); + krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx, struct PAC_DATA *pac_data, krb5_context context, krb5_keyblock *krbtgt_keyblock, krb5_keyblock *service_keyblock, - DATA_BLOB *pac); + DATA_BLOB *pac) ; + krb5_error_code kerberos_create_pac(TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info *server_info, + krb5_context context, + krb5_keyblock *krbtgt_keyblock, + krb5_keyblock *service_keyblock, + krb5_principal client_principal, + time_t tgs_authtime, + DATA_BLOB *pac); #endif /* HAVE_KRB5 */ diff --git a/source4/auth/kerberos/kerberos_pac.c b/source4/auth/kerberos/kerberos_pac.c index b26a25eac1..3294699070 100644 --- a/source4/auth/kerberos/kerberos_pac.c +++ b/source4/auth/kerberos/kerberos_pac.c @@ -33,11 +33,11 @@ #include "librpc/gen_ndr/ndr_krb5pac.h" #include "auth/auth.h" -static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, - DATA_BLOB pac_data, - struct PAC_SIGNATURE_DATA *sig, - krb5_context context, - krb5_keyblock *keyblock) +static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx, + DATA_BLOB pac_data, + struct PAC_SIGNATURE_DATA *sig, + krb5_context context, + krb5_keyblock *keyblock) { krb5_error_code ret; krb5_crypto crypto; @@ -55,7 +55,7 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, if (ret) { DEBUG(0,("krb5_crypto_init() failed: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); - return NT_STATUS_FOOBAR; + return ret; } ret = krb5_verify_checksum(context, crypto, @@ -63,18 +63,9 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, pac_data.data, pac_data.length, &cksum); - if (ret) { - DEBUG(2, ("PAC Verification failed: %s\n", - smb_get_krb5_error_message(context, ret, mem_ctx))); - } - krb5_crypto_destroy(context, crypto); - if (ret) { - return NT_STATUS_ACCESS_DENIED; - } - - return NT_STATUS_OK; + return ret; } NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, @@ -82,17 +73,23 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, DATA_BLOB blob, krb5_context context, krb5_keyblock *krbtgt_keyblock, - krb5_keyblock *service_keyblock) + krb5_keyblock *service_keyblock, + krb5_const_principal client_principal, + time_t tgs_authtime) { + krb5_error_code ret; NTSTATUS status; struct PAC_SIGNATURE_DATA srv_sig; struct PAC_SIGNATURE_DATA *srv_sig_ptr = NULL; struct PAC_SIGNATURE_DATA kdc_sig; struct PAC_SIGNATURE_DATA *kdc_sig_ptr = NULL; struct PAC_LOGON_INFO *logon_info = NULL; + struct PAC_LOGON_NAME *logon_name = NULL; struct PAC_DATA *pac_data; DATA_BLOB modified_pac_blob = data_blob_talloc(mem_ctx, blob.data, blob.length); + NTTIME tgs_authtime_nttime; + krb5_principal client_principal_pac; int i; pac_data = talloc(mem_ctx, struct PAC_DATA); @@ -136,6 +133,7 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, kdc_sig = pac_data->buffers[i].info->kdc_cksum; break; case PAC_TYPE_LOGON_NAME: + logon_name = &pac_data->buffers[i].info->logon_name; break; default: break; @@ -163,28 +161,54 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, '\0', 16); /* verify by service_key */ - status = check_pac_checksum(mem_ctx, + ret = check_pac_checksum(mem_ctx, modified_pac_blob, &srv_sig, context, service_keyblock); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("PAC Decode: Failed to verify the service signature\n")); - return status; + if (ret) { + DEBUG(1, ("PAC Decode: Failed to verify the service signature: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + return NT_STATUS_ACCESS_DENIED; } if (krbtgt_keyblock) { DATA_BLOB service_checksum_blob = data_blob_const(srv_sig_ptr->signature, sizeof(srv_sig_ptr->signature)); - status = check_pac_checksum(mem_ctx, + ret = check_pac_checksum(mem_ctx, service_checksum_blob, &kdc_sig, context, krbtgt_keyblock); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("PAC Decode: Failed to verify the krbtgt signature\n")); - return status; + if (ret) { + DEBUG(1, ("PAC Decode: Failed to verify the KDC signature: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + return NT_STATUS_ACCESS_DENIED; } } + /* Convert to NT time, so as not to loose accuracy in comparison */ + unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime); + + if (tgs_authtime_nttime != logon_name->logon_time) { + DEBUG(2, ("PAC Decode: Logon time mismatch between ticket and PAC!\n")); + DEBUG(2, ("PAC Decode: PAC: %s\n", nt_time_string(mem_ctx, logon_name->logon_time))); + DEBUG(2, ("PAC Decode: Ticket: %s\n", nt_time_string(mem_ctx, tgs_authtime_nttime))); + return NT_STATUS_ACCESS_DENIED; + } + + ret = krb5_parse_name_norealm(context, logon_name->account_name, &client_principal_pac); + if (ret) { + DEBUG(2, ("Could not parse name from incoming PAC: [%s]: %s\n", + logon_name->account_name, + smb_get_krb5_error_message(context, ret, mem_ctx))); + return NT_STATUS_INVALID_PARAMETER; + } + + if (!krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) { + DEBUG(2, ("Name in PAC [%s] does not match principal name in ticket\n", + logon_name->account_name)); + return NT_STATUS_ACCESS_DENIED; + } + #if 0 if (strcasecmp(logon_info->info3.base.account_name.string, "Administrator")== 0) { @@ -205,7 +229,9 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, DATA_BLOB blob, krb5_context context, krb5_keyblock *krbtgt_keyblock, - krb5_keyblock *service_keyblock) + krb5_keyblock *service_keyblock, + krb5_const_principal client_principal, + time_t tgs_authtime) { NTSTATUS nt_status; struct PAC_DATA *pac_data; @@ -215,7 +241,9 @@ static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, blob, context, krbtgt_keyblock, - service_keyblock); + service_keyblock, + client_principal, + tgs_authtime); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } @@ -275,6 +303,7 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, if (cksum.checksum.length == sizeof(sig->signature)) { memcpy(sig->signature, cksum.checksum.data, sizeof(sig->signature)); } + free_Checksum(&cksum); return 0; } @@ -385,6 +414,7 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, krb5_context context, krb5_keyblock *krbtgt_keyblock, krb5_keyblock *service_keyblock, + krb5_principal client_principal, time_t tgs_authtime, DATA_BLOB *pac) { @@ -400,6 +430,8 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, union PAC_INFO *u_KDC_CHECKSUM; union PAC_INFO *u_SRV_CHECKSUM; + char *name; + enum { PAC_BUF_LOGON_INFO = 0, PAC_BUF_LOGON_NAME = 1, @@ -478,11 +510,15 @@ static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, LOGON_INFO->info3 = *sam3; LOGON_INFO->info3.base.last_logon = timeval_to_nttime(&tv); - LOGON_NAME->account_name = server_info->account_name; - + ret = krb5_unparse_name_norealm(context, client_principal, &name); + if (ret) { + return ret; + } + LOGON_NAME->account_name = talloc_strdup(LOGON_NAME, name); + free(name); /* this logon_time field is absolutely critical. This is what - caused all our pac troubles :-) + caused all our PAC troubles :-) */ unix_to_nt_time(&LOGON_NAME->logon_time, tgs_authtime); diff --git a/source4/auth/kerberos/kerberos_verify.c b/source4/auth/kerberos/kerberos_verify.c index b140eb6ae9..dec084299b 100644 --- a/source4/auth/kerberos/kerberos_verify.c +++ b/source4/auth/kerberos/kerberos_verify.c @@ -71,9 +71,10 @@ DATA_BLOB unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data) ***********************************************************************************/ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_context context, - krb5_auth_context auth_context, + krb5_auth_context *auth_context, const char *service, - const DATA_BLOB *ticket, krb5_data *p_packet, + const krb5_data *p_packet, + krb5_flags *ap_req_options, krb5_ticket **pp_tkt, krb5_keyblock **keyblock) { @@ -146,12 +147,10 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex } number_matched_principals++; - p_packet->length = ticket->length; - p_packet->data = (krb5_pointer)ticket->data; *pp_tkt = NULL; - ret = krb5_rd_req_return_keyblock(context, &auth_context, p_packet, + ret = krb5_rd_req_return_keyblock(context, auth_context, p_packet, kt_entry.principal, keytab, - NULL, pp_tkt, keyblock); + ap_req_options, pp_tkt, keyblock); if (ret) { last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx); DEBUG(10, ("ads_keytab_verify_ticket: krb5_rd_req(%s) failed: %s\n", @@ -216,121 +215,28 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex } /********************************************************************************** - Try to verify a ticket using the secrets.tdb. -***********************************************************************************/ - -static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx, - struct cli_credentials *machine_account, - krb5_context context, - krb5_auth_context auth_context, - krb5_principal salt_princ, - const DATA_BLOB *ticket, krb5_data *p_packet, - krb5_ticket **pp_tkt, - krb5_keyblock **keyblock) -{ - krb5_error_code ret = 0; - krb5_error_code our_ret; - krb5_data password; - krb5_enctype *enctypes = NULL; - int i; - char *password_s = talloc_strdup(mem_ctx, cli_credentials_get_password(machine_account)); - if (!password_s) { - DEBUG(1, ("ads_secrets_verify_ticket: Could not obtain password for our local machine account!\n")); - return ENOENT; - } - - ZERO_STRUCTP(keyblock); - - password.data = password_s; - password.length = strlen(password_s); - - /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */ - - if ((ret = get_kerberos_allowed_etypes(context, &enctypes))) { - DEBUG(1,("ads_secrets_verify_ticket: krb5_get_permitted_enctypes failed (%s)\n", - error_message(ret))); - - krb5_free_principal(context, salt_princ); - return ret; - } - - p_packet->length = ticket->length; - p_packet->data = (krb5_pointer)ticket->data; - - /* We need to setup a auth context with each possible encoding type in turn. */ - - ret = KRB5_BAD_ENCTYPE; - for (i=0;enctypes[i];i++) { - krb5_keyblock *key = NULL; - - if (!(key = malloc_p(krb5_keyblock))) { - break; - } - - if (create_kerberos_key_from_string(context, salt_princ, &password, key, enctypes[i])) { - SAFE_FREE(key); - continue; - } - - krb5_auth_con_setuseruserkey(context, auth_context, key); - - krb5_free_keyblock(context, key); - - our_ret = krb5_rd_req_return_keyblock(context, &auth_context, p_packet, - NULL, - NULL, NULL, pp_tkt, - keyblock); - if (!our_ret) { - - DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n", - (unsigned int)enctypes[i] )); - ret = our_ret; - break; - } - - DEBUG((our_ret != KRB5_BAD_ENCTYPE) ? 3 : 10, - ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n", - (unsigned int)enctypes[i], smb_get_krb5_error_message(context, our_ret, mem_ctx))); - - if (our_ret != KRB5_BAD_ENCTYPE) { - ret = our_ret; - } - } - - free_kerberos_etypes(context, enctypes); - - return ret; -} - -/********************************************************************************** Verify an incoming ticket and parse out the principal name and authorization_data if available. ***********************************************************************************/ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, - krb5_auth_context auth_context, + krb5_auth_context *auth_context, const char *realm, const char *service, - const DATA_BLOB *ticket, - char **principal, DATA_BLOB *auth_data, + const DATA_BLOB *enc_ticket, + krb5_ticket **tkt, DATA_BLOB *ap_rep, krb5_keyblock **keyblock) { - NTSTATUS sret = NT_STATUS_LOGON_FAILURE; + krb5_keyblock *local_keyblock; krb5_data packet; - krb5_ticket *tkt = NULL; krb5_principal salt_princ; int ret; + krb5_flags ap_req_options = 0; - char *malloc_principal; - - NTSTATUS creds_nt_status; + NTSTATUS creds_nt_status, status; struct cli_credentials *machine_account; - ZERO_STRUCT(packet); - ZERO_STRUCTP(auth_data); - ZERO_STRUCTP(ap_rep); - machine_account = cli_credentials_init(mem_ctx); cli_credentials_set_conf(machine_account); creds_nt_status = cli_credentials_set_machine_account(machine_account); @@ -360,78 +266,54 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx, * directory. This will eventually prevent replay attacks */ + packet.length = enc_ticket->length; + packet.data = (krb5_pointer)enc_ticket->data; + ret = ads_keytab_verify_ticket(mem_ctx, smb_krb5_context->krb5_context, auth_context, - service, ticket, &packet, &tkt, keyblock); + service, &packet, &ap_req_options, tkt, &local_keyblock); 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); - } - - if (ret) { - goto out; + krb5_keytab keytab; + krb5_principal server; + status = create_memory_keytab(mem_ctx, machine_account, smb_krb5_context, + &keytab); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, + &server); + if (ret == 0) { + ret = krb5_rd_req_return_keyblock(smb_krb5_context->krb5_context, auth_context, &packet, + server, + keytab, &ap_req_options, tkt, + &local_keyblock); + } } - 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", + DEBUG(3,("ads_secrets_verify_ticket: failed to decrypt with error %s\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); - goto out; - } - - *ap_rep = data_blob_talloc(mem_ctx, packet.data, packet.length); - SAFE_FREE(packet.data); - packet.length = 0; - -#if 0 - file_save("/tmp/ticket.dat", ticket->data, ticket->length); -#endif - - *auth_data = get_auth_data_from_tkt(mem_ctx, tkt); - - *auth_data = unwrap_pac(mem_ctx, auth_data); - -#if 0 - if (tkt->enc_part2) { - file_save("/tmp/authdata.dat", - tkt->enc_part2->authorization_data[0]->contents, - tkt->enc_part2->authorization_data[0]->length); + return NT_STATUS_LOGON_FAILURE; } -#endif + *keyblock = local_keyblock; - 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(smb_krb5_context->krb5_context, ret, mem_ctx))); - sret = NT_STATUS_LOGON_FAILURE; - goto out; - } - - *principal = talloc_strdup(mem_ctx, malloc_principal); - SAFE_FREE(malloc_principal); - if (!principal) { - DEBUG(3,("ads_verify_ticket: talloc_strdup() failed\n")); - sret = NT_STATUS_NO_MEMORY; - goto out; - } - - sret = NT_STATUS_OK; - - out: - - if (!NT_STATUS_IS_OK(sret)) { - data_blob_free(auth_data); - } - - if (!NT_STATUS_IS_OK(sret)) { - data_blob_free(ap_rep); - } - - if (tkt != NULL) { - krb5_free_ticket(smb_krb5_context->krb5_context, tkt); + if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED) { + krb5_data packet_out; + ret = krb5_mk_rep(smb_krb5_context->krb5_context, *auth_context, &packet_out); + if (ret) { + krb5_free_ticket(smb_krb5_context->krb5_context, *tkt); + + DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n", + smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); + return NT_STATUS_LOGON_FAILURE; + } + + *ap_rep = data_blob_talloc(mem_ctx, packet_out.data, packet_out.length); + krb5_free_data_contents(smb_krb5_context->krb5_context, &packet_out); + } else { + *ap_rep = data_blob(NULL, 0); } - return sret; + return NT_STATUS_OK; } #endif /* HAVE_KRB5 */ diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index 453263774b..38444f4a13 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -208,7 +208,7 @@ log_timestamp(krb5_context context, strlcpy(renewtime_str, "unset", sizeof(renewtime_str)); kdc_log(context, config, 5, - "%s authtime: %s starttime: %s endtype: %s renew till: %s", + "%s authtime: %s starttime: %s endtime: %s renew till: %s", type, authtime_str, starttime_str, endtime_str, renewtime_str); } @@ -329,8 +329,9 @@ make_etype_info_entry(krb5_context context, ETYPE_INFO_ENTRY *ent, Key *key) { ent->etype = key->key.keytype; if(key->salt){ - ALLOC(ent->salttype); #if 0 + ALLOC(ent->salttype); + if(key->salt->type == hdb_pw_salt) *ent->salttype = 0; /* or 1? or NULL? */ else if(key->salt->type == hdb_afs3_salt) @@ -345,8 +346,17 @@ make_etype_info_entry(krb5_context context, ETYPE_INFO_ENTRY *ent, Key *key) *know* what cell you are using (e.g by assuming that the cell is the same as the realm in lower case) */ -#else +#elif 0 + ALLOC(ent->salttype); *ent->salttype = key->salt->type; +#else + /* + * We shouldn't sent salttype since its incompatible with the + * specification and its break windows clients. The afs + * salting problem is solved by using KRB5-PADATA-AFS3-SALT + * implemented in Heimdal 0.7 and later. + */ + ent->salttype = NULL; #endif krb5_copy_data(context, &key->salt->salt, &ent->salt); @@ -1508,7 +1518,20 @@ fix_transited_encoding(krb5_context context, int num_realms; int i; - if(tr->tr_type != DOMAIN_X500_COMPRESS) { + switch (tr->tr_type) { + case DOMAIN_X500_COMPRESS: + break; + case 0: + /* + * Allow empty content of type 0 because that is was Microsoft + * generates in their TGT. + */ + if (tr->contents.length == 0) + break; + kdc_log(context, config, 0, + "Transited type 0 with non empty content"); + return KRB5KDC_ERR_TRTYPE_NOSUPP; + default: kdc_log(context, config, 0, "Unknown transited type: %u", tr->tr_type); return KRB5KDC_ERR_TRTYPE_NOSUPP; diff --git a/source4/heimdal/lib/gssapi/accept_sec_context.c b/source4/heimdal/lib/gssapi/accept_sec_context.c index 2ba2415112..7412d84eb0 100644 --- a/source4/heimdal/lib/gssapi/accept_sec_context.c +++ b/source4/heimdal/lib/gssapi/accept_sec_context.c @@ -274,215 +274,224 @@ gsskrb5_acceptor_ready( return GSS_S_COMPLETE; } - static OM_uint32 -gsskrb5_acceptor_start( - OM_uint32 * minor_status, - gss_ctx_id_t * context_handle, - const gss_cred_id_t acceptor_cred_handle, - const gss_buffer_t input_token, - const gss_channel_bindings_t input_chan_bindings, - gss_name_t * src_name, - gss_OID * mech_type, - gss_buffer_t output_token, - OM_uint32 * ret_flags, - OM_uint32 * time_rec, - gss_cred_id_t * delegated_cred_handle) +gsskrb5_acceptor_start + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle + ) { - krb5_error_code kret; - OM_uint32 ret = GSS_S_COMPLETE; - krb5_data indata; - krb5_flags ap_options; - OM_uint32 flags; - krb5_ticket *ticket = NULL; - krb5_keytab keytab = NULL; - krb5_keyblock *keyblock = NULL; - int no_wrap = 0; - - /* - * TODO: check the channel_bindings - */ - - /* - * We need a sequence number - */ - krb5_auth_con_addflags(gssapi_krb5_context, - (*context_handle)->auth_context, - KRB5_AUTH_CONTEXT_DO_SEQUENCE, - NULL); - - /* - * We need remove the decapsulate only when GSS_C_DCE_STYLE isn't in use - */ - ret = gssapi_krb5_decapsulate(minor_status, - input_token,&indata, - "\x01\x00", - GSS_KRB5_MECHANISM); - if (ret) { - /* No OID wrapping apparently available. */ - no_wrap = 1; - indata.length = input_token->length; - indata.data = input_token->value; - } + krb5_error_code kret; + OM_uint32 ret = GSS_S_COMPLETE; + krb5_data indata; + krb5_flags ap_options; + OM_uint32 flags; + krb5_ticket *ticket = NULL; + krb5_keytab keytab = NULL; + krb5_keyblock *keyblock = NULL; + krb5_data fwd_data; + int is_cfx = 0; + + krb5_data_zero (&fwd_data); + + /* + * We may, or may not, have an escapsulation. + */ + ret = gssapi_krb5_decapsulate (minor_status, + input_token_buffer, + &indata, + "\x01\x00", + GSS_KRB5_MECHANISM); - /* - * We need to get our keytab - */ - if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) { - if (gssapi_krb5_keytab != NULL) { - keytab = gssapi_krb5_keytab; - } - } else { - keytab = acceptor_cred_handle->keytab; - } + if (ret) { + /* No OID wrapping apparently available. */ + indata.length = input_token_buffer->length; + indata.data = input_token_buffer->value; + } - /* - * We need to check the ticket and create the AP-REP packet - */ - kret = krb5_rd_req_return_keyblock(gssapi_krb5_context, - &(*context_handle)->auth_context, - &indata, - (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred_handle->principal, - keytab, - &ap_options, - &ticket, - &keyblock); - if (kret) { - *minor_status = kret; - gssapi_krb5_set_error_string (); - return GSS_S_FAILURE; + /* + * We need to get our keytab + */ + if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) { + if (gssapi_krb5_keytab != NULL) { + keytab = gssapi_krb5_keytab; } + } else if (acceptor_cred_handle->keytab != NULL) { + keytab = acceptor_cred_handle->keytab; + } + + /* + * We need to check the ticket and create the AP-REP packet + */ + kret = krb5_rd_req_return_keyblock(gssapi_krb5_context, + &(*context_handle)->auth_context, + &indata, + (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred_handle->principal, + keytab, + &ap_options, + &ticket, + &keyblock); + if (kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + gssapi_krb5_set_error_string (); + return ret; + } + + /* + * We need to remember some data on the context_handle + */ + (*context_handle)->ticket = ticket; + (*context_handle)->service_keyblock = keyblock; + (*context_handle)->lifetime = ticket->ticket.endtime; + + /* + * We need to copy the principal names to the context and the calling layer + */ + kret = krb5_copy_principal(gssapi_krb5_context, + ticket->client, + &(*context_handle)->source); + if (kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + gssapi_krb5_set_error_string (); + } - /* - * We need to remember some data on the context_handle - */ - (*context_handle)->ticket = ticket; - (*context_handle)->service_keyblock = keyblock; - (*context_handle)->lifetime = ticket->ticket.endtime; - - /* - * We need to copy the principal names to the context and the calling layer - */ - kret = krb5_copy_principal(gssapi_krb5_context, - ticket->client, - &(*context_handle)->source); - if (kret) { - *minor_status = kret; - gssapi_krb5_set_error_string (); - return GSS_S_FAILURE; - } + kret = krb5_copy_principal (gssapi_krb5_context, + ticket->server, + &(*context_handle)->target); + if (kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + gssapi_krb5_set_error_string (); + return ret; + } + + /* + * We need to setup some compat stuff, this assumes that context_handle->target is already set + */ + ret = _gss_DES3_get_mic_compat(minor_status, *context_handle); + if (ret) { + return ret; + } - kret = krb5_copy_principal(gssapi_krb5_context, - ticket->server, - &(*context_handle)->target); + if (src_name != NULL) { + kret = krb5_copy_principal (gssapi_krb5_context, + ticket->client, + src_name); if (kret) { - *minor_status = kret; - gssapi_krb5_set_error_string (); - return GSS_S_FAILURE; + ret = GSS_S_FAILURE; + *minor_status = kret; + gssapi_krb5_set_error_string (); + return ret; } + } - /* - * We need to setup some compat stuff, this assumes that context_handle->target is already set - */ - ret = _gss_DES3_get_mic_compat(minor_status, *context_handle); - if (ret) return ret; - - /* - * We need to get the flags out of the 8003 checksum - */ - { - krb5_authenticator authenticator; - - kret = krb5_auth_con_getauthenticator(gssapi_krb5_context, + /* + * We need to get the flags out of the 8003 checksum + */ + { + krb5_authenticator authenticator; + + kret = krb5_auth_con_getauthenticator(gssapi_krb5_context, (*context_handle)->auth_context, &authenticator); - if (kret) { - *minor_status = kret; - gssapi_krb5_set_error_string (); - return GSS_S_FAILURE; - } - - ret = gssapi_krb5_verify_8003_checksum(minor_status, - input_chan_bindings, - authenticator->cksum, - &flags, - &(*context_handle)->fwd_data); - krb5_free_authenticator(gssapi_krb5_context, &authenticator); - if (ret) return ret; - } - - /* And remember them for later */ - (*context_handle)->flags = flags; - - if(flags & GSS_C_MUTUAL_FLAG) { - int is_cfx = 0; - krb5_data outbuf; - - gsskrb5_is_cfx(*context_handle, &is_cfx); - - if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) { - kret = krb5_auth_con_addflags(gssapi_krb5_context, - (*context_handle)->auth_context, - KRB5_AUTH_CONTEXT_USE_SUBKEY, - NULL); - (*context_handle)->more_flags |= ACCEPTOR_SUBKEY; - } - - kret = krb5_mk_rep(gssapi_krb5_context, - (*context_handle)->auth_context, - &outbuf); - if (kret) { - *minor_status = kret; - gssapi_krb5_set_error_string (); - return GSS_S_FAILURE; - } - - if (!(flags & GSS_C_DCE_STYLE)) { - ret = gssapi_krb5_encapsulate(minor_status, - &outbuf, - output_token, - "\x02\x00", - GSS_KRB5_MECHANISM); - krb5_data_free (&outbuf); - if (ret) return ret; - } else { - output_token->length = outbuf.length; - output_token->value = outbuf.data; - } + if(kret) { + ret = GSS_S_FAILURE; + *minor_status = kret; + gssapi_krb5_set_error_string (); + return ret; } - /* - * We need to set the return value for the calling layer - */ - if (ret_flags) *ret_flags = flags; - - if (time_rec) { - ret = gssapi_lifetime_left(minor_status, - (*context_handle)->lifetime, - time_rec); - if (ret) return ret; - } + ret = gssapi_krb5_verify_8003_checksum(minor_status, + input_chan_bindings, + authenticator->cksum, + &flags, + &fwd_data); + krb5_free_authenticator(gssapi_krb5_context, &authenticator); + if (ret) + if (ret) return ret; + } + + if(flags & GSS_C_MUTUAL_FLAG) { + krb5_data outbuf; + + gsskrb5_is_cfx(*context_handle, &is_cfx); + + if (is_cfx != 0 + || (ap_options & AP_OPTS_USE_SUBKEY)) { + kret = krb5_auth_con_addflags(gssapi_krb5_context, + (*context_handle)->auth_context, + KRB5_AUTH_CONTEXT_USE_SUBKEY, + NULL); + (*context_handle)->more_flags |= ACCEPTOR_SUBKEY; + } + + kret = krb5_mk_rep(gssapi_krb5_context, + (*context_handle)->auth_context, + &outbuf); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + + if (!(flags & GSS_C_DCE_STYLE)) { + ret = gssapi_krb5_encapsulate(minor_status, + &outbuf, + output_token, + "\x02\x00", + GSS_KRB5_MECHANISM); + krb5_data_free (&outbuf); + if (ret) return ret; + } else { + output_token->length = outbuf.length; + output_token->value = outbuf.data; + } + } + + /* + * We need to send the flags back to the caller + */ + flags |= GSS_C_TRANS_FLAG; - if (src_name) { - kret = krb5_copy_principal(gssapi_krb5_context, - (*context_handle)->source, - src_name); - if (kret) { - *minor_status = kret; - gssapi_krb5_set_error_string (); - return GSS_S_FAILURE; - } - } + if (ret_flags) + *ret_flags = flags; + + /* And remember them for later */ + + (*context_handle)->lifetime = ticket->ticket.endtime; + (*context_handle)->flags = flags; + (*context_handle)->more_flags |= OPEN; + + if (mech_type) + *mech_type = GSS_KRB5_MECHANISM; + + if (time_rec) { + ret = gssapi_lifetime_left(minor_status, + (*context_handle)->lifetime, + time_rec); + if (ret) + if (ret) return ret; + } - /* - * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from the client - */ - if (flags & GSS_C_DCE_STYLE) { - (*context_handle)->state = ACCEPTOR_WAIT_FOR_DCESTYLE; - return GSS_S_CONTINUE_NEEDED; - } + /* + * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from the client + */ + if (flags & GSS_C_DCE_STYLE) { + (*context_handle)->state = ACCEPTOR_WAIT_FOR_DCESTYLE; + return GSS_S_CONTINUE_NEEDED; + } - return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle); + return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle); } static OM_uint32 @@ -490,7 +499,7 @@ gsskrb5_acceptor_wait_for_dcestyle( OM_uint32 * minor_status, gss_ctx_id_t * context_handle, const gss_cred_id_t acceptor_cred_handle, - const gss_buffer_t input_token, + const gss_buffer_t input_token_buffer, const gss_channel_bindings_t input_chan_bindings, gss_name_t * src_name, gss_OID * mech_type, @@ -506,8 +515,8 @@ gsskrb5_acceptor_wait_for_dcestyle( OM_uint32 l_seq_number; /* We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP */ - inbuf.length = input_token->length; - inbuf.data = input_token->value; + inbuf.length = input_token_buffer->length; + inbuf.data = input_token_buffer->value; /* * We need to remeber the old remote seq_number, then check if the client has replied with our local seq_number, @@ -547,18 +556,41 @@ gsskrb5_acceptor_wait_for_dcestyle( */ { krb5_ap_rep_enc_part *repl; + int32_t auth_flags; + + kret = krb5_auth_con_removeflags(gssapi_krb5_context, + (*context_handle)->auth_context, + KRB5_AUTH_CONTEXT_DO_TIME, &auth_flags); + if (kret) { /* Can't happen */ + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } - kret = _krb5_rd_rep_type(gssapi_krb5_context, - (*context_handle)->auth_context, - &inbuf, - &repl, - TRUE); + kret = krb5_rd_rep(gssapi_krb5_context, + (*context_handle)->auth_context, + &inbuf, + &repl); if (kret) { gssapi_krb5_set_error_string (); *minor_status = kret; return GSS_S_FAILURE; } + + /* Because the inbuf above is a final leg from client + * to server, we don't have a use for a 'reply' + * here */ krb5_free_ap_rep_enc_part(gssapi_krb5_context, repl); + + /* Do no harm, put the flags back */ + kret = krb5_auth_con_setflags(gssapi_krb5_context, + (*context_handle)->auth_context, + auth_flags); + if (kret) { /* Can't happen */ + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } } /* We need to check the liftime */ @@ -598,7 +630,7 @@ gsskrb5_acceptor_wait_for_dcestyle( */ { OM_uint32 tmp_r_seq_number; - OM_uint32 l_seq_number; + OM_uint32 tmp_l_seq_number; kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context, (*context_handle)->auth_context, @@ -611,7 +643,7 @@ gsskrb5_acceptor_wait_for_dcestyle( kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context, (*context_handle)->auth_context, - &l_seq_number); + &tmp_l_seq_number); if (kret) { gssapi_krb5_set_error_string (); *minor_status = kret; @@ -621,7 +653,7 @@ gsskrb5_acceptor_wait_for_dcestyle( /* * Here we check if the client has responsed with our local seq_number, */ - if (tmp_r_seq_number != l_seq_number) { + if (tmp_r_seq_number != tmp_l_seq_number) { return GSS_S_UNSEQ_TOKEN; } } @@ -645,73 +677,102 @@ gsskrb5_acceptor_wait_for_dcestyle( } static OM_uint32 -gsskrb5_accept_sec_context( - OM_uint32 * minor_status, - gss_ctx_id_t * context_handle, - const gss_cred_id_t acceptor_cred_handle, - const gss_buffer_t input_token, - const gss_channel_bindings_t input_chan_bindings, - gss_name_t * src_name, - gss_OID * actual_mech_type, - gss_buffer_t output_token, - OM_uint32 * ret_flags, - OM_uint32 * time_rec, - gss_cred_id_t * delegated_cred_handle) +gsskrb5_accept_sec_context + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle + ) { - OM_uint32 ret; - - if (*context_handle == GSS_C_NO_CONTEXT) { - ret = _gsskrb5_create_ctx(minor_status, - context_handle, - input_chan_bindings, - ACCEPTOR_START); - if (ret) return ret; - } + OM_uint32 ret = GSS_S_COMPLETE; + krb5_data fwd_data; + gss_ctx_id_t local_context; - if (actual_mech_type) *actual_mech_type = GSS_KRB5_MECHANISM; + GSSAPI_KRB5_INIT(); - HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex); + krb5_data_zero (&fwd_data); + output_token->length = 0; + output_token->value = NULL; + + if (src_name != NULL) + *src_name = NULL; + if (mech_type) + *mech_type = GSS_KRB5_MECHANISM; + + if (*context_handle == GSS_C_NO_CONTEXT) { + ret = _gsskrb5_create_ctx(minor_status, + &local_context, + input_chan_bindings, + ACCEPTOR_START); + if (ret) return ret; + } else { + local_context = *context_handle; + } + + /* + * TODO: check the channel_bindings + * (above just sets them to krb5 layer) + */ - switch ((*context_handle)->state) { - case ACCEPTOR_START: - ret = gsskrb5_acceptor_start(minor_status, - context_handle, - acceptor_cred_handle, - input_token, - input_chan_bindings, - src_name, - actual_mech_type, - output_token, - ret_flags, - time_rec, - delegated_cred_handle); - break; - case ACCEPTOR_WAIT_FOR_DCESTYLE: - ret = gsskrb5_acceptor_wait_for_dcestyle(minor_status, - context_handle, - acceptor_cred_handle, - input_token, - input_chan_bindings, - src_name, - actual_mech_type, - output_token, - ret_flags, - time_rec, - delegated_cred_handle); - break; - case ACCEPTOR_READY: - /* this function should not be called after it has returned GSS_S_COMPLETE */ - ret = GSS_S_BAD_STATUS; - break; - default: - /* TODO: is this correct here? --metze */ - ret = GSS_S_BAD_STATUS; - break; + HEIMDAL_MUTEX_lock(&(local_context)->ctx_id_mutex); + + switch ((local_context)->state) { + case ACCEPTOR_START: + ret = gsskrb5_acceptor_start(minor_status, + &local_context, + acceptor_cred_handle, + input_token_buffer, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + break; + case ACCEPTOR_WAIT_FOR_DCESTYLE: + ret = gsskrb5_acceptor_wait_for_dcestyle(minor_status, + &local_context, + acceptor_cred_handle, + input_token_buffer, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + break; + case ACCEPTOR_READY: + /* this function should not be called after it has returned GSS_S_COMPLETE */ + ret = GSS_S_BAD_STATUS; + break; + default: + /* TODO: is this correct here? --metze */ + ret = GSS_S_BAD_STATUS; + break; + } + + HEIMDAL_MUTEX_unlock(&(local_context)->ctx_id_mutex); + + if (*context_handle == GSS_C_NO_CONTEXT) { + if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) { + *context_handle = local_context; + } else { + gss_delete_sec_context(minor_status, + &local_context, + NULL); } + } - HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex); - - return ret; + return ret; } static OM_uint32 @@ -1065,53 +1126,45 @@ gss_accept_sec_context gss_cred_id_t * delegated_cred_handle ) { + OM_uint32 ret; ssize_t mech_len; const u_char *p; *minor_status = 0; - if (src_name) *src_name = GSS_C_NO_NAME; - if (mech_type) *mech_type = GSS_C_NO_OID; - - output_token->length = 0; - output_token->value = NULL; - - if (ret_flags) *ret_flags = 0; - if (time_rec) *time_rec = 0; - if (delegated_cred_handle) *delegated_cred_handle = NULL; - - mech_len = gssapi_krb5_get_mech(input_token_buffer->value, - input_token_buffer->length, - &p); - - /* This could be 'dce style' kerberos, where the OID is missing :-( */ - if ((mech_len < 0) || (mech_len == GSS_KRB5_MECHANISM->length - && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_len) == 0)) { - return gsskrb5_accept_sec_context(minor_status, - context_handle, - acceptor_cred_handle, - input_token_buffer, - input_chan_bindings, - src_name, - mech_type, - output_token, - ret_flags, - time_rec, - delegated_cred_handle); - } else if (mech_len == GSS_SPNEGO_MECHANISM->length - && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_len) == 0) { - return spnego_accept_sec_context(minor_status, - context_handle, - acceptor_cred_handle, - input_token_buffer, - input_chan_bindings, - src_name, - mech_type, - output_token, - ret_flags, - time_rec, - delegated_cred_handle); - } - + mech_len = gssapi_krb5_get_mech (input_token_buffer->value, + input_token_buffer->length, + &p); + + /* This could be 'dce style' kerberos, where the OID is missing :-( */ + if ((mech_len < 0) || ((mech_len == GSS_KRB5_MECHANISM->length) + && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_len) == 0)) + ret = gsskrb5_accept_sec_context(minor_status, + context_handle, + acceptor_cred_handle, + input_token_buffer, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + else if (mech_len == GSS_SPNEGO_MECHANISM->length + && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_len) == 0) + ret = spnego_accept_sec_context(minor_status, + context_handle, + acceptor_cred_handle, + input_token_buffer, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + else return GSS_S_BAD_MECH; + + return ret; } diff --git a/source4/heimdal/lib/gssapi/copy_ccache.c b/source4/heimdal/lib/gssapi/copy_ccache.c index 4f2b3f4895..828ca64156 100644 --- a/source4/heimdal/lib/gssapi/copy_ccache.c +++ b/source4/heimdal/lib/gssapi/copy_ccache.c @@ -105,6 +105,25 @@ gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, return GSS_S_COMPLETE; } +OM_uint32 +gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + time_t *authtime) +{ + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + if (context_handle->ticket == NULL) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + *authtime = context_handle->ticket->ticket.authtime; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + OM_uint32 gss_krb5_copy_service_keyblock (OM_uint32 *minor_status, gss_ctx_id_t context_handle, diff --git a/source4/heimdal/lib/gssapi/gssapi.h b/source4/heimdal/lib/gssapi/gssapi.h index 5712581d3f..4ee988b020 100644 --- a/source4/heimdal/lib/gssapi/gssapi.h +++ b/source4/heimdal/lib/gssapi/gssapi.h @@ -809,6 +809,10 @@ gsskrb5_extract_authz_data_from_sec_context int /*ad_type*/, gss_buffer_t /*ad_data*/); OM_uint32 +gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + time_t *authtime); +OM_uint32 gsskrb5_get_initiator_subkey (OM_uint32 * /*minor_status*/, const gss_ctx_id_t context_handle, diff --git a/source4/heimdal/lib/gssapi/init_sec_context.c b/source4/heimdal/lib/gssapi/init_sec_context.c index 6a80934e46..5c6c6a0f8e 100644 --- a/source4/heimdal/lib/gssapi/init_sec_context.c +++ b/source4/heimdal/lib/gssapi/init_sec_context.c @@ -147,6 +147,15 @@ _gsskrb5_create_ctx( return GSS_S_BAD_BINDINGS; } + /* + * We need a sequence number + */ + + krb5_auth_con_addflags(gssapi_krb5_context, + (*context_handle)->auth_context, + KRB5_AUTH_CONTEXT_DO_SEQUENCE, + NULL); + return GSS_S_COMPLETE; } @@ -388,15 +397,6 @@ gsskrb5_initiator_start ret = _gss_DES3_get_mic_compat(minor_status, *context_handle); if (ret) return ret; - /* - * We need a sequence number - */ - - krb5_auth_con_addflags(gssapi_krb5_context, - (*context_handle)->auth_context, - KRB5_AUTH_CONTEXT_DO_SEQUENCE, - NULL); - /* We need the key and a random local subkey */ { kret = krb5_auth_con_setkey(gssapi_krb5_context, diff --git a/source4/heimdal/lib/krb5/krb5-protos.h b/source4/heimdal/lib/krb5/krb5-protos.h index cc619314a3..97f286b83e 100644 --- a/source4/heimdal/lib/krb5/krb5-protos.h +++ b/source4/heimdal/lib/krb5/krb5-protos.h @@ -2378,6 +2378,12 @@ krb5_parse_name ( krb5_principal */*principal*/); krb5_error_code KRB5_LIB_FUNCTION +krb5_parse_name_mustrealm ( + krb5_context /*context*/, + const char */*name*/, + krb5_principal */*principal*/); + +krb5_error_code KRB5_LIB_FUNCTION krb5_parse_name_norealm ( krb5_context /*context*/, const char */*name*/, @@ -3436,13 +3442,6 @@ krb5_write_safe_message ( krb5_error_code KRB5_LIB_FUNCTION krb5_xfree (void */*ptr*/); -krb5_error_code -parse_name ( - krb5_context /*context*/, - const char */*name*/, - krb5_boolean /*short_form*/, - krb5_principal */*principal*/); - #ifdef __cplusplus } #endif diff --git a/source4/heimdal/lib/krb5/rd_rep.c b/source4/heimdal/lib/krb5/rd_rep.c index a92eea5c04..53138d9f45 100644 --- a/source4/heimdal/lib/krb5/rd_rep.c +++ b/source4/heimdal/lib/krb5/rd_rep.c @@ -36,94 +36,80 @@ RCSID("$Id: rd_rep.c,v 1.25 2005/06/17 07:49:33 lha Exp $"); krb5_error_code KRB5_LIB_FUNCTION -_krb5_rd_rep_type(krb5_context context, - krb5_auth_context auth_context, - const krb5_data *inbuf, - krb5_ap_rep_enc_part **repl, - krb5_boolean dce_style_response) +krb5_rd_rep(krb5_context context, + krb5_auth_context auth_context, + const krb5_data *inbuf, + krb5_ap_rep_enc_part **repl) { - krb5_error_code ret; - AP_REP ap_rep; - size_t len; - krb5_data data; - krb5_crypto crypto; + krb5_error_code ret; + AP_REP ap_rep; + size_t len; + krb5_data data; + krb5_crypto crypto; - krb5_data_zero (&data); - ret = 0; + krb5_data_zero (&data); + ret = 0; - ret = decode_AP_REP(inbuf->data, inbuf->length, &ap_rep, &len); - if (ret) - return ret; - if (ap_rep.pvno != 5) { - ret = KRB5KRB_AP_ERR_BADVERSION; - krb5_clear_error_string (context); - goto out; - } - if (ap_rep.msg_type != krb_ap_rep) { - ret = KRB5KRB_AP_ERR_MSG_TYPE; - krb5_clear_error_string (context); - goto out; - } + ret = decode_AP_REP(inbuf->data, inbuf->length, &ap_rep, &len); + if (ret) + return ret; + if (ap_rep.pvno != 5) { + ret = KRB5KRB_AP_ERR_BADVERSION; + krb5_clear_error_string (context); + goto out; + } + if (ap_rep.msg_type != krb_ap_rep) { + ret = KRB5KRB_AP_ERR_MSG_TYPE; + krb5_clear_error_string (context); + goto out; + } - ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto); - if (ret) - goto out; - ret = krb5_decrypt_EncryptedData (context, - crypto, - KRB5_KU_AP_REQ_ENC_PART, - &ap_rep.enc_part, - &data); - krb5_crypto_destroy(context, crypto); - if (ret) - goto out; + ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto); + if (ret) + goto out; + ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_AP_REQ_ENC_PART, + &ap_rep.enc_part, + &data); + krb5_crypto_destroy(context, crypto); + if (ret) + goto out; - *repl = malloc(sizeof(**repl)); - if (*repl == NULL) { - ret = ENOMEM; - krb5_set_error_string (context, "malloc: out of memory"); - goto out; - } - ret = krb5_decode_EncAPRepPart(context, - data.data, - data.length, - *repl, - &len); - if (ret) - return ret; - - if (!dce_style_response) { - if ((*repl)->ctime != auth_context->authenticator->ctime || - (*repl)->cusec != auth_context->authenticator->cusec) { - ret = KRB5KRB_AP_ERR_MUT_FAIL; - krb5_set_error_string (context, "Mutual authentication failed: Timestamps mismatch"); - goto out; - } - } - if ((*repl)->seq_number) - krb5_auth_con_setremoteseqnumber(context, auth_context, - *((*repl)->seq_number)); - if ((*repl)->subkey) - krb5_auth_con_setremotesubkey(context, auth_context, (*repl)->subkey); + *repl = malloc(sizeof(**repl)); + if (*repl == NULL) { + ret = ENOMEM; + krb5_set_error_string (context, "malloc: out of memory"); + goto out; + } + ret = krb5_decode_EncAPRepPart(context, + data.data, + data.length, + *repl, + &len); + if (ret) + return ret; + + if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { + if ((*repl)->ctime != auth_context->authenticator->ctime || + (*repl)->cusec != auth_context->authenticator->cusec) { + ret = KRB5KRB_AP_ERR_MUT_FAIL; + krb5_clear_error_string (context); + goto out; + } + } + if ((*repl)->seq_number) + krb5_auth_con_setremoteseqnumber(context, auth_context, + *((*repl)->seq_number)); + if ((*repl)->subkey) + krb5_auth_con_setremotesubkey(context, auth_context, (*repl)->subkey); -out: - krb5_data_free (&data); - free_AP_REP (&ap_rep); - return ret; + out: + krb5_data_free (&data); + free_AP_REP (&ap_rep); + return ret; } -krb5_error_code KRB5_LIB_FUNCTION -krb5_rd_rep(krb5_context context, - krb5_auth_context auth_context, - const krb5_data *inbuf, - krb5_ap_rep_enc_part **repl) -{ - return _krb5_rd_rep_type(context, - auth_context, - inbuf, - repl, - FALSE); -} - void KRB5_LIB_FUNCTION krb5_free_ap_rep_enc_part (krb5_context context, krb5_ap_rep_enc_part *val) diff --git a/source4/heimdal/lib/krb5/rd_req.c b/source4/heimdal/lib/krb5/rd_req.c index 30ad08bd82..66172c10fb 100644 --- a/source4/heimdal/lib/krb5/rd_req.c +++ b/source4/heimdal/lib/krb5/rd_req.c @@ -33,7 +33,7 @@ #include <krb5_locl.h> -RCSID("$Id: rd_req.c,v 1.57 2005/01/08 20:41:17 lha Exp $"); +RCSID("$Id: rd_req.c,v 1.58 2005/08/27 05:48:57 lha Exp $"); static krb5_error_code decrypt_tkt_enc_part (krb5_context context, @@ -136,6 +136,10 @@ check_transited(krb5_context context, Ticket *ticket, EncTicketPart *enc) int num_realms; krb5_error_code ret; + /* Windows w2k and w2k3 uses this */ + if(enc->transited.tr_type == 0 && enc->transited.contents.length == 0) + return 0; + if(enc->transited.tr_type != DOMAIN_X500_COMPRESS) return KRB5KDC_ERR_TRTYPE_NOSUPP; @@ -561,6 +565,7 @@ krb5_rd_req_return_keyblock(krb5_context context, krb5_error_code ret; krb5_ap_req ap_req; krb5_principal service = NULL; + krb5_keyblock *local_keyblock; if (*auth_context == NULL) { ret = krb5_auth_con_init(context, auth_context); @@ -592,13 +597,13 @@ krb5_rd_req_return_keyblock(krb5_context context, &ap_req, server, keytab, - keyblock); + &local_keyblock); if(ret) goto out; } else { ret = krb5_copy_keyblock(context, (*auth_context)->keyblock, - keyblock); + &local_keyblock); if (ret) goto out; } @@ -607,17 +612,20 @@ krb5_rd_req_return_keyblock(krb5_context context, auth_context, &ap_req, server, - *keyblock, + local_keyblock, 0, ap_req_options, ticket); + if (ret) { + krb5_free_keyblock(context, local_keyblock); + } else { + *keyblock = local_keyblock; + } out: free_AP_REQ(&ap_req); if(service) krb5_free_principal(context, service); - if (ret) - krb5_free_keyblock(context, *keyblock); return ret; } diff --git a/source4/heimdal/lib/roken/roken-common.h b/source4/heimdal/lib/roken/roken-common.h index d85d55f433..c4ba2edb7c 100644 --- a/source4/heimdal/lib/roken/roken-common.h +++ b/source4/heimdal/lib/roken/roken-common.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: roken-common.h,v 1.61 2005/07/07 05:03:30 lha Exp $ */ +/* $Id: roken-common.h,v 1.62 2005/09/01 18:47:35 lha Exp $ */ #ifndef __ROKEN_COMMON_H__ #define __ROKEN_COMMON_H__ @@ -312,43 +312,46 @@ ewrite (int fd, const void *buf, size_t nbytes); struct hostent; const char * ROKEN_LIB_FUNCTION -hostent_find_fqdn (const struct hostent *he); +hostent_find_fqdn (const struct hostent *); void ROKEN_LIB_FUNCTION -esetenv(const char *var, const char *val, int rewrite); +esetenv(const char *, const char *, int); void ROKEN_LIB_FUNCTION -socket_set_address_and_port (struct sockaddr *sa, const void *ptr, int port); +socket_set_address_and_port (struct sockaddr *, const void *, int); size_t ROKEN_LIB_FUNCTION -socket_addr_size (const struct sockaddr *sa); +socket_addr_size (const struct sockaddr *); void ROKEN_LIB_FUNCTION -socket_set_any (struct sockaddr *sa, int af); +socket_set_any (struct sockaddr *, int); size_t ROKEN_LIB_FUNCTION -socket_sockaddr_size (const struct sockaddr *sa); +socket_sockaddr_size (const struct sockaddr *); void * ROKEN_LIB_FUNCTION -socket_get_address (struct sockaddr *sa); +socket_get_address (struct sockaddr *); int ROKEN_LIB_FUNCTION -socket_get_port (const struct sockaddr *sa); +socket_get_port (const struct sockaddr *); void ROKEN_LIB_FUNCTION -socket_set_port (struct sockaddr *sa, int port); +socket_set_port (struct sockaddr *, int); void ROKEN_LIB_FUNCTION -socket_set_portrange (int sock, int restr, int af); +socket_set_portrange (int, int, int); void ROKEN_LIB_FUNCTION -socket_set_debug (int sock); +socket_set_debug (int); void ROKEN_LIB_FUNCTION -socket_set_tos (int sock, int tos); +socket_set_tos (int, int); void ROKEN_LIB_FUNCTION -socket_set_reuseaddr (int sock, int val); +socket_set_reuseaddr (int, int); + +void ROKEN_LIB_FUNCTION +socket_set_ipv6only (int, int); char ** ROKEN_LIB_FUNCTION vstrcollect(va_list *ap); diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index 45b6776f70..20578a786e 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -36,7 +36,7 @@ krb5_error_code ret; NTSTATUS nt_status; struct auth_serversupplied_info *server_info; - char *username, *p; + char *username; const char *realm; DATA_BLOB tmp_blob; TALLOC_CTX *mem_ctx = talloc_named(config, 0, "samba_get_pac context"); @@ -44,7 +44,7 @@ return ENOMEM; } - ret = krb5_unparse_name(context, client, &username); + ret = krb5_unparse_name_norealm(context, client, &username); if (ret != 0) { krb5_set_error_string(context, "get pac: could not parse principal"); @@ -55,12 +55,6 @@ /* parse the principal name */ realm = krb5_principal_get_realm(context, client); - username = talloc_strdup(mem_ctx, username); - p = strchr(username, '@'); - if (p) { - p[0] = '\0'; - } - nt_status = sam_get_server_info(mem_ctx, username, realm, data_blob(NULL, 0), data_blob(NULL, 0), @@ -75,6 +69,7 @@ context, krbtgt_keyblock, server_keyblock, + client, tgs_authtime, &tmp_blob); diff --git a/source4/torture/auth/pac.c b/source4/torture/auth/pac.c index 8b0da02bf3..b99fcfe95e 100644 --- a/source4/torture/auth/pac.c +++ b/source4/torture/auth/pac.c @@ -50,6 +50,9 @@ static BOOL torture_pac_self_check(void) struct auth_serversupplied_info *server_info; struct auth_serversupplied_info *server_info_out; + krb5_principal client_principal; + time_t logon_time = time(NULL); + ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context); if (ret) { @@ -99,13 +102,25 @@ static BOOL torture_pac_self_check(void) talloc_free(mem_ctx); return False; } - + + ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context, + server_info->account_name, &client_principal); + if (ret) { + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &server_keyblock); + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &krbtgt_keyblock); + talloc_free(mem_ctx); + return False; + } + /* OK, go ahead and make a PAC */ ret = kerberos_create_pac(mem_ctx, server_info, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, - time(NULL), + client_principal, + logon_time, &tmp_blob); if (ret) { @@ -117,6 +132,8 @@ static BOOL torture_pac_self_check(void) &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); + krb5_free_principal(smb_krb5_context->krb5_context, + client_principal); talloc_free(mem_ctx); return False; } @@ -128,13 +145,17 @@ static BOOL torture_pac_self_check(void) tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, - &server_keyblock); + &server_keyblock, + client_principal, + logon_time); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); + krb5_free_principal(smb_krb5_context->krb5_context, + client_principal); DEBUG(1, ("PAC decoding failed: %s\n", nt_errstr(nt_status))); @@ -147,13 +168,17 @@ static BOOL torture_pac_self_check(void) tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, - &server_keyblock); + &server_keyblock, + client_principal, + logon_time); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); + krb5_free_principal(smb_krb5_context->krb5_context, + client_principal); printf("PAC decoding (for logon info) failed: %s\n", nt_errstr(nt_status)); @@ -165,6 +190,8 @@ static BOOL torture_pac_self_check(void) &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); + krb5_free_principal(smb_krb5_context->krb5_context, + client_principal); validation.sam3 = &logon_info->info3; nt_status = make_server_info_netlogon_validation(mem_ctx, @@ -249,7 +276,6 @@ static BOOL torture_pac_saved_check(void) struct PAC_LOGON_INFO *logon_info; union netr_Validation validation; const char *pac_file, *pac_kdc_key, *pac_member_key; - struct auth_serversupplied_info *server_info_out; krb5_keyblock server_keyblock; @@ -257,9 +283,13 @@ static BOOL torture_pac_saved_check(void) struct samr_Password *krbtgt_bytes, *krbsrv_bytes; krb5_error_code ret; - struct smb_krb5_context *smb_krb5_context; + const char *principal_string; + krb5_principal client_principal; + const char *authtime_string; + time_t authtime; + ret = smb_krb5_init_context(mem_ctx, &smb_krb5_context); if (ret) { @@ -336,12 +366,40 @@ static BOOL torture_pac_saved_check(void) dump_data(10,tmp_blob.data,tmp_blob.length); + principal_string = lp_parm_string(-1,"torture","pac_client_principal"); + if (!principal_string) { + principal_string = "w2003final$@WIN2K3.THINKER.LOCAL"; + } + + authtime_string = lp_parm_string(-1,"torture","pac_authtime"); + if (!authtime_string) { + authtime = 1120440609; + } else { + authtime = strtoull(authtime_string, NULL, 0); + } + + ret = krb5_parse_name(smb_krb5_context->krb5_context, principal_string, + &client_principal); + if (ret) { + DEBUG(1, ("parsing of client principal [%s] failed: %s\n", + principal_string, + smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); + + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &krbtgt_keyblock); + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &server_keyblock); + talloc_free(mem_ctx); + return False; + } + /* Decode and verify the signaure on the PAC */ nt_status = kerberos_decode_pac(mem_ctx, &pac_data, tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, - &server_keyblock); + &server_keyblock, + client_principal, authtime); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("PAC decoding failed: %s\n", nt_errstr(nt_status))); @@ -350,6 +408,8 @@ static BOOL torture_pac_saved_check(void) &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); + krb5_free_principal(smb_krb5_context->krb5_context, client_principal); + talloc_free(mem_ctx); return False; } @@ -359,13 +419,16 @@ static BOOL torture_pac_saved_check(void) tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, - &server_keyblock); + &server_keyblock, + client_principal, authtime); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); + krb5_free_principal(smb_krb5_context->krb5_context, client_principal); + printf("PAC decoding (for logon info) failed: %s\n", nt_errstr(nt_status)); @@ -383,6 +446,7 @@ static BOOL torture_pac_saved_check(void) &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); + krb5_free_principal(smb_krb5_context->krb5_context, client_principal); printf("PAC decoding (make server info) failed: %s\n", nt_errstr(nt_status)); @@ -398,6 +462,7 @@ static BOOL torture_pac_saved_check(void) &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); + krb5_free_principal(smb_krb5_context->krb5_context, client_principal); printf("PAC Decode resulted in *different* domain SID: %s != %s\n", "S-1-5-21-3048156945-3961193616-3706469200-1005", @@ -418,6 +483,7 @@ static BOOL torture_pac_saved_check(void) &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); + krb5_free_principal(smb_krb5_context->krb5_context, client_principal); DEBUG(0, ("PAC push failed\n")); talloc_free(mem_ctx); @@ -435,6 +501,7 @@ static BOOL torture_pac_saved_check(void) &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); + krb5_free_principal(smb_krb5_context->krb5_context, client_principal); DEBUG(0, ("PAC push failed: original buffer length[%u] != created buffer length[%u]\n", (unsigned)tmp_blob.length, (unsigned)validate_blob.length)); @@ -447,6 +514,7 @@ static BOOL torture_pac_saved_check(void) &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); + krb5_free_principal(smb_krb5_context->krb5_context, client_principal); DEBUG(0, ("PAC push failed: length[%u] matches, but data does not\n", (unsigned)tmp_blob.length)); @@ -454,6 +522,61 @@ static BOOL torture_pac_saved_check(void) return False; } + /* Break the auth time, to ensure we check this vital detail (not setting this caused all the pain in the first place... */ + nt_status = kerberos_decode_pac(mem_ctx, &pac_data, + tmp_blob, + smb_krb5_context->krb5_context, + &krbtgt_keyblock, + &server_keyblock, + client_principal, + authtime + 1); + if (NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("PAC decoding DID NOT fail on broken auth time (time + 1)\n")); + + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &krbtgt_keyblock); + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &server_keyblock); + krb5_free_principal(smb_krb5_context->krb5_context, client_principal); + talloc_free(mem_ctx); + return False; + } + + /* Break the client principal */ + krb5_free_principal(smb_krb5_context->krb5_context, client_principal); + + ret = krb5_parse_name(smb_krb5_context->krb5_context, + "not the right principal", &client_principal); + if (ret) { + DEBUG(1, ("parsing of bogus client principal failed: %s\n", + smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); + + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &krbtgt_keyblock); + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &server_keyblock); + talloc_free(mem_ctx); + return False; + } + + nt_status = kerberos_decode_pac(mem_ctx, &pac_data, + tmp_blob, + smb_krb5_context->krb5_context, + &krbtgt_keyblock, + &server_keyblock, + client_principal, + authtime); + if (NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("PAC decoding DID NOT fail on modified principal\n")); + + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &krbtgt_keyblock); + krb5_free_keyblock_contents(smb_krb5_context->krb5_context, + &server_keyblock); + talloc_free(mem_ctx); + return False; + } + /* Finally... Bugger up the signature, and check we fail the checksum */ tmp_blob.data[tmp_blob.length - 2]++; @@ -461,7 +584,9 @@ static BOOL torture_pac_saved_check(void) tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, - &server_keyblock); + &server_keyblock, + client_principal, + authtime); if (NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("PAC decoding DID NOT fail on broken checksum\n")); |