From 8969da113d80d26f6353670cbeea8fae3e44fa5b Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 15 Jan 2020 14:39:56 +0100 Subject: [PATCH 1/7] CVECVE-2020-25717 selftest: Add user joe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Schneider Reviewed-by: Günther Deschner (cherry picked from commit b4a4adebd94558feb04220a04eadfc8e58624e53) BUG: https://bugzilla.samba.org/show_bug.cgi?id=14901 [abartlet@samba.org Added CVE marker for the CVE this fixes are regression in] --- selftest/target/Samba4.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index e5387132214..e10d8d71162 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -1060,7 +1060,7 @@ servicePrincipalName: http/testupnspn.$ctx->{dnsname} } # Create to users alice and bob! - my $user_account_array = ["alice", "bob", "jane"]; + my $user_account_array = ["alice", "bob", "jane", "joe"]; foreach my $user_account (@{$user_account_array}) { my $samba_tool_cmd = ""; -- 2.25.1 From 9b272b42b18c277887dc4eb657e372dccd3d5f5a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 12 Nov 2021 15:27:58 +0100 Subject: [PATCH 2/7] CVE-2020-25717: idmap_nss: verify that the name of the sid belongs to the configured domain We already check the sid belongs to the domain, but checking the name too feels better and make it easier to understand. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14901 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme [abartlet@samba.org backorted from commit bfd093648b4af51d104096c0cb3535e8706671e5 as header libcli/security/dom_sid.h was not present for struct dom_sid_buf] [abartlet@samba.org fix CVE marker] --- source3/winbindd/idmap_nss.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/source3/winbindd/idmap_nss.c b/source3/winbindd/idmap_nss.c index 9e1efefeb24..3ffffd0a20e 100644 --- a/source3/winbindd/idmap_nss.c +++ b/source3/winbindd/idmap_nss.c @@ -25,6 +25,7 @@ #include "nsswitch/winbind_client.h" #include "idmap.h" #include "lib/winbind_util.h" +#include "libcli/security/dom_sid.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_IDMAP @@ -135,18 +136,21 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_ma for (i = 0; ids[i]; i++) { struct group *gr; enum lsa_SidType type; - const char *p = NULL; + const char *_domain = NULL; + const char *_name = NULL; + char *domain = NULL; char *name = NULL; bool ret; /* by default calls to winbindd are disabled the following call will not recurse so this is safe */ (void)winbind_on(); - ret = winbind_lookup_sid(talloc_tos(), ids[i]->sid, NULL, - &p, &type); + ret = winbind_lookup_sid(talloc_tos(), + ids[i]->sid, + &_domain, + &_name, + &type); (void)winbind_off(); - name = discard_const_p(char, p); - if (!ret) { /* TODO: how do we know if the name is really not mapped, * or something just failed ? */ @@ -154,6 +158,18 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_ma continue; } + domain = discard_const_p(char, _domain); + name = discard_const_p(char, _name); + + if (!strequal(domain, dom->name)) { + struct dom_sid_buf buf; + DBG_ERR("DOMAIN[%s] ignoring SID[%s] belongs to %s [%s\\%s]\n", + dom->name, dom_sid_str_buf(ids[i]->sid, &buf), + sid_type_lookup(type), domain, name); + ids[i]->status = ID_UNMAPPED; + continue; + } + switch (type) { case SID_NAME_USER: { struct passwd *pw; @@ -186,6 +202,7 @@ static NTSTATUS idmap_nss_sids_to_unixids(struct idmap_domain *dom, struct id_ma ids[i]->status = ID_UNKNOWN; break; } + TALLOC_FREE(domain); TALLOC_FREE(name); } return NT_STATUS_OK; -- 2.25.1 From f10e305825cca52588fbee91781c0d5ec5dcf64f Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 12 Nov 2021 14:14:55 +1300 Subject: [PATCH 3/7] CVE-2020-25717: tests/krb5: Add method to automatically obtain server credentials BUG: https://bugzilla.samba.org/show_bug.cgi?id=14901 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 5ea347d3673e35891613c90ca837d1ce4833c1b0) --- python/samba/tests/krb5/kdc_base_test.py | 42 ++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/python/samba/tests/krb5/kdc_base_test.py b/python/samba/tests/krb5/kdc_base_test.py index f64bd0b206e..6e96b982167 100644 --- a/python/samba/tests/krb5/kdc_base_test.py +++ b/python/samba/tests/krb5/kdc_base_test.py @@ -1063,6 +1063,48 @@ class KDCBaseTest(RawKerberosTest): fallback_creds_fn=download_dc_creds) return c + def get_server_creds(self, + require_keys=True, + require_strongest_key=False): + if require_strongest_key: + self.assertTrue(require_keys) + + def download_server_creds(): + samdb = self.get_samdb() + + res = samdb.search(base=samdb.get_default_basedn(), + expression=(f'(|(sAMAccountName={self.host}*)' + f'(dNSHostName={self.host}))'), + scope=ldb.SCOPE_SUBTREE, + attrs=['sAMAccountName', + 'msDS-KeyVersionNumber']) + self.assertEqual(1, len(res)) + dn = res[0].dn + username = str(res[0]['sAMAccountName']) + + creds = KerberosCredentials() + creds.set_domain(self.env_get_var('DOMAIN', 'SERVER')) + creds.set_realm(self.env_get_var('REALM', 'SERVER')) + creds.set_username(username) + + kvno = int(res[0]['msDS-KeyVersionNumber'][0]) + creds.set_kvno(kvno) + creds.set_dn(dn) + + keys = self.get_keys(samdb, dn) + self.creds_set_keys(creds, keys) + + self.creds_set_enctypes(creds) + + return creds + + c = self._get_krb5_creds(prefix='SERVER', + allow_missing_password=True, + allow_missing_keys=not require_keys, + require_strongest_key=require_strongest_key, + fallback_creds_fn=download_server_creds) + return c + def as_req(self, cname, sname, realm, etypes, padata=None, kdc_options=0): '''Send a Kerberos AS_REQ, returns the undecoded response ''' -- 2.25.1 From 9e29bca5530735378aaf46d2d54de7b89dc28afa Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 12 Nov 2021 20:53:30 +1300 Subject: [PATCH 4/7] CVE-2020-25717: nsswitch/nsstest.c: Lower 'non existent uid' to make room for new accounts BUG: https://bugzilla.samba.org/show_bug.cgi?id=14901 Signed-off-by: Joseph Sutton Reviewed-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit fdbee5e074ebd76d659613b8b7114d70f938c38a) --- nsswitch/nsstest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nsswitch/nsstest.c b/nsswitch/nsstest.c index 6d92806cffc..797f2613486 100644 --- a/nsswitch/nsstest.c +++ b/nsswitch/nsstest.c @@ -460,7 +460,7 @@ static void nss_test_errors(void) printf("ERROR Non existent user gave error %d\n", last_error); } - pwd = getpwuid(0xFFF0); + pwd = getpwuid(0xFF00); if (pwd || last_error != NSS_STATUS_NOTFOUND) { total_errors++; printf("ERROR Non existent uid gave error %d\n", last_error); -- 2.25.1 From b8e04947de65b230f84002f13f99094255dc2cab Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 12 Nov 2021 14:20:45 +1300 Subject: [PATCH 5/7] CVE-2020-25717: selftest: turn ad_member_no_nss_wb into ad_member_idmap_nss In reality environments without 'nss_winbind' make use of 'idmap_nss'. For testing, DOMAIN/bob is mapped to the local 'bob', while DOMAIN/jane gets the uid based on the local 'jane' vis idmap_nss. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14901 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Joseph Sutton Signed-off-by: Stefan Metzmacher [metze@samba.org avoid to create a new ad_member_idmap_nss environment and merge it with ad_member_no_nss_wb instead] Reviewed-by: Ralph Boehme [abartlet@samba.org in Backport to Samba 4.10 adjust to different test environments present and older interfaces table] (cherry picked from commit 8a9f2aa2c1cdfa72ad50d7c4f879220fe37654cd) --- selftest/target/Samba.pm | 2 +- selftest/target/Samba3.pm | 24 ++++++++++++++++++++---- source4/selftest/tests.py | 2 +- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm index 034d2ccf58c..8ed3af8aa1c 100644 --- a/selftest/target/Samba.pm +++ b/selftest/target/Samba.pm @@ -431,7 +431,7 @@ sub get_interface($) $interfaces{"offlineadmem"} = 58; - $interfaces{"admemnonsswb"} = 60; + $interfaces{"admemidmapnss"} = 60; $interfaces{"rootdnsforwarder"} = 64; diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 86cff419b57..16bbaa4d33f 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -186,7 +186,7 @@ sub check_env($$) ad_member_idmap_rid => ["ad_dc"], ad_member_idmap_ad => ["fl2008r2dc"], ad_member_offlogon => ["ad_dc"], - ad_member_no_nss_wb => ["ad_dc"], + ad_member_idmap_nss => ["ad_dc"] ); sub setup_nt4_dc @@ -931,7 +931,7 @@ sub setup_ad_member_offlogon 1); } -sub setup_ad_member_no_nss_wb +sub setup_ad_member_idmap_nss { my ($self, $prefix, @@ -942,14 +942,23 @@ sub setup_ad_member_no_nss_wb return "UNKNOWN"; } - print "PROVISIONING AD MEMBER WITHOUT NSS WINBIND..."; + print "PROVISIONING AD MEMBER WITHOUT NSS WINBIND WITH idmap_nss config..."; my $extra_member_options = " + # bob:x:65521:65531:localbob gecos:/:/bin/false + # jane:x:65520:65531:localjane gecos:/:/bin/false + idmap config $dcvars->{DOMAIN} : backend = nss + idmap config $dcvars->{DOMAIN} : range = 65520-65521 + + # Support SMB1 so that we can use posix_whoami(). + client min protocol = CORE + server min protocol = LANMAN1 + username map = $prefix/lib/username.map "; my $ret = $self->provision_ad_member($prefix, - "ADMEMNONSSWB", + "ADMEMIDMAPNSS", $dcvars, $extra_member_options, undef, @@ -958,6 +967,7 @@ sub setup_ad_member_no_nss_wb open(USERMAP, ">$prefix/lib/username.map") or die("Unable to open $prefix/lib/username.map"); print USERMAP " root = $dcvars->{DOMAIN}/root +bob = $dcvars->{DOMAIN}/bob "; close(USERMAP); @@ -1893,6 +1903,8 @@ sub provision($$$$$$$$$) my ($uid_gooduser); my ($uid_eviluser); my ($uid_slashuser); + my ($uid_localbob); + my ($uid_localjane); if ($unix_uid < 0xffff - 13) { $max_uid = 0xffff; @@ -1913,6 +1925,8 @@ sub provision($$$$$$$$$) $uid_gooduser = $max_uid - 11; $uid_eviluser = $max_uid - 12; $uid_slashuser = $max_uid - 13; + $uid_localbob = $max_uid - 14; + $uid_localjane = $max_uid - 15; if ($unix_gids[0] < 0xffff - 8) { $max_gid = 0xffff; @@ -2570,6 +2584,8 @@ user2:x:$uid_user2:$gid_nogroup:user2 gecos:$prefix_abs:/bin/false gooduser:x:$uid_gooduser:$gid_domusers:gooduser gecos:$prefix_abs:/bin/false eviluser:x:$uid_eviluser:$gid_domusers:eviluser gecos::/bin/false slashuser:x:$uid_slashuser:$gid_domusers:slashuser gecos:/:/bin/false +bob:x:$uid_localbob:$gid_domusers:localbob gecos:/:/bin/false +jane:x:$uid_localjane:$gid_domusers:localjane gecos:/:/bin/false "; if ($unix_uid != 0) { print PASSWD "root:x:$uid_root:$gid_root:root gecos:$prefix_abs:/bin/false diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 02c46bb5da6..9c3a456f99f 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -780,7 +780,7 @@ planoldpythontestsuite("ad_dc_smb1", "samba.tests.krb5.test_smb", 'TKT_SIG_SUPPORT': tkt_sig_support, 'EXPECT_PAC': expect_pac }) -planoldpythontestsuite("ad_member_no_nss_wb:local", +planoldpythontestsuite("ad_member_idmap_nss:local", "samba.tests.krb5.test_min_domain_uid", environ={ 'ADMIN_USERNAME': '$DC_USERNAME', -- 2.25.1 From b134d324696f2747f5ee495233f8f05b1f5107d2 Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Fri, 12 Nov 2021 14:22:47 +1300 Subject: [PATCH 6/7] CVE-2020-25717: tests/krb5: Add a test for idmap_nss mapping users to SIDs BUG: https://bugzilla.samba.org/show_bug.cgi?id=14901 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Joseph Sutton Signed-off-by: Stefan Metzmacher [metze@samba.org removed unused tests for a feature that was removed before merging] Reviewed-by: Ralph Boehme (cherry picked from commit 494bf7de6ff3e9abeb3753df0635737b80ce5bb7) --- python/samba/tests/krb5/test_idmap_nss.py | 232 +++++++++++++++++++++ selftest/knownfail.d/idmap_nss_sid_mapping | 2 + source4/selftest/tests.py | 16 ++ 3 files changed, 250 insertions(+) create mode 100755 python/samba/tests/krb5/test_idmap_nss.py create mode 100644 selftest/knownfail.d/idmap_nss_sid_mapping diff --git a/python/samba/tests/krb5/test_idmap_nss.py b/python/samba/tests/krb5/test_idmap_nss.py new file mode 100755 index 00000000000..d3480dbca3f --- /dev/null +++ b/python/samba/tests/krb5/test_idmap_nss.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python3 +# Unix SMB/CIFS implementation. +# Copyright (C) Stefan Metzmacher 2020 +# Copyright (C) 2021 Catalyst.Net Ltd +# +# 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 . +# + +import sys +import os + +from ldb import SCOPE_SUBTREE +from samba import NTSTATUSError +from samba.credentials import DONT_USE_KERBEROS +from samba.dcerpc import security +from samba.ndr import ndr_unpack +from samba.ntstatus import ( + NT_STATUS_NO_IMPERSONATION_TOKEN, + NT_STATUS_LOGON_FAILURE +) +from samba.samba3 import libsmb_samba_internal as libsmb +from samba.samba3 import param as s3param + +from samba.tests.krb5.kdc_base_test import KDCBaseTest + +sys.path.insert(0, 'bin/python') +os.environ['PYTHONUNBUFFERED'] = '1' + +global_asn1_print = False +global_hexdump = False + + +class IdmapNssTests(KDCBaseTest): + + mappeduser_uid = 0xffff - 14 + mappeduser_sid = security.dom_sid(f'S-1-22-1-{mappeduser_uid}') + unmappeduser_uid = 0xffff - 15 + unmappeduser_sid = security.dom_sid(f'S-1-22-1-{unmappeduser_uid}') + + def get_mapped_creds(self, + allow_missing_password=False, + allow_missing_keys=True): + c = self._get_krb5_creds(prefix='MAPPED', + allow_missing_password=allow_missing_password, + allow_missing_keys=allow_missing_keys) + c.set_workstation('') + return c + + def get_unmapped_creds(self, + allow_missing_password=False, + allow_missing_keys=True): + c = self._get_krb5_creds(prefix='UNMAPPED', + allow_missing_password=allow_missing_password, + allow_missing_keys=allow_missing_keys) + c.set_workstation('') + return c + + def get_invalid_creds(self, + allow_missing_password=False, + allow_missing_keys=True): + c = self._get_krb5_creds(prefix='INVALID', + allow_missing_password=allow_missing_password, + allow_missing_keys=allow_missing_keys) + c.set_workstation('') + return c + + # Expect a mapping to the local user SID. + def test_mapped_user_kerberos(self): + user_creds = self.get_mapped_creds() + self._run_idmap_nss_test(user_creds, use_kerberos=True, + expected_first_sid=self.mappeduser_sid, + expected_uid=self.mappeduser_uid) + + # Expect a mapping to the local user SID. + def test_mapped_user_ntlm(self): + user_creds = self.get_mapped_creds() + self._run_idmap_nss_test(user_creds, use_kerberos=False, + expected_first_sid=self.mappeduser_sid, + expected_uid=self.mappeduser_uid) + + def test_mapped_user_no_pac_kerberos(self): + user_creds = self.get_mapped_creds() + self._run_idmap_nss_test( + user_creds, use_kerberos=True, remove_pac=True, + expected_error=NT_STATUS_NO_IMPERSONATION_TOKEN) + + def test_unmapped_user_kerberos(self): + user_creds = self.get_unmapped_creds() + self._run_idmap_nss_test(user_creds, use_kerberos=True, + expected_additional_sid=self.unmappeduser_sid, + expected_uid=self.unmappeduser_uid) + + def test_unmapped_user_ntlm(self): + user_creds = self.get_unmapped_creds() + self._run_idmap_nss_test(user_creds, use_kerberos=False, + expected_additional_sid=self.unmappeduser_sid, + expected_uid=self.unmappeduser_uid) + + def test_unmapped_user_no_pac_kerberos(self): + user_creds = self.get_unmapped_creds() + self._run_idmap_nss_test( + user_creds, use_kerberos=True, remove_pac=True, + expected_error=NT_STATUS_NO_IMPERSONATION_TOKEN) + + def test_invalid_user_kerberos(self): + user_creds = self.get_invalid_creds() + self._run_idmap_nss_test(user_creds, use_kerberos=True, + expected_error=NT_STATUS_LOGON_FAILURE) + + def test_invalid_user_ntlm(self): + user_creds = self.get_invalid_creds() + self._run_idmap_nss_test(user_creds, use_kerberos=False, + expected_error=NT_STATUS_LOGON_FAILURE) + + def test_invalid_user_no_pac_kerberos(self): + user_creds = self.get_invalid_creds() + self._run_idmap_nss_test( + user_creds, use_kerberos=True, remove_pac=True, + expected_error=NT_STATUS_NO_IMPERSONATION_TOKEN) + + def _run_idmap_nss_test(self, user_creds, + use_kerberos, + remove_pac=False, + expected_error=None, + expected_first_sid=None, + expected_additional_sid=None, + expected_uid=None): + if expected_first_sid is not None: + self.assertIsNotNone(expected_uid) + if expected_additional_sid is not None: + self.assertIsNotNone(expected_uid) + if expected_uid is not None: + self.assertIsNone(expected_error) + + if not use_kerberos: + self.assertFalse(remove_pac) + + samdb = self.get_samdb() + + server_name = self.host + service = 'cifs' + share = 'tmp' + + server_creds = self.get_server_creds() + + if expected_first_sid is None: + # Retrieve the user account's SID. + user_name = user_creds.get_username() + res = samdb.search(scope=SCOPE_SUBTREE, + expression=f'(sAMAccountName={user_name})', + attrs=['objectSid']) + self.assertEqual(1, len(res)) + + expected_first_sid = ndr_unpack(security.dom_sid, + res[0].get('objectSid', idx=0)) + + if use_kerberos: + # Talk to the KDC to obtain the service ticket, which gets placed + # into the cache. The machine account name has to match the name in + # the ticket, to ensure that the krbtgt ticket doesn't also need to + # be stored. + creds, cachefile = self.create_ccache_with_user( + user_creds, + server_creds, + service, + server_name, + pac=not remove_pac) + + # Remove the cached creds file. + self.addCleanup(os.remove, cachefile.name) + + # Set the Kerberos 5 creds cache environment variable. This is + # required because the codepath that gets run (gse_krb5) looks for + # it in here and not in the creds object. + krb5_ccname = os.environ.get('KRB5CCNAME', '') + self.addCleanup(os.environ.__setitem__, 'KRB5CCNAME', krb5_ccname) + os.environ['KRB5CCNAME'] = 'FILE:' + cachefile.name + else: + creds = user_creds + creds.set_kerberos_state(DONT_USE_KERBEROS) + + # Connect to a share and retrieve the user SID. + s3_lp = s3param.get_context() + s3_lp.load(self.get_lp().configfile) + + min_protocol = s3_lp.get('client min protocol') + self.addCleanup(s3_lp.set, 'client min protocol', min_protocol) + s3_lp.set('client min protocol', 'NT1') + + max_protocol = s3_lp.get('client max protocol') + self.addCleanup(s3_lp.set, 'client max protocol', max_protocol) + s3_lp.set('client max protocol', 'NT1') + + try: + conn = libsmb.Conn(server_name, share, lp=s3_lp, creds=creds) + except NTSTATUSError as e: + enum, _ = e.args + self.assertEqual(expected_error, enum) + return + else: + self.assertIsNone(expected_error) + + uid, gid, gids, sids, guest = conn.posix_whoami() + + # Ensure that they match. + self.assertEqual(expected_first_sid, sids[0]) + self.assertNotIn(expected_first_sid, sids[1:-1]) + + if expected_additional_sid: + self.assertNotEqual(expected_additional_sid, sids[0]) + self.assertIn(expected_additional_sid, sids) + + self.assertIsNotNone(expected_uid) + self.assertEqual(expected_uid, uid) + + +if __name__ == '__main__': + global_asn1_print = False + global_hexdump = False + import unittest + unittest.main() diff --git a/selftest/knownfail.d/idmap_nss_sid_mapping b/selftest/knownfail.d/idmap_nss_sid_mapping new file mode 100644 index 00000000000..7e1913f03fc --- /dev/null +++ b/selftest/knownfail.d/idmap_nss_sid_mapping @@ -0,0 +1,2 @@ +^samba.tests.krb5.test_idmap_nss.samba.tests.krb5.test_idmap_nss.IdmapNssTests.test_unmapped_user_kerberos +^samba.tests.krb5.test_idmap_nss.samba.tests.krb5.test_idmap_nss.IdmapNssTests.test_unmapped_user_ntlm diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 9c3a456f99f..cb18b5c82a6 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -787,6 +787,22 @@ planoldpythontestsuite("ad_member_idmap_nss:local", 'ADMIN_PASSWORD': '$DC_PASSWORD', 'STRICT_CHECKING': '0' }) +planoldpythontestsuite("ad_member_idmap_nss:local", + "samba.tests.krb5.test_idmap_nss", + environ={ + 'ADMIN_USERNAME': '$DC_USERNAME', + 'ADMIN_PASSWORD': '$DC_PASSWORD', + 'MAPPED_USERNAME': 'bob', + 'MAPPED_PASSWORD': 'Secret007', + 'UNMAPPED_USERNAME': 'jane', + 'UNMAPPED_PASSWORD': 'Secret007', + 'INVALID_USERNAME': 'joe', + 'INVALID_PASSWORD': 'Secret007', + 'STRICT_CHECKING': '0', + 'FAST_SUPPORT': have_fast_support, + 'TKT_SIG_SUPPORT': tkt_sig_support, + 'EXPECT_PAC': expect_pac + }) for env in ["ad_dc", smbv1_disabled_testenv]: planoldpythontestsuite(env, "samba.tests.smb", extra_args=['-U"$USERNAME%$PASSWORD"'], py3_compatible=True) -- 2.25.1 From e05e7ec2d5d0a4ec20a6fdd97b82b1520fd676ca Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 12 Nov 2021 16:10:31 +1300 Subject: [PATCH 7/7] CVE-2020-25717: s3:auth: Fallback to a SID/UID based mapping if the named based lookup fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before the CVE-2020-25717 fixes we had a fallback from getpwnam('DOMAIN\user') to getpwnam('user') which was very dangerous and unpredictable. Now we do the fallback based on sid_to_uid() followed by getpwuid() on the returned uid. This obsoletes 'username map [script]' based workaround adviced for CVE-2020-25717, when nss_winbindd is not used or idmap_nss is actually used. In future we may decide to prefer or only do the SID/UID based lookup, but for now we want to keep this unchanged as much as possible. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14901 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Andrew Bartlett Signed-off-by: Stefan Metzmacher [metze@samba.org moved the new logic into the fallback codepath only in order to avoid behavior changes as much as possible] Reviewed-by: Ralph Boehme Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Mon Nov 15 19:01:56 UTC 2021 on sn-devel-184 [abartlet@samba.org backported from commit 0a546be05295a7e4a552f9f4f0c74aeb2e9a0d6e as usage.py is not present in Samba 4.10] --- selftest/knownfail.d/idmap_nss_sid_mapping | 2 -- source3/auth/auth_util.c | 34 +++++++++++++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) delete mode 100644 selftest/knownfail.d/idmap_nss_sid_mapping diff --git a/selftest/knownfail.d/idmap_nss_sid_mapping b/selftest/knownfail.d/idmap_nss_sid_mapping deleted file mode 100644 index 7e1913f03fc..00000000000 --- a/selftest/knownfail.d/idmap_nss_sid_mapping +++ /dev/null @@ -1,2 +0,0 @@ -^samba.tests.krb5.test_idmap_nss.samba.tests.krb5.test_idmap_nss.IdmapNssTests.test_unmapped_user_kerberos -^samba.tests.krb5.test_idmap_nss.samba.tests.krb5.test_idmap_nss.IdmapNssTests.test_unmapped_user_ntlm diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index c0e5cfd7fa8..b463059f259 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -1837,7 +1837,9 @@ const struct auth_session_info *get_session_info_system(void) ***************************************************************************/ static NTSTATUS check_account(TALLOC_CTX *mem_ctx, const char *domain, - const char *username, char **found_username, + const char *username, + const struct dom_sid *sid, + char **found_username, struct passwd **pwd, bool *username_was_mapped) { @@ -1872,6 +1874,31 @@ static NTSTATUS check_account(TALLOC_CTX *mem_ctx, const char *domain, } passwd = smb_getpwnam(mem_ctx, dom_user, &real_username, false); + if (!passwd && !*username_was_mapped) { + struct dom_sid_buf buf; + uid_t uid; + bool ok; + + DBG_DEBUG("Failed to find authenticated user %s via " + "getpwnam(), fallback to sid_to_uid(%s).\n", + dom_user, dom_sid_str_buf(sid, &buf)); + + ok = sid_to_uid(sid, &uid); + if (!ok) { + DBG_ERR("Failed to convert SID %s to a UID (dom_user[%s])\n", + dom_sid_str_buf(sid, &buf), dom_user); + return NT_STATUS_NO_SUCH_USER; + } + passwd = getpwuid_alloc(mem_ctx, uid); + if (!passwd) { + DBG_ERR("Failed to find local account with UID %lld for SID %s (dom_user[%s])\n", + (long long)uid, + dom_sid_str_buf(sid, &buf), + dom_user); + return NT_STATUS_NO_SUCH_USER; + } + real_username = talloc_strdup(mem_ctx, passwd->pw_name); + } if (!passwd) { DEBUG(3, ("Failed to find authenticated user %s via " "getpwnam(), denying access.\n", dom_user)); @@ -2017,6 +2044,7 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, bool username_was_mapped; struct passwd *pwd; struct auth_serversupplied_info *result; + struct dom_sid sid; TALLOC_CTX *tmp_ctx = talloc_stackframe(); /* @@ -2063,9 +2091,13 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, /* this call will try to create the user if necessary */ + sid_copy(&sid, info3->base.domain_sid); + sid_append_rid(&sid, info3->base.rid); + nt_status = check_account(tmp_ctx, nt_domain, nt_username, + &sid, &found_username, &pwd, &username_was_mapped); -- 2.25.1