diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/winbindd/winbindd_pam.c | 128 | ||||
-rw-r--r-- | source3/winbindd/winbindd_pam_auth_crap.c | 23 | ||||
-rw-r--r-- | source3/winbindd/winbindd_proto.h | 8 |
3 files changed, 153 insertions, 6 deletions
diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index 6ad0baf196..5b6b77b48c 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -38,6 +38,9 @@ #include "passdb/machine_sid.h" #include "auth.h" #include "../lib/tsocket/tsocket.h" +#include "auth/kerberos/pac_utils.h" +#include "auth/gensec/gensec.h" +#include "librpc/crypto/gse_krb5.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND @@ -724,12 +727,12 @@ bool check_request_flags(uint32_t flags) /**************************************************************** ****************************************************************/ -static NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx, - struct winbindd_response *resp, - uint32_t request_flags, - struct netr_SamInfo3 *info3, - const char *name_domain, - const char *name_user) +NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx, + struct winbindd_response *resp, + uint32_t request_flags, + struct netr_SamInfo3 *info3, + const char *name_domain, + const char *name_user) { NTSTATUS result; @@ -2270,3 +2273,116 @@ enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domai return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; } + +#ifdef HAVE_KRB5 +static NTSTATUS extract_pac_vrfy_sigs(TALLOC_CTX *mem_ctx, DATA_BLOB pac_blob, + struct PAC_LOGON_INFO **logon_info) +{ + krb5_context krbctx = NULL; + krb5_error_code k5ret; + krb5_keytab keytab; + krb5_kt_cursor cursor; + krb5_keytab_entry entry; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + + ZERO_STRUCT(entry); + ZERO_STRUCT(cursor); + + k5ret = krb5_init_context(&krbctx); + if (k5ret) { + DEBUG(1, ("Failed to initialize kerberos context: %s\n", + error_message(k5ret))); + status = krb5_to_nt_status(k5ret); + goto out; + } + + k5ret = gse_krb5_get_server_keytab(krbctx, &keytab); + if (k5ret) { + DEBUG(1, ("Failed to get keytab: %s\n", + error_message(k5ret))); + status = krb5_to_nt_status(k5ret); + goto out_free; + } + + k5ret = krb5_kt_start_seq_get(krbctx, keytab, &cursor); + if (k5ret) { + DEBUG(1, ("Failed to start seq: %s\n", + error_message(k5ret))); + status = krb5_to_nt_status(k5ret); + goto out_keytab; + } + + k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor); + while (k5ret == 0) { + status = kerberos_pac_logon_info(mem_ctx, pac_blob, + krbctx, NULL, + KRB5_KT_KEY(&entry), NULL, 0, + logon_info); + if (NT_STATUS_IS_OK(status)) { + break; + } + k5ret = smb_krb5_kt_free_entry(krbctx, &entry); + k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor); + } + + k5ret = krb5_kt_end_seq_get(krbctx, keytab, &cursor); + if (k5ret) { + DEBUG(1, ("Failed to end seq: %s\n", + error_message(k5ret))); + } +out_keytab: + k5ret = krb5_kt_close(krbctx, keytab); + if (k5ret) { + DEBUG(1, ("Failed to close keytab: %s\n", + error_message(k5ret))); + } +out_free: + krb5_free_context(krbctx); +out: + return status; +} + +NTSTATUS winbindd_pam_auth_pac_send(struct winbindd_cli_state *state, + struct netr_SamInfo3 **info3) +{ + struct winbindd_request *req = state->request; + DATA_BLOB pac_blob; + struct PAC_LOGON_INFO *logon_info = NULL; + NTSTATUS result; + + pac_blob = data_blob_const(req->extra_data.data, req->extra_len); + result = extract_pac_vrfy_sigs(state->mem_ctx, pac_blob, &logon_info); + if (!NT_STATUS_IS_OK(result) && + !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) { + DEBUG(1, ("Error during PAC signature verification: %s\n", + nt_errstr(result))); + return result; + } + + if (logon_info) { + /* Signature verification succeeded, trust the PAC */ + netsamlogon_cache_store(NULL, &logon_info->info3); + + } else { + /* Try without signature verification */ + result = kerberos_pac_logon_info(state->mem_ctx, pac_blob, NULL, + NULL, NULL, NULL, 0, + &logon_info); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10, ("Could not extract PAC: %s\n", + nt_errstr(result))); + return result; + } + } + + *info3 = &logon_info->info3; + + return NT_STATUS_OK; +} +#else /* HAVE_KRB5 */ +NTSTATUS winbindd_pam_auth_pac_send(struct winbindd_cli_state *state, + struct netr_SamInfo3 **info3) +{ + return NT_STATUS_NO_SUCH_USER; +} +#endif /* HAVE_KRB5 */ diff --git a/source3/winbindd/winbindd_pam_auth_crap.c b/source3/winbindd/winbindd_pam_auth_crap.c index 2fb5111510..ffbc322fc0 100644 --- a/source3/winbindd/winbindd_pam_auth_crap.c +++ b/source3/winbindd/winbindd_pam_auth_crap.c @@ -22,6 +22,8 @@ struct winbindd_pam_auth_crap_state { struct winbindd_response *response; + struct netr_SamInfo3 *info3; + uint32_t flags; }; static void winbindd_pam_auth_crap_done(struct tevent_req *subreq); @@ -42,6 +44,21 @@ struct tevent_req *winbindd_pam_auth_crap_send( return NULL; } + if (request->flags & WBFLAG_PAM_AUTH_PAC) { + NTSTATUS status; + + state->flags = request->flags; + status = winbindd_pam_auth_pac_send(cli, &state->info3); + if (NT_STATUS_IS_OK(status)) { + /* Defer filling out response to recv */ + tevent_req_done(req); + } else { + tevent_req_nterror(req, status); + } + + return tevent_req_post(req, ev); + } + /* Ensure null termination */ request->data.auth_crap.user[ sizeof(request->data.auth_crap.user)-1] = '\0'; @@ -114,6 +131,12 @@ NTSTATUS winbindd_pam_auth_crap_recv(struct tevent_req *req, set_auth_errors(response, status); return status; } + + if (state->flags & WBFLAG_PAM_AUTH_PAC) { + return append_auth_data(response, response, state->flags, + state->info3, NULL, NULL); + } + *response = *state->response; response->result = WINBINDD_PENDING; state->response = talloc_move(response, &state->response); diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index ec5ec372d1..5cc90f2ab0 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -353,6 +353,12 @@ void ndr_print_winbindd_domain(struct ndr_print *ndr, /* The following definitions come from winbindd/winbindd_pam.c */ bool check_request_flags(uint32_t flags); +NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx, + struct winbindd_response *resp, + uint32_t request_flags, + struct netr_SamInfo3 *info3, + const char *name_domain, + const char *name_user); uid_t get_uid_from_request(struct winbindd_request *request); struct winbindd_domain *find_auth_domain(uint8_t flags, const char *domain_name); @@ -365,6 +371,8 @@ enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain, struct winbindd_cli_state *state) ; enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state); +NTSTATUS winbindd_pam_auth_pac_send(struct winbindd_cli_state *state, + struct netr_SamInfo3 **info3); /* The following definitions come from winbindd/winbindd_util.c */ |