mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
CVE-2020-25717: s3:auth: let auth3_generate_session_info_pac() delegate everything to make_server_info_wbcAuthUserInfo()
This consolidates the code paths used for NTLMSSP and Kerberos! I checked what we were already doing for NTLMSSP, which is this: a) source3/auth/auth_winbind.c calls wbcAuthenticateUserEx() b) as a domain member we require a valid response from winbindd, otherwise we'll return NT_STATUS_NO_LOGON_SERVERS c) we call make_server_info_wbcAuthUserInfo(), which internally calls make_server_info_info3() d) auth_check_ntlm_password() calls smb_pam_accountcheck(unix_username, rhost), where rhost is only an ipv4 or ipv6 address (without reverse dns lookup) e) from auth3_check_password_send/auth3_check_password_recv() server_returned_info will be passed to auth3_generate_session_info(), triggered by gensec_session_info(), which means we'll call into create_local_token() in order to transform auth_serversupplied_info into auth_session_info. For Kerberos gensec_session_info() will call auth3_generate_session_info_pac() via the gensec_generate_session_info_pac() helper function. The current logic is this: a) gensec_generate_session_info_pac() is the function that evaluates the 'gensec:require_pac', which defaulted to 'no' before. b) auth3_generate_session_info_pac() called wbcAuthenticateUserEx() in order to pass the PAC blob to winbindd, but only to prime its cache, e.g. netsamlogon cache and others. Most failures were just ignored. c) If the PAC blob is available, it extracted the PAC_LOGON_INFO from it. d) Then we called the horrible get_user_from_kerberos_info() function: - It uses a first part of the tickets principal name (before the @) as username and combines that with the 'logon_info->base.logon_domain' if the logon_info (PAC) is present. - As a fallback without a PAC it's tries to ask winbindd for a mapping from realm to netbios domain name. - Finally is falls back to using the realm as netbios domain name With this information is builds 'userdomain+winbind_separator+useraccount' and calls map_username() followed by smb_getpwnam() with create=true, Note this is similar to the make_server_info_info3() => check_account() => smb_getpwnam() logic under 3. - It also calls smb_pam_accountcheck(), but may pass the reverse DNS lookup name instead of the ip address as rhost. - It does some MAP_TO_GUEST_ON_BAD_UID logic and auto creates the guest account. e) We called create_info3_from_pac_logon_info() f) make_session_info_krb5() calls gets called and triggers this: - If get_user_from_kerberos_info() mapped to guest, it calls make_server_info_guest() - If create_info3_from_pac_logon_info() created a info3 from logon_info, it calls make_server_info_info3() - Without a PAC it tries pdb_getsampwnam()/make_server_info_sam() with a fallback to make_server_info_pw() From there it calls create_local_token() I tried to change auth3_generate_session_info_pac() to behave similar to auth_winbind.c together with auth3_generate_session_info() as a domain member, as we now rely on a PAC: a) As domain member we require a PAC and always call wbcAuthenticateUserEx() and require a valid response! b) we call make_server_info_wbcAuthUserInfo(), which internally calls make_server_info_info3(). Note make_server_info_info3() handles MAP_TO_GUEST_ON_BAD_UID and make_server_info_guest() internally. c) Similar to auth_check_ntlm_password() we now call smb_pam_accountcheck(unix_username, rhost), where rhost is only an ipv4 or ipv6 address (without reverse dns lookup) d) From there it calls create_local_token() As standalone server (in an MIT realm) we continue with the already existing code logic, which works without a PAC: a) we keep smb_getpwnam() with create=true logic as it also requires an explicit 'add user script' option. b) In the following commits we assert that there's actually no PAC in this mode, which means we can remove unused and confusing code. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14646 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
parent
c4ddf939e0
commit
566c2b296d
@ -46,6 +46,7 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx,
|
||||
uint32_t session_info_flags,
|
||||
struct auth_session_info **session_info)
|
||||
{
|
||||
enum server_role server_role = lp_server_role();
|
||||
TALLOC_CTX *tmp_ctx;
|
||||
struct PAC_LOGON_INFO *logon_info = NULL;
|
||||
struct netr_SamInfo3 *info3_copy = NULL;
|
||||
@ -54,39 +55,59 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx,
|
||||
char *ntuser;
|
||||
char *ntdomain;
|
||||
char *username;
|
||||
char *rhost;
|
||||
const char *rhost;
|
||||
struct passwd *pw;
|
||||
NTSTATUS status;
|
||||
int rc;
|
||||
|
||||
tmp_ctx = talloc_new(mem_ctx);
|
||||
if (!tmp_ctx) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (pac_blob) {
|
||||
#ifdef HAVE_KRB5
|
||||
if (tsocket_address_is_inet(remote_address, "ip")) {
|
||||
rhost = tsocket_address_inet_addr_string(
|
||||
remote_address, tmp_ctx);
|
||||
if (rhost == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
rhost = "127.0.0.1";
|
||||
}
|
||||
|
||||
if (server_role != ROLE_STANDALONE) {
|
||||
struct wbcAuthUserParams params = { 0 };
|
||||
struct wbcAuthUserInfo *info = NULL;
|
||||
struct wbcAuthErrorInfo *err = NULL;
|
||||
struct auth_serversupplied_info *server_info = NULL;
|
||||
char *original_user_name = NULL;
|
||||
char *p = NULL;
|
||||
wbcErr wbc_err;
|
||||
|
||||
if (pac_blob == NULL) {
|
||||
/*
|
||||
* This should already be catched at the main
|
||||
* gensec layer, but better check twice
|
||||
*/
|
||||
status = NT_STATUS_INTERNAL_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Let winbind decode the PAC.
|
||||
* This will also store the user
|
||||
* data in the netsamlogon cache.
|
||||
*
|
||||
* We need to do this *before* we
|
||||
* call get_user_from_kerberos_info()
|
||||
* as that does a user lookup that
|
||||
* expects info in the netsamlogon cache.
|
||||
*
|
||||
* See BUG: https://bugzilla.samba.org/show_bug.cgi?id=11259
|
||||
* This used to be a cache prime
|
||||
* optimization, but now we delegate
|
||||
* all logic to winbindd, as we require
|
||||
* winbindd as domain member anyway.
|
||||
*/
|
||||
params.level = WBC_AUTH_USER_LEVEL_PAC;
|
||||
params.password.pac.data = pac_blob->data;
|
||||
params.password.pac.length = pac_blob->length;
|
||||
|
||||
/* we are contacting the privileged pipe */
|
||||
become_root();
|
||||
wbc_err = wbcAuthenticateUserEx(¶ms, &info, &err);
|
||||
unbecome_root();
|
||||
@ -99,18 +120,90 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx,
|
||||
*/
|
||||
|
||||
switch (wbc_err) {
|
||||
case WBC_ERR_WINBIND_NOT_AVAILABLE:
|
||||
case WBC_ERR_SUCCESS:
|
||||
break;
|
||||
case WBC_ERR_WINBIND_NOT_AVAILABLE:
|
||||
status = NT_STATUS_NO_LOGON_SERVERS;
|
||||
DBG_ERR("winbindd not running - "
|
||||
"but required as domain member: %s\n",
|
||||
nt_errstr(status));
|
||||
goto done;
|
||||
case WBC_ERR_AUTH_ERROR:
|
||||
status = NT_STATUS(err->nt_status);
|
||||
wbcFreeMemory(err);
|
||||
goto done;
|
||||
case WBC_ERR_NO_MEMORY:
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
default:
|
||||
status = NT_STATUS_LOGON_FAILURE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = make_server_info_wbcAuthUserInfo(tmp_ctx,
|
||||
info->account_name,
|
||||
info->domain_name,
|
||||
info, &server_info);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(10, ("make_server_info_wbcAuthUserInfo failed: %s\n",
|
||||
nt_errstr(status)));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* We skip doing this step if the caller asked us not to */
|
||||
if (!(server_info->guest)) {
|
||||
const char *unix_username = server_info->unix_name;
|
||||
|
||||
/* We might not be root if we are an RPC call */
|
||||
become_root();
|
||||
status = smb_pam_accountcheck(unix_username, rhost);
|
||||
unbecome_root();
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(3, ("check_ntlm_password: PAM Account for user [%s] "
|
||||
"FAILED with error %s\n",
|
||||
unix_username, nt_errstr(status)));
|
||||
goto done;
|
||||
}
|
||||
|
||||
DEBUG(5, ("check_ntlm_password: PAM Account for user [%s] "
|
||||
"succeeded\n", unix_username));
|
||||
}
|
||||
|
||||
DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
|
||||
|
||||
p = strchr_m(princ_name, '@');
|
||||
if (!p) {
|
||||
DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
|
||||
princ_name));
|
||||
status = NT_STATUS_LOGON_FAILURE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
original_user_name = talloc_strndup(tmp_ctx, princ_name, p - princ_name);
|
||||
if (original_user_name == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = create_local_token(mem_ctx,
|
||||
server_info,
|
||||
NULL,
|
||||
original_user_name,
|
||||
session_info);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(10, ("create_local_token failed: %s\n",
|
||||
nt_errstr(status)));
|
||||
goto done;
|
||||
}
|
||||
|
||||
goto session_info_ready;
|
||||
}
|
||||
|
||||
/* This is the standalone legacy code path */
|
||||
|
||||
if (pac_blob != NULL) {
|
||||
#ifdef HAVE_KRB5
|
||||
status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL,
|
||||
NULL, NULL, 0, &logon_info);
|
||||
#else
|
||||
@ -121,22 +214,6 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
rc = get_remote_hostname(remote_address,
|
||||
&rhost,
|
||||
tmp_ctx);
|
||||
if (rc < 0) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
if (strequal(rhost, "UNKNOWN")) {
|
||||
rhost = tsocket_address_inet_addr_string(remote_address,
|
||||
tmp_ctx);
|
||||
if (rhost == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
status = get_user_from_kerberos_info(tmp_ctx, rhost,
|
||||
princ_name, logon_info,
|
||||
&is_mapped, &is_guest,
|
||||
@ -170,6 +247,8 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx,
|
||||
goto done;
|
||||
}
|
||||
|
||||
session_info_ready:
|
||||
|
||||
/* setup the string used by %U */
|
||||
set_current_user_info((*session_info)->unix_info->sanitized_username,
|
||||
(*session_info)->unix_info->unix_name,
|
||||
@ -179,7 +258,9 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx,
|
||||
lp_load_with_shares(get_dyn_CONFIGFILE());
|
||||
|
||||
DEBUG(5, (__location__ "OK: user: %s domain: %s client: %s\n",
|
||||
ntuser, ntdomain, rhost));
|
||||
(*session_info)->info->account_name,
|
||||
(*session_info)->info->domain_name,
|
||||
rhost));
|
||||
|
||||
status = NT_STATUS_OK;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user