1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

s3:winbind: Convert PAM_AUTH_CRAP from struct based to NDR based

Signed-off-by: Samuel Cabrero <scabrero@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
Samuel Cabrero 2022-02-25 11:32:14 +01:00 committed by Jeremy Allison
parent dd69be8020
commit c68f21f26f
5 changed files with 199 additions and 155 deletions

View File

@ -196,6 +196,27 @@ interface winbind
[out,ref] wbint_Validation *validation
);
typedef [public] struct {
uint16 level;
[switch_is(level)] netr_Validation *validation;
} wbint_PamAuthCrapValidation;
NTSTATUS wbint_PamAuthCrap(
[in,string,charset(UTF8)] char *client_name,
[in] hyper client_pid,
[in] uint32 flags,
[in, string,charset(UTF8)] char *user,
[in, string,charset(UTF8)] char *domain,
[in, string,charset(UTF8)] char *workstation,
[in] DATA_BLOB lm_resp,
[in] DATA_BLOB nt_resp,
[in] DATA_BLOB chal,
[in] uint32 logon_parameters,
[in] wbint_SidArray *require_membership_of_sid,
[out,ref] uint8 *authoritative,
[out,ref] wbint_PamAuthCrapValidation *validation
);
/* Public methods available via IRPC */
typedef [switch_type(uint16)] union netr_LogonLevel netr_LogonLevel;

View File

@ -30,10 +30,6 @@ static const struct winbindd_child_dispatch_table domain_dispatch_table[] = {
.name = "INIT_CONNECTION",
.struct_cmd = WINBINDD_INIT_CONNECTION,
.struct_fn = winbindd_dual_init_connection,
},{
.name = "AUTH_CRAP",
.struct_cmd = WINBINDD_PAM_AUTH_CRAP,
.struct_fn = winbindd_dual_pam_auth_crap,
},{
.name = "PAM_LOGOFF",
.struct_cmd = WINBINDD_PAM_LOGOFF,

View File

@ -2115,7 +2115,7 @@ done:
* @brief build a tsocket_address for the remote address of the supplied socket
*
*/
static struct tsocket_address *get_remote_address(TALLOC_CTX *mem_ctx, int sock)
_UNUSED_ static struct tsocket_address *get_remote_address(TALLOC_CTX *mem_ctx, int sock)
{
struct sockaddr_storage st = {0};
struct sockaddr *sar = (struct sockaddr *)&st;
@ -2141,7 +2141,7 @@ static struct tsocket_address *get_remote_address(TALLOC_CTX *mem_ctx, int sock)
* @brief build a tsocket_address for the local address of the supplied socket
*
*/
static struct tsocket_address *get_local_address(TALLOC_CTX *mem_ctx, int sock)
_UNUSED_ static struct tsocket_address *get_local_address(TALLOC_CTX *mem_ctx, int sock)
{
struct sockaddr_storage st = {0};
struct sockaddr *sar = (struct sockaddr *)&st;
@ -2836,71 +2836,52 @@ done:
return NT_STATUS_OK;
}
enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
struct winbindd_cli_state *state)
NTSTATUS _wbint_PamAuthCrap(struct pipes_struct *p, struct wbint_PamAuthCrap *r)
{
struct winbindd_domain *domain = wb_child_domain();
NTSTATUS result;
const char *name_user = NULL;
const char *name_domain = NULL;
const char *workstation;
uint64_t logon_id = 0;
uint8_t authoritative = 1;
uint32_t flags = 0;
uint16_t validation_level = UINT16_MAX;
union netr_Validation *validation = NULL;
DATA_BLOB lm_resp = { 0 }, nt_resp = { 0 };
DATA_BLOB chal = data_blob_null;
const struct timeval start_time = timeval_current();
const struct tsocket_address *remote = NULL;
const struct tsocket_address *local = NULL;
struct netr_SamInfo3 *info3 = NULL;
struct wbint_SidArray *sid_array = NULL;
pid_t client_pid;
/* This is child-only, so no check for privileged access is needed
anymore */
/* Ensure null termination */
state->request->data.auth_crap.user[sizeof(state->request->data.auth_crap.user)-1]=0;
state->request->data.auth_crap.domain[sizeof(state->request->data.auth_crap.domain)-1]=0;
name_user = state->request->data.auth_crap.user;
name_domain = state->request->data.auth_crap.domain;
workstation = state->request->data.auth_crap.workstation;
logon_id = generate_random_u64();
remote = get_remote_address(state->mem_ctx, state->sock);
local = get_local_address(state->mem_ctx, state->sock);
DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
name_domain, name_user));
lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp,
state->request->data.auth_crap.lm_resp_len);
if (state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) {
nt_resp = data_blob_talloc(state->mem_ctx,
state->request->extra_data.data,
state->request->data.auth_crap.nt_resp_len);
} else {
nt_resp = data_blob_talloc(state->mem_ctx,
state->request->data.auth_crap.nt_resp,
state->request->data.auth_crap.nt_resp_len);
if (domain == NULL) {
return NT_STATUS_REQUEST_NOT_ACCEPTED;
}
chal = data_blob_const(state->request->data.auth_crap.chal, 8);
/* Cut client_pid to 32bit */
client_pid = r->in.client_pid;
if ((uint64_t)client_pid != r->in.client_pid) {
DBG_DEBUG("pid out of range\n");
return NT_STATUS_INVALID_PARAMETER;
}
logon_id = generate_random_u64();
remote = dcesrv_connection_get_remote_address(p->dce_call->conn);
local = dcesrv_connection_get_local_address(p->dce_call->conn);
DBG_NOTICE("[%"PRIu32"]: pam auth crap domain: %s user: %s\n",
client_pid, r->in.domain, r->in.user);
result = winbind_dual_SamLogon(domain,
state->mem_ctx,
p->mem_ctx,
false, /* interactive */
state->request->data.auth_crap.logon_parameters,
name_user,
name_domain,
/* Bug #3248 - found by Stefan Burkei. */
workstation, /* We carefully set this above so use it... */
r->in.logon_parameters,
r->in.user,
r->in.domain,
r->in.workstation,
logon_id,
state->request->client_name,
state->request->pid,
chal,
lm_resp,
nt_resp,
r->in.client_name,
client_pid,
r->in.chal,
r->in.lm_resp,
r->in.nt_resp,
remote,
local,
&authoritative,
@ -2912,7 +2893,7 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
goto done;
}
result = map_validation_to_info3(state->mem_ctx,
result = map_validation_to_info3(p->mem_ctx,
validation_level,
validation,
&info3);
@ -2920,32 +2901,19 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
goto done;
}
result = extra_data_to_sid_array(
state->request->data.auth_crap.require_membership_of_sid,
state->mem_ctx,
&sid_array);
if (!NT_STATUS_IS_OK(result)) {
DBG_ERR("Failed to parse '%s' into a sid array: %s\n",
state->request->data.auth_crap.require_membership_of_sid,
nt_errstr(result));
goto done;
}
/* Check if the user is in the right group */
result = check_info3_in_group(info3, sid_array);
result = check_info3_in_group(info3, r->in.require_membership_of_sid);
if (!NT_STATUS_IS_OK(result)) {
char *s = NDR_PRINT_STRUCT_STRING(state->mem_ctx,
char *s = NDR_PRINT_STRUCT_STRING(p->mem_ctx,
wbint_SidArray,
sid_array);
r->in.require_membership_of_sid);
DBG_NOTICE("User %s is not in the required groups:\n",
state->request->data.auth_crap.user);
r->in.user);
DEBUGADD(DBGLVL_NOTICE, ("%s", s));
DEBUGADD(DBGLVL_NOTICE,
("CRAP authentication is rejected\n"));
TALLOC_FREE(sid_array);
goto done;
}
TALLOC_FREE(sid_array);
if (!is_allowed_domain(info3->base.logon_domain.string)) {
DBG_NOTICE("Authentication failed for user [%s] "
@ -2956,45 +2924,48 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
goto done;
}
result = append_auth_data(state->mem_ctx, state->response,
state->request->flags,
validation_level,
validation,
name_domain, name_user);
r->out.validation = talloc_zero(p->mem_ctx,
struct wbint_PamAuthCrapValidation);
if (r->out.validation == NULL) {
result = NT_STATUS_NO_MEMORY;
goto done;
}
r->out.validation->level = validation_level;
r->out.validation->validation = talloc_move(r->out.validation,
&validation);
done:
if (state->request->flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
if (r->in.flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
result = nt_status_squash(result);
}
set_auth_errors(state->response, result);
state->response->data.auth.authoritative = authoritative;
*r->out.authoritative = authoritative;
/*
* Log the winbind pam authentication, the logon_id will tie this to
* any of the logons invoked from this request.
*/
log_authentication(
state->mem_ctx,
p->mem_ctx,
domain,
state->request->client_name,
state->pid,
validation_level,
validation,
r->in.client_name,
client_pid,
r->out.validation->level,
r->out.validation->validation,
start_time,
logon_id,
"NTLM_AUTH",
name_user,
name_domain,
workstation,
lm_resp,
nt_resp,
r->in.user,
r->in.domain,
r->in.workstation,
r->in.lm_resp,
r->in.nt_resp,
remote,
local,
result);
return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
return result;
}
enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,

View File

@ -23,14 +23,16 @@
#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 {
struct winbindd_response *response;
uint8_t authoritative;
uint32_t flags;
bool pac_is_trusted;
uint16_t validation_level;
union netr_Validation *validation;
char *domain;
char *user;
struct wbint_PamAuthCrapValidation validation;
NTSTATUS result;
};
static void winbindd_pam_auth_crap_done(struct tevent_req *subreq);
@ -45,6 +47,11 @@ struct tevent_req *winbindd_pam_auth_crap_send(
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;
req = tevent_req_create(mem_ctx, &state,
struct winbindd_pam_auth_crap_state);
@ -55,14 +62,12 @@ struct tevent_req *winbindd_pam_auth_crap_send(
state->flags = request->flags;
if (state->flags & WBFLAG_PAM_AUTH_PAC) {
NTSTATUS status;
status = winbindd_pam_auth_pac_verify(cli,
state,
&state->pac_is_trusted,
&state->validation_level,
&state->validation);
if (tevent_req_nterror(req, status)) {
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);
}
@ -78,10 +83,12 @@ struct tevent_req *winbindd_pam_auth_crap_send(
request->data.auth_crap.workstation[
sizeof(request->data.auth_crap.workstation)-1] = '\0';
DEBUG(3, ("[%5lu]: pam auth crap domain: [%s] user: %s\n",
(unsigned long)cli->pid,
request->data.auth_crap.domain,
request->data.auth_crap.user));
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);
@ -120,8 +127,67 @@ struct tevent_req *winbindd_pam_auth_crap_send(
}
}
subreq = wb_domain_request_send(state, global_event_context(), domain,
request);
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);
}
@ -135,12 +201,11 @@ static void winbindd_pam_auth_crap_done(struct tevent_req *subreq)
subreq, struct tevent_req);
struct winbindd_pam_auth_crap_state *state = tevent_req_data(
req, struct winbindd_pam_auth_crap_state);
int res, err;
NTSTATUS status;
res = wb_domain_request_recv(subreq, state, &state->response, &err);
status = dcerpc_wbint_PamAuthCrap_recv(subreq, state, &state->result);
TALLOC_FREE(subreq);
if (res == -1) {
tevent_req_nterror(req, map_nt_error_from_unix(err));
if (tevent_req_nterror(req, status)) {
return;
}
@ -155,52 +220,40 @@ NTSTATUS winbindd_pam_auth_crap_recv(struct tevent_req *req,
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
set_auth_errors(response, status);
response->data.auth.authoritative = state->authoritative;
return status;
goto out;
}
if (state->flags & WBFLAG_PAM_AUTH_PAC) {
state->response = talloc_zero(state,
struct winbindd_response);
if (state->response == NULL) {
status = NT_STATUS_NO_MEMORY;
set_auth_errors(response, status);
response->data.auth.authoritative = state->authoritative;
return status;
}
state->response->result = WINBINDD_PENDING;
state->response->length = sizeof(struct winbindd_response);
status = append_auth_data(state->response,
state->response,
state->flags,
state->validation_level,
state->validation,
NULL, NULL);
if (NT_STATUS_IS_ERR(status)) {
set_auth_errors(response, status);
response->data.auth.authoritative = state->authoritative;
return status;
}
if (!state->pac_is_trusted) {
/*
* Clear the flag in state to do no add the domain
* from auth below.
*/
state->flags &= ~WBFLAG_PAM_INFO3_TEXT;
}
if (NT_STATUS_IS_ERR(state->result)) {
status = state->result;
goto out;
}
if (NT_STATUS_IS_OK(NT_STATUS(state->response->data.auth.nt_status)) &&
(state->flags & WBFLAG_PAM_INFO3_TEXT)) {
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(
state->response->data.auth.validation_level,
&state->response->data.auth.info3,
&state->response->data.auth.info6);
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");
@ -211,8 +264,11 @@ NTSTATUS winbindd_pam_auth_crap_recv(struct tevent_req *req,
}
}
*response = *state->response;
status = NT_STATUS_OK;
out:
set_auth_errors(response, status);
response->data.auth.authoritative = state->authoritative;
response->result = WINBINDD_PENDING;
state->response = talloc_move(response, &state->response);
return NT_STATUS(response->data.auth.nt_status);
}

View File

@ -441,8 +441,8 @@ struct pipes_struct;
struct wbint_PamAuth;
NTSTATUS _wbint_PamAuth(struct pipes_struct *p,
struct wbint_PamAuth *r);
enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
struct winbindd_cli_state *state) ;
NTSTATUS _wbint_PamAuthCrap(struct pipes_struct *p,
struct wbint_PamAuthCrap *r);
enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
struct winbindd_cli_state *state);
enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,