diff options
Diffstat (limited to 'source4/auth/gensec')
-rw-r--r-- | source4/auth/gensec/gensec_gssapi.c | 114 | ||||
-rw-r--r-- | source4/auth/gensec/gensec_krb5.c | 134 |
2 files changed, 153 insertions, 95 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); |