Andrew Bartlett [Fri, 1 Oct 2021 02:59:28 +0000 (15:59 +1300)]
CVE-2020-25718 dsdb: Bring sid_helper.c into common code as rodc_helper.c
These common routines will assist the KDC to do the same access
checking as the RPC servers need to do regarding which accounts
a RODC can act with regard to.
Andrew Bartlett [Thu, 30 Sep 2021 23:25:30 +0000 (12:25 +1300)]
CVE-2020-25718 s4-rpc_server: Provide wrapper samdb_confirm_rodc_allowed_to_repl_to()
This shares the lookup of the tokenGroups attribute.
There will be a new caller that does not want to do this step,
so this is a wrapper of samdb_confirm_rodc_allowed_to_repl_to_sid_list()
rather than part of it
Andrew Bartlett [Thu, 30 Sep 2021 22:55:11 +0000 (11:55 +1300)]
CVE-2020-25718 s4-rpc_server: Put msDS-KrbTgtLinkBL and UF_INTERDOMAIN_TRUST_ACCOUNT RODC checks in common
While these checks were not in the NETLOGON case, there is no sense where
an RODC should be resetting a bad password count on either a
UF_INTERDOMAIN_TRUST_ACCOUNT nor a RODC krbtgt account.
Andrew Bartlett [Thu, 30 Sep 2021 22:09:48 +0000 (11:09 +1300)]
CVE-2020-25718 s4-rpc_server: Obtain the user tokenGroups earlier
This will allow the creation of a common helper routine that
takes the token SID list (from tokenGroups or struct auth_user_info_dc)
and returns the allowed/denied result.
Andrew Bartlett [Thu, 30 Sep 2021 21:47:29 +0000 (10:47 +1300)]
CVE-2020-25718 s4-rpc_server: Change sid list functions to operate on a array of struct dom_sid
This is instead of an array of struct dom_sid *.
The reason is that auth_user_info_dc has an array of struct dom_sid
(the user token) and for checking if an RODC should be allowed
to print a particular ticket, we want to reuse that a rather
then reconstruct it via tokenGroups.
Signed-off-by: Andreas Schneider <asn@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
[abartlet@samba.org backported due to support for MIT KDB < 10
in Samba 4.14]
[abartlet@samba.org As submitted in patch to Samba bugzilla
to address this issue as https://attachments.samba.org/attachment.cgi?id=16724
on overall bug https://bugzilla.samba.org/show_bug.cgi?id=14725]
Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Joseph Sutton [Tue, 26 Oct 2021 22:18:36 +0000 (11:18 +1300)]
CVE-2020-25719 tests/krb5: Add expected parameters to cache key for obtaining tickets
If multiple calls to get_tgt() or get_service_ticket() specify different
expected parameters, we want to perform the request again so that the
checking can be performed, rather than reusing a previously obtained
ticket and potentially skipping checks.
It should be fine to cache tickets with the same expected parameters, as
tickets that fail to be obtained will not be stored in the cache, so the
checking will happen for every call.
This tightens the logic a bit, in that a message with trailing DELETE
elements is no longer accepted when the bypass flag is set. In any case
this is an unlikely scenario as this is an internal flag set by a private
control in pdb_samba_dsdb_replace_by_sam().
Douglas Bagnall [Wed, 20 Oct 2021 04:15:43 +0000 (17:15 +1300)]
CVE-2020-25722 s4/dsdb/samldb _user_account_control_change() always add final value
dsdb_get_single_valued_attr() was finding the last non-delete element for
userAccountControl and changing its value to the computed value.
Unfortunately, the last non-delete element might not be the last element,
and a subsequent delete might remove it.
This function collects a superset of all the new values for the specified
attribute that could result from an ldb add or modify message.
In most cases -- where there is a single add or modify -- the exact set
of added values is returned, and this is done reasonably efficiently
using the existing element. Where it gets complicated is when there are
multiple elements for the same attribute in a message. Anything added
before a replace or delete will be included in these results but may not
end up in the database if the message runs its course. Examples:
sequence result
1. ADD the element is returned (exact)
2. REPLACE the element is returned (exact)
3. ADD, ADD both elements are concatenated together (exact)
4. ADD, REPLACE both elements are concatenated together (superset)
5. REPLACE, ADD both elements are concatenated together (exact)
6. ADD, DEL, ADD adds are concatenated together (superset)
7. REPLACE, REPLACE both concatenated (superset)
8. DEL, ADD last element is returned (exact)
Why this? In the past we have treated dsdb_get_single_valued_attr() as if
it returned the complete set of possible database changes, when in fact it
only returned the last non-delete. That is, it could have missed values
in examples 3-7 above.
Douglas Bagnall [Fri, 22 Oct 2021 00:14:32 +0000 (13:14 +1300)]
CVE-2020-25722 s4/dsdb/samldb: check for SPN uniqueness, including aliases
Not only should it not be possible to add a servicePrincipalName that
is already present in the domain, it should not be possible to add one
that is implied by an entry in sPNMappings, unless the user is adding
an alias to another SPN and has rights to alter that one.
For example, with the default sPNMappings, cifs/ is an alias pointing to
host/, meaning if there is no cifs/example.com SPN, the host/example.com
one will be used instead. A user can add the cifs/example.com SPN only
if they can also change the host/example.com one (because adding the
cifs/ effectively changes the host/). The reverse is refused in all cases,
unless they happen to be on the same object. That is, if there is a
cifs/example.com SPN, there is no way to add host/example.com elsewhere.
Douglas Bagnall [Fri, 22 Oct 2021 02:27:25 +0000 (15:27 +1300)]
CVE-2020-25722 s4/dsdb/samldb: check sAMAccountName for illegal characters
This only for the real account name, not the account name implicit in
a UPN. It doesn't matter if a UPN implies an illegal sAMAccountName,
since that is not going to conflict with a real one.
Douglas Bagnall [Fri, 22 Oct 2021 00:17:34 +0000 (13:17 +1300)]
CVE-2020-25722 s4/dsdb/samldb: check for clashes in UPNs/samaccountnames
We already know duplicate sAMAccountNames and UserPrincipalNames are bad,
but we also have to check against the values these imply in each other.
For example, imagine users with SAM account names "Alice" and "Bob" in
the realm "example.com". If they do not have explicit UPNs, by the logic
of MS-ADTS 5.1.1.1.1 they use the implict UPNs "alice@example.com" and
"bob@example.com", respectively. If Bob's UPN gets set to
"alice@example.com", it will clash with Alice's implicit one.
Therefore we refuse to allow a UPN that implies an existing SAM account
name and vice versa.
Douglas Bagnall [Mon, 13 Sep 2021 02:15:09 +0000 (14:15 +1200)]
CVE-2020-25722 pytest: test sAMAccountName/userPrincipalName over ldap
Because the sam account name + the dns host name is used as the
default user principal name, we need to check for collisions between
these. Fixes are coming in upcoming patches.
Douglas Bagnall [Thu, 28 Oct 2021 00:07:01 +0000 (13:07 +1300)]
CVE-2020-25722 blackbox/upgrades tests: ignore SPN for ldapcmp
We need to have the SPNs there before someone else nabs them, which
makes the re-provisioned old releases different from the reference
versions that we keep for this comparison.
Douglas Bagnall [Wed, 27 Oct 2021 20:45:36 +0000 (09:45 +1300)]
CVE-2020-25722 s4/provision: add host/ SPNs at the start
There are two reasons for this. Firstly, leaving SPNs unclaimed is
dangerous, as someone else could grab them first. Secondly, in some
circumstances (self join) we try to add a DNS/ SPN a little bit later
in provision. Under the rules we are introducing for CVE-2020-25722,
this will make our later attempts to add HOST/ fail.
This causes a few errors in samba4.blackbox.dbcheck.* tests, which
assert that revivified old domains match stored reference versions.
Now they don't, because they have servicePrincipalNames.
Douglas Bagnall [Wed, 1 Sep 2021 06:35:02 +0000 (18:35 +1200)]
CVE-2020-25722 tests: blackbox samba-tool spn non-admin test
It is soon going to be impossible to add duplicate SPNs (short of
going behind DSDB's back on the local filesystem). Our test of adding
SPNs on non-admin users doubled as the test for adding a duplicate (using
--force). As --force is gone, we add these tests on Guest after the SPN
on Administrator is gone.
This did not actually *force* the creation of a duplicate SPN, it just
ignored the client-side check for the existing copy. Soon we are going
to enforce SPN uniqueness on the server side, and this --force will not
work. This will make the --force test fail, and if that tests fail, so
will others that depend the duplicate values. So we remove those tests.
It is wrong-headed to try to make duplicate SPNs in any case, which is
probably why there is no sign of anyone ever having used this option.
Andrew Bartlett [Mon, 1 Nov 2021 04:21:16 +0000 (17:21 +1300)]
CVE-2020-25722 Check for all errors from acl_check_extended_right() in acl_check_spn()
We should not fail open on error.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Andrew Bartlett [Mon, 1 Nov 2021 04:19:29 +0000 (17:19 +1300)]
CVE-2020-25722 Check all elements in acl_check_spn() not just the first one
Thankfully we are aleady in a loop over all the message elements in
acl_modify() so this is an easy and safe change to make.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Nadezhda Ivanova [Mon, 18 Oct 2021 11:27:59 +0000 (14:27 +0300)]
CVE-2020-25722: s4-acl: Make sure Control Access Rights honor the Applies-to attribute
Validate Writes and Control Access Rights only grant access if the
object is of the type listed in the Right's appliesTo attribute. For
example, even though a Validated-SPN access may be granted to a user
object in the SD, it should only pass if the object is of class
computer This patch enforces the appliesTo attribute classes for
access checks from within the ldb stack.
Nadezhda Ivanova [Mon, 25 Oct 2021 11:54:56 +0000 (14:54 +0300)]
CVE-2020-25722: s4-acl: test Control Access Rights honor the Applies-to attribute
Validate Writes and Control Access Rights should only grant access if the
object is of the type listed in the Right's appliesTo attribute.
Tests to verify this behavior
Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
[abartlet@samba.org Included in backport as changing ACLs while
ACL tests are not checking for unexpected success would be bad]
Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
[abartlet@samba.org Removed transaction hooks, these do nothing over
remote LDAP]
CVE-2020-25717: selftest: configure 'ktest' env with winbindd and idmap_autorid
The 'ktest' environment was/is designed to test kerberos in an active
directory member setup. It was created at a time we wanted to test
smbd/winbindd with kerberos without having the source4 ad dc available.
This still applies to testing the build with system krb5 libraries
but without relying on a running ad dc.
As a domain member setup requires a running winbindd, we should test it
that way, in order to reflect a valid setup.
As a side effect it provides a way to demonstrate that we can accept
smb connections authenticated via kerberos, but no connection to
a domain controller! In order get this working offline, we need an
idmap backend with ID_TYPE_BOTH support, so we use 'autorid', which
should be the default choice.
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.