diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
commit | 8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch) | |
tree | 4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source3/winbindd/winbindd_pam_auth_crap.c | |
parent | Initial commit. (diff) | |
download | samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip |
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source3/winbindd/winbindd_pam_auth_crap.c')
-rw-r--r-- | source3/winbindd/winbindd_pam_auth_crap.c | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/source3/winbindd/winbindd_pam_auth_crap.c b/source3/winbindd/winbindd_pam_auth_crap.c new file mode 100644 index 0000000..e6a32c7 --- /dev/null +++ b/source3/winbindd/winbindd_pam_auth_crap.c @@ -0,0 +1,285 @@ +/* + Unix SMB/CIFS implementation. + async implementation of WINBINDD_PAM_AUTH_CRAP + Copyright (C) Volker Lendecke 2010 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd.h" +#include "rpc_client/util_netlogon.h" +#include "libcli/security/dom_sid.h" +#include "lib/util/string_wrappers.h" +#include "lib/global_contexts.h" +#include "librpc/gen_ndr/ndr_winbind_c.h" + +struct winbindd_pam_auth_crap_state { + uint8_t authoritative; + uint32_t flags; + bool pac_is_trusted; + char *domain; + char *user; + struct wbint_PamAuthCrapValidation validation; + NTSTATUS result; +}; + +static void winbindd_pam_auth_crap_done(struct tevent_req *subreq); + +struct tevent_req *winbindd_pam_auth_crap_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct winbindd_cli_state *cli, + struct winbindd_request *request) +{ + struct tevent_req *req, *subreq; + struct winbindd_pam_auth_crap_state *state; + struct winbindd_domain *domain; + const char *auth_domain = NULL; + DATA_BLOB lm_resp = data_blob_null; + DATA_BLOB nt_resp = data_blob_null; + DATA_BLOB chal = data_blob_null; + struct wbint_SidArray *require_membership_of_sid = NULL; + NTSTATUS status; + bool lmlength_ok = false; + bool ntlength_ok = false; + bool pwlength_ok = false; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_pam_auth_crap_state); + if (req == NULL) { + return NULL; + } + state->authoritative = 1; + state->flags = request->flags; + + if (state->flags & WBFLAG_PAM_AUTH_PAC) { + state->result = winbindd_pam_auth_pac_verify(cli, + state, + &state->pac_is_trusted, + &state->validation.level, + &state->validation.validation); + if (tevent_req_nterror(req, state->result)) { + return tevent_req_post(req, ev); + } + + tevent_req_done(req); + return tevent_req_post(req, ev); + } + + /* Ensure null termination */ + request->data.auth_crap.user[ + sizeof(request->data.auth_crap.user)-1] = '\0'; + request->data.auth_crap.domain[ + sizeof(request->data.auth_crap.domain)-1] = '\0'; + request->data.auth_crap.workstation[ + sizeof(request->data.auth_crap.workstation)-1] = '\0'; + + DBG_NOTICE("[%5lu]: pam auth crap domain: [%s] user: [%s] " + "workstation: [%s]\n", + (unsigned long)cli->pid, + request->data.auth_crap.domain, + request->data.auth_crap.user, + request->data.auth_crap.workstation); + + if (!check_request_flags(request->flags)) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); + return tevent_req_post(req, ev); + } + + auth_domain = request->data.auth_crap.domain; + if (auth_domain[0] == '\0') { + auth_domain = lp_workgroup(); + } + + domain = find_auth_domain(request->flags, auth_domain); + if (domain == NULL) { + /* + * We don't know the domain so + * we're not authoritative + */ + state->authoritative = 0; + tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER); + return tevent_req_post(req, ev); + } + + if (request->data.auth_crap.workstation[0] == '\0') { + fstrcpy(request->data.auth_crap.workstation, lp_netbios_name()); + } + + lmlength_ok = (request->data.auth_crap.lm_resp_len <= + sizeof(request->data.auth_crap.lm_resp)); + + ntlength_ok = (request->data.auth_crap.nt_resp_len <= + sizeof(request->data.auth_crap.nt_resp)); + + ntlength_ok |= + ((request->flags & WBFLAG_BIG_NTLMV2_BLOB) && + (request->extra_len == request->data.auth_crap.nt_resp_len)); + + pwlength_ok = lmlength_ok && ntlength_ok; + + if (!pwlength_ok) { + DBG_ERR("Invalid password length %u/%u\n", + request->data.auth_crap.lm_resp_len, + request->data.auth_crap.nt_resp_len); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + state->domain = talloc_strdup(state, request->data.auth_crap.domain); + if (tevent_req_nomem(state->domain, req)) { + return tevent_req_post(req, ev); + } + + state->user = talloc_strdup(state, request->data.auth_crap.user); + if (tevent_req_nomem(state->user, req)) { + return tevent_req_post(req, ev); + } + + status = extra_data_to_sid_array( + request->data.auth_crap.require_membership_of_sid, + state, + &require_membership_of_sid); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + lm_resp = data_blob_talloc(state, + request->data.auth_crap.lm_resp, + request->data.auth_crap.lm_resp_len); + if (tevent_req_nomem(lm_resp.data, req)) { + return tevent_req_post(req, ev); + } + + if (request->flags & WBFLAG_BIG_NTLMV2_BLOB) { + nt_resp = data_blob_talloc(state, + request->extra_data.data, + request->data.auth_crap.nt_resp_len); + } else { + nt_resp = data_blob_talloc(state, + request->data.auth_crap.nt_resp, + request->data.auth_crap.nt_resp_len); + } + if (tevent_req_nomem(nt_resp.data, req)) { + return tevent_req_post(req, ev); + } + + chal = data_blob_talloc(state, + request->data.auth_crap.chal, + 8); + if (tevent_req_nomem(chal.data, req)) { + return tevent_req_post(req, ev); + } + + subreq = dcerpc_wbint_PamAuthCrap_send(state, + global_event_context(), + dom_child_handle(domain), + request->client_name, + request->pid, + request->flags, + request->data.auth_crap.user, + request->data.auth_crap.domain, + request->data.auth_crap.workstation, + lm_resp, + nt_resp, + chal, + request->data.auth_crap.logon_parameters, + require_membership_of_sid, + &state->authoritative, + &state->validation); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, winbindd_pam_auth_crap_done, req); + return req; +} + +static void winbindd_pam_auth_crap_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct winbindd_pam_auth_crap_state *state = tevent_req_data( + req, struct winbindd_pam_auth_crap_state); + NTSTATUS status; + + status = dcerpc_wbint_PamAuthCrap_recv(subreq, state, &state->result); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + tevent_req_done(req); +} + +NTSTATUS winbindd_pam_auth_crap_recv(struct tevent_req *req, + struct winbindd_response *response) +{ + struct winbindd_pam_auth_crap_state *state = tevent_req_data( + req, struct winbindd_pam_auth_crap_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + goto out; + } + + if (NT_STATUS_IS_ERR(state->result)) { + status = state->result; + goto out; + } + + status = append_auth_data(response, + response, + state->flags, + state->validation.level, + state->validation.validation, + state->domain, + state->user); + if (NT_STATUS_IS_ERR(status)) { + goto out; + } + + if (state->flags & WBFLAG_PAM_AUTH_PAC && !state->pac_is_trusted) { + /* + * Clear the flag just in state to do no add the domain + * from auth below. + */ + state->flags &= ~WBFLAG_PAM_INFO3_TEXT; + } + + if (state->flags & WBFLAG_PAM_INFO3_TEXT) { + bool ok; + + ok = add_trusted_domain_from_auth( + response->data.auth.validation_level, + &response->data.auth.info3, + &response->data.auth.info6); + if (!ok) { + status = NT_STATUS_LOGON_FAILURE; + DBG_ERR("add_trusted_domain_from_auth failed\n"); + set_auth_errors(response, status); + response->data.auth.authoritative = + state->authoritative; + return status; + } + } + + status = NT_STATUS_OK; + +out: + set_auth_errors(response, status); + response->data.auth.authoritative = state->authoritative; + response->result = WINBINDD_PENDING; + return NT_STATUS(response->data.auth.nt_status); +} |