From 597d2a7a29f768f51cbcbc13de56a4dc349e20e4 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 27 Mar 2014 12:58:05 +1300 Subject: [PATCH] auth: Provide a way to use the auth stack for winbindd authentication This adds in flags that allow winbindd to request authentication without directly calling into the auth_sam module. That in turn will allow winbindd to call auth_samba4 and so permit winbindd operation in the AD DC. Andrew Bartlett Change-Id: I27d11075eb8e1a54f034ee2fdcb05360b4203567 Signed-off-by: Andrew Bartlett Reviewed-by: Andreas Schneider --- auth/common_auth.h | 6 +++++- source3/auth/auth.c | 10 ++++++++- source3/auth/auth_sam.c | 2 +- source3/auth/auth_samba4.c | 26 ++++++++++++++++-------- source3/include/auth.h | 5 ++++- source3/winbindd/winbindd_pam.c | 45 ++++++++++++++++++++++++++++++++++++++--- source4/auth/auth.h | 1 + source4/auth/ntlm/auth.c | 5 +++++ source4/auth/ntlm/auth_sam.c | 6 ++++-- 9 files changed, 89 insertions(+), 17 deletions(-) diff --git a/auth/common_auth.h b/auth/common_auth.h index a40f7c2b3d7..d9bde018bf3 100644 --- a/auth/common_auth.h +++ b/auth/common_auth.h @@ -25,7 +25,9 @@ #define USER_INFO_CASE_INSENSITIVE_USERNAME 0x01 /* username may be in any case */ #define USER_INFO_CASE_INSENSITIVE_PASSWORD 0x02 /* password may be in any case */ #define USER_INFO_DONT_CHECK_UNIX_ACCOUNT 0x04 /* don't check unix account status */ -#define USER_INFO_INTERACTIVE_LOGON 0x08 /* don't check unix account status */ +#define USER_INFO_INTERACTIVE_LOGON 0x08 /* Interactive logon */ +#define USER_INFO_LOCAL_SAM_ONLY 0x10 /* Only authenticate against the local SAM */ +#define USER_INFO_INFO3_AND_NO_AUTHZ 0x20 /* Only fill in server_info->info3 and do not do any authorization steps */ enum auth_password_state { AUTH_PASSWORD_PLAIN = 1, @@ -77,6 +79,8 @@ struct loadparm_context; struct ldb_context; struct smb_krb5_context; +#define AUTH_METHOD_LOCAL_SAM 0x01 + struct auth4_context { struct { /* Who set this up in the first place? */ diff --git a/source3/auth/auth.c b/source3/auth/auth.c index 7718142fc11..6d1192ededd 100644 --- a/source3/auth/auth.c +++ b/source3/auth/auth.c @@ -210,6 +210,11 @@ NTSTATUS auth_check_ntlm_password(TALLOC_CTX *mem_ctx, TALLOC_CTX *tmp_ctx; NTSTATUS result; + if (user_info->flags & USER_INFO_LOCAL_SAM_ONLY + && !(auth_method->flags & AUTH_METHOD_LOCAL_SAM)) { + continue; + } + tmp_ctx = talloc_named(mem_ctx, 0, "%s authentication for user %s\\%s", @@ -253,7 +258,10 @@ NTSTATUS auth_check_ntlm_password(TALLOC_CTX *mem_ctx, if (NT_STATUS_IS_OK(nt_status)) { unix_username = (*pserver_info)->unix_name; - if (!(*pserver_info)->guest) { + + /* We skip doing this step if the caller asked us not to */ + if (!(user_info->flags & USER_INFO_INFO3_AND_NO_AUTHZ) + && !(*pserver_info)->guest) { const char *rhost; if (tsocket_address_is_inet(user_info->remote_host, "ip")) { diff --git a/source3/auth/auth_sam.c b/source3/auth/auth_sam.c index a34f9a58521..c4100d5a4e1 100644 --- a/source3/auth/auth_sam.c +++ b/source3/auth/auth_sam.c @@ -121,7 +121,7 @@ static NTSTATUS auth_init_sam(struct auth_context *auth_context, const char *par } result->auth = auth_samstrict_auth; result->name = "sam"; - + result->flags = AUTH_METHOD_LOCAL_SAM; *auth_method = result; return NT_STATUS_OK; } diff --git a/source3/auth/auth_samba4.c b/source3/auth/auth_samba4.c index d9d71512a2b..284a91f30b1 100644 --- a/source3/auth/auth_samba4.c +++ b/source3/auth/auth_samba4.c @@ -145,14 +145,23 @@ static NTSTATUS check_samba4_security(const struct auth_context *auth_context, goto done; } - nt_status = make_server_info_info3(mem_ctx, user_info->client.account_name, - user_info->mapped.domain_name, server_info, - info3); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(10, ("make_server_info_info3 failed: %s\n", - nt_errstr(nt_status))); - TALLOC_FREE(frame); - return nt_status; + if (user_info->flags & USER_INFO_INFO3_AND_NO_AUTHZ) { + *server_info = make_server_info(mem_ctx); + if (*server_info == NULL) { + nt_status = NT_STATUS_NO_MEMORY; + goto done; + } + (*server_info)->info3 = talloc_steal(*server_info, info3); + + } else { + nt_status = make_server_info_info3(mem_ctx, user_info->client.account_name, + user_info->mapped.domain_name, server_info, + info3); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(10, ("make_server_info_info3 failed: %s\n", + nt_errstr(nt_status))); + goto done; + } } nt_status = NT_STATUS_OK; @@ -356,6 +365,7 @@ static NTSTATUS auth_init_samba4(struct auth_context *auth_context, result->auth = check_samba4_security; result->prepare_gensec = prepare_gensec; result->make_auth4_context = make_auth4_context_s4; + result->flags = AUTH_METHOD_LOCAL_SAM; if (param && *param) { auth_context->forced_samba4_methods = talloc_strdup(result, param); diff --git a/source3/include/auth.h b/source3/include/auth.h index acae5a83c6c..d35936b243c 100644 --- a/source3/include/auth.h +++ b/source3/include/auth.h @@ -107,6 +107,8 @@ typedef struct auth_methods /* Used to keep tabs on things like the cli for SMB server authentication */ void *private_data; + uint32_t flags; + } auth_methods; typedef NTSTATUS (*auth_init_function)(struct auth_context *, const char *, struct auth_methods **); @@ -130,7 +132,8 @@ enum session_key_use_intent { /* Changed from 1 -> 2 to add the logon_parameters field. */ /* Changed from 2 -> 3 when we reworked many auth structures to use IDL or be in common with Samba4 */ -#define AUTH_INTERFACE_VERSION 3 +/* Changed from 3 -> 4 when we reworked added the flags */ +#define AUTH_INTERFACE_VERSION 4 #include "auth/proto.h" diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index 65f27dfcadb..c432afac1a2 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -1212,13 +1212,16 @@ static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx, const DATA_BLOB *nt_resp, struct netr_SamInfo3 **pinfo3) { + struct auth_context *auth_context; + struct auth_serversupplied_info *server_info; struct auth_usersupplied_info *user_info = NULL; struct tsocket_address *local; + struct netr_SamInfo3 *info3; NTSTATUS status; int rc; TALLOC_CTX *frame = talloc_stackframe(); - rc = tsocket_address_inet_from_strings(mem_ctx, + rc = tsocket_address_inet_from_strings(frame, "ip", "127.0.0.1", 0, @@ -1235,13 +1238,49 @@ static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx, TALLOC_FREE(frame); return status; } + user_info->logon_parameters = logon_parameters; /* We don't want any more mapping of the username */ user_info->mapped_state = True; - status = check_sam_security_info3(challenge, mem_ctx, user_info, - pinfo3); + /* We don't want to come back to winbindd or to do PAM account checks */ + user_info->flags |= USER_INFO_LOCAL_SAM_ONLY | USER_INFO_INFO3_AND_NO_AUTHZ; + + status = make_auth_context_fixed(frame, &auth_context, challenge->data); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Failed to test authentication with check_sam_security_info3: %s\n", nt_errstr(status))); + TALLOC_FREE(frame); + return status; + } + + status = auth_check_ntlm_password(mem_ctx, + auth_context, + user_info, + &server_info); + + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return status; + } + + info3 = talloc_zero(mem_ctx, struct netr_SamInfo3); + if (info3 == NULL) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + + status = serverinfo_to_SamInfo3(server_info, info3); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + TALLOC_FREE(info3); + DEBUG(0, ("serverinfo_to_SamInfo3 failed: %s\n", + nt_errstr(status))); + return status; + } + + *pinfo3 = info3; DEBUG(10, ("Authenticaticating user %s\\%s returned %s\n", domain, user, nt_errstr(status))); TALLOC_FREE(frame); diff --git a/source4/auth/auth.h b/source4/auth/auth.h index 0b6b1d35831..c472d86d1ed 100644 --- a/source4/auth/auth.h +++ b/source4/auth/auth.h @@ -72,6 +72,7 @@ struct auth_operations { const char *principal, struct ldb_dn *user_dn, struct auth_user_info_dc **interim_info); + uint32_t flags; }; struct auth_method_context { diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c index 642d8684e59..6d5747eb783 100644 --- a/source4/auth/ntlm/auth.c +++ b/source4/auth/ntlm/auth.c @@ -342,6 +342,11 @@ static void auth_check_password_async_trigger(struct tevent_context *ev, for (method=state->auth_ctx->methods; method; method = method->next) { + if (state->user_info->flags & USER_INFO_LOCAL_SAM_ONLY + && !(method->ops->flags & AUTH_METHOD_LOCAL_SAM)) { + continue; + } + /* we fill in state->method here so debug messages in the callers know which method failed */ state->method = method; diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c index 6b184f8d32e..6e2dd440f7b 100644 --- a/source4/auth/ntlm/auth_sam.c +++ b/source4/auth/ntlm/auth_sam.c @@ -677,14 +677,16 @@ static const struct auth_operations sam_ignoredomain_ops = { .name = "sam_ignoredomain", .want_check = authsam_ignoredomain_want_check, .check_password = authsam_check_password_internals, - .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper + .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, + .flags = AUTH_METHOD_LOCAL_SAM }; static const struct auth_operations sam_ops = { .name = "sam", .want_check = authsam_want_check, .check_password = authsam_check_password_internals, - .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper + .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper, + .flags = AUTH_METHOD_LOCAL_SAM }; _PUBLIC_ NTSTATUS auth4_sam_init(void); -- 2.11.4.GIT