X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source4%2Fauth%2Fgensec%2Fgensec_krb5.c;h=f17245ccec0d83b95e094aca3d6989a74d54a652;hb=130432987826662c2187e7a88ad9a2d9dda0cd1e;hp=ff26018ae233924b2cbb2cbd05b8ce4e77e3e973;hpb=8ca88042f0f4dae9f0207ec5de3074f26a2ef9cb;p=metze%2Fsamba%2Fwip.git diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c index ff26018ae233..f17245ccec0d 100644 --- a/source4/auth/gensec/gensec_krb5.c +++ b/source4/auth/gensec/gensec_krb5.c @@ -31,10 +31,16 @@ #include "lib/tsocket/tsocket.h" #include "librpc/rpc/dcerpc.h" #include "auth/credentials/credentials.h" +#include "auth/credentials/credentials_krb5.h" +#include "auth/kerberos/kerberos_credentials.h" #include "auth/gensec/gensec.h" #include "auth/gensec/gensec_proto.h" +#include "auth/gensec/gensec_toplevel_proto.h" #include "param/param.h" #include "auth/auth_sam_reply.h" +#include "lib/util/util_net.h" + +_PUBLIC_ NTSTATUS gensec_krb5_init(void); enum GENSEC_KRB5_STATE { GENSEC_KRB5_SERVER_START, @@ -44,8 +50,6 @@ enum GENSEC_KRB5_STATE { }; struct gensec_krb5_state { - DATA_BLOB session_key; - DATA_BLOB pac; enum GENSEC_KRB5_STATE state_position; struct smb_krb5_context *smb_krb5_context; krb5_auth_context auth_context; @@ -90,8 +94,7 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security, bool krb5_error_code ret; struct gensec_krb5_state *gensec_krb5_state; struct cli_credentials *creds; - const struct socket_address *peer_addr; - const struct tsocket_address *tlocal_addr; + const struct tsocket_address *tlocal_addr, *tremote_addr; krb5_address my_krb5_addr, peer_krb5_addr; creds = gensec_get_credentials(gensec_security); @@ -110,14 +113,11 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security, bool 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); gensec_krb5_state->gssapi = gssapi; talloc_set_destructor(gensec_krb5_state, gensec_krb5_destroy); if (cli_credentials_get_krb5_context(creds, - gensec_security->event_ctx, gensec_security->settings->lp_ctx, &gensec_krb5_state->smb_krb5_context)) { talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; @@ -152,6 +152,7 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security, bool (struct sockaddr *) &ss, sizeof(struct sockaddr_storage)); if (socklen < 0) { + talloc_free(gensec_krb5_state); return NT_STATUS_INTERNAL_ERROR; } ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, @@ -165,10 +166,20 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security, bool } } - peer_addr = gensec_get_peer_addr(gensec_security); - if (peer_addr && peer_addr->sockaddr) { - ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, - peer_addr->sockaddr, &peer_krb5_addr); + tremote_addr = gensec_get_remote_address(gensec_security); + if (tremote_addr) { + ssize_t socklen; + struct sockaddr_storage ss; + + socklen = tsocket_address_bsd_sockaddr(tremote_addr, + (struct sockaddr *) &ss, + sizeof(struct sockaddr_storage)); + if (socklen < 0) { + talloc_free(gensec_krb5_state); + return NT_STATUS_INTERNAL_ERROR; + } + ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, + (const struct sockaddr *) &ss, &peer_krb5_addr); if (ret) { DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, @@ -181,7 +192,7 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security, bool ret = krb5_auth_con_setaddrs(gensec_krb5_state->smb_krb5_context->krb5_context, gensec_krb5_state->auth_context, tlocal_addr ? &my_krb5_addr : NULL, - peer_addr ? &peer_krb5_addr : NULL); + tremote_addr ? &peer_krb5_addr : NULL); if (ret) { DEBUG(1,("gensec_krb5_start: krb5_auth_con_setaddrs failed (%s)\n", smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, @@ -221,15 +232,9 @@ static NTSTATUS gensec_fake_gssapi_krb5_server_start(struct gensec_security *gen static NTSTATUS gensec_krb5_common_client_start(struct gensec_security *gensec_security, bool gssapi) { + const char *hostname; struct gensec_krb5_state *gensec_krb5_state; - krb5_error_code ret; NTSTATUS nt_status; - struct ccache_container *ccache_container; - const char *hostname; - - const char *principal; - krb5_data in_data; - hostname = gensec_get_target_hostname(gensec_security); if (!hostname) { DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n")); @@ -264,27 +269,54 @@ static NTSTATUS gensec_krb5_common_client_start(struct gensec_security *gensec_s gensec_krb5_state->ap_req_options |= AP_OPTS_MUTUAL_REQUIRED; } } + return NT_STATUS_OK; +} + +static NTSTATUS gensec_krb5_common_client_creds(struct gensec_security *gensec_security, bool gssapi) +{ + struct gensec_krb5_state *gensec_krb5_state; + krb5_error_code ret; + struct ccache_container *ccache_container; + const char *error_string; + const char *principal; + const char *hostname; + krb5_data in_data; + struct tevent_context *previous_ev; + + gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data; principal = gensec_get_target_principal(gensec_security); + hostname = gensec_get_target_hostname(gensec_security); ret = cli_credentials_get_ccache(gensec_get_credentials(gensec_security), gensec_security->event_ctx, - gensec_security->settings->lp_ctx, &ccache_container); + gensec_security->settings->lp_ctx, &ccache_container, &error_string); switch (ret) { case 0: break; case KRB5KDC_ERR_PREAUTH_FAILED: + case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: return NT_STATUS_LOGON_FAILURE; case KRB5_KDC_UNREACH: - DEBUG(3, ("Cannot reach a KDC we require to contact %s\n", principal)); + DEBUG(3, ("Cannot reach a KDC we require to contact %s: %s\n", principal, error_string)); + return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */ + case KRB5_CC_NOTFOUND: + case KRB5_CC_END: + DEBUG(3, ("Error preparing credentials we require to contact %s : %s\n", principal, error_string)); return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */ default: - DEBUG(1, ("gensec_krb5_start: Aquiring initiator credentials failed: %s\n", error_message(ret))); + DEBUG(1, ("gensec_krb5_start: Aquiring initiator credentials failed: %s\n", error_string)); return NT_STATUS_UNSUCCESSFUL; } in_data.length = 0; - if (principal && lp_client_use_spnego_principal(gensec_security->settings->lp_ctx)) { + /* Do this every time, in case we have weird recursive issues here */ + ret = smb_krb5_context_set_event_ctx(gensec_krb5_state->smb_krb5_context, gensec_security->event_ctx, &previous_ev); + if (ret != 0) { + DEBUG(1, ("gensec_krb5_start: Setting event context failed\n")); + return NT_STATUS_NO_MEMORY; + } + if (principal) { krb5_principal target_principal; ret = krb5_parse_name(gensec_krb5_state->smb_krb5_context->krb5_context, principal, &target_principal); @@ -307,6 +339,9 @@ static NTSTATUS gensec_krb5_common_client_start(struct gensec_security *gensec_s &in_data, ccache_container->ccache, &gensec_krb5_state->enc_ticket); } + + smb_krb5_context_remove_event_ctx(gensec_krb5_state->smb_krb5_context, previous_ev, gensec_security->event_ctx); + switch (ret) { case 0: return NT_STATUS_OK; @@ -399,6 +434,11 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, { DATA_BLOB unwrapped_out; + nt_status = gensec_krb5_common_client_creds(gensec_security, gensec_krb5_state->gssapi); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + if (gensec_krb5_state->gssapi) { unwrapped_out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->enc_ticket.data, gensec_krb5_state->enc_ticket.length); @@ -464,6 +504,8 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, uint8_t tok_id[2]; struct keytab_container *keytab; krb5_principal server_in_keytab; + const char *error_string; + enum credentials_obtained obtained; if (!in.data) { return NT_STATUS_INVALID_PARAMETER; @@ -471,7 +513,6 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, /* Grab the keytab, however generated */ ret = cli_credentials_get_keytab(gensec_get_credentials(gensec_security), - gensec_security->event_ctx, gensec_security->settings->lp_ctx, &keytab); if (ret) { return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; @@ -480,9 +521,10 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, /* This ensures we lookup the correct entry in that keytab */ ret = principal_from_credentials(out_mem_ctx, gensec_get_credentials(gensec_security), gensec_krb5_state->smb_krb5_context, - &server_in_keytab); + &server_in_keytab, &obtained, &error_string); if (ret) { + DEBUG(2,("Failed to make credentials from principal: %s\n", error_string)); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } @@ -527,6 +569,7 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, } static NTSTATUS gensec_krb5_session_key(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, DATA_BLOB *session_key) { struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data; @@ -539,11 +582,6 @@ static NTSTATUS gensec_krb5_session_key(struct gensec_security *gensec_security, return NT_STATUS_NO_USER_SESSION_KEY; } - if (gensec_krb5_state->session_key.data) { - *session_key = gensec_krb5_state->session_key; - return NT_STATUS_OK; - } - switch (gensec_security->gensec_role) { case GENSEC_CLIENT: err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey); @@ -555,9 +593,8 @@ static NTSTATUS gensec_krb5_session_key(struct gensec_security *gensec_security, if (err == 0 && skey != NULL) { DEBUG(10, ("Got KRB5 session key of length %d\n", (int)KRB5_KEY_LENGTH(skey))); - gensec_krb5_state->session_key = data_blob_talloc(gensec_krb5_state, - KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey)); - *session_key = gensec_krb5_state->session_key; + *session_key = data_blob_talloc(mem_ctx, + KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey)); dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length); krb5_free_keyblock(context, skey); @@ -569,12 +606,13 @@ static NTSTATUS gensec_krb5_session_key(struct gensec_security *gensec_security, } static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx_out, struct auth_session_info **_session_info) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data; krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context; - struct auth_serversupplied_info *server_info = NULL; + struct auth_user_info_dc *user_info_dc = NULL; struct auth_session_info *session_info = NULL; struct PAC_LOGON_INFO *logon_info; @@ -586,7 +624,7 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security krb5_error_code ret; - TALLOC_CTX *mem_ctx = talloc_new(gensec_security); + TALLOC_CTX *mem_ctx = talloc_new(mem_ctx_out); if (!mem_ctx) { return NT_STATUS_NO_MEMORY; } @@ -606,6 +644,7 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security DEBUG(1, ("Unable to parse client principal: %s\n", smb_get_krb5_error_message(context, ret, mem_ctx))); + krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return NT_STATUS_NO_MEMORY; } @@ -619,8 +658,9 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security principal_string, smb_get_krb5_error_message(context, ret, mem_ctx))); - krb5_free_principal(context, client_principal); free(principal_string); + krb5_free_principal(context, client_principal); + talloc_free(mem_ctx); return NT_STATUS_ACCESS_DENIED; } else if (ret) { /* NO pac */ @@ -632,34 +672,31 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security DEBUG(1, ("Unable to find PAC for %s, resorting to local user lookup: %s", principal_string, smb_get_krb5_error_message(context, ret, mem_ctx))); - nt_status = gensec_security->auth_context->get_server_info_principal(mem_ctx, + nt_status = gensec_security->auth_context->get_user_info_dc_principal(mem_ctx, gensec_security->auth_context, principal_string, - &server_info); + NULL, &user_info_dc); if (!NT_STATUS_IS_OK(nt_status)) { + free(principal_string); + krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return nt_status; } } else { DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access\n", principal_string)); - return NT_STATUS_ACCESS_DENIED; - } - - krb5_free_principal(context, client_principal); - free(principal_string); - - if (!NT_STATUS_IS_OK(nt_status)) { + free(principal_string); + krb5_free_principal(context, client_principal); talloc_free(mem_ctx); - return nt_status; + return NT_STATUS_ACCESS_DENIED; } } else { /* Found pac */ union netr_Validation validation; - free(principal_string); pac = data_blob_talloc(mem_ctx, pac_data.data, pac_data.length); if (!pac.data) { + free(principal_string); krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return NT_STATUS_NO_MEMORY; @@ -667,48 +704,53 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security /* decode and verify the pac */ nt_status = kerberos_pac_logon_info(gensec_krb5_state, - gensec_security->settings->iconv_convenience, - &logon_info, pac, + pac, gensec_krb5_state->smb_krb5_context->krb5_context, NULL, gensec_krb5_state->keyblock, client_principal, - gensec_krb5_state->ticket->ticket.authtime, NULL); - krb5_free_principal(context, client_principal); + gensec_krb5_state->ticket->ticket.authtime, &logon_info); if (!NT_STATUS_IS_OK(nt_status)) { + free(principal_string); + krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return nt_status; } validation.sam3 = &logon_info->info3; - nt_status = make_server_info_netlogon_validation(mem_ctx, + nt_status = make_user_info_dc_netlogon_validation(mem_ctx, NULL, 3, &validation, - &server_info); + true, /* This user was authenticated */ + &user_info_dc); if (!NT_STATUS_IS_OK(nt_status)) { + free(principal_string); + krb5_free_principal(context, client_principal); talloc_free(mem_ctx); return nt_status; } } - /* references the server_info into the session_info */ - nt_status = auth_generate_session_info(mem_ctx, gensec_security->event_ctx, gensec_security->settings->lp_ctx, server_info, &session_info); + free(principal_string); + krb5_free_principal(context, client_principal); + + /* references the user_info_dc into the session_info */ + nt_status = gensec_generate_session_info(mem_ctx, gensec_security, user_info_dc, &session_info); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); return nt_status; } - nt_status = gensec_krb5_session_key(gensec_security, &session_info->session_key); + nt_status = gensec_krb5_session_key(gensec_security, session_info, &session_info->session_key); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); return nt_status; } - *_session_info = session_info; + *_session_info = talloc_steal(mem_ctx_out, session_info); - talloc_steal(gensec_krb5_state, session_info); talloc_free(mem_ctx); return NT_STATUS_OK; }