From 3047d0e67023ba81996cccd535a522cab6f69f58 Mon Sep 17 00:00:00 2001 From: haochenstar Date: Thu, 9 Dec 2021 10:44:38 +0800 Subject: [PATCH] fix CVE-2020-25717,CVE-2020-25718,CVE-2020-25719,CVE-2020-25721,CVE-2020-25722,CVE-2016-2124,CVE-2021-3738 --- ...-libcli-sesssetup-don-t-fallback-to-.patch | 65 ++ backport-0000-CVE-2020-25718-simplify.patch | 110 +++ ...it-samba-Make-ks_get_principal-inter.patch | 57 ++ ...rb5pac-Add-new-buffers-for-samAccoun.patch | 90 +++ ...-torture-drsuapi-maintain-priv-admin.patch | 61 ++ ...-libsmb-don-t-fallback-to-non-spnego.patch | 50 ++ ...inbindd-add-generic-wb_parent_idmap_.patch | 411 +++++++++++ ...2020-25718-trailing-chunk-must-match.patch | 144 ++++ ...5719-mit-samba-Add-ks_free_principal.patch | 101 +++ ...uth-Fill-in-the-new-HAS_SAM_NAME_AND.patch | 43 ++ ...sdb-Move-krbtgt-password-setup-after.patch | 149 ++++ ...-rpc_server-common-provide-assoc_gro.patch | 183 +++++ ...b_xids2sids-make-use-of-the-new-wb_p.patch | 362 ++++++++++ ...E-2020-25718-fix-ldb_comparison_fold.patch | 42 ++ ...and-verify-PAC-with-ticket-principal.patch | 70 ++ ...sdb-Restrict-the-setting-of-privileg.patch | 235 ++++++ ...-rpc_server-drsuapi-make-use-of-asso.patch | 106 +++ ...b_sids2xids-call-wb_parent_idmap_set.patch | 94 +++ ...25718-catch-potential-overflow-error.patch | 105 +++ ...it-samba-If-we-use-client_princ-alwa.patch | 153 ++++ ...sdb-objectclass-computer-becomes-UF_.patch | 137 ++++ ...-rpc_server-dnsserver-make-use-of-dc.patch | 60 ++ ...inbindd-defer-the-setup_child-from-i.patch | 96 +++ ...it-samba-Add-mit_samba_princ_needs_p.patch | 49 ++ ...sdb-Prohibit-mismatch-between-UF_-ac.patch | 264 +++++++ ...-rpc_server-lsa-make-use-of-dcesrv_s.patch | 43 ++ ...b_sids2xids-build-state-idmap_doms-b.patch | 169 +++++ ...E-2020-25718-Fix-Message-items-for-a.patch | 47 ++ ...it-samba-Rework-PAC-handling-in-kdb_.patch | 199 ++++++ ...sdb-Add-restrictions-on-computer-acc.patch | 249 +++++++ ...-rpc_server-netlogon-make-use-of-dce.patch | 340 +++++++++ ...inbindd-allow-idmap-backends-to-mark.patch | 83 +++ ...-0006-CVE-2020-25718-Change-sid-list.patch | 304 ++++++++ ...amdb-Fill-in-isCriticalSystemObject-.patch | 42 ++ ...-rpc_server-samr-make-use-of-dcesrv_.patch | 176 +++++ ...3-idmap_hash-reliable-return-ID_TYPE.patch | 104 +++ ...-0007-CVE-2020-25718-Obtain-the-user.patch | 117 +++ ...4-acl-Make-sure-Control-Access-Right.patch | 472 +++++++++++++ ...inbindd-call-wb_parent_idmap_setup_s.patch | 81 +++ ...tLinkBL-put-RODC-reveal-never-reveal.patch | 195 +++++ ...heck-all-elements-in-acl_check_spn-n.patch | 97 +++ ...inbind-ensure-wb_parent_idmap_setup_.patch | 109 +++ ...CVE-2020-25718-Put-msDS-KrbTgtLinkBL.patch | 110 +++ ...heck-for-all-errors-from-acl_check_e.patch | 35 + ...uth_sam-use-pdb_get_domain_info-to-l.patch | 228 ++++++ ...CVE-2020-25718-Confirm-that-the-RODC.patch | 89 +++ ...4-dsdb-cracknames-always-free-tmp_ct.patch | 54 ++ ...3-winbindd-make-sure-we-default-to-r.patch | 176 +++++ ...4-provision-add-host-SPNs-at-the-sta.patch | 65 ++ ...4-auth-ntlm-make-sure-auth_check_pas.patch | 39 + ...4-dsdb-samldb-add-samldb_get_single_.patch | 85 +++ ...oadparm-Add-new-parameter-min-domain.patch | 101 +++ ...4-dsdb-samldb-check-for-clashes-in-U.patch | 279 ++++++++ ...717-s3-auth-Check-minimum-domain-uid.patch | 53 ++ ...4-dsdb-samldb-check-sAMAccountName-f.patch | 101 +++ ...3-auth-we-should-not-try-to-autocrea.patch | 36 + ...4-dsdb-samldb-check-for-SPN-uniquene.patch | 667 ++++++++++++++++++ ...3-auth-no-longer-let-check_account-a.patch | 42 ++ ...4-dsdb-samldb-reject-SPN-with-too-fe.patch | 82 +++ ...3-auth-remove-fallbacks-in-smb_getpw.patch | 181 +++++ ...4-dsdb-modules-add-dsdb_get_expected.patch | 178 +++++ ...3-auth-don-t-let-create_local_token-.patch | 48 ++ ...4-dsdb-samldb-samldb_get_single_valu.patch | 49 ++ ...VE-2020-25717-auth-gensec-always-req.patch | 76 ++ ...4-dsdb-samldb-samldb_sam_accountname.patch | 47 ++ ...3-ntlm_auth-fix-memory-leaks-in-ntlm.patch | 77 ++ ...4-dsdb-samldb-samldb_schema_add_hand.patch | 43 ++ ...3-ntlm_auth-let-ntlm_auth_generate_s.patch | 145 ++++ ...4-dsdb-samldb-samldb_schema_add_hand.patch | 43 ++ ...4-dsdb-samldb-samldb_prim_group_chan.patch | 43 ++ ...nfo-in-auth3_generate_session_info_p.patch | 52 ++ ...3-auth-let-auth3_generate_session_in.patch | 319 +++++++++ ...4-dsdb-samldb-samldb_user_account_co.patch | 46 ++ ...3-auth-let-auth3_generate_session_in.patch | 85 +++ ...4-dsdb-samldb-_user_account_control_.patch | 48 ++ ...4-dsdb-samldb-samldb_pwd_last_set_ch.patch | 43 ++ ...4-dsdb-samldb-samldb_lockout_time-ch.patch | 43 ++ ...4-dsdb-samldb-samldb_group_type_chan.patch | 43 ++ ...4-dsdb-samldb-samldb_service_princip.patch | 52 ++ ...4-dsdb-samldb-samldb_fsmo_role_owner.patch | 43 ++ ...4-dsdb-samldb-samldb_fsmo_role_owner.patch | 63 ++ ...4-dsdb-pwd_hash-password_hash_bypass.patch | 70 ++ ...4-dsdb-pwd_hash-rework-pwdLastSet-by.patch | 72 ++ ...nsure-the-structural-objectclass-can.patch | 90 +++ ...dc-Do-not-honour-a-request-for-a-3-p.patch | 55 ++ ...elftest-Ensure-check-for-duplicate-s.patch | 67 ++ ...1456624-Uninitialized-scalar-variabl.patch | 33 + samba.spec | 97 ++- 88 files changed, 10556 insertions(+), 1 deletion(-) create mode 100644 backport-0000-CVE-2016-2124-s4-libcli-sesssetup-don-t-fallback-to-.patch create mode 100644 backport-0000-CVE-2020-25718-simplify.patch create mode 100644 backport-0000-CVE-2020-25719-mit-samba-Make-ks_get_principal-inter.patch create mode 100644 backport-0000-CVE-2020-25721-krb5pac-Add-new-buffers-for-samAccoun.patch create mode 100644 backport-0000-CVE-2021-3738-s4-torture-drsuapi-maintain-priv-admin.patch create mode 100644 backport-0001-CVE-2016-2124-s3-libsmb-don-t-fallback-to-non-spnego.patch create mode 100644 backport-0001-CVE-2020-25717-winbindd-add-generic-wb_parent_idmap_.patch create mode 100644 backport-0001-CVE-2020-25718-trailing-chunk-must-match.patch create mode 100644 backport-0001-CVE-2020-25719-mit-samba-Add-ks_free_principal.patch create mode 100644 backport-0001-CVE-2020-25721-auth-Fill-in-the-new-HAS_SAM_NAME_AND.patch create mode 100644 backport-0001-CVE-2020-25722-dsdb-Move-krbtgt-password-setup-after.patch create mode 100644 backport-0001-CVE-2021-3738-s4-rpc_server-common-provide-assoc_gro.patch create mode 100644 backport-0002-CVE-2020-25717-wb_xids2sids-make-use-of-the-new-wb_p.patch create mode 100644 backport-0002-CVE-2020-25718-fix-ldb_comparison_fold.patch create mode 100644 backport-0002-CVE-2020-25719-sign-and-verify-PAC-with-ticket-principal.patch create mode 100644 backport-0002-CVE-2020-25722-dsdb-Restrict-the-setting-of-privileg.patch create mode 100644 backport-0002-CVE-2021-3738-s4-rpc_server-drsuapi-make-use-of-asso.patch create mode 100644 backport-0003-CVE-2020-25717-wb_sids2xids-call-wb_parent_idmap_set.patch create mode 100644 backport-0003-CVE-2020-25718-catch-potential-overflow-error.patch create mode 100644 backport-0003-CVE-2020-25719-mit-samba-If-we-use-client_princ-alwa.patch create mode 100644 backport-0003-CVE-2020-25722-dsdb-objectclass-computer-becomes-UF_.patch create mode 100644 backport-0003-CVE-2021-3738-s4-rpc_server-dnsserver-make-use-of-dc.patch create mode 100644 backport-0004-CVE-2020-25717-winbindd-defer-the-setup_child-from-i.patch create mode 100644 backport-0004-CVE-2020-25719-mit-samba-Add-mit_samba_princ_needs_p.patch create mode 100644 backport-0004-CVE-2020-25722-dsdb-Prohibit-mismatch-between-UF_-ac.patch create mode 100644 backport-0004-CVE-2021-3738-s4-rpc_server-lsa-make-use-of-dcesrv_s.patch create mode 100644 backport-0005-CVE-2020-25717-wb_sids2xids-build-state-idmap_doms-b.patch create mode 100644 backport-0005-CVE-2020-25718-Fix-Message-items-for-a.patch create mode 100644 backport-0005-CVE-2020-25719-mit-samba-Rework-PAC-handling-in-kdb_.patch create mode 100644 backport-0005-CVE-2020-25722-dsdb-Add-restrictions-on-computer-acc.patch create mode 100644 backport-0005-CVE-2021-3738-s4-rpc_server-netlogon-make-use-of-dce.patch create mode 100644 backport-0006-CVE-2020-25717-winbindd-allow-idmap-backends-to-mark.patch create mode 100644 backport-0006-CVE-2020-25718-Change-sid-list.patch create mode 100644 backport-0006-CVE-2020-25722-samdb-Fill-in-isCriticalSystemObject-.patch create mode 100644 backport-0006-CVE-2021-3738-s4-rpc_server-samr-make-use-of-dcesrv_.patch create mode 100644 backport-0007-CVE-2020-25717-s3-idmap_hash-reliable-return-ID_TYPE.patch create mode 100644 backport-0007-CVE-2020-25718-Obtain-the-user.patch create mode 100644 backport-0007-CVE-2020-25722-s4-acl-Make-sure-Control-Access-Right.patch create mode 100644 backport-0008-CVE-2020-25717-winbindd-call-wb_parent_idmap_setup_s.patch create mode 100644 backport-0008-CVE-2020-25718-Put-msDS-KrbTgtLinkBL-put-RODC-reveal-never-reveal.patch create mode 100644 backport-0008-CVE-2020-25722-Check-all-elements-in-acl_check_spn-n.patch create mode 100644 backport-0009-CVE-2020-25717-winbind-ensure-wb_parent_idmap_setup_.patch create mode 100644 backport-0009-CVE-2020-25718-Put-msDS-KrbTgtLinkBL.patch create mode 100644 backport-0009-CVE-2020-25722-Check-for-all-errors-from-acl_check_e.patch create mode 100644 backport-0010-CVE-2020-25717-auth_sam-use-pdb_get_domain_info-to-l.patch create mode 100644 backport-0010-CVE-2020-25718-Confirm-that-the-RODC.patch create mode 100644 backport-0010-CVE-2020-25722-s4-dsdb-cracknames-always-free-tmp_ct.patch create mode 100644 backport-0011-CVE-2020-25717-s3-winbindd-make-sure-we-default-to-r.patch create mode 100644 backport-0011-CVE-2020-25722-s4-provision-add-host-SPNs-at-the-sta.patch create mode 100644 backport-0012-CVE-2020-25717-s4-auth-ntlm-make-sure-auth_check_pas.patch create mode 100644 backport-0012-CVE-2020-25722-s4-dsdb-samldb-add-samldb_get_single_.patch create mode 100644 backport-0013-CVE-2020-25717-loadparm-Add-new-parameter-min-domain.patch create mode 100644 backport-0013-CVE-2020-25722-s4-dsdb-samldb-check-for-clashes-in-U.patch create mode 100644 backport-0014-CVE-2020-25717-s3-auth-Check-minimum-domain-uid.patch create mode 100644 backport-0014-CVE-2020-25722-s4-dsdb-samldb-check-sAMAccountName-f.patch create mode 100644 backport-0015-CVE-2020-25717-s3-auth-we-should-not-try-to-autocrea.patch create mode 100644 backport-0015-CVE-2020-25722-s4-dsdb-samldb-check-for-SPN-uniquene.patch create mode 100644 backport-0016-CVE-2020-25717-s3-auth-no-longer-let-check_account-a.patch create mode 100644 backport-0016-CVE-2020-25722-s4-dsdb-samldb-reject-SPN-with-too-fe.patch create mode 100644 backport-0017-CVE-2020-25717-s3-auth-remove-fallbacks-in-smb_getpw.patch create mode 100644 backport-0017-CVE-2020-25722-s4-dsdb-modules-add-dsdb_get_expected.patch create mode 100644 backport-0018-CVE-2020-25717-s3-auth-don-t-let-create_local_token-.patch create mode 100644 backport-0018-CVE-2020-25722-s4-dsdb-samldb-samldb_get_single_valu.patch create mode 100644 backport-0019-CVE-2020-25719-CVE-2020-25717-auth-gensec-always-req.patch create mode 100644 backport-0019-CVE-2020-25722-s4-dsdb-samldb-samldb_sam_accountname.patch create mode 100644 backport-0020-CVE-2020-25717-s3-ntlm_auth-fix-memory-leaks-in-ntlm.patch create mode 100644 backport-0020-CVE-2020-25722-s4-dsdb-samldb-samldb_schema_add_hand.patch create mode 100644 backport-0021-CVE-2020-25717-s3-ntlm_auth-let-ntlm_auth_generate_s.patch create mode 100644 backport-0021-CVE-2020-25722-s4-dsdb-samldb-samldb_schema_add_hand.patch create mode 100644 backport-0022-CVE-2020-25722-s4-dsdb-samldb-samldb_prim_group_chan.patch create mode 100644 backport-0022-use-set_current_user_info-in-auth3_generate_session_info_p.patch create mode 100644 backport-0023-CVE-2020-25717-s3-auth-let-auth3_generate_session_in.patch create mode 100644 backport-0023-CVE-2020-25722-s4-dsdb-samldb-samldb_user_account_co.patch create mode 100644 backport-0024-CVE-2020-25717-s3-auth-let-auth3_generate_session_in.patch create mode 100644 backport-0024-CVE-2020-25722-s4-dsdb-samldb-_user_account_control_.patch create mode 100644 backport-0025-CVE-2020-25722-s4-dsdb-samldb-samldb_pwd_last_set_ch.patch create mode 100644 backport-0026-CVE-2020-25722-s4-dsdb-samldb-samldb_lockout_time-ch.patch create mode 100644 backport-0027-CVE-2020-25722-s4-dsdb-samldb-samldb_group_type_chan.patch create mode 100644 backport-0028-CVE-2020-25722-s4-dsdb-samldb-samldb_service_princip.patch create mode 100644 backport-0029-CVE-2020-25722-s4-dsdb-samldb-samldb_fsmo_role_owner.patch create mode 100644 backport-0030-CVE-2020-25722-s4-dsdb-samldb-samldb_fsmo_role_owner.patch create mode 100644 backport-0031-CVE-2020-25722-s4-dsdb-pwd_hash-password_hash_bypass.patch create mode 100644 backport-0032-CVE-2020-25722-s4-dsdb-pwd_hash-rework-pwdLastSet-by.patch create mode 100644 backport-0033-CVE-2020-25722-Ensure-the-structural-objectclass-can.patch create mode 100644 backport-0034-CVE-2020-25722-kdc-Do-not-honour-a-request-for-a-3-p.patch create mode 100644 backport-0035-CVE-2020-25722-selftest-Ensure-check-for-duplicate-s.patch create mode 100644 backport-winbind-Fix-CID-1456624-Uninitialized-scalar-variabl.patch diff --git a/backport-0000-CVE-2016-2124-s4-libcli-sesssetup-don-t-fallback-to-.patch b/backport-0000-CVE-2016-2124-s4-libcli-sesssetup-don-t-fallback-to-.patch new file mode 100644 index 0000000..67953e7 --- /dev/null +++ b/backport-0000-CVE-2016-2124-s4-libcli-sesssetup-don-t-fallback-to-.patch @@ -0,0 +1,65 @@ +From 4290223ed40183e5f01c25da00df438b9ccf302a Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 24 Nov 2016 09:12:59 +0100 +Subject: [PATCH 254/266] CVE-2016-2124: s4:libcli/sesssetup: don't fallback to + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=4290223ed40183e5f01c25da00df438b9ccf302a + + non spnego authentication if we require kerberos + +We should not send NTLM[v2] data on the wire if the user asked for kerberos +only. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=12444 + +Signed-off-by: Stefan Metzmacher +--- + source4/libcli/smb_composite/sesssetup.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/source4/libcli/smb_composite/sesssetup.c b/source4/libcli/smb_composite/sesssetup.c +index 6ee4929e8d7..a0a1f4baa56 100644 +--- a/source4/libcli/smb_composite/sesssetup.c ++++ b/source4/libcli/smb_composite/sesssetup.c +@@ -620,6 +620,8 @@ struct composite_context *smb_composite_sesssetup_send(struct smbcli_session *se + struct composite_context *c; + struct sesssetup_state *state; + NTSTATUS status; ++ enum credentials_use_kerberos krb5_state = ++ cli_credentials_get_kerberos_state(io->in.credentials); + + c = composite_create(session, session->transport->ev); + if (c == NULL) return NULL; +@@ -635,6 +637,10 @@ struct composite_context *smb_composite_sesssetup_send(struct smbcli_session *se + + /* no session setup at all in earliest protocol varients */ + if (session->transport->negotiate.protocol < PROTOCOL_LANMAN1) { ++ if (krb5_state == CRED_MUST_USE_KERBEROS) { ++ composite_error(c, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT); ++ return c; ++ } + ZERO_STRUCT(io->out); + composite_done(c); + return c; +@@ -642,9 +648,17 @@ struct composite_context *smb_composite_sesssetup_send(struct smbcli_session *se + + /* see what session setup interface we will use */ + if (session->transport->negotiate.protocol < PROTOCOL_NT1) { ++ if (krb5_state == CRED_MUST_USE_KERBEROS) { ++ composite_error(c, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT); ++ return c; ++ } + status = session_setup_old(c, session, io, &state->req); + } else if (!session->transport->options.use_spnego || + !(io->in.capabilities & CAP_EXTENDED_SECURITY)) { ++ if (krb5_state == CRED_MUST_USE_KERBEROS) { ++ composite_error(c, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT); ++ return c; ++ } + status = session_setup_nt1(c, session, io, &state->req); + } else { + struct tevent_req *subreq = NULL; +-- +2.23.0 + diff --git a/backport-0000-CVE-2020-25718-simplify.patch b/backport-0000-CVE-2020-25718-simplify.patch new file mode 100644 index 0000000..7b9ff3b --- /dev/null +++ b/backport-0000-CVE-2020-25718-simplify.patch @@ -0,0 +1,110 @@ +From 6f4ebdc95e40eaedc850604327a57730f35232e5 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Tue, 8 Dec 2020 22:00:55 +1300 +Subject: [PATCH 001/284] CVE-2020-25718 ldb/attrib_handler casefold: simplify + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=6f4ebdc95e40eaedc850604327a57730f35232e5 + + space dropping + +As seen in CVE-2021-20277, ldb_handler_fold() has been making mistakes +when collapsing spaces down to a single space. + +This patch fixes the way it handles internal spaces (CVE-2021-20277 +was about leading spaces), and involves a rewrite of the parsing loop. + +The bug has a detailed description of the problem. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14656 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Autobuild-User(master): Andrew Bartlett +Autobuild-Date(master): Wed Apr 7 03:16:39 UTC 2021 on sn-devel-184 + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 + +(cherry picked from commit 24ddc1ca9cad95673bdd8023d99867707b37085f) +--- + lib/ldb/common/attrib_handlers.c | 53 +++++++++++++++----------------- + 1 files changed, 25 insertions(+), 28 deletions(-) + +diff --git a/lib/ldb/common/attrib_handlers.c b/lib/ldb/common/attrib_handlers.c +index c6ef5ad477b0..f0fd4f50d8df 100644 +--- a/lib/ldb/common/attrib_handlers.c ++++ b/lib/ldb/common/attrib_handlers.c +@@ -54,8 +54,8 @@ int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx, + int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out) + { +- char *s, *t; +- size_t l; ++ char *s, *t, *start; ++ bool in_space; + + if (!in || !out || !(in->data)) { + return -1; +@@ -67,36 +67,33 @@ int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx, + return -1; + } + +- s = (char *)(out->data); +- +- /* remove trailing spaces if any */ +- l = strlen(s); +- while (l > 0 && s[l - 1] == ' ') l--; +- s[l] = '\0'; +- +- /* remove leading spaces if any */ +- if (*s == ' ') { +- for (t = s; *s == ' '; s++, l--) ; +- +- /* remove leading spaces by moving down the string */ +- memmove(t, s, l); +- +- s = t; ++ start = (char *)(out->data); ++ in_space = true; ++ t = start; ++ for (s = start; *s != '\0'; s++) { ++ if (*s == ' ') { ++ if (in_space) { ++ /* ++ * We already have one (or this is the start) ++ * and we don't want to add more ++ */ ++ continue; ++ } ++ in_space = true; ++ } else { ++ in_space = false; ++ } ++ *t = *s; ++ t++; + } + +- /* check middle spaces */ +- while ((t = strchr(s, ' ')) != NULL) { +- for (s = t; *s == ' '; s++) ; +- +- if ((s - t) > 1) { +- l = strlen(s); +- +- /* remove all spaces but one by moving down the string */ +- memmove(t + 1, s, l); +- } ++ if (in_space && t != start) { ++ /* the loop will have left a single trailing space */ ++ t--; + } ++ *t = '\0'; + +- out->length = strlen((char *)out->data); ++ out->length = t - start; + return 0; + } + +-- +2.25.1 diff --git a/backport-0000-CVE-2020-25719-mit-samba-Make-ks_get_principal-inter.patch b/backport-0000-CVE-2020-25719-mit-samba-Make-ks_get_principal-inter.patch new file mode 100644 index 0000000..a31bf14 --- /dev/null +++ b/backport-0000-CVE-2020-25719-mit-samba-Make-ks_get_principal-inter.patch @@ -0,0 +1,57 @@ +From 4754bf4daf3ca5e9809a8a9d538d8ae38c9ef344 Mon Sep 17 00:00:00 2001 +From: Andreas Schneider +Date: Mon, 12 Jul 2021 12:32:12 +0200 +Subject: [PATCH 200/266] CVE-2020-25719 mit-samba: Make ks_get_principal() + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=4754bf4daf3ca5e9809a8a9d538d8ae38c9ef344 + + internally public + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 + +Signed-off-by: Andreas Schneider +Reviewed-by: Andrew Bartlett +--- + source4/kdc/mit-kdb/kdb_samba.h | 5 +++++ + source4/kdc/mit-kdb/kdb_samba_principals.c | 8 ++++---- + 2 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/source4/kdc/mit-kdb/kdb_samba.h b/source4/kdc/mit-kdb/kdb_samba.h +index ad4f6e27573..132dcfed363 100644 +--- a/source4/kdc/mit-kdb/kdb_samba.h ++++ b/source4/kdc/mit-kdb/kdb_samba.h +@@ -41,6 +41,11 @@ + + struct mit_samba_context *ks_get_context(krb5_context kcontext); + ++krb5_error_code ks_get_principal(krb5_context context, ++ krb5_const_principal principal, ++ unsigned int kflags, ++ krb5_db_entry **kentry); ++ + bool ks_data_eq_string(krb5_data d, const char *s); + + krb5_data ks_make_data(void *data, unsigned int len); +diff --git a/source4/kdc/mit-kdb/kdb_samba_principals.c b/source4/kdc/mit-kdb/kdb_samba_principals.c +index 8b67436dc47..79219e5a274 100644 +--- a/source4/kdc/mit-kdb/kdb_samba_principals.c ++++ b/source4/kdc/mit-kdb/kdb_samba_principals.c +@@ -33,10 +33,10 @@ + #define ADMIN_LIFETIME 60*60*3 /* 3 hours */ + #define CHANGEPW_LIFETIME 60*5 /* 5 minutes */ + +-static krb5_error_code ks_get_principal(krb5_context context, +- krb5_const_principal principal, +- unsigned int kflags, +- krb5_db_entry **kentry) ++krb5_error_code ks_get_principal(krb5_context context, ++ krb5_const_principal principal, ++ unsigned int kflags, ++ krb5_db_entry **kentry) + { + struct mit_samba_context *mit_ctx; + krb5_error_code code; +-- +2.23.0 + diff --git a/backport-0000-CVE-2020-25721-krb5pac-Add-new-buffers-for-samAccoun.patch b/backport-0000-CVE-2020-25721-krb5pac-Add-new-buffers-for-samAccoun.patch new file mode 100644 index 0000000..323f43c --- /dev/null +++ b/backport-0000-CVE-2020-25721-krb5pac-Add-new-buffers-for-samAccoun.patch @@ -0,0 +1,90 @@ +From 52a505512a2b7d077a4b458a77094c2d2ff72e5e Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 27 Sep 2021 11:20:19 +1300 +Subject: [PATCH 081/266] CVE-2020-25721 krb5pac: Add new buffers for + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=52a505512a2b7d077a4b458a77094c2d2ff72e5e + + samAccountName and objectSID + +These appear when PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID is set. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14835 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton +--- + librpc/idl/krb5pac.idl | 18 ++++++++++++++++-- + librpc/ndr/ndr_krb5pac.c | 4 ++-- + 2 files changed, 18 insertions(+), 4 deletions(-) + +diff --git a/librpc/idl/krb5pac.idl b/librpc/idl/krb5pac.idl +index 515150ab9cd..ed488dee425 100644 +--- a/librpc/idl/krb5pac.idl ++++ b/librpc/idl/krb5pac.idl +@@ -86,15 +86,29 @@ interface krb5pac + } PAC_CONSTRAINED_DELEGATION; + + typedef [bitmap32bit] bitmap { +- PAC_UPN_DNS_FLAG_CONSTRUCTED = 0x00000001 ++ PAC_UPN_DNS_FLAG_CONSTRUCTED = 0x00000001, ++ PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID = 0x00000002 + } PAC_UPN_DNS_FLAGS; + ++ typedef struct { ++ [value(2*strlen_m(samaccountname))] uint16 samaccountname_size; ++ [relative_short,subcontext(0),subcontext_size(samaccountname_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *samaccountname; ++ [value(ndr_size_dom_sid(objectsid, ndr->flags))] uint16 objectsid_size; ++ [relative_short,subcontext(0),subcontext_size(objectsid_size)] dom_sid *objectsid; ++ } PAC_UPN_DNS_INFO_SAM_NAME_AND_SID; ++ ++ typedef [nodiscriminant] union { ++ [case(PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID)] PAC_UPN_DNS_INFO_SAM_NAME_AND_SID sam_name_and_sid; ++ [default]; ++ } PAC_UPN_DNS_INFO_EX; ++ + typedef struct { + [value(2*strlen_m(upn_name))] uint16 upn_name_size; + [relative_short,subcontext(0),subcontext_size(upn_name_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *upn_name; + [value(2*strlen_m(dns_domain_name))] uint16 dns_domain_name_size; + [relative_short,subcontext(0),subcontext_size(dns_domain_name_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *dns_domain_name; + PAC_UPN_DNS_FLAGS flags; ++ [switch_is(flags & PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID)] PAC_UPN_DNS_INFO_EX ex; + } PAC_UPN_DNS_INFO; + + typedef [public] struct { +@@ -142,7 +156,7 @@ interface krb5pac + + typedef [public,nopush,nopull] struct { + PAC_TYPE type; +- [value(_ndr_size_PAC_INFO(info, type, 0))] uint32 _ndr_size; ++ [value(_ndr_size_PAC_INFO(info, type, LIBNDR_FLAG_ALIGN8))] uint32 _ndr_size; + /* + * We need to have two subcontexts to get the padding right, + * the outer subcontext uses NDR_ROUND(_ndr_size, 8), while +diff --git a/librpc/ndr/ndr_krb5pac.c b/librpc/ndr/ndr_krb5pac.c +index a9ae2c4a789..57b28df9e52 100644 +--- a/librpc/ndr/ndr_krb5pac.c ++++ b/librpc/ndr/ndr_krb5pac.c +@@ -41,7 +41,7 @@ enum ndr_err_code ndr_push_PAC_BUFFER(struct ndr_push *ndr, int ndr_flags, const + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_PAC_TYPE(ndr, NDR_SCALARS, r->type)); +- NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, _ndr_size_PAC_INFO(r->info,r->type,0))); ++ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, _ndr_size_PAC_INFO(r->info,r->type,LIBNDR_FLAG_ALIGN8))); + { + uint32_t _flags_save_PAC_INFO = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8); +@@ -59,7 +59,7 @@ enum ndr_err_code ndr_push_PAC_BUFFER(struct ndr_push *ndr, int ndr_flags, const + { + struct ndr_push *_ndr_info_pad; + struct ndr_push *_ndr_info; +- size_t _ndr_size = _ndr_size_PAC_INFO(r->info, r->type, 0); ++ size_t _ndr_size = _ndr_size_PAC_INFO(r->info, r->type, LIBNDR_FLAG_ALIGN8); + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info_pad, 0, NDR_ROUND(_ndr_size, 8))); + NDR_CHECK(ndr_push_subcontext_start(_ndr_info_pad, &_ndr_info, 0, _ndr_size)); + NDR_CHECK(ndr_push_set_switch_value(_ndr_info, r->info, r->type)); +-- +2.23.0 + diff --git a/backport-0000-CVE-2021-3738-s4-torture-drsuapi-maintain-priv-admin.patch b/backport-0000-CVE-2021-3738-s4-torture-drsuapi-maintain-priv-admin.patch new file mode 100644 index 0000000..805aab8 --- /dev/null +++ b/backport-0000-CVE-2021-3738-s4-torture-drsuapi-maintain-priv-admin.patch @@ -0,0 +1,61 @@ +From ec1ea05e8f1dcca14ed7a92a0645da9ff73f33d3 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 5 Aug 2021 10:34:06 +0200 +Subject: [PATCH 258/266] CVE-2021-3738 s4:torture/drsuapi: maintain + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=ec1ea05e8f1dcca14ed7a92a0645da9ff73f33d3 + + priv->admin_credentials + +This will be used in the next commits. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14468 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org Backported from patch for master to use + the older popt functions as master has the new common command + line handling] +--- + source4/torture/rpc/drsuapi.c | 3 +++ + source4/torture/rpc/drsuapi.h | 1 + + 2 files changed, 4 insertions(+) + +diff --git a/source4/torture/rpc/drsuapi.c b/source4/torture/rpc/drsuapi.c +index 1cd595e5d8e..3e8105af07b 100644 +--- a/source4/torture/rpc/drsuapi.c ++++ b/source4/torture/rpc/drsuapi.c +@@ -22,6 +22,7 @@ + */ + + #include "includes.h" ++#include "lib/cmdline/popt_common.h" + #include "librpc/gen_ndr/ndr_drsuapi_c.h" + #include "torture/rpc/torture_rpc.h" + #include "param/param.h" +@@ -777,6 +778,8 @@ bool torture_drsuapi_tcase_setup_common(struct torture_context *tctx, struct DsP + + torture_assert(tctx, priv, "Invalid argument"); + ++ priv->admin_credentials = popt_get_cmdline_credentials(); ++ + torture_comment(tctx, "Create DRSUAPI pipe\n"); + status = torture_rpc_connection(tctx, + &priv->drs_pipe, +diff --git a/source4/torture/rpc/drsuapi.h b/source4/torture/rpc/drsuapi.h +index f327c54cda4..3cc4be49d99 100644 +--- a/source4/torture/rpc/drsuapi.h ++++ b/source4/torture/rpc/drsuapi.h +@@ -27,6 +27,7 @@ + * Data structure common for most of DRSUAPI tests + */ + struct DsPrivate { ++ struct cli_credentials *admin_credentials; + struct dcerpc_pipe *drs_pipe; + struct policy_handle bind_handle; + struct GUID bind_guid; +-- +2.23.0 + diff --git a/backport-0001-CVE-2016-2124-s3-libsmb-don-t-fallback-to-non-spnego.patch b/backport-0001-CVE-2016-2124-s3-libsmb-don-t-fallback-to-non-spnego.patch new file mode 100644 index 0000000..1b52297 --- /dev/null +++ b/backport-0001-CVE-2016-2124-s3-libsmb-don-t-fallback-to-non-spnego.patch @@ -0,0 +1,50 @@ +From 721e40dd379a85e153c31b294d1054eeb3718aa0 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 27 Oct 2016 10:40:28 +0200 +Subject: [PATCH 255/266] CVE-2016-2124: s3:libsmb: don't fallback to non + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=721e40dd379a85e153c31b294d1054eeb3718aa0 + + spnego authentication if we require kerberos + +We should not send NTLM[v2] nor plaintext data on the wire if the user +asked for kerberos only. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=12444 + +Signed-off-by: Stefan Metzmacher +--- + source3/libsmb/cliconnect.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c +index 1fb1f0127b9..a79abfaf157 100644 +--- a/source3/libsmb/cliconnect.c ++++ b/source3/libsmb/cliconnect.c +@@ -1443,6 +1443,8 @@ struct tevent_req *cli_session_setup_creds_send(TALLOC_CTX *mem_ctx, + uint32_t in_sess_key = 0; + const char *in_native_os = NULL; + const char *in_native_lm = NULL; ++ krb5_state = ++ cli_credentials_get_kerberos_state(creds); + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, +@@ -1484,6 +1486,13 @@ struct tevent_req *cli_session_setup_creds_send(TALLOC_CTX *mem_ctx, + return req; + } + ++ if (krb5_state == CRED_MUST_USE_KERBEROS) { ++ DBG_WARNING("Kerberos authentication requested, but " ++ "the server does not support SPNEGO authentication\n"); ++ tevent_req_nterror(req, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT); ++ return tevent_req_post(req, ev); ++ } ++ + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN1) { + /* + * SessionSetupAndX was introduced by LANMAN 1.0. So we skip +-- +2.23.0 + diff --git a/backport-0001-CVE-2020-25717-winbindd-add-generic-wb_parent_idmap_.patch b/backport-0001-CVE-2020-25717-winbindd-add-generic-wb_parent_idmap_.patch new file mode 100644 index 0000000..ac5b545 --- /dev/null +++ b/backport-0001-CVE-2020-25717-winbindd-add-generic-wb_parent_idmap_.patch @@ -0,0 +1,411 @@ +From f3957ca5ce206e1224874e6495780b5130d6de0c Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 11 Sep 2020 12:16:00 +0200 +Subject: [PATCH 011/266] CVE-2020-25717 winbindd: add generic + wb_parent_idmap_setup_send/recv() helpers + +This is more or less a copy of wb_xids2sids_init_dom_maps_send/recv, +but it's more generic and doesn't imply global state. + +It also closes a initialization race by using a tevent_queue to +serialize the calls. + +In the next commits we'll replace wb_xids2sids_init_dom_maps_send/recv. + +We'll also use the new function in the wb_sids2xids code. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Gary Lockyer + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit 209e81a2ea8c972ee57e2f0c9579da843c0e2ac7) +--- + source3/winbindd/winbindd.h | 13 ++ + source3/winbindd/winbindd_idmap.c | 314 ++++++++++++++++++++++++++++++ + source3/winbindd/winbindd_proto.h | 5 + + 3 files changed, 332 insertions(+) + +Conflict:bool is_idmap_child(const struct winbindd_child *child); --> struct dcerpc_binding_handle *idmap_child_handle(void); +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=f3957ca5ce206e1224874e6495780b5130d6de0c + +diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h +index a72d6aa7830..480ba4f1282 100644 +--- a/source3/winbindd/winbindd.h ++++ b/source3/winbindd/winbindd.h +@@ -189,6 +189,19 @@ struct winbindd_domain { + struct winbindd_domain *prev, *next; + }; + ++struct wb_parent_idmap_config_dom { ++ unsigned low_id; ++ unsigned high_id; ++ const char *name; ++ struct dom_sid sid; ++}; ++ ++struct wb_parent_idmap_config { ++ struct tevent_queue *queue; ++ uint32_t num_doms; ++ struct wb_parent_idmap_config_dom *doms; ++}; ++ + struct wb_acct_info { + const char *acct_name; /* account name */ + const char *acct_desc; /* account name */ +diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c +index bd5f3a67aad..487f27fd94d 100644 +--- a/source3/winbindd/winbindd_idmap.c ++++ b/source3/winbindd/winbindd_idmap.c +@@ -23,12 +23,21 @@ + + #include "includes.h" + #include "winbindd.h" ++#include "../libcli/security/security.h" ++#include "passdb/lookup_sid.h" + + #undef DBGC_CLASS + #define DBGC_CLASS DBGC_WINBIND + + static struct winbindd_child static_idmap_child; + ++/* ++ * Map idmap ranges to domain names, taken from smb.conf. This is ++ * stored in the parent winbind and used to assemble xids2sids/sids2xids calls ++ * into per-idmap-domain chunks. ++ */ ++static struct wb_parent_idmap_config static_parent_idmap_config; ++ + struct winbindd_child *idmap_child(void) + { + return &static_idmap_child; +@@ -73,3 +82,308 @@ void init_idmap_child(void) + idmap_dispatch_table, + "log.winbindd", "idmap"); + } ++ ++struct wb_parent_idmap_setup_state { ++ struct tevent_context *ev; ++ struct wb_parent_idmap_config *cfg; ++ size_t dom_idx; ++}; ++ ++static void wb_parent_idmap_setup_cleanup(struct tevent_req *req, ++ enum tevent_req_state req_state) ++{ ++ struct wb_parent_idmap_setup_state *state = ++ tevent_req_data(req, ++ struct wb_parent_idmap_setup_state); ++ ++ if (req_state == TEVENT_REQ_DONE) { ++ state->cfg = NULL; ++ return; ++ } ++ ++ if (state->cfg == NULL) { ++ return; ++ } ++ ++ state->cfg->num_doms = 0; ++ TALLOC_FREE(state->cfg->doms); ++ state->cfg = NULL; ++} ++ ++static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq); ++static bool wb_parent_idmap_setup_scan_config(const char *domname, ++ void *private_data); ++static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req); ++static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq); ++ ++struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev) ++{ ++ struct tevent_req *req = NULL; ++ struct wb_parent_idmap_setup_state *state = NULL; ++ struct tevent_req *subreq = NULL; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct wb_parent_idmap_setup_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ *state = (struct wb_parent_idmap_setup_state) { ++ .ev = ev, ++ .cfg = &static_parent_idmap_config, ++ .dom_idx = 0, ++ }; ++ ++ if (state->cfg->queue == NULL) { ++ state->cfg->queue = tevent_queue_create(NULL, ++ "wb_parent_idmap_config_queue"); ++ if (tevent_req_nomem(state->cfg->queue, req)) { ++ return tevent_req_post(req, ev); ++ } ++ } ++ ++ subreq = tevent_queue_wait_send(state, state->ev, state->cfg->queue); ++ if (tevent_req_nomem(subreq, req)) { ++ return tevent_req_post(req, ev); ++ } ++ tevent_req_set_callback(subreq, ++ wb_parent_idmap_setup_queue_wait_done, ++ req); ++ ++ return req; ++} ++ ++static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = ++ tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct wb_parent_idmap_setup_state *state = ++ tevent_req_data(req, ++ struct wb_parent_idmap_setup_state); ++ bool ok; ++ ++ /* ++ * Note we don't call TALLOC_FREE(subreq) here in order to block the ++ * queue until tevent_req_received() in wb_parent_idmap_setup_recv() ++ * will destroy it implicitly. ++ */ ++ ok = tevent_queue_wait_recv(subreq); ++ if (!ok) { ++ DBG_ERR("tevent_queue_wait_recv() failed\n"); ++ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); ++ return; ++ } ++ ++ if (state->cfg->num_doms != 0) { ++ /* ++ * If we're not the first one we're done. ++ */ ++ tevent_req_done(req); ++ return; ++ } ++ ++ /* ++ * From this point we start changing state->cfg, ++ * which is &static_parent_idmap_config, ++ * so we better setup a cleanup function ++ * to undo the changes on failure. ++ */ ++ tevent_req_set_cleanup_fn(req, wb_parent_idmap_setup_cleanup); ++ ++ /* ++ * Put the passdb idmap domain first. We always need to try ++ * there first. ++ */ ++ state->cfg->doms = talloc_zero_array(NULL, ++ struct wb_parent_idmap_config_dom, ++ 1); ++ if (tevent_req_nomem(state->cfg->doms, req)) { ++ return; ++ } ++ state->cfg->doms[0].low_id = 0; ++ state->cfg->doms[0].high_id = UINT_MAX; ++ state->cfg->doms[0].name = talloc_strdup(state->cfg->doms, ++ get_global_sam_name()); ++ if (tevent_req_nomem(state->cfg->doms[0].name, req)) { ++ return; ++ } ++ state->cfg->num_doms += 1; ++ ++ lp_scan_idmap_domains(wb_parent_idmap_setup_scan_config, req); ++ if (!tevent_req_is_in_progress(req)) { ++ return; ++ } ++ ++ wb_parent_idmap_setup_lookupname_next(req); ++} ++ ++static bool wb_parent_idmap_setup_scan_config(const char *domname, ++ void *private_data) ++{ ++ struct tevent_req *req = ++ talloc_get_type_abort(private_data, ++ struct tevent_req); ++ struct wb_parent_idmap_setup_state *state = ++ tevent_req_data(req, ++ struct wb_parent_idmap_setup_state); ++ struct wb_parent_idmap_config_dom *map = NULL; ++ size_t i; ++ const char *range; ++ unsigned low_id, high_id; ++ int ret; ++ ++ range = idmap_config_const_string(domname, "range", NULL); ++ if (range == NULL) { ++ DBG_DEBUG("No range for domain %s found\n", domname); ++ return false; ++ } ++ ++ ret = sscanf(range, "%u - %u", &low_id, &high_id); ++ if (ret != 2) { ++ DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n", ++ range, domname); ++ return false; ++ } ++ ++ if (low_id > high_id) { ++ DBG_DEBUG("Invalid range %u - %u for domain %s\n", ++ low_id, high_id, domname); ++ return false; ++ } ++ ++ for (i=0; icfg->num_doms; i++) { ++ if (strequal(domname, state->cfg->doms[i].name)) { ++ map = &state->cfg->doms[i]; ++ break; ++ } ++ } ++ ++ if (map == NULL) { ++ struct wb_parent_idmap_config_dom *tmp; ++ char *name; ++ ++ name = talloc_strdup(state, domname); ++ if (name == NULL) { ++ DBG_ERR("talloc failed\n"); ++ return false; ++ } ++ ++ tmp = talloc_realloc( ++ NULL, state->cfg->doms, struct wb_parent_idmap_config_dom, ++ state->cfg->num_doms+1); ++ if (tmp == NULL) { ++ DBG_ERR("talloc failed\n"); ++ return false; ++ } ++ state->cfg->doms = tmp; ++ ++ map = &state->cfg->doms[state->cfg->num_doms]; ++ state->cfg->num_doms += 1; ++ ZERO_STRUCTP(map); ++ map->name = talloc_move(state->cfg->doms, &name); ++ } ++ ++ map->low_id = low_id; ++ map->high_id = high_id; ++ ++ return false; ++} ++ ++static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req) ++{ ++ struct wb_parent_idmap_setup_state *state = ++ tevent_req_data(req, ++ struct wb_parent_idmap_setup_state); ++ struct wb_parent_idmap_config_dom *dom = ++ &state->cfg->doms[state->dom_idx]; ++ struct tevent_req *subreq = NULL; ++ ++ next_domain: ++ if (state->dom_idx == state->cfg->num_doms) { ++ tevent_req_done(req); ++ return; ++ } ++ ++ if (strequal(dom->name, "*")) { ++ state->dom_idx++; ++ goto next_domain; ++ } ++ ++ subreq = wb_lookupname_send(state, ++ state->ev, ++ dom->name, ++ dom->name, ++ "", ++ LOOKUP_NAME_NO_NSS); ++ if (tevent_req_nomem(subreq, req)) { ++ return; ++ } ++ tevent_req_set_callback(subreq, ++ wb_parent_idmap_setup_lookupname_done, ++ req); ++} ++ ++static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = ++ tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct wb_parent_idmap_setup_state *state = ++ tevent_req_data(req, ++ struct wb_parent_idmap_setup_state); ++ struct wb_parent_idmap_config_dom *dom = ++ &state->cfg->doms[state->dom_idx]; ++ enum lsa_SidType type; ++ NTSTATUS status; ++ ++ status = wb_lookupname_recv(subreq, &dom->sid, &type); ++ TALLOC_FREE(subreq); ++ if (!NT_STATUS_IS_OK(status)) { ++ DBG_ERR("Lookup domain name '%s' failed '%s'\n", ++ dom->name, ++ nt_errstr(status)); ++ ++ state->dom_idx++; ++ wb_parent_idmap_setup_lookupname_next(req); ++ return; ++ } ++ ++ if (type != SID_NAME_DOMAIN) { ++ struct dom_sid_buf buf; ++ ++ DBG_ERR("SID %s for idmap domain name '%s' " ++ "not a domain SID\n", ++ dom_sid_str_buf(&dom->sid, &buf), ++ dom->name); ++ ++ ZERO_STRUCT(dom->sid); ++ } ++ ++ state->dom_idx++; ++ wb_parent_idmap_setup_lookupname_next(req); ++ ++ return; ++} ++ ++NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req, ++ const struct wb_parent_idmap_config **_cfg) ++{ ++ const struct wb_parent_idmap_config *cfg = &static_parent_idmap_config; ++ NTSTATUS status; ++ ++ *_cfg = NULL; ++ ++ if (tevent_req_is_nterror(req, &status)) { ++ tevent_req_received(req); ++ return status; ++ } ++ ++ /* ++ * Note state->cfg is already set to NULL by ++ * wb_parent_idmap_setup_cleanup() ++ */ ++ *_cfg = cfg; ++ tevent_req_received(req); ++ return NT_STATUS_OK; ++} +diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h +index 97c38018aac..8923bb3124f 100644 +--- a/source3/winbindd/winbindd_proto.h ++++ b/source3/winbindd/winbindd_proto.h +@@ -364,6 +364,11 @@ NTSTATUS winbindd_print_groupmembers(struct db_context *members, + + /* The following definitions come from winbindd/winbindd_idmap.c */ + ++struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev); ++NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req, ++ const struct wb_parent_idmap_config **_cfg); ++ + void init_idmap_child(void); + struct winbindd_child *idmap_child(void); + struct dcerpc_binding_handle *idmap_child_handle(void); +-- +2.23.0 + diff --git a/backport-0001-CVE-2020-25718-trailing-chunk-must-match.patch b/backport-0001-CVE-2020-25718-trailing-chunk-must-match.patch new file mode 100644 index 0000000..44c647f --- /dev/null +++ b/backport-0001-CVE-2020-25718-trailing-chunk-must-match.patch @@ -0,0 +1,144 @@ +From 84998f4d717de484c510594e00fd0a6f07babf1c Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 3 Mar 2021 19:17:36 +1300 +Subject: [PATCH 002/284] CVE-2020-25718 ldb_match: trailing chunk must match + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=84998f4d717de484c510594e00fd0a6f07babf1c + + end of string +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A wildcard search is divided into chunks by the asterisks. While most +chunks match the first suitable string, the last chunk matches the +last possible string (unless there is a trailing asterisk, in which +case this distinction is moot). + +We always knew this in our hearts, but we tried to do it in a funny +complicated way that stepped through the string, comparing here and +there, leading to CVE-2019-3824 and missed matches (bug 14044). + +With this patch, we just jump to the end of the string and compare it. +As well as being correct, this should also improve performance, as the +previous algorithm involved a quadratic loop of erroneous memmem()s. + +See https://tools.ietf.org/html/rfc4517 + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14044 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Bj枚rn Jacke +Reviewed-by: Andrew Bartlett + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 + +(cherry picked from commit cc098f1cad04b2cfec4ddd6b2511cd5a600f31c6) +--- + lib/ldb/common/ldb_match.c | 80 +++++++++++++++++--------------------- + 1 file changed, 35 insertions(+), 45 deletions(-) + +diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c +index 829afa77e716..da595615bd94 100644 +--- a/lib/ldb/common/ldb_match.c ++++ b/lib/ldb/common/ldb_match.c +@@ -295,8 +295,9 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, + uint8_t *p; + + chunk = tree->u.substring.chunks[c]; +- if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch; +- ++ if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) { ++ goto mismatch; ++ } + /* + * Empty strings are returned as length 0. Ensure + * we can cope with this. +@@ -304,52 +305,41 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, + if (cnk.length == 0) { + goto mismatch; + } +- /* +- * Values might be binary blobs. Don't use string +- * search, but memory search instead. +- */ +- p = memmem((const void *)val.data,val.length, +- (const void *)cnk.data, cnk.length); +- if (p == NULL) goto mismatch; +- +- /* +- * At this point we know cnk.length <= val.length as +- * otherwise there could be no match +- */ ++ if (cnk.length > val.length) { ++ goto mismatch; ++ } + +- if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) { +- uint8_t *g; +- uint8_t *end = val.data + val.length; +- do { /* greedy */ +- +- /* +- * haystack is a valid pointer in val +- * because the memmem() can only +- * succeed if the needle (cnk.length) +- * is <= haystacklen +- * +- * p will be a pointer at least +- * cnk.length from the end of haystack +- */ +- uint8_t *haystack +- = p + cnk.length; +- size_t haystacklen +- = end - (haystack); +- +- g = memmem(haystack, +- haystacklen, +- (const uint8_t *)cnk.data, +- cnk.length); +- if (g) { +- p = g; +- } +- } while(g); ++ if ( (tree->u.substring.chunks[c + 1]) == NULL && ++ (! tree->u.substring.end_with_wildcard) ) { ++ /* ++ * The last bit, after all the asterisks, must match ++ * exactly the last bit of the string. ++ */ ++ int cmp; ++ p = val.data + val.length - cnk.length; ++ cmp = memcmp(p, ++ cnk.data, ++ cnk.length); ++ if (cmp != 0) { ++ goto mismatch; ++ } ++ } else { ++ /* ++ * Values might be binary blobs. Don't use string ++ * search, but memory search instead. ++ */ ++ p = memmem((const void *)val.data, val.length, ++ (const void *)cnk.data, cnk.length); ++ if (p == NULL) { ++ goto mismatch; ++ } ++ /* move val to the end of the match */ ++ p += cnk.length; ++ val.length -= (p - val.data); ++ val.data = p; + } +- val.length = val.length - (p - (uint8_t *)(val.data)) - cnk.length; +- val.data = (uint8_t *)(p + cnk.length); + c++; +- talloc_free(cnk.data); +- cnk.data = NULL; ++ TALLOC_FREE(cnk.data); + } + + /* last chunk may not have reached end of string */ +-- +2.25.1 diff --git a/backport-0001-CVE-2020-25719-mit-samba-Add-ks_free_principal.patch b/backport-0001-CVE-2020-25719-mit-samba-Add-ks_free_principal.patch new file mode 100644 index 0000000..183c98f --- /dev/null +++ b/backport-0001-CVE-2020-25719-mit-samba-Add-ks_free_principal.patch @@ -0,0 +1,101 @@ +From 9902f1b0bf30b663a457230d3b3dcd92fd279879 Mon Sep 17 00:00:00 2001 +From: Andreas Schneider +Date: Wed, 14 Jul 2021 14:51:34 +0200 +Subject: [PATCH 201/266] CVE-2020-25719 mit-samba: Add ks_free_principal() + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=9902f1b0bf30b663a457230d3b3dcd92fd279879 + + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 + +[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 +Reviewed-by: Douglas Bagnall +--- + source4/kdc/mit-kdb/kdb_samba.h | 2 + + source4/kdc/mit-kdb/kdb_samba_principals.c | 52 ++++++++++++++++++++++ + 2 files changed, 54 insertions(+) + +diff --git a/source4/kdc/mit-kdb/kdb_samba.h b/source4/kdc/mit-kdb/kdb_samba.h +index 132dcfed363..2ff8642cc50 100644 +--- a/source4/kdc/mit-kdb/kdb_samba.h ++++ b/source4/kdc/mit-kdb/kdb_samba.h +@@ -46,6 +46,8 @@ krb5_error_code ks_get_principal(krb5_context context, + unsigned int kflags, + krb5_db_entry **kentry); + ++void ks_free_principal(krb5_context context, krb5_db_entry *entry); ++ + bool ks_data_eq_string(krb5_data d, const char *s); + + krb5_data ks_make_data(void *data, unsigned int len); +diff --git a/source4/kdc/mit-kdb/kdb_samba_principals.c b/source4/kdc/mit-kdb/kdb_samba_principals.c +index 79219e5a274..cc67c2392be 100644 +--- a/source4/kdc/mit-kdb/kdb_samba_principals.c ++++ b/source4/kdc/mit-kdb/kdb_samba_principals.c +@@ -59,6 +59,58 @@ cleanup: + return code; + } + ++static void ks_free_principal_e_data(krb5_context context, krb5_octet *e_data) ++{ ++ struct samba_kdc_entry *skdc_entry; ++ ++ skdc_entry = talloc_get_type_abort(e_data, ++ struct samba_kdc_entry); ++ talloc_set_destructor(skdc_entry, NULL); ++ TALLOC_FREE(skdc_entry); ++} ++ ++void ks_free_principal(krb5_context context, krb5_db_entry *entry) ++{ ++ krb5_tl_data *tl_data_next = NULL; ++ krb5_tl_data *tl_data = NULL; ++ size_t i, j; ++ ++ if (entry != NULL) { ++ krb5_free_principal(context, entry->princ); ++ ++ for (tl_data = entry->tl_data; tl_data; tl_data = tl_data_next) { ++ tl_data_next = tl_data->tl_data_next; ++ if (tl_data->tl_data_contents != NULL) { ++ free(tl_data->tl_data_contents); ++ } ++ free(tl_data); ++ } ++ ++ if (entry->key_data != NULL) { ++ for (i = 0; i < entry->n_key_data; i++) { ++ for (j = 0; j < entry->key_data[i].key_data_ver; j++) { ++ if (entry->key_data[i].key_data_length[j] != 0) { ++ if (entry->key_data[i].key_data_contents[j] != NULL) { ++ memset(entry->key_data[i].key_data_contents[j], 0, entry->key_data[i].key_data_length[j]); ++ free(entry->key_data[i].key_data_contents[j]); ++ } ++ } ++ entry->key_data[i].key_data_contents[j] = NULL; ++ entry->key_data[i].key_data_length[j] = 0; ++ entry->key_data[i].key_data_type[j] = 0; ++ } ++ } ++ free(entry->key_data); ++ } ++ ++ if (entry->e_data) { ++ ks_free_principal_e_data(context, entry->e_data); ++ } ++ ++ free(entry); ++ } ++} ++ + static krb5_boolean ks_is_master_key_principal(krb5_context context, + krb5_const_principal princ) + { +-- +2.23.0 + diff --git a/backport-0001-CVE-2020-25721-auth-Fill-in-the-new-HAS_SAM_NAME_AND.patch b/backport-0001-CVE-2020-25721-auth-Fill-in-the-new-HAS_SAM_NAME_AND.patch new file mode 100644 index 0000000..4b7e401 --- /dev/null +++ b/backport-0001-CVE-2020-25721-auth-Fill-in-the-new-HAS_SAM_NAME_AND.patch @@ -0,0 +1,43 @@ +From c59f5762ead77bcf9add3994a88a6d2b8e383869 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 27 Sep 2021 12:10:02 +1300 +Subject: [PATCH 227/266] CVE-2020-25721 auth: Fill in the new + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=c59f5762ead77bcf9add3994a88a6d2b8e383869 + + HAS_SAM_NAME_AND_SID values + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14835 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton +--- + python/samba/tests/krb5/s4u_tests.py | 2 -- + selftest/knownfail_heimdal_kdc | 10 ---------- + selftest/knownfail_mit_kdc | 4 ---- + source4/kdc/pac-glue.c | 8 ++++++++ + 4 files changed, 8 insertions(+), 16 deletions(-) + +diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c +index cb0a923fc2d..95f71c04b23 100644 +--- a/source4/kdc/pac-glue.c ++++ b/source4/kdc/pac-glue.c +@@ -101,6 +101,14 @@ NTSTATUS samba_get_upn_info_pac_blob(TALLOC_CTX *mem_ctx, + pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_CONSTRUCTED; + } + ++ pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID; ++ ++ pac_upn.upn_dns_info.ex.sam_name_and_sid.samaccountname ++ = info->info->account_name; ++ ++ pac_upn.upn_dns_info.ex.sam_name_and_sid.objectsid ++ = &info->sids[0]; ++ + ndr_err = ndr_push_union_blob(upn_data, mem_ctx, &pac_upn, + PAC_TYPE_UPN_DNS_INFO, + (ndr_push_flags_fn_t)ndr_push_PAC_INFO); +-- +2.23.0 + diff --git a/backport-0001-CVE-2020-25722-dsdb-Move-krbtgt-password-setup-after.patch b/backport-0001-CVE-2020-25722-dsdb-Move-krbtgt-password-setup-after.patch new file mode 100644 index 0000000..44a49aa --- /dev/null +++ b/backport-0001-CVE-2020-25722-dsdb-Move-krbtgt-password-setup-after.patch @@ -0,0 +1,149 @@ +From 0c20aa465c4543055fcb38d3e28cefb9ee603f87 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Thu, 12 Aug 2021 11:10:09 +1200 +Subject: [PATCH 056/266] CVE-2020-25722 dsdb: Move krbtgt password setup after + the point of checking if any passwords are changed + +This allows the add of an RODC, before setting the password, to avoid +this module, which helps isolate testing of security around the +msDS-SecondaryKrbTgtNumber attribute. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14703 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/0c20aa465c4543055fcb38d3e28cefb9ee603f87 + +--- + .../dsdb/samdb/ldb_modules/password_hash.c | 106 +++++++++--------- + 1 files changed, 53 insertions(+), 53 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c +index 82d9e8ebd2e..bb437a3b982 100644 +--- a/source4/dsdb/samdb/ldb_modules/password_hash.c ++++ b/source4/dsdb/samdb/ldb_modules/password_hash.c +@@ -2476,6 +2476,59 @@ static int setup_password_fields(struct setup_password_fields_io *io) + return LDB_SUCCESS; + } + ++ if (io->u.is_krbtgt) { ++ size_t min = 196; ++ size_t max = 255; ++ size_t diff = max - min; ++ size_t len = max; ++ struct ldb_val *krbtgt_utf16 = NULL; ++ ++ if (!io->ac->pwd_reset) { ++ return dsdb_module_werror(io->ac->module, ++ LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS, ++ WERR_DS_ATT_ALREADY_EXISTS, ++ "Password change on krbtgt not permitted!"); ++ } ++ ++ if (io->n.cleartext_utf16 == NULL) { ++ return dsdb_module_werror(io->ac->module, ++ LDB_ERR_UNWILLING_TO_PERFORM, ++ WERR_DS_INVALID_ATTRIBUTE_SYNTAX, ++ "Password reset on krbtgt requires UTF16!"); ++ } ++ ++ /* ++ * Instead of taking the callers value, ++ * we just generate a new random value here. ++ * ++ * Include null termination in the array. ++ */ ++ if (diff > 0) { ++ size_t tmp; ++ ++ generate_random_buffer((uint8_t *)&tmp, sizeof(tmp)); ++ ++ tmp %= diff; ++ ++ len = min + tmp; ++ } ++ ++ krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val); ++ if (krbtgt_utf16 == NULL) { ++ return ldb_oom(ldb); ++ } ++ ++ *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16, ++ (len+1)*2); ++ if (krbtgt_utf16->data == NULL) { ++ return ldb_oom(ldb); ++ } ++ krbtgt_utf16->length = len * 2; ++ generate_secret_buffer(krbtgt_utf16->data, ++ krbtgt_utf16->length); ++ io->n.cleartext_utf16 = krbtgt_utf16; ++ } ++ + /* transform the old password (for password changes) */ + ret = setup_given_passwords(io, &io->og); + if (ret != LDB_SUCCESS) { +@@ -3653,59 +3706,6 @@ static int setup_io(struct ph_context *ac, + return ldb_operr(ldb); + } + +- if (io->u.is_krbtgt) { +- size_t min = 196; +- size_t max = 255; +- size_t diff = max - min; +- size_t len = max; +- struct ldb_val *krbtgt_utf16 = NULL; +- +- if (!ac->pwd_reset) { +- return dsdb_module_werror(ac->module, +- LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS, +- WERR_DS_ATT_ALREADY_EXISTS, +- "Password change on krbtgt not permitted!"); +- } +- +- if (io->n.cleartext_utf16 == NULL) { +- return dsdb_module_werror(ac->module, +- LDB_ERR_UNWILLING_TO_PERFORM, +- WERR_DS_INVALID_ATTRIBUTE_SYNTAX, +- "Password reset on krbtgt requires UTF16!"); +- } +- +- /* +- * Instead of taking the callers value, +- * we just generate a new random value here. +- * +- * Include null termination in the array. +- */ +- if (diff > 0) { +- size_t tmp; +- +- generate_random_buffer((uint8_t *)&tmp, sizeof(tmp)); +- +- tmp %= diff; +- +- len = min + tmp; +- } +- +- krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val); +- if (krbtgt_utf16 == NULL) { +- return ldb_oom(ldb); +- } +- +- *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16, +- (len+1)*2); +- if (krbtgt_utf16->data == NULL) { +- return ldb_oom(ldb); +- } +- krbtgt_utf16->length = len * 2; +- generate_secret_buffer(krbtgt_utf16->data, +- krbtgt_utf16->length); +- io->n.cleartext_utf16 = krbtgt_utf16; +- } +- + if (existing_msg != NULL) { + NTSTATUS status; + +-- +2.23.0 + diff --git a/backport-0001-CVE-2021-3738-s4-rpc_server-common-provide-assoc_gro.patch b/backport-0001-CVE-2021-3738-s4-rpc_server-common-provide-assoc_gro.patch new file mode 100644 index 0000000..0a606a6 --- /dev/null +++ b/backport-0001-CVE-2021-3738-s4-rpc_server-common-provide-assoc_gro.patch @@ -0,0 +1,183 @@ +From 7c3b037600077ade1d0ee97f5707e1c5061c1b28 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 5 Aug 2021 14:22:32 +0200 +Subject: [PATCH 261/266] CVE-2021-3738 s4:rpc_server/common: provide + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=7c3b037600077ade1d0ee97f5707e1c5061c1b28 + + assoc_group aware dcesrv_samdb_connect_as_{system,user}() helpers + +We already had dcesrv_samdb_connect_as_system(), but it uses the per +connection memory of auth_session_info and remote_address. + +But in order to use the samdb connection on a per association group +context/policy handle, we need to make copies, which last for the +whole lifetime of the 'samdb' context. + +We need the same logic also for all cases we make use of +the almost same logic where we want to create a samdb context +on behalf of the authenticated user (without allowing system access), +so we introduce dcesrv_samdb_connect_as_user(). + +In the end we need to replace all direct callers to samdb_connect() +from source4/rpc_server. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14468 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source4/rpc_server/common/server_info.c | 121 ++++++++++++++++++++---- + 1 file changed, 105 insertions(+), 16 deletions(-) + +diff --git a/source4/rpc_server/common/server_info.c b/source4/rpc_server/common/server_info.c +index 6e475bcc796..a2af37653ef 100644 +--- a/source4/rpc_server/common/server_info.c ++++ b/source4/rpc_server/common/server_info.c +@@ -28,6 +28,8 @@ + #include "param/param.h" + #include "rpc_server/common/common.h" + #include "libds/common/roles.h" ++#include "auth/auth_util.h" ++#include "lib/tsocket/tsocket.h" + + /* + Here are common server info functions used by some dcerpc server interfaces +@@ -188,30 +190,117 @@ bool dcesrv_common_validate_share_name(TALLOC_CTX *mem_ctx, const char *share_na + return true; + } + +-/* +- * Open an ldb connection under the system session and save the remote users +- * session details in a ldb_opaque. This will allow the audit logging to +- * log the original session for operations performed in the system session. +- */ +-struct ldb_context *dcesrv_samdb_connect_as_system( ++static struct ldb_context *dcesrv_samdb_connect_common( + TALLOC_CTX *mem_ctx, +- struct dcesrv_call_state *dce_call) ++ struct dcesrv_call_state *dce_call, ++ bool as_system) + { + struct ldb_context *samdb = NULL; ++ struct auth_session_info *system_session_info = NULL; ++ const struct auth_session_info *call_session_info = ++ dcesrv_call_session_info(dce_call); ++ struct auth_session_info *user_session_info = NULL; ++ struct auth_session_info *ldb_session_info = NULL; ++ struct auth_session_info *audit_session_info = NULL; ++ struct tsocket_address *remote_address = NULL; ++ ++ if (as_system) { ++ system_session_info = system_session(dce_call->conn->dce_ctx->lp_ctx); ++ if (system_session_info == NULL) { ++ return NULL; ++ } ++ } ++ ++ user_session_info = copy_session_info(mem_ctx, call_session_info); ++ if (user_session_info == NULL) { ++ return NULL; ++ } ++ ++ if (dce_call->conn->remote_address != NULL) { ++ remote_address = tsocket_address_copy(dce_call->conn->remote_address, ++ user_session_info); ++ if (remote_address == NULL) { ++ return NULL; ++ } ++ } ++ ++ if (system_session_info != NULL) { ++ ldb_session_info = system_session_info; ++ audit_session_info = user_session_info; ++ } else { ++ ldb_session_info = user_session_info; ++ audit_session_info = NULL; ++ } ++ ++ /* ++ * We need to make sure every argument ++ * stays arround for the lifetime of 'samdb', ++ * typically it is allocated on the scope of ++ * an assoc group, so we can't reference dce_call->conn, ++ * as the assoc group may stay when the current connection ++ * gets disconnected. ++ * ++ * The following are global per process: ++ * - dce_call->conn->dce_ctx->lp_ctx ++ * - dce_call->event_ctx ++ * - system_session ++ * ++ * We make a copy of: ++ * - dce_call->conn->remote_address ++ * - dce_call->auth_state->session_info ++ */ + samdb = samdb_connect( + mem_ctx, + dce_call->event_ctx, + dce_call->conn->dce_ctx->lp_ctx, +- system_session(dce_call->conn->dce_ctx->lp_ctx), +- dce_call->conn->remote_address, ++ ldb_session_info, ++ remote_address, + 0); +- if (samdb) { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); +- ldb_set_opaque( +- samdb, +- DSDB_NETWORK_SESSION_INFO, +- session_info); ++ if (samdb == NULL) { ++ talloc_free(user_session_info); ++ return NULL; + } ++ talloc_move(samdb, &user_session_info); ++ ++ if (audit_session_info != NULL) { ++ int ret; ++ ++ ret = ldb_set_opaque(samdb, ++ DSDB_NETWORK_SESSION_INFO, ++ audit_session_info); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(samdb); ++ return NULL; ++ } ++ } ++ + return samdb; + } ++ ++/* ++ * Open an ldb connection under the system session and save the remote users ++ * session details in a ldb_opaque. This will allow the audit logging to ++ * log the original session for operations performed in the system session. ++ * ++ * Access checks are required by the caller! ++ */ ++struct ldb_context *dcesrv_samdb_connect_as_system( ++ TALLOC_CTX *mem_ctx, ++ struct dcesrv_call_state *dce_call) ++{ ++ return dcesrv_samdb_connect_common(mem_ctx, dce_call, ++ true /* as_system */); ++} ++ ++/* ++ * Open an ldb connection under the remote users session details. ++ * ++ * Access checks are done at the ldb level. ++ */ ++struct ldb_context *dcesrv_samdb_connect_as_user( ++ TALLOC_CTX *mem_ctx, ++ struct dcesrv_call_state *dce_call) ++{ ++ return dcesrv_samdb_connect_common(mem_ctx, dce_call, ++ false /* not as_system */); ++} +-- +2.23.0 + diff --git a/backport-0002-CVE-2020-25717-wb_xids2sids-make-use-of-the-new-wb_p.patch b/backport-0002-CVE-2020-25717-wb_xids2sids-make-use-of-the-new-wb_p.patch new file mode 100644 index 0000000..259f795 --- /dev/null +++ b/backport-0002-CVE-2020-25717-wb_xids2sids-make-use-of-the-new-wb_p.patch @@ -0,0 +1,362 @@ +From 5e04b985acc4c774e0057056887a9f1ed05faf9b Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 11 Sep 2020 12:31:13 +0200 +Subject: [PATCH 012/266] CVE-2020-25717 wb_xids2sids: make use of the new + wb_parent_idmap_setup_send/recv() helpers + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Gary Lockyer + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit a8f57c94fc2294c309ecb18ea79d0acac86c495b) +--- + source3/winbindd/wb_xids2sids.c | 255 +++----------------------------- + 1 file changed, 17 insertions(+), 238 deletions(-) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=5e04b985acc4c774e0057056887a9f1ed05faf9b + +diff --git a/source3/winbindd/wb_xids2sids.c b/source3/winbindd/wb_xids2sids.c +index f88c9be58a8..c68939b2bcd 100644 +--- a/source3/winbindd/wb_xids2sids.c ++++ b/source3/winbindd/wb_xids2sids.c +@@ -25,231 +25,13 @@ + #include "librpc/gen_ndr/ndr_netlogon.h" + #include "passdb/lookup_sid.h" + +-struct wb_xids2sids_dom_map { +- unsigned low_id; +- unsigned high_id; +- const char *name; +- struct dom_sid sid; +-}; +- +-/* +- * Map idmap ranges to domain names, taken from smb.conf. This is +- * stored in the parent winbind and used to assemble xid2sid calls +- * into per-idmap-domain chunks. +- */ +-static struct wb_xids2sids_dom_map *dom_maps; +- +-static bool wb_xids2sids_add_dom(const char *domname, +- void *private_data) +-{ +- struct wb_xids2sids_dom_map *map = NULL; +- size_t num_maps = talloc_array_length(dom_maps); +- size_t i; +- const char *range; +- unsigned low_id, high_id; +- int ret; +- +- range = idmap_config_const_string(domname, "range", NULL); +- if (range == NULL) { +- DBG_DEBUG("No range for domain %s found\n", domname); +- return false; +- } +- +- ret = sscanf(range, "%u - %u", &low_id, &high_id); +- if (ret != 2) { +- DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n", +- range, domname); +- return false; +- } +- +- if (low_id > high_id) { +- DBG_DEBUG("Invalid range %u - %u for domain %s\n", +- low_id, high_id, domname); +- return false; +- } +- +- for (i=0; iname = talloc_move(dom_maps, &name); +- } +- +- map->low_id = low_id; +- map->high_id = high_id; +- +- return false; +-} +- +-struct wb_xids2sids_init_dom_maps_state { +- struct tevent_context *ev; +- struct tevent_req *req; +- size_t dom_idx; +-}; +- +-static void wb_xids2sids_init_dom_maps_lookupname_next( +- struct wb_xids2sids_init_dom_maps_state *state); +- +-static void wb_xids2sids_init_dom_maps_lookupname_done( +- struct tevent_req *subreq); +- +-static struct tevent_req *wb_xids2sids_init_dom_maps_send( +- TALLOC_CTX *mem_ctx, struct tevent_context *ev) +-{ +- struct tevent_req *req = NULL; +- struct wb_xids2sids_init_dom_maps_state *state = NULL; +- +- req = tevent_req_create(mem_ctx, &state, +- struct wb_xids2sids_init_dom_maps_state); +- if (req == NULL) { +- return NULL; +- } +- *state = (struct wb_xids2sids_init_dom_maps_state) { +- .ev = ev, +- .req = req, +- .dom_idx = 0, +- }; +- +- if (dom_maps != NULL) { +- tevent_req_done(req); +- return tevent_req_post(req, ev); +- } +- /* +- * Put the passdb idmap domain first. We always need to try +- * there first. +- */ +- +- dom_maps = talloc_zero_array(NULL, struct wb_xids2sids_dom_map, 1); +- if (tevent_req_nomem(dom_maps, req)) { +- return tevent_req_post(req, ev); +- } +- dom_maps[0].low_id = 0; +- dom_maps[0].high_id = UINT_MAX; +- dom_maps[0].name = talloc_strdup(dom_maps, get_global_sam_name()); +- if (tevent_req_nomem(dom_maps[0].name, req)) { +- TALLOC_FREE(dom_maps); +- return tevent_req_post(req, ev); +- } +- +- lp_scan_idmap_domains(wb_xids2sids_add_dom, NULL); +- +- wb_xids2sids_init_dom_maps_lookupname_next(state); +- if (!tevent_req_is_in_progress(req)) { +- tevent_req_post(req, ev); +- } +- return req; +-} +- +-static void wb_xids2sids_init_dom_maps_lookupname_next( +- struct wb_xids2sids_init_dom_maps_state *state) +-{ +- struct tevent_req *subreq = NULL; +- +- if (state->dom_idx == talloc_array_length(dom_maps)) { +- tevent_req_done(state->req); +- return; +- } +- +- if (strequal(dom_maps[state->dom_idx].name, "*")) { +- state->dom_idx++; +- if (state->dom_idx == talloc_array_length(dom_maps)) { +- tevent_req_done(state->req); +- return; +- } +- } +- +- subreq = wb_lookupname_send(state, +- state->ev, +- dom_maps[state->dom_idx].name, +- dom_maps[state->dom_idx].name, +- "", +- LOOKUP_NAME_NO_NSS); +- if (tevent_req_nomem(subreq, state->req)) { +- return; +- } +- tevent_req_set_callback(subreq, +- wb_xids2sids_init_dom_maps_lookupname_done, +- state->req); +-} +- +-static void wb_xids2sids_init_dom_maps_lookupname_done( +- struct tevent_req *subreq) +-{ +- struct tevent_req *req = tevent_req_callback_data( +- subreq, struct tevent_req); +- struct wb_xids2sids_init_dom_maps_state *state = tevent_req_data( +- req, struct wb_xids2sids_init_dom_maps_state); +- enum lsa_SidType type; +- NTSTATUS status; +- +- status = wb_lookupname_recv(subreq, +- &dom_maps[state->dom_idx].sid, +- &type); +- TALLOC_FREE(subreq); +- if (!NT_STATUS_IS_OK(status)) { +- DBG_WARNING("Lookup domain name '%s' failed '%s'\n", +- dom_maps[state->dom_idx].name, +- nt_errstr(status)); +- +- state->dom_idx++; +- wb_xids2sids_init_dom_maps_lookupname_next(state); +- return; +- } +- +- if (type != SID_NAME_DOMAIN) { +- struct dom_sid_buf buf; +- +- DBG_WARNING("SID %s for idmap domain name '%s' " +- "not a domain SID\n", +- dom_sid_str_buf(&dom_maps[state->dom_idx].sid, +- &buf), +- dom_maps[state->dom_idx].name); +- +- ZERO_STRUCT(dom_maps[state->dom_idx].sid); +- } +- +- state->dom_idx++; +- wb_xids2sids_init_dom_maps_lookupname_next(state); +- +- return; +-} +- +-static NTSTATUS wb_xids2sids_init_dom_maps_recv(struct tevent_req *req) +-{ +- return tevent_req_simple_recv_ntstatus(req); +-} +- + struct wb_xids2sids_dom_state { + struct tevent_context *ev; + struct unixid *all_xids; + const bool *cached; + size_t num_all_xids; + struct dom_sid *all_sids; +- struct wb_xids2sids_dom_map *dom_map; ++ const struct wb_parent_idmap_config_dom *dom_map; + bool tried_dclookup; + + size_t num_dom_xids; +@@ -262,7 +44,7 @@ static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq); + + static struct tevent_req *wb_xids2sids_dom_send( + TALLOC_CTX *mem_ctx, struct tevent_context *ev, +- struct wb_xids2sids_dom_map *dom_map, ++ const struct wb_parent_idmap_config_dom *dom_map, + struct unixid *xids, + const bool *cached, + size_t num_xids, +@@ -334,7 +116,7 @@ static void wb_xids2sids_dom_done(struct tevent_req *subreq) + subreq, struct tevent_req); + struct wb_xids2sids_dom_state *state = tevent_req_data( + req, struct wb_xids2sids_dom_state); +- struct wb_xids2sids_dom_map *dom_map = state->dom_map; ++ const struct wb_parent_idmap_config_dom *dom_map = state->dom_map; + NTSTATUS status, result; + size_t i; + size_t dom_sid_idx; +@@ -437,10 +219,11 @@ struct wb_xids2sids_state { + bool *cached; + + size_t dom_idx; ++ const struct wb_parent_idmap_config *cfg; + }; + ++static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq); + static void wb_xids2sids_done(struct tevent_req *subreq); +-static void wb_xids2sids_init_dom_maps_done(struct tevent_req *subreq); + + struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +@@ -495,38 +278,32 @@ struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx, + } + } + +- subreq = wb_xids2sids_init_dom_maps_send( +- state, state->ev); ++ subreq = wb_parent_idmap_setup_send(state, state->ev); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } +- tevent_req_set_callback(subreq, wb_xids2sids_init_dom_maps_done, req); ++ tevent_req_set_callback(subreq, wb_xids2sids_idmap_setup_done, req); + return req; + } + +-static void wb_xids2sids_init_dom_maps_done(struct tevent_req *subreq) ++static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq) + { + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_xids2sids_state *state = tevent_req_data( + req, struct wb_xids2sids_state); +- size_t num_domains; + NTSTATUS status; + +- status = wb_xids2sids_init_dom_maps_recv(subreq); ++ status = wb_parent_idmap_setup_recv(subreq, &state->cfg); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } +- +- num_domains = talloc_array_length(dom_maps); +- if (num_domains == 0) { +- tevent_req_done(req); +- return; +- } ++ SMB_ASSERT(state->cfg->num_doms > 0); + + subreq = wb_xids2sids_dom_send( +- state, state->ev, &dom_maps[state->dom_idx], ++ state, state->ev, ++ &state->cfg->doms[state->dom_idx], + state->xids, state->cached, state->num_xids, state->sids); + if (tevent_req_nomem(subreq, req)) { + return; +@@ -541,7 +318,6 @@ static void wb_xids2sids_done(struct tevent_req *subreq) + subreq, struct tevent_req); + struct wb_xids2sids_state *state = tevent_req_data( + req, struct wb_xids2sids_state); +- size_t num_domains = talloc_array_length(dom_maps); + size_t i; + NTSTATUS status; + +@@ -553,10 +329,13 @@ static void wb_xids2sids_done(struct tevent_req *subreq) + + state->dom_idx += 1; + +- if (state->dom_idx < num_domains) { ++ if (state->dom_idx < state->cfg->num_doms) { ++ const struct wb_parent_idmap_config_dom *dom_map = ++ &state->cfg->doms[state->dom_idx]; ++ + subreq = wb_xids2sids_dom_send(state, + state->ev, +- &dom_maps[state->dom_idx], ++ dom_map, + state->xids, + state->cached, + state->num_xids, +-- +2.23.0 + diff --git a/backport-0002-CVE-2020-25718-fix-ldb_comparison_fold.patch b/backport-0002-CVE-2020-25718-fix-ldb_comparison_fold.patch new file mode 100644 index 0000000..32deec3 --- /dev/null +++ b/backport-0002-CVE-2020-25718-fix-ldb_comparison_fold.patch @@ -0,0 +1,42 @@ +From a94ea2c5bcb6d62b4fe6dda590cf3ed44616f6a2 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Sat, 6 Mar 2021 16:05:15 +1300 +Subject: [PATCH 003/284] CVE-2020-25718 ldb: fix ldb_comparison_fold + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=a94ea2c5bcb6d62b4fe6dda590cf3ed44616f6a2 + + off-by-one overrun + +We run one character over in comparing all the bytes in two ldb_vals. + +In almost all circumstances both ldb_vals would have an allocated '\0' +in the overrun position, but it is best not to rely on that. + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 + +(cherry picked from commit 2b2f4f519454beb6f2a46705675a62274019fc09) +--- + lib/ldb/common/attrib_handlers.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/ldb/common/attrib_handlers.c b/lib/ldb/common/attrib_handlers.c +index f0fd4f50d8df..6a885065f773 100644 +--- a/lib/ldb/common/attrib_handlers.c ++++ b/lib/ldb/common/attrib_handlers.c +@@ -334,8 +334,8 @@ int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx, + if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2)) + break; + if (*s1 == ' ') { +- while (n1 && s1[0] == s1[1]) { s1++; n1--; } +- while (n2 && s2[0] == s2[1]) { s2++; n2--; } ++ while (n1 > 1 && s1[0] == s1[1]) { s1++; n1--; } ++ while (n2 > 1 && s2[0] == s2[1]) { s2++; n2--; } + } + s1++; s2++; + n1--; n2--; +-- +2.25.1 diff --git a/backport-0002-CVE-2020-25719-sign-and-verify-PAC-with-ticket-principal.patch b/backport-0002-CVE-2020-25719-sign-and-verify-PAC-with-ticket-principal.patch new file mode 100644 index 0000000..3db632a --- /dev/null +++ b/backport-0002-CVE-2020-25719-sign-and-verify-PAC-with-ticket-principal.patch @@ -0,0 +1,70 @@ +From 34347586375dea9b615fb6a0218bcb5927031e4d Mon Sep 17 00:00:00 2001 +From: Isaac Boukris +Date: Thu, 16 Jan 2020 22:00:21 +0100 +Subject: [PATCH] Sign and verify PAC with ticket principal instead of canon + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=34347586375dea9b615fb6a0218bcb5927031e4d + + principal + +With MIT library 1.18 the KDC no longer set +KRB5_KDB_FLAG_CANONICALIZE for enterprise principals which allows +us to not canonicalize them (like in Windows / Heimdal). + +However, it now breaks the PAC signature verification as it was +wrongly done using canonical client rather than ticket client name. + +Signed-off-by: Isaac Boukris +Reviewed-by: Andreas Schneider +Reviewed-by: Guenther Deschner +--- + source4/kdc/mit-kdb/kdb_samba_policies.c | 12 ++---------- + 1 file changed, 2 insertions(+), 10 deletions(-) + +diff --git a/source4/kdc/mit-kdb/kdb_samba_policies.c b/source4/kdc/mit-kdb/kdb_samba_policies.c +index 586cf81451d..2eec496fa92 100644 +--- a/source4/kdc/mit-kdb/kdb_samba_policies.c ++++ b/source4/kdc/mit-kdb/kdb_samba_policies.c +@@ -301,20 +301,12 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context, + krb5_authdata **tgt_auth_data, + krb5_authdata ***signed_auth_data) + { +- krb5_const_principal ks_client_princ; + krb5_authdata **authdata = NULL; + krb5_boolean is_as_req; + krb5_error_code code; + krb5_pac pac = NULL; + krb5_data pac_data; + +- /* Prefer canonicalised name from client entry */ +- if (client != NULL) { +- ks_client_princ = client->princ; +- } else { +- ks_client_princ = client_princ; +- } +- + is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0); + + if (is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) { +@@ -354,7 +346,7 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context, + if (!is_as_req) { + code = ks_verify_pac(context, + flags, +- ks_client_princ, ++ client_princ, + client, + server, + krbtgt, +@@ -381,7 +373,7 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context, + goto done; + } + +- code = krb5_pac_sign(context, pac, authtime, ks_client_princ, ++ code = krb5_pac_sign(context, pac, authtime, client_princ, + server_key, krbtgt_key, &pac_data); + if (code != 0) { + DBG_ERR("krb5_pac_sign failed: %d\n", code); +-- +GitLab + diff --git a/backport-0002-CVE-2020-25722-dsdb-Restrict-the-setting-of-privileg.patch b/backport-0002-CVE-2020-25722-dsdb-Restrict-the-setting-of-privileg.patch new file mode 100644 index 0000000..d62277f --- /dev/null +++ b/backport-0002-CVE-2020-25722-dsdb-Restrict-the-setting-of-privileg.patch @@ -0,0 +1,235 @@ +From 448585950bda2c1daab8ffeb3971870ed0416634 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Fri, 13 Aug 2021 17:42:23 +1200 +Subject: [PATCH 057/266] CVE-2020-25722 dsdb: Restrict the setting of + privileged attributes during LDAP add/modify + +The remaining failures in the priv_attrs (not the strict one) test are +due to missing objectclass constraints on the administrator which should +be addressed, but are not a security issue. + +A better test for confirming constraints between objectclass and +userAccountControl UF_NORMAL_ACCONT/UF_WORKSTATION_TRUST values would +be user_account_control.py. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14703 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14778 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14775 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/448585950bda2c1daab8ffeb3971870ed0416634 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 148 +++++++++++++++++++++--- + 1 files changed, 129 insertions(+), 19 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 4da8564c77a..cb5fda324a4 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -1976,6 +1976,29 @@ static int samldb_check_user_account_control_invariants(struct samldb_ctx *ac, + return ret; + } + ++static int samldb_get_domain_secdesc(struct samldb_ctx *ac, ++ struct security_descriptor **domain_sd) ++{ ++ const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL}; ++ struct ldb_result *res; ++ struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module)); ++ int ret = dsdb_module_search_dn(ac->module, ac, &res, ++ domain_dn, ++ sd_attrs, ++ DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ++ ac->req); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ if (res->count != 1) { ++ return ldb_module_operr(ac->module); ++ } ++ ++ return dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(ac->module), ++ ac, res->msgs[0], domain_sd); ++ ++} ++ + /** + * Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 userAccountControl is honoured + * +@@ -1987,12 +2010,8 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac, + { + int i, ret = 0; + bool need_acl_check = false; +- struct ldb_result *res; +- const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL}; + struct security_token *user_token; + struct security_descriptor *domain_sd; +- struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module)); +- struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + const struct uac_to_guid { + uint32_t uac; + uint32_t priv_to_change_from; +@@ -2078,21 +2097,7 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac, + return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; + } + +- ret = dsdb_module_search_dn(ac->module, ac, &res, +- domain_dn, +- sd_attrs, +- DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, +- ac->req); +- if (ret != LDB_SUCCESS) { +- return ret; +- } +- if (res->count != 1) { +- return ldb_module_operr(ac->module); +- } +- +- ret = dsdb_get_sd_from_ldb_message(ldb, +- ac, res->msgs[0], &domain_sd); +- ++ ret = samldb_get_domain_secdesc(ac, &domain_sd); + if (ret != LDB_SUCCESS) { + return ret; + } +@@ -2154,6 +2159,8 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac, + return ldb_module_operr(ac->module); + } + if (map[i].guid) { ++ struct ldb_dn *domain_dn ++ = ldb_get_default_basedn(ldb_module_get_ctx(ac->module)); + dsdb_acl_debug(domain_sd, acl_user_token(ac->module), + domain_dn, + true, +@@ -3486,7 +3493,98 @@ static char *refer_if_rodc(struct ldb_context *ldb, struct ldb_request *req, + return NULL; + } + ++/* ++ * Restrict all access to sensitive attributes. ++ * ++ * We don't want to even inspect the values, so we can use the same ++ * routine for ADD and MODIFY. ++ * ++ */ ++ ++static int samldb_check_sensitive_attributes(struct samldb_ctx *ac) ++{ ++ struct ldb_message_element *el = NULL; ++ struct security_token *user_token = NULL; ++ int ret; ++ ++ if (dsdb_module_am_system(ac->module)) { ++ return LDB_SUCCESS; ++ } ++ ++ user_token = acl_user_token(ac->module); ++ if (user_token == NULL) { ++ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; ++ } ++ ++ el = ldb_msg_find_element(ac->msg, "sidHistory"); ++ if (el) { ++ /* ++ * sidHistory is restricted to the (not implemented ++ * yet in Samba) DsAddSidHistory call (direct LDB access is ++ * as SYSTEM so will bypass this). ++ * ++ * If you want to modify this, say to merge domains, ++ * directly modify the sam.ldb as root. ++ */ ++ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module), ++ "sidHistory " ++ "(entry %s) cannot be created " ++ "or changed over LDAP!", ++ ldb_dn_get_linearized(ac->msg->dn)); ++ return LDB_ERR_UNWILLING_TO_PERFORM; ++ } + ++ el = ldb_msg_find_element(ac->msg, "msDS-SecondaryKrbTgtNumber"); ++ if (el) { ++ struct security_descriptor *domain_sd; ++ /* ++ * msDS-SecondaryKrbTgtNumber allows the creator to ++ * become an RODC, this is trusted as an RODC ++ * account ++ */ ++ ret = samldb_get_domain_secdesc(ac, &domain_sd); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ ret = acl_check_extended_right(ac, domain_sd, ++ user_token, ++ GUID_DRS_DS_INSTALL_REPLICA, ++ SEC_ADS_CONTROL_ACCESS, ++ NULL); ++ if (ret != LDB_SUCCESS) { ++ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module), ++ "msDS-SecondaryKrbTgtNumber " ++ "(entry %s) cannot be created " ++ "or changed without " ++ "DS-Install-Replica extended right!", ++ ldb_dn_get_linearized(ac->msg->dn)); ++ return ret; ++ } ++ } ++ ++ el = ldb_msg_find_element(ac->msg, "msDS-AllowedToDelegateTo"); ++ if (el) { ++ /* ++ * msDS-AllowedToDelegateTo is incredibly powerful, ++ * given that it allows a server to become ANY USER on ++ * the target server only listed by SPN so needs to be ++ * protected just as the userAccountControl ++ * UF_TRUSTED_FOR_DELEGATION is. ++ */ ++ ++ bool have_priv = security_token_has_privilege(user_token, ++ SEC_PRIV_ENABLE_DELEGATION); ++ if (have_priv == false) { ++ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module), ++ "msDS-AllowedToDelegateTo " ++ "(entry %s) cannot be created " ++ "or changed without SePrivEnableDelegation!", ++ ldb_dn_get_linearized(ac->msg->dn)); ++ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; ++ } ++ } ++ return LDB_SUCCESS; ++} + /* add */ + static int samldb_add(struct ldb_module *module, struct ldb_request *req) + { +@@ -3533,6 +3631,12 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req) + return ldb_operr(ldb); + } + ++ ret = samldb_check_sensitive_attributes(ac); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(ac); ++ return ret; ++ } ++ + el = ldb_msg_find_element(ac->msg, "fSMORoleOwner"); + if (el != NULL) { + ret = samldb_fsmo_role_owner_check(ac); +@@ -3740,6 +3844,12 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) + return ldb_operr(ldb); + } + ++ ret = samldb_check_sensitive_attributes(ac); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(ac); ++ return ret; ++ } ++ + if (is_undelete == NULL) { + el = ldb_msg_find_element(ac->msg, "primaryGroupID"); + if (el != NULL) { +-- +2.23.0 + diff --git a/backport-0002-CVE-2021-3738-s4-rpc_server-drsuapi-make-use-of-asso.patch b/backport-0002-CVE-2021-3738-s4-rpc_server-drsuapi-make-use-of-asso.patch new file mode 100644 index 0000000..f0a6e8d --- /dev/null +++ b/backport-0002-CVE-2021-3738-s4-rpc_server-drsuapi-make-use-of-asso.patch @@ -0,0 +1,106 @@ +From 061c125c6129634d220c1074fa8ed5eaa8b0e09c Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 5 Aug 2021 13:31:29 +0200 +Subject: [PATCH 262/266] CVE-2021-3738 s4:rpc_server/drsuapi: make use of + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=061c125c6129634d220c1074fa8ed5eaa8b0e09c + + assoc_group aware dcesrv_samdb_connect_as_*() helpers + +This avoids a crash that's triggered by windows clients using +DsCrackNames across multiple connections within an association group +on the same DsBind context(policy) handle. + +It also improves the auditing for the dcesrv_samdb_connect_as_system() case. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14468 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source4/rpc_server/drsuapi/dcesrv_drsuapi.c | 55 +++++++------------ + 1 files changed, 19 insertions(+), 36 deletions(-) + +diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c +index 7e2b6174d2f..239971d7009 100644 +--- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c ++++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c +@@ -73,9 +73,7 @@ static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_C + uint32_t supported_extensions; + uint32_t req_length; + int ret; +- struct auth_session_info *auth_info; + WERROR werr; +- bool connected_as_system = false; + + r->out.bind_info = NULL; + ZERO_STRUCTP(r->out.bind_handle); +@@ -86,45 +84,30 @@ static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_C + /* if this is a DC connecting, give them system level access */ + werr = drs_security_level_check(dce_call, NULL, SECURITY_DOMAIN_CONTROLLER, NULL); + if (W_ERROR_IS_OK(werr)) { +- DEBUG(3,(__location__ ": doing DsBind with system_session\n")); +- auth_info = system_session(dce_call->conn->dce_ctx->lp_ctx); +- connected_as_system = true; ++ DBG_NOTICE("doing DsBind with system_session\n"); ++ b_state->sam_ctx_system = dcesrv_samdb_connect_as_system(b_state, dce_call); ++ if (b_state->sam_ctx_system == NULL) { ++ return WERR_DS_UNAVAILABLE; ++ } ++ b_state->sam_ctx = b_state->sam_ctx_system; + } else { +- auth_info = dcesrv_call_session_info(dce_call); +- } +- +- /* +- * connect to the samdb +- */ +- b_state->sam_ctx = samdb_connect( +- b_state, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- auth_info, +- dce_call->conn->remote_address, +- 0); +- if (!b_state->sam_ctx) { +- return WERR_FOOBAR; +- } ++ b_state->sam_ctx = dcesrv_samdb_connect_as_user(b_state, dce_call); ++ if (b_state->sam_ctx == NULL) { ++ return WERR_DS_UNAVAILABLE; ++ } + +- if (connected_as_system) { +- b_state->sam_ctx_system = b_state->sam_ctx; +- } else { +- /* an RODC also needs system samdb access for secret +- attribute replication */ ++ /* ++ * an RODC also needs system samdb access for secret ++ * attribute replication ++ */ + werr = drs_security_level_check(dce_call, NULL, SECURITY_RO_DOMAIN_CONTROLLER, + samdb_domain_sid(b_state->sam_ctx)); + if (W_ERROR_IS_OK(werr)) { +- b_state->sam_ctx_system +- = samdb_connect( +- b_state, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- system_session(dce_call->conn->dce_ctx->lp_ctx), +- dce_call->conn->remote_address, +- 0); +- if (!b_state->sam_ctx_system) { +- return WERR_FOOBAR; ++ DBG_NOTICE("doing DsBind as RODC\n"); ++ b_state->sam_ctx_system = ++ dcesrv_samdb_connect_as_system(b_state, dce_call); ++ if (b_state->sam_ctx_system == NULL) { ++ return WERR_DS_UNAVAILABLE; + } + } + } +-- +2.23.0 + diff --git a/backport-0003-CVE-2020-25717-wb_sids2xids-call-wb_parent_idmap_set.patch b/backport-0003-CVE-2020-25717-wb_sids2xids-call-wb_parent_idmap_set.patch new file mode 100644 index 0000000..c6e3162 --- /dev/null +++ b/backport-0003-CVE-2020-25717-wb_sids2xids-call-wb_parent_idmap_set.patch @@ -0,0 +1,94 @@ +From a3cca16fac5d834f2f29e1daa31ced38938fada9 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 11 Sep 2020 12:52:40 +0200 +Subject: [PATCH 013/266] CVE-2020-25717 wb_sids2xids: call + wb_parent_idmap_setup_send/recv as the first step + +This isn't really used yet, but it will in the next commits. + +Also idmap_child_handle() will soon assert that +wb_parent_idmap_setup_send/recv() was called before it's used. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Gary Lockyer + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit d42aaeba6e0820acd17f204ff7ab6d1aede1b303) + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/a3cca16fac5d834f2f29e1daa31ced38938fada9 +--- + source3/winbindd/wb_sids2xids.c | 34 +++++++++++++++++++++++++++++---- + 1 file changed, 30 insertions(+), 4 deletions(-) + +diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c +index b47856520ea..59f6ba5891e 100644 +--- a/source3/winbindd/wb_sids2xids.c ++++ b/source3/winbindd/wb_sids2xids.c +@@ -29,6 +29,8 @@ + struct wb_sids2xids_state { + struct tevent_context *ev; + ++ const struct wb_parent_idmap_config *cfg; ++ + struct dom_sid *sids; + uint32_t num_sids; + +@@ -58,7 +60,7 @@ struct wb_sids2xids_state { + struct wbint_TransIDArray ids; + }; + +- ++static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq); + static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map); + static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq); + static void wb_sids2xids_done(struct tevent_req *subreq); +@@ -126,15 +128,39 @@ struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx, + return tevent_req_post(req, ev); + } + +- subreq = wb_lookupsids_send(state, ev, state->non_cached, +- state->num_non_cached); ++ subreq = wb_parent_idmap_setup_send(state, state->ev); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } +- tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req); ++ tevent_req_set_callback(subreq, wb_sids2xids_idmap_setup_done, req); + return req; + } + ++static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data( ++ subreq, struct tevent_req); ++ struct wb_sids2xids_state *state = tevent_req_data( ++ req, struct wb_sids2xids_state); ++ NTSTATUS status; ++ ++ status = wb_parent_idmap_setup_recv(subreq, &state->cfg); ++ TALLOC_FREE(subreq); ++ if (tevent_req_nterror(req, status)) { ++ return; ++ } ++ SMB_ASSERT(state->cfg->num_doms > 0); ++ ++ subreq = wb_lookupsids_send(state, ++ state->ev, ++ state->non_cached, ++ state->num_non_cached); ++ if (tevent_req_nomem(subreq, req)) { ++ return; ++ } ++ tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req); ++} ++ + static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map) + { + struct unixid id; +-- +2.23.0 + diff --git a/backport-0003-CVE-2020-25718-catch-potential-overflow-error.patch b/backport-0003-CVE-2020-25718-catch-potential-overflow-error.patch new file mode 100644 index 0000000..85870b9 --- /dev/null +++ b/backport-0003-CVE-2020-25718-catch-potential-overflow-error.patch @@ -0,0 +1,105 @@ +From 5e63f9c3c5e3d48e1aaf625649cb065c0dfae1df Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 19 Jan 2021 16:53:55 +0100 +Subject: [PATCH 004/284] CVE-2020-25718 pyldb: catch potential overflow error + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=5e63f9c3c5e3d48e1aaf625649cb065c0dfae1df + + in py_timestring +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Pair-Programmed-With: Bj枚rn Baumbach + +Signed-off-by: Stefan Metzmacher +Signed-off-by: Bj枚rn Baumbach +Reviewed-by: Andrew Bartlett + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 + +(cherry picked from commit 71e8b24b8a031de26b21539e36a60f459257d2fd) +--- + lib/ldb/common/ldb_msg.c | 1 + + lib/ldb/pyldb.c | 7 +++++++ + lib/ldb/tests/python/api.py | 19 +++++++++++++++++++ + 3 files changed, 27 insertions(+) + +diff --git a/lib/ldb/common/ldb_msg.c b/lib/ldb/common/ldb_msg.c +index 7131f013f71b..57dfc5a04c2b 100644 +--- a/lib/ldb/common/ldb_msg.c ++++ b/lib/ldb/common/ldb_msg.c +@@ -1272,6 +1272,7 @@ char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t) + + if (r != 17) { + talloc_free(ts); ++ errno = EOVERFLOW; + return NULL; + } + +diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c +index d093daedf5c7..257351b2bc45 100644 +--- a/lib/ldb/pyldb.c ++++ b/lib/ldb/pyldb.c +@@ -4227,6 +4227,13 @@ static PyObject *py_timestring(PyObject *module, PyObject *args) + if (!PyArg_ParseTuple(args, "l", &t_val)) + return NULL; + tresult = ldb_timestring(NULL, (time_t) t_val); ++ if (tresult == NULL) { ++ /* ++ * Most likely EOVERFLOW from gmtime() ++ */ ++ PyErr_SetFromErrno(PyExc_OSError); ++ return NULL; ++ } + ret = PyUnicode_FromString(tresult); + talloc_free(tresult); + return ret; +diff --git a/lib/ldb/tests/python/api.py b/lib/ldb/tests/python/api.py +index 675b5859af8f..8d154aac6adf 100755 +--- a/lib/ldb/tests/python/api.py ++++ b/lib/ldb/tests/python/api.py +@@ -5,10 +5,12 @@ + import os + from unittest import TestCase + import sys ++sys.path.insert(0, "bin/python") + import gc + import time + import ldb + import shutil ++import errno + + PY3 = sys.version_info > (3, 0) + +@@ -42,10 +44,27 @@ class NoContextTests(TestCase): + self.assertEqual("19700101000000.0Z", ldb.timestring(0)) + self.assertEqual("20071119191012.0Z", ldb.timestring(1195499412)) + ++ self.assertEqual("00000101000000.0Z", ldb.timestring(-62167219200)) ++ self.assertEqual("99991231235959.0Z", ldb.timestring(253402300799)) ++ ++ # should result with OSError EOVERFLOW from gmtime() ++ with self.assertRaises(OSError) as err: ++ ldb.timestring(-62167219201) ++ self.assertEqual(err.exception.errno, errno.EOVERFLOW) ++ with self.assertRaises(OSError) as err: ++ ldb.timestring(253402300800) ++ self.assertEqual(err.exception.errno, errno.EOVERFLOW) ++ with self.assertRaises(OSError) as err: ++ ldb.timestring(0x7fffffffffffffff) ++ self.assertEqual(err.exception.errno, errno.EOVERFLOW) ++ + def test_string_to_time(self): + self.assertEqual(0, ldb.string_to_time("19700101000000.0Z")) + self.assertEqual(1195499412, ldb.string_to_time("20071119191012.0Z")) + ++ self.assertEqual(-62167219200, ldb.string_to_time("00000101000000.0Z")) ++ self.assertEqual(253402300799, ldb.string_to_time("99991231235959.0Z")) ++ + def test_binary_encode(self): + encoded = ldb.binary_encode(b'test\\x') + decoded = ldb.binary_decode(encoded) +-- +2.25.1 diff --git a/backport-0003-CVE-2020-25719-mit-samba-If-we-use-client_princ-alwa.patch b/backport-0003-CVE-2020-25719-mit-samba-If-we-use-client_princ-alwa.patch new file mode 100644 index 0000000..6ca140f --- /dev/null +++ b/backport-0003-CVE-2020-25719-mit-samba-If-we-use-client_princ-alwa.patch @@ -0,0 +1,153 @@ +From 940ddac4572b3caa419579c3bf60f6af0e019d18 Mon Sep 17 00:00:00 2001 +From: Andreas Schneider +Date: Mon, 12 Jul 2021 11:20:29 +0200 +Subject: [PATCH 202/266] CVE-2020-25719 mit-samba: If we use client_princ, + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=940ddac4572b3caa419579c3bf60f6af0e019d18 + + always lookup the db entry + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 + +Signed-off-by: Andreas Schneider +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org backported due to support for MIT KDB < 10 + in Samba 4.14] +--- + source4/kdc/mit-kdb/kdb_samba_policies.c | 81 ++++++++++++++++++++++-- + 1 file changed, 75 insertions(+), 6 deletions(-) + +diff --git a/source4/kdc/mit-kdb/kdb_samba_policies.c b/source4/kdc/mit-kdb/kdb_samba_policies.c +index 9197551ed61..dce87c50049 100644 +--- a/source4/kdc/mit-kdb/kdb_samba_policies.c ++++ b/source4/kdc/mit-kdb/kdb_samba_policies.c +@@ -323,6 +323,8 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context, + krb5_authdata **tgt_auth_data, + krb5_authdata ***signed_auth_data) + { ++ krb5_const_principal ks_client_princ = NULL; ++ krb5_db_entry *client_entry = NULL; + krb5_authdata **authdata = NULL; + krb5_boolean is_as_req; + krb5_error_code code; +@@ -341,8 +343,72 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context, + + is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0); + ++ /* ++ * When using s4u2proxy client_princ actually refers to the proxied user ++ * while client->princ to the proxy service asking for the TGS on behalf ++ * of the proxied user. So always use client_princ in preference. ++ * ++ * Note that when client principal is not NULL, client entry might be ++ * NULL for cross-realm case, so we need to make sure to not ++ * dereference NULL pointer here. ++ */ ++ if (client_princ != NULL) { ++ ks_client_princ = client_princ; ++ if (!is_as_req) { ++ krb5_boolean is_equal = false; ++ ++ if (client != NULL && client->princ != NULL) { ++ is_equal = ++ krb5_principal_compare(context, ++ client_princ, ++ client->princ); ++ } ++ ++ /* ++ * When client principal is the same as supplied client ++ * entry, don't fetch it. ++ */ ++ if (!is_equal) { ++ code = ks_get_principal(context, ++ ks_client_princ, ++ 0, ++ &client_entry); ++ if (code != 0) { ++ char *client_name = NULL; ++ ++ (void)krb5_unparse_name(context, ++ ks_client_princ, ++ &client_name); ++ ++ DBG_DEBUG("We didn't find the client " ++ "principal [%s] in our " ++ "database.\n", ++ client_name); ++ SAFE_FREE(client_name); ++ ++ /* ++ * If we didn't find client_princ in our ++ * database it might be from another ++ * realm. ++ */ ++ client_entry = NULL; ++ } ++ } ++ } ++ } else { ++ if (client == NULL) { ++ *signed_auth_data = NULL; ++ return 0; ++ } ++ ks_client_princ = client->princ; ++ } ++ ++ if (client_entry == NULL) { ++ client_entry = client; ++ } ++ + if (is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) { +- code = ks_get_pac(context, client, client_key, &pac); ++ code = ks_get_pac(context, client_entry, client_key, &pac); + if (code != 0) { + goto done; + } +@@ -351,8 +417,8 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context, + if (!is_as_req) { + code = ks_verify_pac(context, + flags, +- client_princ, +- client, ++ ks_client_princ, ++ client_entry, + server, + krbtgt, + server_key, +@@ -365,9 +431,9 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context, + } + } + +- if (pac == NULL && client != NULL) { ++ if (pac == NULL) { + +- code = ks_get_pac(context, client, client_key, &pac); ++ code = ks_get_pac(context, client_entry, client_key, &pac); + if (code != 0) { + goto done; + } +@@ -378,7 +444,7 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context, + goto done; + } + +- code = krb5_pac_sign(context, pac, authtime, client_princ, ++ code = krb5_pac_sign(context, pac, authtime, ks_client_princ, + server_key, krbtgt_key, &pac_data); + if (code != 0) { + DBG_ERR("krb5_pac_sign failed: %d\n", code); +@@ -412,6 +478,9 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context, + code = 0; + + done: ++ if (client_entry != NULL && client_entry != client) { ++ ks_free_principal(context, client_entry); ++ } + krb5_pac_free(context, pac); + krb5_free_authdata(context, authdata); + +-- +2.23.0 + diff --git a/backport-0003-CVE-2020-25722-dsdb-objectclass-computer-becomes-UF_.patch b/backport-0003-CVE-2020-25722-dsdb-objectclass-computer-becomes-UF_.patch new file mode 100644 index 0000000..13dc8a1 --- /dev/null +++ b/backport-0003-CVE-2020-25722-dsdb-objectclass-computer-becomes-UF_.patch @@ -0,0 +1,137 @@ +From e3021debe82e6a35f128eb600bc11df40c441a98 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Thu, 16 Sep 2021 08:46:42 +1200 +Subject: [PATCH 063/266] CVE-2020-25722 dsdb: objectclass computer becomes + UF_WORKSTATION_TRUST by default + +There are a lot of knownfail entries added with this commit. These +all need to be addressed and removed in subsequent commits which +will restructure the tests to pass within this new reality. + +This default applies even to users with administrator rights, +as changing the default based on permissions would break +to many assumptions. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/e3021debe82e6a35f128eb600bc11df40c441a98 + +--- + selftest/knownfail.d/uac_objectclass_restrict | 42 +++++++++++++++++++ + source4/dsdb/samdb/ldb_modules/samldb.c | 27 +++++++++--- + 2 files changed, 64 insertions(+), 5 deletions(-) + create mode 100644 selftest/knownfail.d/uac_objectclass_restrict + +diff --git a/selftest/knownfail.d/uac_objectclass_restrict b/selftest/knownfail.d/uac_objectclass_restrict +new file mode 100644 +index 00000000000..a076f9cfedb +--- /dev/null ++++ b/selftest/knownfail.d/uac_objectclass_restrict +@@ -0,0 +1,42 @@ ++# Knownfail entries due to restricting the creation of computer/user ++# accounts (in terms of userAccountControl) that do not match the objectclass ++# ++# All these tests need to be fixed and the entries here removed ++ ++^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_isCriticalSystemObject\(fl2008r2dc\) ++^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_userAccountControl\(fl2008r2dc\) ++^samba4.sam.python\(fl2008r2dc\).__main__.SamTests.test_users_groups\(fl2008r2dc\) ++^samba4.ldap.python\(ad_dc_default\).__main__.BasicTests.test_all\(ad_dc_default\) ++^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_isCriticalSystemObject\(ad_dc_default\) ++^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_userAccountControl\(ad_dc_default\) ++^samba4.sam.python\(ad_dc_default\).__main__.SamTests.test_users_groups\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_add_computer_sd_cc\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_admin_mod_uac\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_mod_computer_cc\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x10000000\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x20000000\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x40000000\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_0x80000000\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_00000004\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_00000400\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_00004000\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_00008000\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_ACCOUNTDISABLE\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_DONT_EXPIRE_PASSWD\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_DONT_REQUIRE_PREAUTH\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_HOMEDIR_REQUIRED\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_LOCKOUT\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_MNS_LOGON_ACCOUNT\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_NORMAL_ACCOUNT\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_NOT_DELEGATED\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_NO_AUTH_DATA_REQUIRED\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_PASSWD_CANT_CHANGE\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_PASSWD_NOTREQD\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_PASSWORD_EXPIRED\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_SCRIPT\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_SMARTCARD_REQUIRED\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_USE_AES_KEYS\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_USE_DES_KEY_ONLY\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_set_UF_WORKSTATION_TRUST_ACCOUNT\(ad_dc_default\) ++^samba4.user_account_control.python\(ad_dc_default\).__main__.UserAccountControlTests.test_uac_bits_unrelated_modify_UF_NORMAL_ACCOUNT\(ad_dc_default\) +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index cb5fda324a4..8df86f29883 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -1413,19 +1413,33 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) + + switch(ac->type) { + case SAMLDB_TYPE_USER: { ++ bool is_computer_objectclass; + bool uac_generated = false, uac_add_flags = false; +- ++ uint32_t default_user_account_control = UF_NORMAL_ACCOUNT; + /* Step 1.2: Default values */ + ret = dsdb_user_obj_set_defaults(ldb, ac->msg, ac->req); + if (ret != LDB_SUCCESS) return ret; + ++ is_computer_objectclass ++ = (samdb_find_attribute(ldb, ++ ac->msg, ++ "objectclass", ++ "computer") ++ != NULL); ++ ++ if (is_computer_objectclass) { ++ default_user_account_control ++ = UF_WORKSTATION_TRUST_ACCOUNT; ++ } ++ ++ + /* On add operations we might need to generate a + * "userAccountControl" (if it isn't specified). */ + el = ldb_msg_find_element(ac->msg, "userAccountControl"); + if ((el == NULL) && (ac->req->operation == LDB_ADD)) { + ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg, + "userAccountControl", +- UF_NORMAL_ACCOUNT); ++ default_user_account_control); + if (ret != LDB_SUCCESS) { + return ret; + } +@@ -1444,11 +1458,14 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) + raw_uac = user_account_control; + /* + * "userAccountControl" = 0 or missing one of +- * the types means "UF_NORMAL_ACCOUNT". See +- * MS-SAMR 3.1.1.8.10 point 8 ++ * the types means "UF_NORMAL_ACCOUNT" ++ * or "UF_WORKSTATION_TRUST_ACCOUNT" (if a computer). ++ * See MS-SAMR 3.1.1.8.10 point 8 + */ + if ((user_account_control & UF_ACCOUNT_TYPE_MASK) == 0) { +- user_account_control = UF_NORMAL_ACCOUNT | user_account_control; ++ user_account_control ++ = default_user_account_control ++ | user_account_control; + uac_generated = true; + } + +-- +2.23.0 + diff --git a/backport-0003-CVE-2021-3738-s4-rpc_server-dnsserver-make-use-of-dc.patch b/backport-0003-CVE-2021-3738-s4-rpc_server-dnsserver-make-use-of-dc.patch new file mode 100644 index 0000000..c953d19 --- /dev/null +++ b/backport-0003-CVE-2021-3738-s4-rpc_server-dnsserver-make-use-of-dc.patch @@ -0,0 +1,60 @@ +From caf3d32f68f91ea83c7f601577dd1f7c98f030e5 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 5 Aug 2021 14:22:47 +0200 +Subject: [PATCH 263/266] CVE-2021-3738 s4:rpc_server/dnsserver: make use of + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=caf3d32f68f91ea83c7f601577dd1f7c98f030e5 + + dcesrv_samdb_connect_as_user() helper + +This is not strictly required, but it makes it easier to audit that +source4/rpc_server no longer calls samdb_connect() directly. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14468 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source4/rpc_server/dnsserver/dcerpc_dnsserver.c | 11 ++--------- + 1 file changed, 2 insertions(+), 9 deletions(-) + +diff --git a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c +index 88efc01f154..b84b737d0b8 100644 +--- a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c ++++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c +@@ -22,6 +22,7 @@ + #include "includes.h" + #include "talloc.h" + #include "rpc_server/dcerpc_server.h" ++#include "rpc_server/common/common.h" + #include "dsdb/samdb/samdb.h" + #include "lib/util/dlinklist.h" + #include "librpc/gen_ndr/ndr_dnsserver.h" +@@ -104,8 +105,6 @@ static void dnsserver_reload_zones(struct dnsserver_state *dsstate) + + static struct dnsserver_state *dnsserver_connect(struct dcesrv_call_state *dce_call) + { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); + struct dnsserver_state *dsstate; + struct dnsserver_zone *zones, *z, *znext; + struct dnsserver_partition *partitions, *p; +@@ -125,13 +124,7 @@ static struct dnsserver_state *dnsserver_connect(struct dcesrv_call_state *dce_c + + dsstate->lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + +- /* FIXME: create correct auth_session_info for connecting user */ +- dsstate->samdb = samdb_connect(dsstate, +- dce_call->event_ctx, +- dsstate->lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ dsstate->samdb = dcesrv_samdb_connect_as_user(dsstate, dce_call); + if (dsstate->samdb == NULL) { + DEBUG(0,("dnsserver: Failed to open samdb")); + goto failed; +-- +2.23.0 + diff --git a/backport-0004-CVE-2020-25717-winbindd-defer-the-setup_child-from-i.patch b/backport-0004-CVE-2020-25717-winbindd-defer-the-setup_child-from-i.patch new file mode 100644 index 0000000..666482e --- /dev/null +++ b/backport-0004-CVE-2020-25717-winbindd-defer-the-setup_child-from-i.patch @@ -0,0 +1,96 @@ +From 3812930e641d10d1ead10b52ddc7240dd585d0f6 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 11 Sep 2020 15:42:42 +0200 +Subject: [PATCH 016/266] CVE-2020-25717 winbindd: defer the setup_child() from + init_idmap_child() + +At startup we trigger a wb_parent_idmap_setup_send() and make +sure setup_child() is called just before wb_parent_idmap_setup_recv() +finished. + +This makes sure our view of the idmap config in the parent matches +what we have in the child. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Gary Lockyer + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit 28e020c0a863411cfa95e3b1ed943d922b8635bd) +--- + source3/winbindd/winbindd_idmap.c | 45 ++++++++++++++++++++++++++++--- + 1 file changed, 42 insertions(+), 3 deletions(-) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=3812930e641d10d1ead10b52ddc7240dd585d0f6 + +diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c +index 14836e3b8a0..3e2461478a9 100644 +--- a/source3/winbindd/winbindd_idmap.c ++++ b/source3/winbindd/winbindd_idmap.c +@@ -81,11 +81,44 @@ static const struct winbindd_child_dispatch_table idmap_dispatch_table[] = { + } + }; + ++static void init_idmap_child_done(struct tevent_req *subreq); ++ + void init_idmap_child(void) + { +- setup_child(NULL, &static_idmap_child, +- idmap_dispatch_table, +- "log.winbindd", "idmap"); ++ struct tevent_req *subreq = NULL; ++ ++ subreq = wb_parent_idmap_setup_send(global_event_context(), ++ global_event_context()); ++ if (subreq == NULL) { ++ /* ++ * This is only an optimization, so we're free to ++ * to ignore errors ++ */ ++ DBG_ERR("wb_parent_idmap_setup_send() failed\n"); ++ return; ++ } ++ tevent_req_set_callback(subreq, init_idmap_child_done, NULL); ++ DBG_DEBUG("wb_parent_idmap_setup_send() started\n"); ++} ++ ++static void init_idmap_child_done(struct tevent_req *subreq) ++{ ++ const struct wb_parent_idmap_config *cfg = NULL; ++ NTSTATUS status; ++ ++ status = wb_parent_idmap_setup_recv(subreq, &cfg); ++ TALLOC_FREE(subreq); ++ if (!NT_STATUS_IS_OK(status)) { ++ /* ++ * This is only an optimization, so we're free to ++ * to ignore errors ++ */ ++ DBG_ERR("wb_parent_idmap_setup_recv() failed %s\n", ++ nt_errstr(status)); ++ return; ++ } ++ ++ DBG_DEBUG("wb_parent_idmap_setup_recv() finished\n"); + } + + struct wb_parent_idmap_setup_state { +@@ -306,6 +339,12 @@ static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req) + + next_domain: + if (state->dom_idx == state->cfg->num_doms) { ++ /* ++ * We're done, so start the idmap child ++ */ ++ setup_child(NULL, &static_idmap_child, ++ idmap_dispatch_table, ++ "log.winbindd", "idmap"); + tevent_req_done(req); + return; + } +-- +2.23.0 + diff --git a/backport-0004-CVE-2020-25719-mit-samba-Add-mit_samba_princ_needs_p.patch b/backport-0004-CVE-2020-25719-mit-samba-Add-mit_samba_princ_needs_p.patch new file mode 100644 index 0000000..f244d00 --- /dev/null +++ b/backport-0004-CVE-2020-25719-mit-samba-Add-mit_samba_princ_needs_p.patch @@ -0,0 +1,49 @@ +From 0e09aaa3e6410ba6963099a3504c70603180a66d Mon Sep 17 00:00:00 2001 +From: Andreas Schneider +Date: Mon, 12 Jul 2021 13:12:00 +0200 +Subject: [PATCH 203/266] CVE-2020-25719 mit-samba: Add + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=0e09aaa3e6410ba6963099a3504c70603180a66d + + mit_samba_princ_needs_pac() + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 + +Signed-off-by: Andreas Schneider +Reviewed-by: Andrew Bartlett +--- + source4/kdc/mit_samba.c | 8 ++++++++ + source4/kdc/mit_samba.h | 2 ++ + 2 files changed, 10 insertions(+) + +diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c +index 689e14e1c38..6aed3134544 100644 +--- a/source4/kdc/mit_samba.c ++++ b/source4/kdc/mit_samba.c +@@ -1153,3 +1153,11 @@ void mit_samba_update_bad_password_count(krb5_db_entry *db_entry) + p->msg, + ldb_get_default_basedn(p->kdc_db_ctx->samdb)); + } ++ ++bool mit_samba_princ_needs_pac(krb5_db_entry *db_entry) ++{ ++ struct samba_kdc_entry *skdc_entry = ++ talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry); ++ ++ return samba_princ_needs_pac(skdc_entry); ++} +diff --git a/source4/kdc/mit_samba.h b/source4/kdc/mit_samba.h +index ba824557bd5..636c77ec97c 100644 +--- a/source4/kdc/mit_samba.h ++++ b/source4/kdc/mit_samba.h +@@ -85,4 +85,6 @@ void mit_samba_zero_bad_password_count(krb5_db_entry *db_entry); + + void mit_samba_update_bad_password_count(krb5_db_entry *db_entry); + ++bool mit_samba_princ_needs_pac(krb5_db_entry *db_entry); ++ + #endif /* _MIT_SAMBA_H */ +-- +2.23.0 + diff --git a/backport-0004-CVE-2020-25722-dsdb-Prohibit-mismatch-between-UF_-ac.patch b/backport-0004-CVE-2020-25722-dsdb-Prohibit-mismatch-between-UF_-ac.patch new file mode 100644 index 0000000..4b2ce38 --- /dev/null +++ b/backport-0004-CVE-2020-25722-dsdb-Prohibit-mismatch-between-UF_-ac.patch @@ -0,0 +1,264 @@ +From f77231f1ae963599b834dde167a8854da08ca6d7 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Fri, 22 Oct 2021 16:07:46 +1300 +Subject: [PATCH 066/266] CVE-2020-25722 dsdb: Prohibit mismatch between UF_ + account types and objectclass. + +There are a lot of knownfail entries added with this commit. These +all need to be addressed and removed in subsequent commits which +will restructure the tests to pass within this new reality. + +The restriction is not applied to users with administrator rights, +as this breaks a lot of tests and provides no security benefit. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/f77231f1ae963599b834dde167a8854da08ca6d7 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 153 ++++++++++++++---- + 1 files changed, 122 insertions(+), 31 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 8df86f29883..15459abcbca 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -1365,7 +1365,8 @@ static int samldb_check_user_account_control_rules(struct samldb_ctx *ac, + struct dom_sid *sid, + uint32_t req_uac, + uint32_t user_account_control, +- uint32_t user_account_control_old); ++ uint32_t user_account_control_old, ++ bool is_computer_objectclass); + + /* + * "Objectclass" trigger (MS-SAMR 3.1.1.8.1) +@@ -1484,21 +1485,12 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) + ret = samldb_check_user_account_control_rules(ac, NULL, + raw_uac, + user_account_control, +- 0); ++ 0, ++ is_computer_objectclass); + if (ret != LDB_SUCCESS) { + return ret; + } + +- /* Workstation and (read-only) DC objects do need objectclass "computer" */ +- if ((samdb_find_attribute(ldb, ac->msg, +- "objectclass", "computer") == NULL) && +- (user_account_control & +- (UF_SERVER_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT))) { +- ldb_set_errstring(ldb, +- "samldb: Requested account type does need objectclass 'computer'!"); +- return LDB_ERR_OBJECT_CLASS_VIOLATION; +- } +- + /* add "sAMAccountType" attribute */ + ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL); + if (ret != LDB_SUCCESS) { +@@ -1993,6 +1985,106 @@ static int samldb_check_user_account_control_invariants(struct samldb_ctx *ac, + return ret; + } + ++/* ++ * It would be best if these rules apply, always, but for now they ++ * apply only to non-admins ++ */ ++static int samldb_check_user_account_control_objectclass_invariants( ++ struct samldb_ctx *ac, ++ uint32_t user_account_control, ++ uint32_t user_account_control_old, ++ bool is_computer_objectclass) ++{ ++ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); ++ ++ uint32_t old_ufa = user_account_control_old & UF_ACCOUNT_TYPE_MASK; ++ uint32_t new_ufa = user_account_control & UF_ACCOUNT_TYPE_MASK; ++ ++ uint32_t old_rodc = user_account_control_old & UF_PARTIAL_SECRETS_ACCOUNT; ++ uint32_t new_rodc = user_account_control & UF_PARTIAL_SECRETS_ACCOUNT; ++ ++ bool is_admin; ++ struct security_token *user_token ++ = acl_user_token(ac->module); ++ if (user_token == NULL) { ++ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; ++ } ++ ++ is_admin ++ = security_token_has_builtin_administrators(user_token); ++ ++ ++ /* ++ * We want to allow changes to (eg) disable an account ++ * that was created wrong, only checking the ++ * objectclass if the account type changes. ++ */ ++ if (old_ufa == new_ufa && old_rodc == new_rodc) { ++ return LDB_SUCCESS; ++ } ++ ++ switch (new_ufa) { ++ case UF_NORMAL_ACCOUNT: ++ if (is_computer_objectclass && !is_admin) { ++ ldb_asprintf_errstring(ldb, ++ "%08X: samldb: UF_NORMAL_ACCOUNT " ++ "requires objectclass 'user' not 'computer'!", ++ W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4)); ++ return LDB_ERR_OBJECT_CLASS_VIOLATION; ++ } ++ break; ++ ++ case UF_INTERDOMAIN_TRUST_ACCOUNT: ++ if (is_computer_objectclass) { ++ ldb_asprintf_errstring(ldb, ++ "%08X: samldb: UF_INTERDOMAIN_TRUST_ACCOUNT " ++ "requires objectclass 'user' not 'computer'!", ++ W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4)); ++ return LDB_ERR_OBJECT_CLASS_VIOLATION; ++ } ++ break; ++ ++ case UF_WORKSTATION_TRUST_ACCOUNT: ++ if (!is_computer_objectclass) { ++ /* ++ * Modify of a user account account into a ++ * workstation without objectclass computer ++ * as an admin is still permitted, but not ++ * to make an RODC ++ */ ++ if (is_admin ++ && ac->req->operation == LDB_MODIFY ++ && new_rodc == 0) { ++ break; ++ } ++ ldb_asprintf_errstring(ldb, ++ "%08X: samldb: UF_WORKSTATION_TRUST_ACCOUNT " ++ "requires objectclass 'computer'!", ++ W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4)); ++ return LDB_ERR_OBJECT_CLASS_VIOLATION; ++ } ++ break; ++ ++ case UF_SERVER_TRUST_ACCOUNT: ++ if (!is_computer_objectclass) { ++ ldb_asprintf_errstring(ldb, ++ "%08X: samldb: UF_SERVER_TRUST_ACCOUNT " ++ "requires objectclass 'computer'!", ++ W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4)); ++ return LDB_ERR_OBJECT_CLASS_VIOLATION; ++ } ++ break; ++ ++ default: ++ ldb_asprintf_errstring(ldb, ++ "%08X: samldb: invalid userAccountControl[0x%08X]", ++ W_ERROR_V(WERR_INVALID_PARAMETER), ++ user_account_control); ++ return LDB_ERR_OTHER; ++ } ++ return LDB_SUCCESS; ++} ++ + static int samldb_get_domain_secdesc(struct samldb_ctx *ac, + struct security_descriptor **domain_sd) + { +@@ -2191,7 +2283,8 @@ static int samldb_check_user_account_control_rules(struct samldb_ctx *ac, + struct dom_sid *sid, + uint32_t req_uac, + uint32_t user_account_control, +- uint32_t user_account_control_old) ++ uint32_t user_account_control_old, ++ bool is_computer_objectclass) + { + int ret; + struct dsdb_control_password_user_account_control *uac = NULL; +@@ -2200,6 +2293,14 @@ static int samldb_check_user_account_control_rules(struct samldb_ctx *ac, + if (ret != LDB_SUCCESS) { + return ret; + } ++ ret = samldb_check_user_account_control_objectclass_invariants(ac, ++ user_account_control, ++ user_account_control_old, ++ is_computer_objectclass); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ + ret = samldb_check_user_account_control_acl(ac, sid, user_account_control, user_account_control_old); + if (ret != LDB_SUCCESS) { + return ret; +@@ -2261,7 +2362,7 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) + "objectSid", + NULL + }; +- bool is_computer = false; ++ bool is_computer_objectclass = false; + bool old_is_critical = false; + bool new_is_critical = false; + +@@ -2316,7 +2417,10 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) + "lockoutTime", 0); + old_is_critical = ldb_msg_find_attr_as_bool(res->msgs[0], + "isCriticalSystemObject", 0); +- /* When we do not have objectclass "computer" we cannot switch to a (read-only) DC */ ++ /* ++ * When we do not have objectclass "computer" we cannot ++ * switch to a workstation or (RO)DC ++ */ + el = ldb_msg_find_element(res->msgs[0], "objectClass"); + if (el == NULL) { + return ldb_operr(ldb); +@@ -2324,7 +2428,7 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) + computer_val = data_blob_string_const("computer"); + val = ldb_msg_find_val(el, &computer_val); + if (val != NULL) { +- is_computer = true; ++ is_computer_objectclass = true; + } + + old_ufa = old_uac & UF_ACCOUNT_TYPE_MASK; +@@ -2349,7 +2453,8 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) + ret = samldb_check_user_account_control_rules(ac, sid, + raw_uac, + new_uac, +- old_uac); ++ old_uac, ++ is_computer_objectclass); + if (ret != LDB_SUCCESS) { + return ret; + } +@@ -2371,25 +2476,11 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) + case UF_WORKSTATION_TRUST_ACCOUNT: + new_is_critical = false; + if (new_uac & UF_PARTIAL_SECRETS_ACCOUNT) { +- if (!is_computer) { +- ldb_asprintf_errstring(ldb, +- "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT " +- "requires objectclass 'computer'!", +- W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4)); +- return LDB_ERR_UNWILLING_TO_PERFORM; +- } + new_is_critical = true; + } + break; + + case UF_SERVER_TRUST_ACCOUNT: +- if (!is_computer) { +- ldb_asprintf_errstring(ldb, +- "%08X: samldb: UF_SERVER_TRUST_ACCOUNT " +- "requires objectclass 'computer'!", +- W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4)); +- return LDB_ERR_UNWILLING_TO_PERFORM; +- } + new_is_critical = true; + break; + +-- +2.23.0 + diff --git a/backport-0004-CVE-2021-3738-s4-rpc_server-lsa-make-use-of-dcesrv_s.patch b/backport-0004-CVE-2021-3738-s4-rpc_server-lsa-make-use-of-dcesrv_s.patch new file mode 100644 index 0000000..2ca57ac --- /dev/null +++ b/backport-0004-CVE-2021-3738-s4-rpc_server-lsa-make-use-of-dcesrv_s.patch @@ -0,0 +1,43 @@ +From 79d62d83e23fe5969cb432262ab9addad59a3b8d Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 5 Aug 2021 14:24:25 +0200 +Subject: [PATCH 264/266] CVE-2021-3738 s4:rpc_server/lsa: make use of + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=79d62d83e23fe5969cb432262ab9addad59a3b8d + + dcesrv_samdb_connect_as_user() helper + +This avoids a crash that's triggered by windows clients using +handles from OpenPolicy[2]() on across multiple connections within +an association group. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14468 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source4/rpc_server/lsa/lsa_init.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/source4/rpc_server/lsa/lsa_init.c b/source4/rpc_server/lsa/lsa_init.c +index f33b61c4035..400c5093079 100644 +--- a/source4/rpc_server/lsa/lsa_init.c ++++ b/source4/rpc_server/lsa/lsa_init.c +@@ -71,12 +71,7 @@ NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, + } + + /* make sure the sam database is accessible */ +- state->sam_ldb = samdb_connect(state, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ state->sam_ldb = dcesrv_samdb_connect_as_user(state, dce_call); + if (state->sam_ldb == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } +-- +2.23.0 + diff --git a/backport-0005-CVE-2020-25717-wb_sids2xids-build-state-idmap_doms-b.patch b/backport-0005-CVE-2020-25717-wb_sids2xids-build-state-idmap_doms-b.patch new file mode 100644 index 0000000..efb5256 --- /dev/null +++ b/backport-0005-CVE-2020-25717-wb_sids2xids-build-state-idmap_doms-b.patch @@ -0,0 +1,169 @@ +From ed1542b9f37734bc77906c4ba49ea6ea3be09af8 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 10 Sep 2020 17:13:14 +0200 +Subject: [PATCH 026/266] CVE-2020-25717 wb_sids2xids: build state->idmap_doms + based on wb_parent_idmap_config + +In future we'll try to avoid wb_lookupsids_send() and only call +it if needed. + +The domain name passed should be only relevant to find the correct +idmap backend, and these should all be available in +wb_parent_idmap_config as it was created before the idmap child was forked. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Gary Lockyer + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit c55f4f37589130a0d8952489da175bbcf53f6748) +--- + source3/winbindd/wb_sids2xids.c | 101 +++++++++++++++++++------------- + 1 file changed, 61 insertions(+), 40 deletions(-) + +Conflict:lookup_sids --> non_cached +lookup_count --> num_non_cached +li --> i +delete 'uint32_t ai = state->tmp_idx[i]' +state->all_ids.ids[i] --> &state->ids.ids[i] +add 't->xid.id = UINT32_MAX; +t->xid.type = t->type;' +type_hint --> type +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=ed1542b9f37734bc77906c4ba49ea6ea3be09af8 + +diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c +index 21bf5f901f3..3a3d47abbe5 100644 +--- a/source3/winbindd/wb_sids2xids.c ++++ b/source3/winbindd/wb_sids2xids.c +@@ -193,6 +193,7 @@ static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq) + struct wb_sids2xids_state *state = tevent_req_data( + req, struct wb_sids2xids_state); + NTSTATUS status; ++ uint32_t i; + + status = wb_parent_idmap_setup_recv(subreq, &state->cfg); + TALLOC_FREE(subreq); +@@ -201,6 +202,66 @@ static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq) + } + SMB_ASSERT(state->cfg->num_doms > 0); + ++ /* ++ * Now we build a list with all domain ++ * with non cached entries ++ */ ++ for (i=0; inum_sids; i++) { ++ struct wbint_TransID *t = &state->ids.ids[i]; ++ struct dom_sid domain_sid; ++ const char *domain_name = NULL; ++ int domain_index; ++ uint32_t rid = 0; ++ uint32_t di; ++ ++ if (t->domain_index == UINT32_MAX) { ++ /* ignore already filled entries */ ++ continue; ++ } ++ ++ sid_copy(&domain_sid, &state->sids[i]); ++ sid_split_rid(&domain_sid, &rid); ++ ++ for (di = 0; di < state->cfg->num_doms; di++) { ++ struct wb_parent_idmap_config_dom *dom = ++ &state->cfg->doms[di]; ++ bool match; ++ ++ match = dom_sid_equal(&domain_sid, ++ &dom->sid); ++ if (!match) { ++ continue; ++ } ++ ++ domain_name = dom->name; ++ break; ++ } ++ if (domain_name == NULL) { ++ struct winbindd_domain *wb_domain = NULL; ++ ++ /* ++ * Try to fill the name if we already know it ++ */ ++ wb_domain = find_domain_from_sid_noinit(&state->sids[i]); ++ if (wb_domain != NULL) { ++ domain_name = wb_domain->name; ++ } ++ } ++ if (domain_name == NULL) { ++ domain_name = ""; ++ } ++ ++ domain_index = init_lsa_ref_domain_list(state, ++ &state->idmap_doms, ++ domain_name, ++ &domain_sid); ++ if (domain_index == -1) { ++ tevent_req_oom(req); ++ return; ++ } ++ t->domain_index = domain_index; ++ } ++ + subreq = wb_lookupsids_send(state, + state->ev, + state->non_cached, +@@ -251,51 +312,11 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) + } + + for (i=0; inum_non_cached; i++) { +- const struct dom_sid *sid = &state->non_cached[i]; +- struct dom_sid dom_sid; + struct lsa_TranslatedName *n = &names->names[i]; + struct wbint_TransID *t = &state->ids.ids[i]; +- int domain_index; +- const char *domain_name = NULL; +- +- if (n->sid_index != UINT32_MAX) { +- const struct lsa_DomainInfo *info; +- bool match; +- +- info = &domains->domains[n->sid_index]; +- match = dom_sid_in_domain(info->sid, sid); +- if (match) { +- domain_name = info->name.string; +- } +- } +- if (domain_name == NULL) { +- struct winbindd_domain *wb_domain = NULL; +- +- /* +- * This is needed to handle Samba DCs +- * which always return sid_index == UINT32_MAX for +- * unknown sids. +- */ +- wb_domain = find_domain_from_sid_noinit(sid); +- if (wb_domain != NULL) { +- domain_name = wb_domain->name; +- } +- } +- if (domain_name == NULL) { +- domain_name = ""; +- } + +- sid_copy(&dom_sid, sid); +- sid_split_rid(&dom_sid, &t->rid); + t->type = lsa_SidType_to_id_type(n->sid_type); +- domain_index = init_lsa_ref_domain_list( +- state, &state->idmap_doms, domain_name, &dom_sid); +- if (domain_index == -1) { +- tevent_req_oom(req); +- return; +- } +- t->domain_index = domain_index; + + t->xid.id = UINT32_MAX; + t->xid.type = t->type; + } +-- +2.23.0 + diff --git a/backport-0005-CVE-2020-25718-Fix-Message-items-for-a.patch b/backport-0005-CVE-2020-25718-Fix-Message-items-for-a.patch new file mode 100644 index 0000000..468832d --- /dev/null +++ b/backport-0005-CVE-2020-25718-Fix-Message-items-for-a.patch @@ -0,0 +1,47 @@ +From 0af7600146dda42beb4c06a197f76ae51156cd21 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 28 May 2021 14:15:43 +1200 +Subject: [PATCH 006/284] CVE-2020-25718 pyldb: Fix Message.items() for a + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=0af7600146dda42beb4c06a197f76ae51156cd21 + + message containing elements + +Previously, message elements were being freed before the call to +Py_BuildValue(), resulting in an exception being raised. Additionally, +only the first element of the returned list was ever assigned to. + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 + +(cherry picked from commit 3e4ec0a90a222c1cff4a91912afc703ca4cbbb0e) +--- + lib/ldb/pyldb.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c +index 257351b2bc45..df7c5c54eaaa 100644 +--- a/lib/ldb/pyldb.c ++++ b/lib/ldb/pyldb.c +@@ -3535,13 +3535,13 @@ static PyObject *py_ldb_msg_items(PyLdbMessageObject *self, + PyObject *value = NULL; + PyObject *py_el = PyLdbMessageElement_FromMessageElement(&msg->elements[i], msg->elements); + int res = 0; +- Py_CLEAR(py_el); + value = Py_BuildValue("(sO)", msg->elements[i].name, py_el); ++ Py_CLEAR(py_el); + if (value == NULL ) { + Py_CLEAR(l); + return NULL; + } +- res = PyList_SetItem(l, 0, value); ++ res = PyList_SetItem(l, j, value); + if (res == -1) { + Py_CLEAR(l); + return NULL; +-- +2.25.1 diff --git a/backport-0005-CVE-2020-25719-mit-samba-Rework-PAC-handling-in-kdb_.patch b/backport-0005-CVE-2020-25719-mit-samba-Rework-PAC-handling-in-kdb_.patch new file mode 100644 index 0000000..2d20742 --- /dev/null +++ b/backport-0005-CVE-2020-25719-mit-samba-Rework-PAC-handling-in-kdb_.patch @@ -0,0 +1,199 @@ +From f99cff8c0515d5f29aba9d605415744b1d1c3b08 Mon Sep 17 00:00:00 2001 +From: Andreas Schneider +Date: Mon, 12 Jul 2021 14:00:19 +0200 +Subject: [PATCH 205/266] CVE-2020-25719 mit-samba: Rework PAC handling in + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=f99cff8c0515d5f29aba9d605415744b1d1c3b08 + + kdb_samba_db_sign_auth_data() + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14561 + +Signed-off-by: Andreas Schneider +Reviewed-by: Andrew Bartlett +--- + selftest/knownfail_mit_kdc | 6 +- + source4/kdc/mit-kdb/kdb_samba_policies.c | 116 ++++++++++++++++++----- + 2 files changed, 93 insertions(+), 29 deletions(-) + +diff --git a/source4/kdc/mit-kdb/kdb_samba_policies.c b/source4/kdc/mit-kdb/kdb_samba_policies.c +index dce87c50049..7bc9a7b3347 100644 +--- a/source4/kdc/mit-kdb/kdb_samba_policies.c ++++ b/source4/kdc/mit-kdb/kdb_samba_policies.c +@@ -4,7 +4,7 @@ + Samba KDB plugin for MIT Kerberos + + Copyright (c) 2010 Simo Sorce . +- Copyright (c) 2014 Andreas Schneider ++ Copyright (c) 2014-2021 Andreas Schneider + + 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 +@@ -325,11 +325,16 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context, + { + krb5_const_principal ks_client_princ = NULL; + krb5_db_entry *client_entry = NULL; ++ krb5_authdata **pac_auth_data = NULL; + krb5_authdata **authdata = NULL; + krb5_boolean is_as_req; + krb5_error_code code; + krb5_pac pac = NULL; + krb5_data pac_data; ++ bool with_pac = false; ++ bool generate_pac = false; ++ char *client_name = NULL; ++ + + is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0); + +@@ -374,8 +379,6 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context, + 0, + &client_entry); + if (code != 0) { +- char *client_name = NULL; +- + (void)krb5_unparse_name(context, + ks_client_princ, + &client_name); +@@ -407,43 +410,105 @@ krb5_error_code kdb_samba_db_sign_auth_data(krb5_context context, + client_entry = client; + } + +- if (is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) { ++ if (is_as_req) { ++ with_pac = mit_samba_princ_needs_pac(client_entry); ++ } else { ++ with_pac = mit_samba_princ_needs_pac(server); ++ } ++ ++ code = krb5_unparse_name(context, ++ client_princ, ++ &client_name); ++ if (code != 0) { ++ goto done; ++ } ++ ++ if (is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC) != 0) { ++ generate_pac = true; ++ } ++ ++ DBG_DEBUG("*** Sign data for client principal: %s [%s %s%s]\n", ++ client_name, ++ is_as_req ? "AS-REQ" : "TGS_REQ", ++ with_pac ? is_as_req ? "WITH_PAC" : "FIND_PAC" : "NO_PAC", ++ generate_pac ? " GENERATE_PAC" : ""); ++ ++ /* ++ * Generate PAC for the AS-REQ or check or generate one for the TGS if ++ * needed. ++ */ ++ if (with_pac && generate_pac) { ++ DBG_DEBUG("Generate PAC for AS-REQ [%s]\n", client_name); + code = ks_get_pac(context, client_entry, client_key, &pac); + if (code != 0) { + goto done; + } +- } +- +- if (!is_as_req) { +- code = ks_verify_pac(context, +- flags, +- ks_client_princ, +- client_entry, +- server, +- krbtgt, +- server_key, +- krbtgt_key, +- authtime, +- tgt_auth_data, +- &pac); ++ } else if (with_pac && !is_as_req) { ++ /* ++ * Find the PAC in the TGS, if one exists. ++ */ ++ code = krb5_find_authdata(context, ++ tgt_auth_data, ++ NULL, ++ KRB5_AUTHDATA_WIN2K_PAC, ++ &pac_auth_data); + if (code != 0) { ++ DBG_ERR("krb5_find_authdata failed: %d\n", code); + goto done; + } +- } ++ DBG_DEBUG("Found PAC data for TGS-REQ [%s]\n", client_name); + +- if (pac == NULL) { ++ if (pac_auth_data != NULL && pac_auth_data[0] != NULL) { ++ if (pac_auth_data[1] != NULL) { ++ DBG_ERR("Invalid PAC data!\n"); ++ code = KRB5KDC_ERR_BADOPTION; ++ goto done; ++ } + +- code = ks_get_pac(context, client_entry, client_key, &pac); +- if (code != 0) { +- goto done; ++ DBG_DEBUG("Verify PAC for TGS [%s]\n", ++ client_name); ++ ++ code = ks_verify_pac(context, ++ flags, ++ ks_client_princ, ++ client_entry, ++ server, ++ krbtgt, ++ server_key, ++ krbtgt_key, ++ authtime, ++ tgt_auth_data, ++ &pac); ++ if (code != 0) { ++ goto done; ++ } ++ } else { ++ if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) { ++ DBG_DEBUG("Generate PAC for constrained" ++ "delegation TGS [%s]\n", ++ client_name); ++ ++ code = ks_get_pac(context, ++ client_entry, ++ client_key, ++ &pac); ++ if (code != 0 && code != ENOENT) { ++ goto done; ++ } ++ } + } + } + + if (pac == NULL) { +- code = KRB5_KDB_DBTYPE_NOSUP; ++ DBG_DEBUG("No PAC data - we're done [%s]\n", client_name); ++ *signed_auth_data = NULL; ++ code = 0; + goto done; + } + ++ DBG_DEBUG("Signing PAC for %s [%s]\n", ++ is_as_req ? "AS-REQ" : "TGS-REQ", ++ client_name); + code = krb5_pac_sign(context, pac, authtime, ks_client_princ, + server_key, krbtgt_key, &pac_data); + if (code != 0) { +@@ -481,8 +546,9 @@ done: + if (client_entry != NULL && client_entry != client) { + ks_free_principal(context, client_entry); + } +- krb5_pac_free(context, pac); ++ SAFE_FREE(client_name); + krb5_free_authdata(context, authdata); ++ krb5_pac_free(context, pac); + + return code; + } +-- +2.23.0 + diff --git a/backport-0005-CVE-2020-25722-dsdb-Add-restrictions-on-computer-acc.patch b/backport-0005-CVE-2020-25722-dsdb-Add-restrictions-on-computer-acc.patch new file mode 100644 index 0000000..15af407 --- /dev/null +++ b/backport-0005-CVE-2020-25722-dsdb-Add-restrictions-on-computer-acc.patch @@ -0,0 +1,249 @@ +From a76d5d6202379c1f38f7f91df1cce006754463b2 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Wed, 22 Sep 2021 11:29:02 +1200 +Subject: [PATCH 070/266] CVE-2020-25722 dsdb: Add restrictions on computer + accounts without a trailing $ + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/a76d5d6202379c1f38f7f91df1cce006754463b2 +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 172 +++++++++++++++++++++--- + 1 file changed, 155 insertions(+), 17 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 283a2de..7881dd0 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -68,6 +68,13 @@ struct samldb_ctx { + /* used for add operations */ + enum samldb_add_type type; + ++ /* ++ * should we apply the need_trailing_dollar restriction to ++ * samAccountName ++ */ ++ ++ bool need_trailing_dollar; ++ + /* the resulting message */ + struct ldb_message *msg; + +@@ -232,12 +239,86 @@ static int samldb_unique_attr_check(struct samldb_ctx *ac, const char *attr, + + static int samldb_sam_accountname_valid_check(struct samldb_ctx *ac) + { +- int ret = samldb_unique_attr_check(ac, "samAccountName", NULL, +- ldb_get_default_basedn( +- ldb_module_get_ctx(ac->module))); +- if (ret == LDB_ERR_OBJECT_CLASS_VIOLATION) { ++ int ret = 0; ++ bool is_admin; ++ struct security_token *user_token = NULL; ++ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); ++ struct ldb_message_element *el = dsdb_get_single_valued_attr(ac->msg, "samAccountName", ++ ac->req->operation); ++ if (el == NULL || el->num_values == 0) { ++ ldb_asprintf_errstring(ldb, ++ "%08X: samldb: 'samAccountName' can't be deleted/empty!", ++ W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION)); ++ if (ac->req->operation == LDB_ADD) { ++ return LDB_ERR_CONSTRAINT_VIOLATION; ++ } else { ++ return LDB_ERR_UNWILLING_TO_PERFORM; ++ } ++ } ++ ++ ret = samldb_unique_attr_check(ac, "samAccountName", NULL, ++ ldb_get_default_basedn( ++ ldb_module_get_ctx(ac->module))); ++ ++ /* ++ * Error code munging to try and match what must be some quite ++ * strange code-paths in Windows ++ */ ++ if (ret == LDB_ERR_CONSTRAINT_VIOLATION ++ && ac->req->operation == LDB_MODIFY) { ++ ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; ++ } else if (ret == LDB_ERR_OBJECT_CLASS_VIOLATION) { + ret = LDB_ERR_CONSTRAINT_VIOLATION; + } ++ ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ ++ if (!ac->need_trailing_dollar) { ++ return LDB_SUCCESS; ++ } ++ ++ /* This does not permit a single $ */ ++ if (el->values[0].length < 2) { ++ ldb_asprintf_errstring(ldb, ++ "%08X: samldb: 'samAccountName' " ++ "can't just be one character!", ++ W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION)); ++ return LDB_ERR_UNWILLING_TO_PERFORM; ++ } ++ ++ user_token = acl_user_token(ac->module); ++ if (user_token == NULL) { ++ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; ++ } ++ ++ is_admin ++ = security_token_has_builtin_administrators(user_token); ++ ++ if (is_admin) { ++ /* ++ * Administrators are allowed to select strange names. ++ * This is poor practice but not prevented. ++ */ ++ return false; ++ } ++ ++ if (el->values[0].data[el->values[0].length - 1] != '$') { ++ ldb_asprintf_errstring(ldb, ++ "%08X: samldb: 'samAccountName' " ++ "must have a trailing $!", ++ W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION)); ++ return LDB_ERR_UNWILLING_TO_PERFORM; ++ } ++ if (el->values[0].data[el->values[0].length - 2] == '$') { ++ ldb_asprintf_errstring(ldb, ++ "%08X: samldb: 'samAccountName' " ++ "must not have a double trailing $!", ++ W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION)); ++ return LDB_ERR_UNWILLING_TO_PERFORM; ++ } ++ + return ret; + } + +@@ -554,17 +635,32 @@ static int samldb_schema_add_handle_mapiid(struct samldb_ctx *ac) + } + + /* sAMAccountName handling */ +-static int samldb_generate_sAMAccountName(struct ldb_context *ldb, ++static int samldb_generate_sAMAccountName(struct samldb_ctx *ac, + struct ldb_message *msg) + { ++ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + char *name; + +- /* Format: $000000-000000000000 */ ++ /* ++ * This is currently a Samba-only behaviour, to add a trailing ++ * $ even for the generated accounts. ++ */ ++ ++ if (ac->need_trailing_dollar) { ++ /* Format: $000000-00000000000$ */ ++ name = talloc_asprintf(msg, "$%.6X-%.6X%.5X$", ++ (unsigned int)generate_random(), ++ (unsigned int)generate_random(), ++ (unsigned int)generate_random()); ++ } else { ++ /* Format: $000000-000000000000 */ ++ ++ name = talloc_asprintf(msg, "$%.6X-%.6X%.6X", ++ (unsigned int)generate_random(), ++ (unsigned int)generate_random(), ++ (unsigned int)generate_random()); ++ } + +- name = talloc_asprintf(msg, "$%.6X-%.6X%.6X", +- (unsigned int)generate_random(), +- (unsigned int)generate_random(), +- (unsigned int)generate_random()); + if (name == NULL) { + return ldb_oom(ldb); + } +@@ -573,11 +669,10 @@ static int samldb_generate_sAMAccountName(struct ldb_context *ldb, + + static int samldb_check_sAMAccountName(struct samldb_ctx *ac) + { +- struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + int ret; + + if (ldb_msg_find_element(ac->msg, "sAMAccountName") == NULL) { +- ret = samldb_generate_sAMAccountName(ldb, ac->msg); ++ ret = samldb_generate_sAMAccountName(ac, ac->msg); + if (ret != LDB_SUCCESS) { + return ret; + } +@@ -1473,6 +1568,20 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac) + if (ret != LDB_SUCCESS) { + return ret; + } ++ ++ /* ++ * Require, for non-admin modifications, a trailing $ ++ * for either objectclass=computer or a trust account ++ * type in userAccountControl ++ */ ++ if ((user_account_control ++ & UF_TRUST_ACCOUNT_MASK) != 0) { ++ ac->need_trailing_dollar = true; ++ } ++ ++ if (is_computer_objectclass) { ++ ac->need_trailing_dollar = true; ++ } + + /* add "sAMAccountType" attribute */ + ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL); +@@ -3989,12 +4098,41 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) + + el = ldb_msg_find_element(ac->msg, "sAMAccountName"); + if (el != NULL) { ++ uint32_t user_account_control; ++ struct ldb_result *res = NULL; ++ const char * const attrs[] = { "userAccountControl", ++ "objectclass", ++ NULL }; ++ ret = dsdb_module_search_dn(ac->module, ++ ac, ++ &res, ++ ac->msg->dn, ++ attrs, ++ DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ++ ac->req); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ ++ user_account_control ++ = ldb_msg_find_attr_as_uint(res->msgs[0], ++ "userAccountControl", ++ 0); ++ ++ if ((user_account_control ++ & UF_TRUST_ACCOUNT_MASK) != 0) { ++ ac->need_trailing_dollar = true; ++ ++ } else if (samdb_find_attribute(ldb, ++ res->msgs[0], ++ "objectclass", ++ "computer") ++ != NULL) { ++ ac->need_trailing_dollar = true; ++ } ++ + ret = samldb_sam_accountname_valid_check(ac); +- /* +- * Other errors are checked for elsewhere, we just +- * want to prevent duplicates +- */ +- if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) { ++ if (ret != LDB_SUCCESS) { + return ret; + } + } +-- +2.27.0 + diff --git a/backport-0005-CVE-2021-3738-s4-rpc_server-netlogon-make-use-of-dce.patch b/backport-0005-CVE-2021-3738-s4-rpc_server-netlogon-make-use-of-dce.patch new file mode 100644 index 0000000..4dfb25b --- /dev/null +++ b/backport-0005-CVE-2021-3738-s4-rpc_server-netlogon-make-use-of-dce.patch @@ -0,0 +1,340 @@ +From 08b6c8fda591c129adecd0779bf4a62386b8c740 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 5 Aug 2021 15:09:04 +0200 +Subject: [PATCH 265/266] CVE-2021-3738 s4:rpc_server/netlogon: make use of + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=08b6c8fda591c129adecd0779bf4a62386b8c740 + + dcesrv_samdb_connect_as_*() helper + +This is not strictly required, but it makes it easier to audit that +source4/rpc_server no longer calls samdb_connect() directly and +also improves auditing for the dcesrv_samdb_connect_as_system() case. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14468 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source4/rpc_server/netlogon/dcerpc_netlogon.c | 136 +++--------------- + 1 file changed, 18 insertions(+), 118 deletions(-) + +diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c +index 09d0252c0c2..a1036a36787 100644 +--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c ++++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c +@@ -23,6 +23,7 @@ + + #include "includes.h" + #include "rpc_server/dcerpc_server.h" ++#include "rpc_server/common/common.h" + #include "auth/auth.h" + #include "auth/auth_sam_reply.h" + #include "dsdb/samdb/samdb.h" +@@ -283,12 +284,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper( + return NT_STATUS_INVALID_PARAMETER; + } + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- system_session(dce_call->conn->dce_ctx->lp_ctx), +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } +@@ -756,12 +752,7 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet(struct dcesrv_call_state *dce_call + &creds); + NT_STATUS_NOT_OK_RETURN(nt_status); + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- system_session(dce_call->conn->dce_ctx->lp_ctx), +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } +@@ -825,12 +816,7 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal + &creds); + NT_STATUS_NOT_OK_RETURN(nt_status); + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- system_session(dce_call->conn->dce_ctx->lp_ctx), +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } +@@ -1716,8 +1702,6 @@ static NTSTATUS dcesrv_netr_AccountSync(struct dcesrv_call_state *dce_call, TALL + static WERROR dcesrv_netr_GetDcName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct netr_GetDcName *r) + { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); + const char * const attrs[] = { NULL }; + struct ldb_context *sam_ctx; + struct ldb_message **res; +@@ -1744,12 +1728,7 @@ static WERROR dcesrv_netr_GetDcName(struct dcesrv_call_state *dce_call, TALLOC_C + */ + } + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return WERR_DS_UNAVAILABLE; + } +@@ -1951,13 +1930,8 @@ static WERROR dcesrv_netr_LogonControl_base_call(struct dcesrv_netr_LogonControl + if (!ok) { + struct ldb_context *sam_ctx; + +- sam_ctx = samdb_connect( +- state, +- state->dce_call->event_ctx, +- lp_ctx, +- system_session(lp_ctx), +- state->dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_system(state, ++ state->dce_call); + if (sam_ctx == NULL) { + return WERR_DS_UNAVAILABLE; + } +@@ -2154,8 +2128,6 @@ static WERROR fill_trusted_domains_array(TALLOC_CTX *mem_ctx, + static WERROR dcesrv_netr_GetAnyDCName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct netr_GetAnyDCName *r) + { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); + struct netr_DomainTrustList *trusts; + struct ldb_context *sam_ctx; + struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; +@@ -2169,12 +2141,7 @@ static WERROR dcesrv_netr_GetAnyDCName(struct dcesrv_call_state *dce_call, TALLO + r->in.domainname = lpcfg_workgroup(lp_ctx); + } + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return WERR_DS_UNAVAILABLE; + } +@@ -2316,17 +2283,9 @@ static WERROR dcesrv_netr_NETRLOGONCOMPUTECLIENTDIGEST(struct dcesrv_call_state + static WERROR dcesrv_netr_DsRGetSiteName(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct netr_DsRGetSiteName *r) + { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); + struct ldb_context *sam_ctx; +- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return WERR_DS_UNAVAILABLE; + } +@@ -2525,12 +2484,7 @@ static NTSTATUS dcesrv_netr_LogonGetDomainInfo(struct dcesrv_call_state *dce_cal + } + NT_STATUS_NOT_OK_RETURN(status); + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- system_session(dce_call->conn->dce_ctx->lp_ctx), +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } +@@ -2922,12 +2876,7 @@ static NTSTATUS dcesrv_netr_NetrLogonSendToSam(struct dcesrv_call_state *dce_cal + return NT_STATUS_INVALID_PARAMETER; + } + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- system_session(dce_call->conn->dce_ctx->lp_ctx), +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } +@@ -3038,8 +2987,6 @@ static void dcesrv_netr_DsRGetDCName_base_done(struct tevent_req *subreq); + static WERROR dcesrv_netr_DsRGetDCName_base_call(struct dcesrv_netr_DsRGetDCName_base_state *state) + { + struct dcesrv_call_state *dce_call = state->dce_call; +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); + TALLOC_CTX *mem_ctx = state->mem_ctx; + struct netr_DsRGetDCNameEx2 *r = &state->r; + struct ldb_context *sam_ctx; +@@ -3062,12 +3009,7 @@ static WERROR dcesrv_netr_DsRGetDCName_base_call(struct dcesrv_netr_DsRGetDCName + + ZERO_STRUCTP(r->out.info); + +- sam_ctx = samdb_connect(state, +- dce_call->event_ctx, +- lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return WERR_DS_UNAVAILABLE; + } +@@ -3522,11 +3464,8 @@ static WERROR dcesrv_netr_NetrEnumerateTrustedDomainsEx(struct dcesrv_call_state + static WERROR dcesrv_netr_DsRAddressToSitenamesExW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct netr_DsRAddressToSitenamesExW *r) + { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); + struct ldb_context *sam_ctx; + struct netr_DsRAddressToSitenamesExWCtr *ctr; +- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + sa_family_t sin_family; + struct sockaddr_in *addr; + #ifdef HAVE_IPV6 +@@ -3539,12 +3478,7 @@ static WERROR dcesrv_netr_DsRAddressToSitenamesExW(struct dcesrv_call_state *dce + const char *res; + uint32_t i; + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return WERR_DS_UNAVAILABLE; + } +@@ -3656,18 +3590,10 @@ static WERROR dcesrv_netr_DsRAddressToSitenamesW(struct dcesrv_call_state *dce_c + static WERROR dcesrv_netr_DsrGetDcSiteCoverageW(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct netr_DsrGetDcSiteCoverageW *r) + { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); + struct ldb_context *sam_ctx; + struct DcSitesCtr *ctr; +- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return WERR_DS_UNAVAILABLE; + } +@@ -3793,8 +3719,6 @@ static WERROR dcesrv_netr_DsrEnumerateDomainTrusts(struct dcesrv_call_state *dce + TALLOC_CTX *mem_ctx, + struct netr_DsrEnumerateDomainTrusts *r) + { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); + struct netr_DomainTrustList *trusts; + struct ldb_context *sam_ctx; + int ret; +@@ -3836,12 +3760,7 @@ static WERROR dcesrv_netr_DsrEnumerateDomainTrusts(struct dcesrv_call_state *dce + trusts->count = 0; + r->out.trusts = trusts; + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return WERR_GEN_FAILURE; + } +@@ -3951,7 +3870,6 @@ static WERROR dcesrv_netr_DsRGetForestTrustInformation(struct dcesrv_call_state + TALLOC_CTX *mem_ctx, + struct netr_DsRGetForestTrustInformation *r) + { +- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + struct auth_session_info *session_info = + dcesrv_call_session_info(dce_call); + enum security_user_level security_level; +@@ -3975,12 +3893,7 @@ static WERROR dcesrv_netr_DsRGetForestTrustInformation(struct dcesrv_call_state + return WERR_INVALID_FLAGS; + } + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return WERR_GEN_FAILURE; + } +@@ -4107,9 +4020,6 @@ static NTSTATUS dcesrv_netr_GetForestTrustInformation(struct dcesrv_call_state * + TALLOC_CTX *mem_ctx, + struct netr_GetForestTrustInformation *r) + { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); +- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; + struct netlogon_creds_CredentialState *creds = NULL; + struct ldb_context *sam_ctx = NULL; + struct ldb_dn *domain_dn = NULL; +@@ -4133,12 +4043,7 @@ static NTSTATUS dcesrv_netr_GetForestTrustInformation(struct dcesrv_call_state * + return NT_STATUS_NOT_IMPLEMENTED; + } + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return NT_STATUS_INTERNAL_ERROR; + } +@@ -4232,12 +4137,7 @@ static NTSTATUS dcesrv_netr_ServerGetTrustInfo(struct dcesrv_call_state *dce_cal + return NT_STATUS_INVALID_PARAMETER; + } + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- lp_ctx, +- system_session(lp_ctx), +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } +-- +2.23.0 + diff --git a/backport-0006-CVE-2020-25717-winbindd-allow-idmap-backends-to-mark.patch b/backport-0006-CVE-2020-25717-winbindd-allow-idmap-backends-to-mark.patch new file mode 100644 index 0000000..9bd8ff6 --- /dev/null +++ b/backport-0006-CVE-2020-25717-winbindd-allow-idmap-backends-to-mark.patch @@ -0,0 +1,83 @@ +From 04e10a843187810e97bf565731ddc5d70b0f4245 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 15 Sep 2020 17:26:11 +0200 +Subject: [PATCH 027/266] CVE-2020-25717 winbindd: allow idmap backends to mark + entries with ID_[TYPE_WB_]REQUIRE_TYPE + +This must only be used between winbindd parent and child! +It must not leak into outside world. + +Some backends require ID_TYPE_UID or ID_TYPE_GID as type_hint, +while others may only need ID_TYPE_BOTH in order to validate that +the domain exists. + +This will allow us to skip the wb_lookupsids_send/recv in the winbindd parent +in future and only do that on demand. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Gary Lockyer + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit 493f5d6b078e0b0f80d1ef25043e2834cb4fcb87) +--- + librpc/idl/idmap.idl | 23 +++++++++++++++++-- + source3/passdb/lookup_sid.c | 7 ++++++ + source3/winbindd/idmap_autorid.c | 6 ++--- + source3/winbindd/idmap_ldap.c | 29 ++++++++++++++++++++++++ + source3/winbindd/idmap_rw.c | 32 +++++++++++++++++++++++++-- + source3/winbindd/idmap_tdb_common.c | 22 +++++++++++++++++- + source3/winbindd/wb_sids2xids.c | 11 +++++++++ + source3/winbindd/winbindd_dual_srv.c | 6 +++++ + source3/winbindd/winbindd_getgroups.c | 7 ++++++ + 9 files changed, 135 insertions(+), 8 deletions(-) + +Conflict:only remain the first chunk +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=04e10a843187810e97bf565731ddc5d70b0f4245 + +diff --git a/librpc/idl/idmap.idl b/librpc/idl/idmap.idl +index 54fd888dcab..e58e39210c7 100644 +--- a/librpc/idl/idmap.idl ++++ b/librpc/idl/idmap.idl +@@ -11,7 +11,18 @@ interface idmap + ID_TYPE_NOT_SPECIFIED, + ID_TYPE_UID, + ID_TYPE_GID, +- ID_TYPE_BOTH ++ ID_TYPE_BOTH, ++ /* ++ * This are internal between winbindd ++ * parent and child. ++ * ++ * It means the idmap backend/child requires a valid type_hint ++ * for wbint_Sids2UnixIDs(): ++ * ++ * - ID_TYPE_UID or ID_TYPE_GID means the user/group exists ++ * - ID_TYPE_BOTH means that only the domain exist ++ */ ++ ID_TYPE_WB_REQUIRE_TYPE + } id_type; + + typedef [public] struct { +@@ -23,7 +34,15 @@ interface idmap + ID_UNKNOWN, + ID_MAPPED, + ID_UNMAPPED, +- ID_EXPIRED ++ ID_EXPIRED, ++ /* ++ * This means the idmap backend requires a valid type_hint ++ * in order to map a sid to a unix id. ++ * ++ * - ID_TYPE_UID or ID_TYPE_GID means the user/group exists ++ * - ID_TYPE_BOTH means that only the domain exist ++ */ ++ ID_REQUIRE_TYPE + } id_mapping; + + typedef [public] struct { +-- +2.23.0 + diff --git a/backport-0006-CVE-2020-25718-Change-sid-list.patch b/backport-0006-CVE-2020-25718-Change-sid-list.patch new file mode 100644 index 0000000..8da5773 --- /dev/null +++ b/backport-0006-CVE-2020-25718-Change-sid-list.patch @@ -0,0 +1,304 @@ +From fc65e4b49c9900aeca06276f05f31e20d28a6c20 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Fri, 1 Oct 2021 10:47:29 +1300 +Subject: [PATCH 232/284] CVE-2020-25718 s4-rpc_server: Change sid list + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=fc65e4b49c9900aeca06276f05f31e20d28a6c20 + + 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. + +This also avoids a lot of memory allocation. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton +--- + source4/rpc_server/common/sid_helper.c | 44 +++++++++---------- + source4/rpc_server/drsuapi/getncchanges.c | 33 +++++++++----- + source4/rpc_server/netlogon/dcerpc_netlogon.c | 33 +++++++++----- + 3 files changed, 67 insertions(+), 43 deletions(-) + +diff --git a/source4/rpc_server/common/sid_helper.c b/source4/rpc_server/common/sid_helper.c +index 698249391ef5..65d7e7c7271e 100644 +--- a/source4/rpc_server/common/sid_helper.c ++++ b/source4/rpc_server/common/sid_helper.c +@@ -29,13 +29,16 @@ + /* + see if any SIDs in list1 are in list2 + */ +-bool sid_list_match(const struct dom_sid **list1, const struct dom_sid **list2) ++bool sid_list_match(uint32_t num_sids1, ++ const struct dom_sid *list1, ++ uint32_t num_sids2, ++ const struct dom_sid *list2) + { + unsigned int i, j; + /* do we ever have enough SIDs here to worry about O(n^2) ? */ +- for (i=0; list1[i]; i++) { +- for (j=0; list2[j]; j++) { +- if (dom_sid_equal(list1[i], list2[j])) { ++ for (i=0; i < num_sids1; i++) { ++ for (j=0; j < num_sids2; j++) { ++ if (dom_sid_equal(&list1[i], &list2[j])) { + return true; + } + } +@@ -51,9 +54,10 @@ WERROR samdb_result_sid_array_ndr(struct ldb_context *sam_ctx, + struct ldb_message *msg, + TALLOC_CTX *mem_ctx, + const char *attr, +- const struct dom_sid ***sids, +- const struct dom_sid **additional_sids, +- unsigned int num_additional) ++ uint32_t *num_sids, ++ struct dom_sid **sids, ++ const struct dom_sid *additional_sids, ++ unsigned int num_additional) + { + struct ldb_message_element *el; + unsigned int i, j; +@@ -65,30 +69,25 @@ WERROR samdb_result_sid_array_ndr(struct ldb_context *sam_ctx, + } + + /* Make array long enough for NULL and additional SID */ +- (*sids) = talloc_array(mem_ctx, const struct dom_sid *, +- el->num_values + num_additional + 1); ++ (*sids) = talloc_array(mem_ctx, struct dom_sid, ++ el->num_values + num_additional); + W_ERROR_HAVE_NO_MEMORY(*sids); + + for (i=0; inum_values; i++) { + enum ndr_err_code ndr_err; +- struct dom_sid *sid; + +- sid = talloc(*sids, struct dom_sid); +- W_ERROR_HAVE_NO_MEMORY(sid); +- +- ndr_err = ndr_pull_struct_blob(&el->values[i], sid, sid, ++ ndr_err = ndr_pull_struct_blob_all_noalloc(&el->values[i], &(*sids)[i], + (ndr_pull_flags_fn_t)ndr_pull_dom_sid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return WERR_INTERNAL_DB_CORRUPTION; + } +- (*sids)[i] = sid; + } + + for (j = 0; j < num_additional; j++) { + (*sids)[i++] = additional_sids[j]; + } + +- (*sids)[i] = NULL; ++ *num_sids = i; + + return WERR_OK; + } +@@ -101,7 +100,8 @@ WERROR samdb_result_sid_array_dn(struct ldb_context *sam_ctx, + struct ldb_message *msg, + TALLOC_CTX *mem_ctx, + const char *attr, +- const struct dom_sid ***sids) ++ uint32_t *num_sids, ++ struct dom_sid **sids) + { + struct ldb_message_element *el; + unsigned int i; +@@ -112,23 +112,21 @@ WERROR samdb_result_sid_array_dn(struct ldb_context *sam_ctx, + return WERR_OK; + } + +- (*sids) = talloc_array(mem_ctx, const struct dom_sid *, el->num_values + 1); ++ (*sids) = talloc_array(mem_ctx, struct dom_sid, el->num_values + 1); + W_ERROR_HAVE_NO_MEMORY(*sids); + + for (i=0; inum_values; i++) { + struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, sam_ctx, &el->values[i]); + NTSTATUS status; +- struct dom_sid *sid; ++ struct dom_sid sid = { 0, }; + +- sid = talloc(*sids, struct dom_sid); +- W_ERROR_HAVE_NO_MEMORY(sid); +- status = dsdb_get_extended_dn_sid(dn, sid, "SID"); ++ status = dsdb_get_extended_dn_sid(dn, &sid, "SID"); + if (!NT_STATUS_IS_OK(status)) { + return WERR_INTERNAL_DB_CORRUPTION; + } + (*sids)[i] = sid; + } +- (*sids)[i] = NULL; ++ *num_sids = i; + + return WERR_OK; + } +diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c +index e458b2a99311..c7d2addd104d 100644 +--- a/source4/rpc_server/drsuapi/getncchanges.c ++++ b/source4/rpc_server/drsuapi/getncchanges.c +@@ -1171,10 +1171,10 @@ static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state, + const char *rodc_attrs[] = { "msDS-KrbTgtLink", "msDS-NeverRevealGroup", "msDS-RevealOnDemandGroup", "objectGUID", NULL }; + const char *obj_attrs[] = { "tokenGroups", "objectSid", "UserAccountControl", "msDS-KrbTgtLinkBL", NULL }; + struct ldb_result *rodc_res = NULL, *obj_res = NULL; +- const struct dom_sid **never_reveal_sids, **reveal_sids, **token_sids; ++ uint32_t num_never_reveal_sids, num_reveal_sids, num_token_sids; ++ struct dom_sid *never_reveal_sids, *reveal_sids, *token_sids; + const struct dom_sid *object_sid = NULL; + WERROR werr; +- const struct dom_sid *additional_sids[] = { NULL, NULL }; + + DEBUG(3,(__location__ ": DRSUAPI_EXOP_REPL_SECRET extended op on %s\n", + drs_ObjectIdentifier_to_string(mem_ctx, ncRoot))); +@@ -1259,12 +1259,13 @@ static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state, + + /* if the object SID is equal to the user_sid, allow */ + object_sid = samdb_result_dom_sid(mem_ctx, obj_res->msgs[0], "objectSid"); ++ if (object_sid == NULL) { ++ goto failed; ++ } + if (dom_sid_equal(user_sid, object_sid)) { + goto allowed; + } + +- additional_sids[0] = object_sid; +- + /* + * Must be an RODC account at this point, verify machine DN matches the + * SID account +@@ -1294,13 +1295,17 @@ static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state, + } + + werr = samdb_result_sid_array_dn(b_state->sam_ctx_system, rodc_res->msgs[0], +- mem_ctx, "msDS-NeverRevealGroup", &never_reveal_sids); ++ mem_ctx, "msDS-NeverRevealGroup", ++ &num_never_reveal_sids, ++ &never_reveal_sids); + if (!W_ERROR_IS_OK(werr)) { + goto denied; + } + + werr = samdb_result_sid_array_dn(b_state->sam_ctx_system, rodc_res->msgs[0], +- mem_ctx, "msDS-RevealOnDemandGroup", &reveal_sids); ++ mem_ctx, "msDS-RevealOnDemandGroup", ++ &num_reveal_sids, ++ &reveal_sids); + if (!W_ERROR_IS_OK(werr)) { + goto denied; + } +@@ -1311,19 +1316,27 @@ static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state, + * TODO determine if sIDHistory is required for this check + */ + werr = samdb_result_sid_array_ndr(b_state->sam_ctx_system, obj_res->msgs[0], +- mem_ctx, "tokenGroups", &token_sids, +- additional_sids, 1); ++ mem_ctx, "tokenGroups", ++ &num_token_sids, ++ &token_sids, ++ object_sid, 1); + if (!W_ERROR_IS_OK(werr) || token_sids==NULL) { + goto denied; + } + + if (never_reveal_sids && +- sid_list_match(token_sids, never_reveal_sids)) { ++ sid_list_match(num_token_sids, ++ token_sids, ++ num_never_reveal_sids, ++ never_reveal_sids)) { + goto denied; + } + + if (reveal_sids && +- sid_list_match(token_sids, reveal_sids)) { ++ sid_list_match(num_token_sids, ++ token_sids, ++ num_reveal_sids, ++ reveal_sids)) { + goto allowed; + } + +diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c +index 9972138dbdef..c8dd0ceeb775 100644 +--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c ++++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c +@@ -2850,10 +2850,10 @@ static bool sam_rodc_access_check(struct ldb_context *sam_ctx, + struct ldb_dn *rodc_dn; + int ret; + struct ldb_result *rodc_res = NULL, *obj_res = NULL; +- const struct dom_sid *additional_sids[] = { NULL, NULL }; + WERROR werr; + struct dom_sid *object_sid; +- const struct dom_sid **never_reveal_sids, **reveal_sids, **token_sids; ++ uint32_t num_never_reveal_sids, num_reveal_sids, num_token_sids; ++ struct dom_sid *never_reveal_sids, *reveal_sids, *token_sids; + + rodc_dn = ldb_dn_new_fmt(mem_ctx, sam_ctx, "", + dom_sid_string(mem_ctx, user_sid)); +@@ -2868,17 +2868,22 @@ static bool sam_rodc_access_check(struct ldb_context *sam_ctx, + if (ret != LDB_SUCCESS || obj_res->count != 1) goto denied; + + object_sid = samdb_result_dom_sid(mem_ctx, obj_res->msgs[0], "objectSid"); +- +- additional_sids[0] = object_sid; ++ if (object_sid == NULL) { ++ goto denied; ++ } + + werr = samdb_result_sid_array_dn(sam_ctx, rodc_res->msgs[0], +- mem_ctx, "msDS-NeverRevealGroup", &never_reveal_sids); ++ mem_ctx, "msDS-NeverRevealGroup", ++ &num_never_reveal_sids, ++ &never_reveal_sids); + if (!W_ERROR_IS_OK(werr)) { + goto denied; + } + + werr = samdb_result_sid_array_dn(sam_ctx, rodc_res->msgs[0], +- mem_ctx, "msDS-RevealOnDemandGroup", &reveal_sids); ++ mem_ctx, "msDS-RevealOnDemandGroup", ++ &num_reveal_sids, ++ &reveal_sids); + if (!W_ERROR_IS_OK(werr)) { + goto denied; + } +@@ -2889,19 +2894,27 @@ static bool sam_rodc_access_check(struct ldb_context *sam_ctx, + * TODO determine if sIDHistory is required for this check + */ + werr = samdb_result_sid_array_ndr(sam_ctx, obj_res->msgs[0], +- mem_ctx, "tokenGroups", &token_sids, +- additional_sids, 1); ++ mem_ctx, "tokenGroups", ++ &num_token_sids, ++ &token_sids, ++ object_sid, 1); + if (!W_ERROR_IS_OK(werr) || token_sids==NULL) { + goto denied; + } + + if (never_reveal_sids && +- sid_list_match(token_sids, never_reveal_sids)) { ++ sid_list_match(num_token_sids, ++ token_sids, ++ num_never_reveal_sids, ++ never_reveal_sids)) { + goto denied; + } + + if (reveal_sids && +- sid_list_match(token_sids, reveal_sids)) { ++ sid_list_match(num_token_sids, ++ token_sids, ++ num_reveal_sids, ++ reveal_sids)) { + goto allowed; + } + +-- +2.25.1 diff --git a/backport-0006-CVE-2020-25722-samdb-Fill-in-isCriticalSystemObject-.patch b/backport-0006-CVE-2020-25722-samdb-Fill-in-isCriticalSystemObject-.patch new file mode 100644 index 0000000..93cdcd9 --- /dev/null +++ b/backport-0006-CVE-2020-25722-samdb-Fill-in-isCriticalSystemObject-.patch @@ -0,0 +1,42 @@ +From 55d821ca8b5baaa69f88127b228bd4906e2cee68 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Thu, 21 Oct 2021 13:02:42 +1300 +Subject: [PATCH 072/266] CVE-2020-25722 samdb: Fill in isCriticalSystemObject + on any account type change + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/55d821ca8b5baaa69f88127b228bd4906e2cee68 +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 10 ++++++++-- + 1 files changed, 8 insertions(+), 2 deletions(-) + delete mode 100644 selftest/knownfail.d/sam-isCriticalSystemObject + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index aeef663d2f0..5352af1099f 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -2621,8 +2621,14 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) + el->flags = LDB_FLAG_MOD_REPLACE; + } + +- /* "isCriticalSystemObject" might be set/changed */ +- if (old_is_critical != new_is_critical) { ++ /* ++ * "isCriticalSystemObject" might be set/changed ++ * ++ * Even a change from UF_NORMAL_ACCOUNT (implicitly FALSE) to ++ * UF_WORKSTATION_TRUST_ACCOUNT (actually FALSE) triggers ++ * creating the attribute. ++ */ ++ if (old_is_critical != new_is_critical || old_atype != new_atype) { + ret = ldb_msg_add_string(ac->msg, "isCriticalSystemObject", + new_is_critical ? "TRUE": "FALSE"); + if (ret != LDB_SUCCESS) { +-- +2.23.0 + diff --git a/backport-0006-CVE-2021-3738-s4-rpc_server-samr-make-use-of-dcesrv_.patch b/backport-0006-CVE-2021-3738-s4-rpc_server-samr-make-use-of-dcesrv_.patch new file mode 100644 index 0000000..888727b --- /dev/null +++ b/backport-0006-CVE-2021-3738-s4-rpc_server-samr-make-use-of-dcesrv_.patch @@ -0,0 +1,176 @@ +From 0203330e2fa23482d99809e777ccb8a93a728aa3 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 5 Aug 2021 14:24:40 +0200 +Subject: [PATCH 266/266] CVE-2021-3738 s4:rpc_server/samr: make use of + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=0203330e2fa23482d99809e777ccb8a93a728aa3 + + dcesrv_samdb_connect_as_*() helper + +This avoids a crash that's triggered by windows clients using +handles from samr_Connect*() on across multiple connections within +an association group. + +In other cases is not strictly required, but it makes it easier to audit that +source4/rpc_server no longer calls samdb_connect() directly and also +improves the auditing for the dcesrv_samdb_connect_as_system() case. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14468 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org Backported from master as Samba 4.13 does not + call dcerpc_is_transport_encrypted() and so session_info becomes + unused.] +--- + source4/rpc_server/samr/dcesrv_samr.c | 19 ++------------ + source4/rpc_server/samr/samr_password.c | 33 ++++--------------------- + 2 files changed, 7 insertions(+), 45 deletions(-) + +diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c +index 7345cac6bd6..c810aac7c8a 100644 +--- a/source4/rpc_server/samr/dcesrv_samr.c ++++ b/source4/rpc_server/samr/dcesrv_samr.c +@@ -210,8 +210,6 @@ exit: + static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct samr_Connect *r) + { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); + struct samr_connect_state *c_state; + struct dcesrv_handle *handle; + +@@ -223,18 +221,12 @@ static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_C + } + + /* make sure the sam database is accessible */ +- c_state->sam_ctx = samdb_connect(c_state, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ c_state->sam_ctx = dcesrv_samdb_connect_as_user(c_state, dce_call); + if (c_state->sam_ctx == NULL) { + talloc_free(c_state); + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + +- + handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_CONNECT); + if (!handle) { + talloc_free(c_state); +@@ -4807,8 +4799,6 @@ static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_st + static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct samr_GetDomPwInfo *r) + { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); + struct ldb_message **msgs; + int ret; + const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL }; +@@ -4816,12 +4806,7 @@ static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TAL + + ZERO_STRUCTP(r->out.info); + +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } +diff --git a/source4/rpc_server/samr/samr_password.c b/source4/rpc_server/samr/samr_password.c +index 52a644176e2..9144c23155b 100644 +--- a/source4/rpc_server/samr/samr_password.c ++++ b/source4/rpc_server/samr/samr_password.c +@@ -22,6 +22,7 @@ + + #include "includes.h" + #include "rpc_server/dcerpc_server.h" ++#include "rpc_server/common/common.h" + #include "rpc_server/samr/dcesrv_samr.h" + #include "system/time.h" + #include "../lib/crypto/crypto.h" +@@ -101,8 +102,6 @@ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, + TALLOC_CTX *mem_ctx, + struct samr_OemChangePasswordUser2 *r) + { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); + NTSTATUS status = NT_STATUS_WRONG_PASSWORD; + DATA_BLOB new_password, new_unicode_password; + char *new_pass; +@@ -146,12 +145,7 @@ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, + + /* Connect to a SAMDB with system privileges for fetching the old pw + * hashes. */ +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- system_session(dce_call->conn->dce_ctx->lp_ctx), +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } +@@ -249,12 +243,7 @@ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, + } + + /* Connect to a SAMDB with user privileges for the password change */ +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } +@@ -327,8 +316,6 @@ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, + TALLOC_CTX *mem_ctx, + struct samr_ChangePasswordUser3 *r) + { +- struct auth_session_info *session_info = +- dcesrv_call_session_info(dce_call); + NTSTATUS status = NT_STATUS_WRONG_PASSWORD; + DATA_BLOB new_password; + struct ldb_context *sam_ctx = NULL; +@@ -374,12 +361,7 @@ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, + + /* Connect to a SAMDB with system privileges for fetching the old pw + * hashes. */ +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- system_session(dce_call->conn->dce_ctx->lp_ctx), +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_system(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } +@@ -485,12 +467,7 @@ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, + } + + /* Connect to a SAMDB with user privileges for the password change */ +- sam_ctx = samdb_connect(mem_ctx, +- dce_call->event_ctx, +- dce_call->conn->dce_ctx->lp_ctx, +- session_info, +- dce_call->conn->remote_address, +- 0); ++ sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } +-- +2.23.0 + diff --git a/backport-0007-CVE-2020-25717-s3-idmap_hash-reliable-return-ID_TYPE.patch b/backport-0007-CVE-2020-25717-s3-idmap_hash-reliable-return-ID_TYPE.patch new file mode 100644 index 0000000..f09de4f --- /dev/null +++ b/backport-0007-CVE-2020-25717-s3-idmap_hash-reliable-return-ID_TYPE.patch @@ -0,0 +1,104 @@ +From 4925a110c4e0586ca74566beca2450bbc4d18e4c Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 23 Oct 2020 12:21:57 +0200 +Subject: [PATCH 029/266] CVE-2020-25717 s3:idmap_hash: reliable return + ID_TYPE_BOTH + +idmap_hash used to bounce back the requested type, +which was ID_TYPE_UID, ID_TYPE_GID or ID_TYPE_NOT_SPECIFIED +before as the winbindd parent always used a lookupsids. +When the lookupsids failed because of an unknown domain, +the idmap child weren't requested at all and the caller +sees ID_TYPE_NOT_SPECIFIED. + +This module should have supported ID_TYPE_BOTH since +samba-4.1.0, similar to idmap_rid and idmap_autorid. + +Now that the winbindd parent will pass ID_TYPE_BOTH in order to +indicate that the domain exists, it's better to always return +ID_TYPE_BOTH instead of a random mix of ID_TYPE_UID, ID_TYPE_GID +or ID_TYPE_BOTH. In order to request a type_hint it will return +ID_REQUIRE_TYPE for ID_TYPE_NOT_SPECIFIED, which means that +the parent at least assures that the domain sid exists. +And the caller still gets ID_TYPE_NOT_SPECIFIED if the +domain doesn't exist. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 + +Signed-off-by: Stefan Metzmacher + +Autobuild-User(master): Stefan Metzmacher +Autobuild-Date(master): Fri Jan 22 11:32:46 UTC 2021 on sn-devel-184 + +(cherry picked from commit d8339056eef2845805f573bd8b0f3323370ecc8f) +Reviewed-by: Ralph Boehme + +Autobuild-User(v4-14-test): Karolin Seeger +Autobuild-Date(v4-14-test): Wed Jan 27 17:06:51 UTC 2021 on sn-devel-184 + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit 99673b77b069674a6145552eb870de8829dfa503) +--- + source3/winbindd/idmap_hash/idmap_hash.c | 35 ++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=4925a110c4e0586ca74566beca2450bbc4d18e4c + +diff --git a/source3/winbindd/idmap_hash/idmap_hash.c b/source3/winbindd/idmap_hash/idmap_hash.c +index be0ba45a044..d0bed7631a6 100644 +--- a/source3/winbindd/idmap_hash/idmap_hash.c ++++ b/source3/winbindd/idmap_hash/idmap_hash.c +@@ -261,6 +261,25 @@ static NTSTATUS sids_to_unixids(struct idmap_domain *dom, + + ids[i]->status = ID_UNMAPPED; + ++ if (ids[i]->xid.type == ID_TYPE_NOT_SPECIFIED) { ++ /* ++ * idmap_hash used to bounce back the requested type, ++ * which was ID_TYPE_UID, ID_TYPE_GID or ++ * ID_TYPE_NOT_SPECIFIED before as the winbindd parent ++ * always used a lookupsids. When the lookupsids ++ * failed because of an unknown domain, the idmap child ++ * weren't requested at all and the caller sees ++ * ID_TYPE_NOT_SPECIFIED. ++ * ++ * Now that the winbindd parent will pass ID_TYPE_BOTH ++ * in order to indicate that the domain exists. ++ * We should ask the parent to fallback to lookupsids ++ * if the domain is not known yet. ++ */ ++ ids[i]->status = ID_REQUIRE_TYPE; ++ continue; ++ } ++ + sid_copy(&sid, ids[i]->sid); + sid_split_rid(&sid, &rid); + +@@ -270,6 +289,22 @@ static NTSTATUS sids_to_unixids(struct idmap_domain *dom, + /* Check that both hashes are non-zero*/ + + if (h_domain && h_rid) { ++ /* ++ * idmap_hash used to bounce back the requested type, ++ * which was ID_TYPE_UID, ID_TYPE_GID or ++ * ID_TYPE_NOT_SPECIFIED before as the winbindd parent ++ * always used a lookupsids. ++ * ++ * This module should have supported ID_TYPE_BOTH since ++ * samba-4.1.0, similar to idmap_rid and idmap_autorid. ++ * ++ * Now that the winbindd parent will pass ID_TYPE_BOTH ++ * in order to indicate that the domain exists, it's ++ * better to always return ID_TYPE_BOTH instead of a ++ * random mix of ID_TYPE_UID, ID_TYPE_GID or ++ * ID_TYPE_BOTH. ++ */ ++ ids[i]->xid.type = ID_TYPE_BOTH; + ids[i]->xid.id = combine_hashes(h_domain, h_rid); + ids[i]->status = ID_MAPPED; + } +-- +2.23.0 + diff --git a/backport-0007-CVE-2020-25718-Obtain-the-user.patch b/backport-0007-CVE-2020-25718-Obtain-the-user.patch new file mode 100644 index 0000000..bceb8c5 --- /dev/null +++ b/backport-0007-CVE-2020-25718-Obtain-the-user.patch @@ -0,0 +1,117 @@ +From 96ed96ea6a535185ecefeff6612e13f86d79de62 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Fri, 1 Oct 2021 11:09:48 +1300 +Subject: [PATCH 233/284] CVE-2020-25718 s4-rpc_server: Obtain the user + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=96ed96ea6a535185ecefeff6612e13f86d79de62 + + 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. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton +--- + source4/rpc_server/drsuapi/getncchanges.c | 28 +++++++++---------- + source4/rpc_server/netlogon/dcerpc_netlogon.c | 28 +++++++++---------- + 2 files changed, 28 insertions(+), 28 deletions(-) + +diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c +index c7d2addd104d..bc30e73e06bf 100644 +--- a/source4/rpc_server/drsuapi/getncchanges.c ++++ b/source4/rpc_server/drsuapi/getncchanges.c +@@ -1282,6 +1282,20 @@ static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state, + goto allowed; + } + ++ /* ++ * The SID list needs to include itself as well as the tokenGroups. ++ * ++ * TODO determine if sIDHistory is required for this check ++ */ ++ werr = samdb_result_sid_array_ndr(b_state->sam_ctx_system, obj_res->msgs[0], ++ mem_ctx, "tokenGroups", ++ &num_token_sids, ++ &token_sids, ++ object_sid, 1); ++ if (!W_ERROR_IS_OK(werr) || token_sids==NULL) { ++ goto denied; ++ } ++ + /* but it isn't allowed to get anyone elses krbtgt secrets */ + if (samdb_result_dn(b_state->sam_ctx_system, mem_ctx, + obj_res->msgs[0], "msDS-KrbTgtLinkBL", NULL)) { +@@ -1310,20 +1324,6 @@ static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state, + goto denied; + } + +- /* +- * The SID list needs to include itself as well as the tokenGroups. +- * +- * TODO determine if sIDHistory is required for this check +- */ +- werr = samdb_result_sid_array_ndr(b_state->sam_ctx_system, obj_res->msgs[0], +- mem_ctx, "tokenGroups", +- &num_token_sids, +- &token_sids, +- object_sid, 1); +- if (!W_ERROR_IS_OK(werr) || token_sids==NULL) { +- goto denied; +- } +- + if (never_reveal_sids && + sid_list_match(num_token_sids, + token_sids, +diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c +index c8dd0ceeb775..51c6666a1649 100644 +--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c ++++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c +@@ -2872,6 +2872,20 @@ static bool sam_rodc_access_check(struct ldb_context *sam_ctx, + goto denied; + } + ++ /* ++ * The SID list needs to include itself as well as the tokenGroups. ++ * ++ * TODO determine if sIDHistory is required for this check ++ */ ++ werr = samdb_result_sid_array_ndr(sam_ctx, obj_res->msgs[0], ++ mem_ctx, "tokenGroups", ++ &num_token_sids, ++ &token_sids, ++ object_sid, 1); ++ if (!W_ERROR_IS_OK(werr) || token_sids==NULL) { ++ goto denied; ++ } ++ + werr = samdb_result_sid_array_dn(sam_ctx, rodc_res->msgs[0], + mem_ctx, "msDS-NeverRevealGroup", + &num_never_reveal_sids, +@@ -2888,20 +2902,6 @@ static bool sam_rodc_access_check(struct ldb_context *sam_ctx, + goto denied; + } + +- /* +- * The SID list needs to include itself as well as the tokenGroups. +- * +- * TODO determine if sIDHistory is required for this check +- */ +- werr = samdb_result_sid_array_ndr(sam_ctx, obj_res->msgs[0], +- mem_ctx, "tokenGroups", +- &num_token_sids, +- &token_sids, +- object_sid, 1); +- if (!W_ERROR_IS_OK(werr) || token_sids==NULL) { +- goto denied; +- } +- + if (never_reveal_sids && + sid_list_match(num_token_sids, + token_sids, +-- +2.25.1 diff --git a/backport-0007-CVE-2020-25722-s4-acl-Make-sure-Control-Access-Right.patch b/backport-0007-CVE-2020-25722-s4-acl-Make-sure-Control-Access-Right.patch new file mode 100644 index 0000000..88b7426 --- /dev/null +++ b/backport-0007-CVE-2020-25722-s4-acl-Make-sure-Control-Access-Right.patch @@ -0,0 +1,472 @@ +From ae9eb6c7d85deda7a20867eeecb8835defc1990a Mon Sep 17 00:00:00 2001 +From: Nadezhda Ivanova +Date: Mon, 18 Oct 2021 14:27:59 +0300 +Subject: [PATCH 136/266] 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. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14832 + +Signed-off-by: Nadezhda Ivanova +Reviewed-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/ae9eb6c7d85deda7a20867eeecb8835defc1990a +--- + source4/dsdb/common/util.c | 11 +++ + source4/dsdb/samdb/ldb_modules/acl.c | 87 +++++++++++++++++++---- + source4/dsdb/samdb/ldb_modules/acl_util.c | 40 +++++++++++ + source4/dsdb/samdb/ldb_modules/dirsync.c | 13 +++- + source4/dsdb/samdb/ldb_modules/samldb.c | 56 ++++++++------- + 6 files changed, 168 insertions(+), 40 deletions(-) + delete mode 100644 selftest/knownfail.d/bug-14832 + +diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c +index ef03782f588..62e04d08003 100644 +--- a/source4/dsdb/common/util.c ++++ b/source4/dsdb/common/util.c +@@ -1179,6 +1179,17 @@ struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) + return new_dn; + } + ++struct ldb_dn *samdb_extended_rights_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) ++{ ++ struct ldb_dn *new_dn; ++ ++ new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx)); ++ if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Extended-Rights")) { ++ talloc_free(new_dn); ++ return NULL; ++ } ++ return new_dn; ++} + /* + work out the domain sid for the current open ldb + */ +diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c +index b1bbf936006..9cae15881de 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl.c ++++ b/source4/dsdb/samdb/ldb_modules/acl.c +@@ -698,7 +698,12 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx, + return LDB_SUCCESS; + } + +- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), ++ ret = acl_check_extended_right(tmp_ctx, ++ module, ++ req, ++ objectclass, ++ sd, ++ acl_user_token(module), + GUID_DRS_VALIDATE_SPN, + SEC_ADS_SELF_WRITE, + sid); +@@ -911,7 +916,7 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req) + return ldb_next_request(module, req); + } + +-/* ckecks if modifications are allowed on "Member" attribute */ ++/* checks if modifications are allowed on "Member" attribute */ + static int acl_check_self_membership(TALLOC_CTX *mem_ctx, + struct ldb_module *module, + struct ldb_request *req, +@@ -925,6 +930,16 @@ static int acl_check_self_membership(TALLOC_CTX *mem_ctx, + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct ldb_dn *user_dn; + struct ldb_message_element *member_el; ++ const struct ldb_message *msg = NULL; ++ ++ if (req->operation == LDB_MODIFY) { ++ msg = req->op.mod.message; ++ } else if (req->operation == LDB_ADD) { ++ msg = req->op.add.message; ++ } else { ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ + /* if we have wp, we can do whatever we like */ + if (acl_check_access_on_attribute(module, + mem_ctx, +@@ -935,13 +950,13 @@ static int acl_check_self_membership(TALLOC_CTX *mem_ctx, + return LDB_SUCCESS; + } + /* if we are adding/deleting ourselves, check for self membership */ +- ret = dsdb_find_dn_by_sid(ldb, mem_ctx, +- &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX], ++ ret = dsdb_find_dn_by_sid(ldb, mem_ctx, ++ &acl_user_token(module)->sids[PRIMARY_USER_SID_INDEX], + &user_dn); + if (ret != LDB_SUCCESS) { + return ret; + } +- member_el = ldb_msg_find_element(req->op.mod.message, "member"); ++ member_el = ldb_msg_find_element(msg, "member"); + if (!member_el) { + return ldb_operr(ldb); + } +@@ -955,13 +970,18 @@ static int acl_check_self_membership(TALLOC_CTX *mem_ctx, + return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; + } + } +- ret = acl_check_extended_right(mem_ctx, sd, acl_user_token(module), ++ ret = acl_check_extended_right(mem_ctx, ++ module, ++ req, ++ objectclass, ++ sd, ++ acl_user_token(module), + GUID_DRS_SELF_MEMBERSHIP, + SEC_ADS_SELF_WRITE, + sid); + if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { + dsdb_acl_debug(sd, acl_user_token(module), +- req->op.mod.message->dn, ++ msg->dn, + true, + 10); + } +@@ -1021,6 +1041,9 @@ static int acl_check_password_rights( + * so we don't have to strict verification of the input. + */ + ret = acl_check_extended_right(tmp_ctx, ++ module, ++ req, ++ objectclass, + sd, + acl_user_token(module), + GUID_DRS_USER_CHANGE_PASSWORD, +@@ -1044,7 +1067,12 @@ static int acl_check_password_rights( + * the only caller is samdb_set_password_internal(), + * so we don't have to strict verification of the input. + */ +- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), ++ ret = acl_check_extended_right(tmp_ctx, ++ module, ++ req, ++ objectclass, ++ sd, ++ acl_user_token(module), + GUID_DRS_FORCE_CHANGE_PASSWORD, + SEC_ADS_CONTROL_ACCESS, + sid); +@@ -1097,7 +1125,12 @@ static int acl_check_password_rights( + if (rep_attr_cnt > 0) { + pav->pwd_reset = true; + +- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), ++ ret = acl_check_extended_right(tmp_ctx, ++ module, ++ req, ++ objectclass, ++ sd, ++ acl_user_token(module), + GUID_DRS_FORCE_CHANGE_PASSWORD, + SEC_ADS_CONTROL_ACCESS, + sid); +@@ -1107,7 +1140,12 @@ static int acl_check_password_rights( + if (add_attr_cnt != del_attr_cnt) { + pav->pwd_reset = true; + +- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), ++ ret = acl_check_extended_right(tmp_ctx, ++ module, ++ req, ++ objectclass, ++ sd, ++ acl_user_token(module), + GUID_DRS_FORCE_CHANGE_PASSWORD, + SEC_ADS_CONTROL_ACCESS, + sid); +@@ -1117,7 +1155,12 @@ static int acl_check_password_rights( + if (add_val_cnt == 1 && del_val_cnt == 1) { + pav->pwd_reset = false; + +- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), ++ ret = acl_check_extended_right(tmp_ctx, ++ module, ++ req, ++ objectclass, ++ sd, ++ acl_user_token(module), + GUID_DRS_USER_CHANGE_PASSWORD, + SEC_ADS_CONTROL_ACCESS, + sid); +@@ -1131,7 +1174,12 @@ static int acl_check_password_rights( + if (add_val_cnt == 1 && del_val_cnt == 0) { + pav->pwd_reset = true; + +- ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), ++ ret = acl_check_extended_right(tmp_ctx, ++ module, ++ req, ++ objectclass, ++ sd, ++ acl_user_token(module), + GUID_DRS_FORCE_CHANGE_PASSWORD, + SEC_ADS_CONTROL_ACCESS, + sid); +@@ -1686,6 +1734,9 @@ static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx, + struct ldb_result *acl_res; + struct security_descriptor *sd = NULL; + struct dom_sid *sid = NULL; ++ const struct dsdb_schema *schema = NULL; ++ const struct dsdb_class *objectclass = NULL; ++ struct ldb_context *ldb = ldb_module_get_ctx(module); + static const char *acl_attrs[] = { + "nTSecurityDescriptor", + "objectClass", +@@ -1706,10 +1757,20 @@ static int acl_check_reanimate_tombstone(TALLOC_CTX *mem_ctx, + + ret = dsdb_get_sd_from_ldb_message(mem_ctx, req, acl_res->msgs[0], &sd); + sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid"); ++ schema = dsdb_get_schema(ldb, req); ++ if (!schema) { ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]); + if (ret != LDB_SUCCESS || !sd) { + return ldb_operr(ldb_module_get_ctx(module)); + } +- return acl_check_extended_right(mem_ctx, sd, acl_user_token(module), ++ return acl_check_extended_right(mem_ctx, ++ module, ++ req, ++ objectclass, ++ sd, ++ acl_user_token(module), + GUID_DRS_REANIMATE_TOMBSTONE, + SEC_ADS_CONTROL_ACCESS, sid); + } +diff --git a/source4/dsdb/samdb/ldb_modules/acl_util.c b/source4/dsdb/samdb/ldb_modules/acl_util.c +index f917d99517a..08a95c1c310 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl_util.c ++++ b/source4/dsdb/samdb/ldb_modules/acl_util.c +@@ -197,6 +197,9 @@ fail: + + /* checks for validated writes */ + int acl_check_extended_right(TALLOC_CTX *mem_ctx, ++ struct ldb_module *module, ++ struct ldb_request *req, ++ const struct dsdb_class *objectclass, + struct security_descriptor *sd, + struct security_token *token, + const char *ext_right, +@@ -208,6 +211,43 @@ int acl_check_extended_right(TALLOC_CTX *mem_ctx, + uint32_t access_granted; + struct object_tree *root = NULL; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); ++ static const char *no_attrs[] = { NULL }; ++ struct ldb_result *extended_rights_res = NULL; ++ struct ldb_dn *extended_rights_dn = NULL; ++ struct ldb_context *ldb = ldb_module_get_ctx(module); ++ int ret = 0; ++ ++ /* ++ * Find the extended right and check if applies to ++ * the objectclass of the object ++ */ ++ extended_rights_dn = samdb_extended_rights_dn(ldb, req); ++ if (!extended_rights_dn) { ++ ldb_set_errstring(ldb, ++ "access_check: CN=Extended-Rights dn could not be generated!"); ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ ++ /* Note: we are checking only the structural object class. */ ++ ret = dsdb_module_search(module, req, &extended_rights_res, ++ extended_rights_dn, LDB_SCOPE_ONELEVEL, ++ no_attrs, ++ DSDB_FLAG_NEXT_MODULE | ++ DSDB_FLAG_AS_SYSTEM, ++ req, ++ "(&(rightsGuid=%s)(appliesTo=%s))", ++ ext_right, ++ GUID_string(tmp_ctx, ++ &(objectclass->schemaIDGUID))); ++ ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } else if (extended_rights_res->count == 0 ) { ++ ldb_debug(ldb, LDB_DEBUG_TRACE, ++ "acl_check_extended_right: Could not find appliesTo for %s\n", ++ ext_right); ++ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; ++ } + + GUID_from_string(ext_right, &right); + +diff --git a/source4/dsdb/samdb/ldb_modules/dirsync.c b/source4/dsdb/samdb/ldb_modules/dirsync.c +index 21555491159..a58e290607c 100644 +--- a/source4/dsdb/samdb/ldb_modules/dirsync.c ++++ b/source4/dsdb/samdb/ldb_modules/dirsync.c +@@ -1065,7 +1065,9 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req + if (!(dirsync_ctl->flags & LDAP_DIRSYNC_OBJECT_SECURITY)) { + struct dom_sid *sid; + struct security_descriptor *sd = NULL; +- const char *acl_attrs[] = { "nTSecurityDescriptor", "objectSid", NULL }; ++ const char *acl_attrs[] = { "nTSecurityDescriptor", "objectSid", "objectClass", NULL }; ++ const struct dsdb_schema *schema = NULL; ++ const struct dsdb_class *objectclass = NULL; + /* + * If we don't have the flag and if we have the "replicate directory change" granted + * then we upgrade ourself to system to not be blocked by the acl +@@ -1095,7 +1097,14 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req + if (ret != LDB_SUCCESS) { + return ret; + } +- ret = acl_check_extended_right(dsc, sd, acl_user_token(module), GUID_DRS_GET_CHANGES, SEC_ADS_CONTROL_ACCESS, sid); ++ schema = dsdb_get_schema(ldb, req); ++ if (!schema) { ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]); ++ ret = acl_check_extended_right(dsc, module, req, objectclass, ++ sd, acl_user_token(module), ++ GUID_DRS_GET_CHANGES, SEC_ADS_CONTROL_ACCESS, sid); + + if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { + return ret; +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 5352af1099f..6db7840b0c1 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -2192,12 +2192,15 @@ static int samldb_check_user_account_control_objectclass_invariants( + return LDB_SUCCESS; + } + +-static int samldb_get_domain_secdesc(struct samldb_ctx *ac, +- struct security_descriptor **domain_sd) ++static int samldb_get_domain_secdesc_and_oc(struct samldb_ctx *ac, ++ struct security_descriptor **domain_sd, ++ const struct dsdb_class **objectclass) + { +- const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL}; ++ const char * const sd_attrs[] = {"ntSecurityDescriptor", "objectClass", NULL}; + struct ldb_result *res; + struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module)); ++ const struct dsdb_schema *schema = NULL; ++ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + int ret = dsdb_module_search_dn(ac->module, ac, &res, + domain_dn, + sd_attrs, +@@ -2210,6 +2213,11 @@ static int samldb_get_domain_secdesc(struct samldb_ctx *ac, + return ldb_module_operr(ac->module); + } + ++ schema = dsdb_get_schema(ldb, ac->req); ++ if (!schema) { ++ return ldb_module_operr(ac->module);; ++ } ++ *objectclass = dsdb_get_structural_oc_from_msg(schema, res->msgs[0]); + return dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(ac->module), + ac, res->msgs[0], domain_sd); + +@@ -2228,6 +2236,7 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac, + bool need_acl_check = false; + struct security_token *user_token; + struct security_descriptor *domain_sd; ++ const struct dsdb_class *objectclass = NULL; + const struct uac_to_guid { + uint32_t uac; + uint32_t priv_to_change_from; +@@ -2313,7 +2322,7 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac, + return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; + } + +- ret = samldb_get_domain_secdesc(ac, &domain_sd); ++ ret = samldb_get_domain_secdesc_and_oc(ac, &domain_sd, &objectclass); + if (ret != LDB_SUCCESS) { + return ret; + } +@@ -2344,7 +2353,11 @@ static int samldb_check_user_account_control_acl(struct samldb_ctx *ac, + ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; + } + } else if (map[i].guid) { +- ret = acl_check_extended_right(ac, domain_sd, ++ ret = acl_check_extended_right(ac, ++ ac->module, ++ ac->req, ++ objectclass, ++ domain_sd, + user_token, + map[i].guid, + SEC_ADS_CONTROL_ACCESS, +@@ -2684,12 +2697,11 @@ static int samldb_check_pwd_last_set_acl(struct samldb_ctx *ac, + { + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + int ret = 0; +- struct ldb_result *res = NULL; +- const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL}; + struct security_token *user_token = NULL; + struct security_descriptor *domain_sd = NULL; + struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module)); + const char *operation = ""; ++ const struct dsdb_class *objectclass = NULL; + + if (dsdb_module_am_system(ac->module)) { + return LDB_SUCCESS; +@@ -2711,24 +2723,15 @@ static int samldb_check_pwd_last_set_acl(struct samldb_ctx *ac, + return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; + } + +- ret = dsdb_module_search_dn(ac->module, ac, &res, +- domain_dn, +- sd_attrs, +- DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, +- ac->req); +- if (ret != LDB_SUCCESS) { +- return ret; +- } +- if (res->count != 1) { +- return ldb_module_operr(ac->module); +- } +- +- ret = dsdb_get_sd_from_ldb_message(ldb, ac, res->msgs[0], &domain_sd); ++ ret = samldb_get_domain_secdesc_and_oc(ac, &domain_sd, &objectclass); + if (ret != LDB_SUCCESS) { + return ret; + } +- +- ret = acl_check_extended_right(ac, domain_sd, ++ ret = acl_check_extended_right(ac, ++ ac->module, ++ ac->req, ++ objectclass, ++ domain_sd, + user_token, + GUID_DRS_UNEXPIRE_PASSWORD, + SEC_ADS_CONTROL_ACCESS, +@@ -3758,16 +3761,21 @@ static int samldb_check_sensitive_attributes(struct samldb_ctx *ac) + el = ldb_msg_find_element(ac->msg, "msDS-SecondaryKrbTgtNumber"); + if (el) { + struct security_descriptor *domain_sd; ++ const struct dsdb_class *objectclass = NULL; + /* + * msDS-SecondaryKrbTgtNumber allows the creator to + * become an RODC, this is trusted as an RODC + * account + */ +- ret = samldb_get_domain_secdesc(ac, &domain_sd); ++ ret = samldb_get_domain_secdesc_and_oc(ac, &domain_sd, &objectclass); + if (ret != LDB_SUCCESS) { + return ret; + } +- ret = acl_check_extended_right(ac, domain_sd, ++ ret = acl_check_extended_right(ac, ++ ac->module, ++ ac->req, ++ objectclass, ++ domain_sd, + user_token, + GUID_DRS_DS_INSTALL_REPLICA, + SEC_ADS_CONTROL_ACCESS, +-- +2.23.0 + diff --git a/backport-0008-CVE-2020-25717-winbindd-call-wb_parent_idmap_setup_s.patch b/backport-0008-CVE-2020-25717-winbindd-call-wb_parent_idmap_setup_s.patch new file mode 100644 index 0000000..8d8816e --- /dev/null +++ b/backport-0008-CVE-2020-25717-winbindd-call-wb_parent_idmap_setup_s.patch @@ -0,0 +1,81 @@ +From 4a68c748e47e906f0d812a1572168e677afc1eb4 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 31 Aug 2021 17:04:56 +0200 +Subject: [PATCH 030/266] CVE-2020-25717 winbindd: call + wb_parent_idmap_setup_send() in wb_queryuser_send() + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14804 + +Signed-off-by: Ralph Boehme +Reviewed-by: Volker Lendecke +(cherry picked from commit 39c2ec72cb77945c3eb611fb1d7d7e9aad52bdfd) + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit 7d1dd87a6538f8c7f1e4938b0ff52cbd231fff90) +--- + source3/winbindd/wb_queryuser.c | 30 +++++++++++++++++++++++++++--- + 1 file changed, 27 insertions(+), 3 deletions(-) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=4a68c748e47e906f0d812a1572168e677afc1eb4 + +diff --git a/source3/winbindd/wb_queryuser.c b/source3/winbindd/wb_queryuser.c +index 9db51909c02..f5bc96f03f6 100644 +--- a/source3/winbindd/wb_queryuser.c ++++ b/source3/winbindd/wb_queryuser.c +@@ -25,10 +25,12 @@ + + struct wb_queryuser_state { + struct tevent_context *ev; +- struct wbint_userinfo *info; ++ struct wbint_userinfo *info; ++ const struct wb_parent_idmap_config *idmap_cfg; + bool tried_dclookup; + }; + ++static void wb_queryuser_idmap_setup_done(struct tevent_req *subreq); + static void wb_queryuser_got_uid(struct tevent_req *subreq); + static void wb_queryuser_got_domain(struct tevent_req *subreq); + static void wb_queryuser_got_dc(struct tevent_req *subreq); +@@ -60,13 +62,35 @@ struct tevent_req *wb_queryuser_send(TALLOC_CTX *mem_ctx, + + sid_copy(&info->user_sid, user_sid); + ++ subreq = wb_parent_idmap_setup_send(state, state->ev); ++ if (tevent_req_nomem(subreq, req)) { ++ return tevent_req_post(req, ev); ++ } ++ tevent_req_set_callback(subreq, wb_queryuser_idmap_setup_done, req); ++ return req; ++} ++ ++static void wb_queryuser_idmap_setup_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data( ++ subreq, struct tevent_req); ++ struct wb_queryuser_state *state = tevent_req_data( ++ req, struct wb_queryuser_state); ++ NTSTATUS status; ++ ++ status = wb_parent_idmap_setup_recv(subreq, &state->idmap_cfg); ++ TALLOC_FREE(subreq); ++ if (tevent_req_nterror(req, status)) { ++ return; ++ } ++ + subreq = wb_sids2xids_send( + state, state->ev, &state->info->user_sid, 1); + if (tevent_req_nomem(subreq, req)) { +- return tevent_req_post(req, ev); ++ return; + } + tevent_req_set_callback(subreq, wb_queryuser_got_uid, req); +- return req; ++ return; + } + + static void wb_queryuser_got_uid(struct tevent_req *subreq) +-- +2.23.0 + diff --git a/backport-0008-CVE-2020-25718-Put-msDS-KrbTgtLinkBL-put-RODC-reveal-never-reveal.patch b/backport-0008-CVE-2020-25718-Put-msDS-KrbTgtLinkBL-put-RODC-reveal-never-reveal.patch new file mode 100644 index 0000000..00fee87 --- /dev/null +++ b/backport-0008-CVE-2020-25718-Put-msDS-KrbTgtLinkBL-put-RODC-reveal-never-reveal.patch @@ -0,0 +1,195 @@ +From 43f321dce53fbc7865933041ba3c877b9ee5cb6c Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Fri, 1 Oct 2021 11:38:16 +1300 +Subject: [PATCH] CVE-2020-25718 s4-rpc_server: Put RODC reveal/never reveal + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=43f321dce53fbc7865933041ba3c877b9ee5cb6c + + logic into a single helper function + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton +--- + source4/rpc_server/common/sid_helper.c | 49 +++++++++++++++++++ + source4/rpc_server/drsuapi/getncchanges.c | 37 +++----------- + source4/rpc_server/netlogon/dcerpc_netlogon.c | 38 +++----------- + 3 files changed, 63 insertions(+), 61 deletions(-) + +diff --git a/source4/rpc_server/common/sid_helper.c b/source4/rpc_server/common/sid_helper.c +index 65d7e7c7271..eaeab236fc0 100644 +--- a/source4/rpc_server/common/sid_helper.c ++++ b/source4/rpc_server/common/sid_helper.c +@@ -130,3 +130,52 @@ WERROR samdb_result_sid_array_dn(struct ldb_context *sam_ctx, + + return WERR_OK; + } ++ ++WERROR samdb_confirm_rodc_allowed_to_repl_to_sid_list(struct ldb_context *sam_ctx, ++ struct ldb_message *rodc_msg, ++ uint32_t num_token_sids, ++ struct dom_sid *token_sids) ++{ ++ uint32_t num_never_reveal_sids, num_reveal_sids; ++ struct dom_sid *never_reveal_sids, *reveal_sids; ++ TALLOC_CTX *frame = talloc_stackframe(); ++ WERROR werr = samdb_result_sid_array_dn(sam_ctx, rodc_msg, ++ frame, "msDS-NeverRevealGroup", ++ &num_never_reveal_sids, ++ &never_reveal_sids); ++ if (!W_ERROR_IS_OK(werr)) { ++ TALLOC_FREE(frame); ++ return WERR_DS_DRA_SECRETS_DENIED; ++ } ++ ++ werr = samdb_result_sid_array_dn(sam_ctx, rodc_msg, ++ frame, "msDS-RevealOnDemandGroup", ++ &num_reveal_sids, ++ &reveal_sids); ++ if (!W_ERROR_IS_OK(werr)) { ++ TALLOC_FREE(frame); ++ return WERR_DS_DRA_SECRETS_DENIED; ++ } ++ ++ if (never_reveal_sids && ++ sid_list_match(num_token_sids, ++ token_sids, ++ num_never_reveal_sids, ++ never_reveal_sids)) { ++ TALLOC_FREE(frame); ++ return WERR_DS_DRA_SECRETS_DENIED; ++ } ++ ++ if (reveal_sids && ++ sid_list_match(num_token_sids, ++ token_sids, ++ num_reveal_sids, ++ reveal_sids)) { ++ TALLOC_FREE(frame); ++ return WERR_OK; ++ } ++ ++ TALLOC_FREE(frame); ++ return WERR_DS_DRA_SECRETS_DENIED; ++ ++} +diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c +index bc30e73e06b..3b1d674573f 100644 +--- a/source4/rpc_server/drsuapi/getncchanges.c ++++ b/source4/rpc_server/drsuapi/getncchanges.c +@@ -1171,8 +1171,8 @@ static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state, + const char *rodc_attrs[] = { "msDS-KrbTgtLink", "msDS-NeverRevealGroup", "msDS-RevealOnDemandGroup", "objectGUID", NULL }; + const char *obj_attrs[] = { "tokenGroups", "objectSid", "UserAccountControl", "msDS-KrbTgtLinkBL", NULL }; + struct ldb_result *rodc_res = NULL, *obj_res = NULL; +- uint32_t num_never_reveal_sids, num_reveal_sids, num_token_sids; +- struct dom_sid *never_reveal_sids, *reveal_sids, *token_sids; ++ uint32_t num_token_sids; ++ struct dom_sid *token_sids; + const struct dom_sid *object_sid = NULL; + WERROR werr; + +@@ -1308,35 +1308,12 @@ static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state, + goto denied; + } + +- werr = samdb_result_sid_array_dn(b_state->sam_ctx_system, rodc_res->msgs[0], +- mem_ctx, "msDS-NeverRevealGroup", +- &num_never_reveal_sids, +- &never_reveal_sids); +- if (!W_ERROR_IS_OK(werr)) { +- goto denied; +- } +- +- werr = samdb_result_sid_array_dn(b_state->sam_ctx_system, rodc_res->msgs[0], +- mem_ctx, "msDS-RevealOnDemandGroup", +- &num_reveal_sids, +- &reveal_sids); +- if (!W_ERROR_IS_OK(werr)) { +- goto denied; +- } +- +- if (never_reveal_sids && +- sid_list_match(num_token_sids, +- token_sids, +- num_never_reveal_sids, +- never_reveal_sids)) { +- goto denied; +- } ++ werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(b_state->sam_ctx_system, ++ rodc_res->msgs[0], ++ num_token_sids, ++ token_sids); + +- if (reveal_sids && +- sid_list_match(num_token_sids, +- token_sids, +- num_reveal_sids, +- reveal_sids)) { ++ if (W_ERROR_IS_OK(werr)) { + goto allowed; + } + +diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c +index 51c6666a164..1aecd65bb61 100644 +--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c ++++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c +@@ -2852,8 +2852,8 @@ static bool sam_rodc_access_check(struct ldb_context *sam_ctx, + struct ldb_result *rodc_res = NULL, *obj_res = NULL; + WERROR werr; + struct dom_sid *object_sid; +- uint32_t num_never_reveal_sids, num_reveal_sids, num_token_sids; +- struct dom_sid *never_reveal_sids, *reveal_sids, *token_sids; ++ uint32_t num_token_sids; ++ struct dom_sid *token_sids; + + rodc_dn = ldb_dn_new_fmt(mem_ctx, sam_ctx, "", + dom_sid_string(mem_ctx, user_sid)); +@@ -2886,38 +2886,14 @@ static bool sam_rodc_access_check(struct ldb_context *sam_ctx, + goto denied; + } + +- werr = samdb_result_sid_array_dn(sam_ctx, rodc_res->msgs[0], +- mem_ctx, "msDS-NeverRevealGroup", +- &num_never_reveal_sids, +- &never_reveal_sids); +- if (!W_ERROR_IS_OK(werr)) { +- goto denied; +- } +- +- werr = samdb_result_sid_array_dn(sam_ctx, rodc_res->msgs[0], +- mem_ctx, "msDS-RevealOnDemandGroup", +- &num_reveal_sids, +- &reveal_sids); +- if (!W_ERROR_IS_OK(werr)) { +- goto denied; +- } ++ werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(sam_ctx, ++ rodc_res->msgs[0], ++ num_token_sids, ++ token_sids); + +- if (never_reveal_sids && +- sid_list_match(num_token_sids, +- token_sids, +- num_never_reveal_sids, +- never_reveal_sids)) { +- goto denied; +- } +- +- if (reveal_sids && +- sid_list_match(num_token_sids, +- token_sids, +- num_reveal_sids, +- reveal_sids)) { ++ if (W_ERROR_IS_OK(werr)) { + goto allowed; + } +- + denied: + return false; + allowed: +-- +2.25.1 + diff --git a/backport-0008-CVE-2020-25722-Check-all-elements-in-acl_check_spn-n.patch b/backport-0008-CVE-2020-25722-Check-all-elements-in-acl_check_spn-n.patch new file mode 100644 index 0000000..efa1b4c --- /dev/null +++ b/backport-0008-CVE-2020-25722-Check-all-elements-in-acl_check_spn-n.patch @@ -0,0 +1,97 @@ +From f1c64ed29ea0911beaa1cd3b80915ef5b44085af Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 1 Nov 2021 17:19:29 +1300 +Subject: [PATCH 137/266] 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 +Reviewed-by: Joseph Sutton + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/f1c64ed29ea0911beaa1cd3b80915ef5b44085af + +--- + source4/dsdb/samdb/ldb_modules/acl.c | 31 +++++++++++++++++++++------- + 1 files changed, 23 insertions(+), 8 deletions(-) + delete mode 100644 selftest/knownfail.d/acl-spn + +diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c +index 9cae15881de..d0b3da4d9e8 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl.c ++++ b/source4/dsdb/samdb/ldb_modules/acl.c +@@ -653,9 +653,14 @@ success: + return LDB_SUCCESS; + } + ++/* ++ * Passing in 'el' is critical, we want to check all the values. ++ * ++ */ + static int acl_check_spn(TALLOC_CTX *mem_ctx, + struct ldb_module *module, + struct ldb_request *req, ++ const struct ldb_message_element *el, + struct security_descriptor *sd, + struct dom_sid *sid, + const struct dsdb_attribute *attr, +@@ -667,7 +672,6 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx, + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct ldb_result *acl_res; + struct ldb_result *netbios_res; +- struct ldb_message_element *el; + struct ldb_dn *partitions_dn = samdb_partitions_dn(ldb, tmp_ctx); + uint32_t userAccountControl; + const char *samAccountName; +@@ -717,6 +721,23 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx, + return ret; + } + ++ /* ++ * If we have "validated write spn", allow delete of any ++ * existing value (this keeps constrained delete to the same ++ * rules as unconstrained) ++ */ ++ if (req->operation == LDB_MODIFY) { ++ /* ++ * If not add or replace (eg delete), ++ * return success ++ */ ++ if ((el->flags ++ & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)) == 0) { ++ talloc_free(tmp_ctx); ++ return LDB_SUCCESS; ++ } ++ } ++ + ret = dsdb_module_search_dn(module, tmp_ctx, + &acl_res, req->op.mod.message->dn, + acl_attrs, +@@ -745,13 +766,6 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx, + + netbios_name = ldb_msg_find_attr_as_string(netbios_res->msgs[0], "nETBIOSName", NULL); + +- el = ldb_msg_find_element(req->op.mod.message, "servicePrincipalName"); +- if (!el) { +- talloc_free(tmp_ctx); +- return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, +- "Error finding element for servicePrincipalName."); +- } +- + /* NTDSDSA objectGuid of object we are checking SPN for */ + if (userAccountControl & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) { + ret = dsdb_module_find_ntdsguid_for_computer(module, tmp_ctx, +@@ -1510,6 +1524,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) + ret = acl_check_spn(tmp_ctx, + module, + req, ++ el, + sd, + sid, + attr, +-- +2.23.0 + diff --git a/backport-0009-CVE-2020-25717-winbind-ensure-wb_parent_idmap_setup_.patch b/backport-0009-CVE-2020-25717-winbind-ensure-wb_parent_idmap_setup_.patch new file mode 100644 index 0000000..37d2bb8 --- /dev/null +++ b/backport-0009-CVE-2020-25717-winbind-ensure-wb_parent_idmap_setup_.patch @@ -0,0 +1,109 @@ +From 4a39d8a1610b635760ac182be894d206eb0a1ee7 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Fri, 20 Aug 2021 15:04:49 +0200 +Subject: [PATCH 031/266] CVE-2020-25717 winbind: ensure + wb_parent_idmap_setup_send() gets called in winbindd_allocate_uid_send() + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14804 +RN: winbindd can crash because idmap child state is not fully initialized + +Signed-off-by: Ralph Boehme +Reviewed-by: Volker Lendecke + +Autobuild-User(master): Volker Lendecke +Autobuild-Date(master): Thu Sep 2 15:20:06 UTC 2021 on sn-devel-184 + +(cherry picked from commit d0f6d54354b02f5591706814fbd1e4844788fdfa) + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit 446f89510f2e55a551e2975a6cbf01c6a023ba0c) +--- + source3/winbindd/winbindd_allocate_uid.c | 44 +++++++++++++++++++++--- + 1 file changed, 39 insertions(+), 5 deletions(-) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=4a39d8a1610b635760ac182be894d206eb0a1ee7 + +diff --git a/source3/winbindd/winbindd_allocate_uid.c b/source3/winbindd/winbindd_allocate_uid.c +index 69ce61c872e..64711f1b661 100644 +--- a/source3/winbindd/winbindd_allocate_uid.c ++++ b/source3/winbindd/winbindd_allocate_uid.c +@@ -22,9 +22,11 @@ + #include "librpc/gen_ndr/ndr_winbind_c.h" + + struct winbindd_allocate_uid_state { ++ struct tevent_context *ev; + uint64_t uid; + }; + ++static void winbindd_allocate_uid_initialized(struct tevent_req *subreq); + static void winbindd_allocate_uid_done(struct tevent_req *subreq); + + struct tevent_req *winbindd_allocate_uid_send(TALLOC_CTX *mem_ctx, +@@ -34,25 +36,57 @@ struct tevent_req *winbindd_allocate_uid_send(TALLOC_CTX *mem_ctx, + { + struct tevent_req *req, *subreq; + struct winbindd_allocate_uid_state *state; +- struct dcerpc_binding_handle *child_binding_handle = NULL; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_allocate_uid_state); + if (req == NULL) { + return NULL; + } ++ state->ev = ev; + + DEBUG(3, ("allocate_uid\n")); + +- child_binding_handle = idmap_child_handle(); ++ subreq = wb_parent_idmap_setup_send(state, ev); ++ if (tevent_req_nomem(subreq, req)) { ++ return tevent_req_post(req, ev); ++ } ++ tevent_req_set_callback(subreq, winbindd_allocate_uid_initialized, req); ++ return req; ++} ++ ++static void winbindd_allocate_uid_initialized(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data( ++ subreq, struct tevent_req); ++ struct dcerpc_binding_handle *child_binding_handle = NULL; ++ struct winbindd_allocate_uid_state *state = tevent_req_data( ++ req, struct winbindd_allocate_uid_state); ++ const struct wb_parent_idmap_config *cfg = NULL; ++ NTSTATUS status; ++ ++ status = wb_parent_idmap_setup_recv(subreq, &cfg); ++ TALLOC_FREE(subreq); ++ if (tevent_req_nterror(req, status)) { ++ return; ++ } ++ if (cfg->num_doms == 0) { ++ /* ++ * idmap_tdb also returns UNSUCCESSFUL if a range is full ++ */ ++ tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL); ++ return; ++ } ++ ++ child_binding_handle = idmap_child_handle(); + +- subreq = dcerpc_wbint_AllocateUid_send(state, ev, child_binding_handle, ++ subreq = dcerpc_wbint_AllocateUid_send(state, ++ state->ev, ++ child_binding_handle, + &state->uid); + if (tevent_req_nomem(subreq, req)) { +- return tevent_req_post(req, ev); ++ return; + } + tevent_req_set_callback(subreq, winbindd_allocate_uid_done, req); +- return req; + } + + static void winbindd_allocate_uid_done(struct tevent_req *subreq) +-- +2.23.0 + diff --git a/backport-0009-CVE-2020-25718-Put-msDS-KrbTgtLinkBL.patch b/backport-0009-CVE-2020-25718-Put-msDS-KrbTgtLinkBL.patch new file mode 100644 index 0000000..781548f --- /dev/null +++ b/backport-0009-CVE-2020-25718-Put-msDS-KrbTgtLinkBL.patch @@ -0,0 +1,110 @@ +From f83e48a60bee40e5a20ed8281aca97906d047639 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Fri, 1 Oct 2021 11:55:11 +1300 +Subject: [PATCH 235/284] CVE-2020-25718 s4-rpc_server: Put msDS-KrbTgtLinkBL + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=f83e48a60bee40e5a20ed8281aca97906d047639 + + 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. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton +--- + source4/rpc_server/common/sid_helper.c | 29 ++++++++++++++++--- + source4/rpc_server/drsuapi/getncchanges.c | 13 +-------- + source4/rpc_server/netlogon/dcerpc_netlogon.c | 1 + + 3 files changed, 27 insertions(+), 16 deletions(-) + +diff --git a/source4/rpc_server/common/sid_helper.c b/source4/rpc_server/common/sid_helper.c +index eaeab236fc01..ab2b4373b473 100644 +--- a/source4/rpc_server/common/sid_helper.c ++++ b/source4/rpc_server/common/sid_helper.c +@@ -133,16 +133,37 @@ WERROR samdb_result_sid_array_dn(struct ldb_context *sam_ctx, + + WERROR samdb_confirm_rodc_allowed_to_repl_to_sid_list(struct ldb_context *sam_ctx, + struct ldb_message *rodc_msg, ++ struct ldb_message *obj_msg, + uint32_t num_token_sids, + struct dom_sid *token_sids) + { + uint32_t num_never_reveal_sids, num_reveal_sids; + struct dom_sid *never_reveal_sids, *reveal_sids; + TALLOC_CTX *frame = talloc_stackframe(); +- WERROR werr = samdb_result_sid_array_dn(sam_ctx, rodc_msg, +- frame, "msDS-NeverRevealGroup", +- &num_never_reveal_sids, +- &never_reveal_sids); ++ WERROR werr; ++ ++ /* ++ * We are not allowed to get anyone elses krbtgt secrets (and ++ * in callers that don't shortcut before this, the RODC should ++ * not deal with any krbtgt) ++ */ ++ if (samdb_result_dn(sam_ctx, frame, ++ obj_msg, "msDS-KrbTgtLinkBL", NULL)) { ++ TALLOC_FREE(frame); ++ return WERR_DS_DRA_SECRETS_DENIED; ++ } ++ ++ if (ldb_msg_find_attr_as_uint(obj_msg, ++ "userAccountControl", 0) & ++ UF_INTERDOMAIN_TRUST_ACCOUNT) { ++ TALLOC_FREE(frame); ++ return WERR_DS_DRA_SECRETS_DENIED; ++ } ++ ++ werr = samdb_result_sid_array_dn(sam_ctx, rodc_msg, ++ frame, "msDS-NeverRevealGroup", ++ &num_never_reveal_sids, ++ &never_reveal_sids); + if (!W_ERROR_IS_OK(werr)) { + TALLOC_FREE(frame); + return WERR_DS_DRA_SECRETS_DENIED; +diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c +index 3b1d674573ff..a9d305fc9a05 100644 +--- a/source4/rpc_server/drsuapi/getncchanges.c ++++ b/source4/rpc_server/drsuapi/getncchanges.c +@@ -1296,20 +1296,9 @@ static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state, + goto denied; + } + +- /* but it isn't allowed to get anyone elses krbtgt secrets */ +- if (samdb_result_dn(b_state->sam_ctx_system, mem_ctx, +- obj_res->msgs[0], "msDS-KrbTgtLinkBL", NULL)) { +- goto denied; +- } +- +- if (ldb_msg_find_attr_as_uint(obj_res->msgs[0], +- "userAccountControl", 0) & +- UF_INTERDOMAIN_TRUST_ACCOUNT) { +- goto denied; +- } +- + werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(b_state->sam_ctx_system, + rodc_res->msgs[0], ++ obj_res->msgs[0], + num_token_sids, + token_sids); + +diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c +index 1aecd65bb618..92dd693ddcc1 100644 +--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c ++++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c +@@ -2888,6 +2888,7 @@ static bool sam_rodc_access_check(struct ldb_context *sam_ctx, + + werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(sam_ctx, + rodc_res->msgs[0], ++ obj_res->msgs[0], + num_token_sids, + token_sids); + +-- +2.25.1 diff --git a/backport-0009-CVE-2020-25722-Check-for-all-errors-from-acl_check_e.patch b/backport-0009-CVE-2020-25722-Check-for-all-errors-from-acl_check_e.patch new file mode 100644 index 0000000..198e514 --- /dev/null +++ b/backport-0009-CVE-2020-25722-Check-for-all-errors-from-acl_check_e.patch @@ -0,0 +1,35 @@ +From ef7f582772a6c621205fd16a8a7f2b826b7397d7 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 1 Nov 2021 17:21:16 +1300 +Subject: [PATCH 138/266] 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 +Reviewed-by: Joseph Sutton + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/ef7f582772a6c621205fd16a8a7f2b826b7397d7 + +--- + source4/dsdb/samdb/ldb_modules/acl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c +index d0b3da4d9e8..712724909e3 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl.c ++++ b/source4/dsdb/samdb/ldb_modules/acl.c +@@ -712,7 +712,7 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx, + SEC_ADS_SELF_WRITE, + sid); + +- if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { ++ if (ret != LDB_SUCCESS) { + dsdb_acl_debug(sd, acl_user_token(module), + req->op.mod.message->dn, + true, +-- +2.23.0 + diff --git a/backport-0010-CVE-2020-25717-auth_sam-use-pdb_get_domain_info-to-l.patch b/backport-0010-CVE-2020-25717-auth_sam-use-pdb_get_domain_info-to-l.patch new file mode 100644 index 0000000..2a855d8 --- /dev/null +++ b/backport-0010-CVE-2020-25717-auth_sam-use-pdb_get_domain_info-to-l.patch @@ -0,0 +1,228 @@ +From eb4123b5caed6c5cbfe8ef050f198e2d5a03f8b7 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 11 Nov 2020 14:42:55 +0200 +Subject: [PATCH 032/266] CVE-2020-25717 auth_sam: use pdb_get_domain_info to + look up DNS forest information + +When Samba is used as a part of FreeIPA domain controller, Windows +clients for a trusted AD forest may try to authenticate (perform logon +operation) as a REALM\name user account. + +Fix auth_sam plugins to accept DNS forest name if we are running on a DC +with PASSDB module providing domain information (e.g. pdb_get_domain_info() +returning non-NULL structure). Right now, only FreeIPA or Samba AD DC +PASSDB backends return this information but Samba AD DC configuration is +explicitly ignored by the two auth_sam (strict and netlogon3) modules. + +Detailed logs below: + +[2020/11/11 09:23:53.281296, 1, pid=42677, effective(65534, 65534), real(65534, 0), class=rpc_parse] ../../librpc/ndr/ndr.c:482(ndr_print_function_debug) + netr_LogonSamLogonWithFlags: struct netr_LogonSamLogonWithFlags + in: struct netr_LogonSamLogonWithFlags + server_name : * + server_name : '\\master.ipa.test' + computer_name : * + computer_name : 'AD1' + credential : * + credential: struct netr_Authenticator + cred: struct netr_Credential + data : 529f4b087c5f6546 + timestamp : Wed Nov 11 09:23:55 AM 2020 UTC + return_authenticator : * + return_authenticator: struct netr_Authenticator + cred: struct netr_Credential + data : 204f28f622010000 + timestamp : Fri May 2 06:37:50 AM 1986 UTC + logon_level : NetlogonNetworkTransitiveInformation (6) + logon : * + logon : union netr_LogonLevel(case 6) + network : * + network: struct netr_NetworkInfo + identity_info: struct netr_IdentityInfo + domain_name: struct lsa_String + length : 0x0010 (16) + size : 0x01fe (510) + string : * + string : 'IPA.TEST' + parameter_control : 0x00002ae0 (10976) + 0: MSV1_0_CLEARTEXT_PASSWORD_ALLOWED + 0: MSV1_0_UPDATE_LOGON_STATISTICS + 0: MSV1_0_RETURN_USER_PARAMETERS + 0: MSV1_0_DONT_TRY_GUEST_ACCOUNT + 1: MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT + 1: MSV1_0_RETURN_PASSWORD_EXPIRY + 1: MSV1_0_USE_CLIENT_CHALLENGE + 0: MSV1_0_TRY_GUEST_ACCOUNT_ONLY + 1: MSV1_0_RETURN_PROFILE_PATH + 0: MSV1_0_TRY_SPECIFIED_DOMAIN_ONLY + 1: MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT + 0: MSV1_0_DISABLE_PERSONAL_FALLBACK + 1: MSV1_0_ALLOW_FORCE_GUEST + 0: MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED + 0: MSV1_0_USE_DOMAIN_FOR_ROUTING_ONLY + 0: MSV1_0_ALLOW_MSVCHAPV2 + 0: MSV1_0_S4U2SELF + 0: MSV1_0_CHECK_LOGONHOURS_FOR_S4U + 0: MSV1_0_SUBAUTHENTICATION_DLL_EX + logon_id : 0x0000000000884ef2 (8933106) + account_name: struct lsa_String + length : 0x000e (14) + size : 0x000e (14) + string : * + string : 'idmuser' + workstation: struct lsa_String + length : 0x0000 (0) + size : 0x0000 (0) + string : * + string : '' + challenge : 417207867bd33c74 + nt: struct netr_ChallengeResponse + length : 0x00c0 (192) + size : 0x00c0 (192) + data : * + data: ARRAY(192) + [0000] A5 24 62 6E 31 DF 69 66 9E DC 54 D6 63 4C D6 2F .$bn1.if ..T.cL./ + [0010] 01 01 00 00 00 00 00 00 50 37 D7 60 0C B8 D6 01 ........ P7.`.... + [0020] 15 1B 38 4F 47 95 4D 62 00 00 00 00 02 00 0E 00 ..8OG.Mb ........ + [0030] 57 00 49 00 4E 00 32 00 30 00 31 00 36 00 01 00 W.I.N.2. 0.1.6... + [0040] 06 00 41 00 44 00 31 00 04 00 18 00 77 00 69 00 ..A.D.1. ....w.i. + [0050] 6E 00 32 00 30 00 31 00 36 00 2E 00 74 00 65 00 n.2.0.1. 6...t.e. + [0060] 73 00 74 00 03 00 20 00 61 00 64 00 31 00 2E 00 s.t... . a.d.1... + [0070] 77 00 69 00 6E 00 32 00 30 00 31 00 36 00 2E 00 w.i.n.2. 0.1.6... + [0080] 74 00 65 00 73 00 74 00 05 00 18 00 77 00 69 00 t.e.s.t. ....w.i. + [0090] 6E 00 32 00 30 00 31 00 36 00 2E 00 74 00 65 00 n.2.0.1. 6...t.e. + [00A0] 73 00 74 00 07 00 08 00 50 37 D7 60 0C B8 D6 01 s.t..... P7.`.... + [00B0] 06 00 04 00 02 00 00 00 00 00 00 00 00 00 00 00 ........ ........ + lm: struct netr_ChallengeResponse + length : 0x0018 (24) + size : 0x0018 (24) + data : * + data : 000000000000000000000000000000000000000000000000 + validation_level : 0x0006 (6) + flags : * + flags : 0x00000000 (0) + 0: NETLOGON_SAMLOGON_FLAG_PASS_TO_FOREST_ROOT + 0: NETLOGON_SAMLOGON_FLAG_PASS_CROSS_FOREST_HOP + 0: NETLOGON_SAMLOGON_FLAG_RODC_TO_OTHER_DOMAIN + 0: NETLOGON_SAMLOGON_FLAG_RODC_NTLM_REQUEST + +In such case checks for a workgroup name will not match the DNS forest +name used in the username specification: + +[2020/11/11 09:23:53.283055, 3, pid=42677, effective(65534, 65534), real(65534, 0), class=auth] ../../source3/auth/auth.c:200(auth_check_ntlm_password) + check_ntlm_password: Checking password for unmapped user [IPA.TEST]\[idmuser]@[] with the new password interface +[2020/11/11 09:23:53.283073, 3, pid=42677, effective(65534, 65534), real(65534, 0), class=auth] ../../source3/auth/auth.c:203(auth_check_ntlm_password) + check_ntlm_password: mapped user is: [IPA.TEST]\[idmuser]@[] +[2020/11/11 09:23:53.283082, 10, pid=42677, effective(65534, 65534), real(65534, 0), class=auth] ../../source3/auth/auth.c:213(auth_check_ntlm_password) + check_ntlm_password: auth_context challenge created by fixed +[2020/11/11 09:23:53.283091, 10, pid=42677, effective(65534, 65534), real(65534, 0), class=auth] ../../source3/auth/auth.c:216(auth_check_ntlm_password) + challenge is: +[2020/11/11 09:23:53.283099, 5, pid=42677, effective(65534, 65534), real(65534, 0)] ../../lib/util/util.c:678(dump_data) + [0000] 41 72 07 86 7B D3 3C 74 Ar..{. +Reviewed-by: Andreas Schneider + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +(cherry picked from commit 2a8b672652dcbcf55ec59be537773d76f0f14d0a) +--- + source3/auth/auth_sam.c | 45 +++++++++++++++++++++++++++++++++++++---- + 1 file changed, 41 insertions(+), 4 deletions(-) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=eb4123b5caed6c5cbfe8ef050f198e2d5a03f8b7 + +diff --git a/source3/auth/auth_sam.c b/source3/auth/auth_sam.c +index 3c12f959faf..e8e0d543f8c 100644 +--- a/source3/auth/auth_sam.c ++++ b/source3/auth/auth_sam.c +@@ -22,6 +22,7 @@ + + #include "includes.h" + #include "auth.h" ++#include "passdb.h" + + #undef DBGC_CLASS + #define DBGC_CLASS DBGC_AUTH +@@ -142,10 +143,28 @@ static NTSTATUS auth_samstrict_auth(const struct auth_context *auth_context, + break; + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: +- if ( !is_local_name && !is_my_domain ) { +- DEBUG(6,("check_samstrict_security: %s is not one of my local names or domain name (DC)\n", +- effective_domain)); +- return NT_STATUS_NOT_IMPLEMENTED; ++ if (!is_local_name && !is_my_domain) { ++ /* If we are running on a DC that has PASSDB module with domain ++ * information, check if DNS forest name is matching the domain ++ * name. This is the case of FreeIPA domain controller when ++ * trusted AD DCs attempt to authenticate FreeIPA users using ++ * the forest root domain (which is the only domain in FreeIPA). ++ */ ++ struct pdb_domain_info *dom_info = NULL; ++ ++ dom_info = pdb_get_domain_info(mem_ctx); ++ if ((dom_info != NULL) && (dom_info->dns_forest != NULL)) { ++ is_my_domain = strequal(user_info->mapped.domain_name, ++ dom_info->dns_forest); ++ } ++ ++ TALLOC_FREE(dom_info); ++ if (!is_my_domain) { ++ DEBUG(6,("check_samstrict_security: %s is not one " ++ "of my local names or domain name (DC)\n", ++ effective_domain)); ++ return NT_STATUS_NOT_IMPLEMENTED; ++ } + } + + break; +@@ -230,6 +249,24 @@ static NTSTATUS auth_sam_netlogon3_auth(const struct auth_context *auth_context, + } + + is_my_domain = strequal(user_info->mapped.domain_name, lp_workgroup()); ++ if (!is_my_domain) { ++ /* If we are running on a DC that has PASSDB module with domain ++ * information, check if DNS forest name is matching the domain ++ * name. This is the case of FreeIPA domain controller when ++ * trusted AD DCs attempt to authenticate FreeIPA users using ++ * the forest root domain (which is the only domain in FreeIPA). ++ */ ++ struct pdb_domain_info *dom_info = NULL; ++ dom_info = pdb_get_domain_info(mem_ctx); ++ ++ if ((dom_info != NULL) && (dom_info->dns_forest != NULL)) { ++ is_my_domain = strequal(user_info->mapped.domain_name, ++ dom_info->dns_forest); ++ } ++ ++ TALLOC_FREE(dom_info); ++ } ++ + if (!is_my_domain) { + DBG_INFO("%s is not our domain name (DC for %s)\n", + effective_domain, lp_workgroup()); +-- +2.23.0 + diff --git a/backport-0010-CVE-2020-25718-Confirm-that-the-RODC.patch b/backport-0010-CVE-2020-25718-Confirm-that-the-RODC.patch new file mode 100644 index 0000000..3ac8727 --- /dev/null +++ b/backport-0010-CVE-2020-25718-Confirm-that-the-RODC.patch @@ -0,0 +1,89 @@ +From a3443838c09576bace20a12ffb0605ec56b3fe28 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Fri, 1 Oct 2021 12:01:12 +1300 +Subject: [PATCH 236/284] CVE-2020-25718 s4-rpc_server: Confirm that the RODC + +Conflict: NA +Reference: https://git.samba.org/samba.git/?p=samba.git;a=patch;h=a3443838c09576bace20a12ffb0605ec56b3fe28 + + has the UF_PARTIAL_SECRETS_ACCOUNT bit + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14558 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton +--- + source4/rpc_server/common/sid_helper.c | 13 +++++++++++++ + source4/rpc_server/drsuapi/getncchanges.c | 7 ++++++- + source4/rpc_server/netlogon/dcerpc_netlogon.c | 7 ++++++- + 3 files changed, 25 insertions(+), 2 deletions(-) + +diff --git a/source4/rpc_server/common/sid_helper.c b/source4/rpc_server/common/sid_helper.c +index ab2b4373b473..99c5fc20d9d5 100644 +--- a/source4/rpc_server/common/sid_helper.c ++++ b/source4/rpc_server/common/sid_helper.c +@@ -141,6 +141,7 @@ WERROR samdb_confirm_rodc_allowed_to_repl_to_sid_list(struct ldb_context *sam_ct + struct dom_sid *never_reveal_sids, *reveal_sids; + TALLOC_CTX *frame = talloc_stackframe(); + WERROR werr; ++ uint32_t rodc_uac; + + /* + * We are not allowed to get anyone elses krbtgt secrets (and +@@ -160,6 +161,18 @@ WERROR samdb_confirm_rodc_allowed_to_repl_to_sid_list(struct ldb_context *sam_ct + return WERR_DS_DRA_SECRETS_DENIED; + } + ++ /* Be very sure the RODC is really an RODC */ ++ rodc_uac = ldb_msg_find_attr_as_uint(rodc_msg, ++ "userAccountControl", ++ 0); ++ if ((rodc_uac & UF_PARTIAL_SECRETS_ACCOUNT) ++ != UF_PARTIAL_SECRETS_ACCOUNT) { ++ TALLOC_FREE(frame); ++ DBG_ERR("Attempt to use an RODC account that is not an RODC: %s\n", ++ ldb_dn_get_linearized(rodc_msg->dn)); ++ return WERR_DS_DRA_SECRETS_DENIED; ++ } ++ + werr = samdb_result_sid_array_dn(sam_ctx, rodc_msg, + frame, "msDS-NeverRevealGroup", + &num_never_reveal_sids, +diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c +index a9d305fc9a05..2fbd178cedca 100644 +--- a/source4/rpc_server/drsuapi/getncchanges.c ++++ b/source4/rpc_server/drsuapi/getncchanges.c +@@ -1168,7 +1168,12 @@ static WERROR getncchanges_repl_secret(struct drsuapi_bind_state *b_state, + struct ldb_dn *ntds_dn = NULL, *server_dn = NULL; + struct ldb_dn *rodc_dn, *krbtgt_link_dn; + int ret; +- const char *rodc_attrs[] = { "msDS-KrbTgtLink", "msDS-NeverRevealGroup", "msDS-RevealOnDemandGroup", "objectGUID", NULL }; ++ const char *rodc_attrs[] = { "msDS-KrbTgtLink", ++ "msDS-NeverRevealGroup", ++ "msDS-RevealOnDemandGroup", ++ "objectGUID", ++ "userAccountControl", ++ NULL }; + const char *obj_attrs[] = { "tokenGroups", "objectSid", "UserAccountControl", "msDS-KrbTgtLinkBL", NULL }; + struct ldb_result *rodc_res = NULL, *obj_res = NULL; + uint32_t num_token_sids; +diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c +index 92dd693ddcc1..ff33389401c1 100644 +--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c ++++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c +@@ -2845,7 +2845,12 @@ static bool sam_rodc_access_check(struct ldb_context *sam_ctx, + struct dom_sid *user_sid, + struct ldb_dn *obj_dn) + { +- const char *rodc_attrs[] = { "msDS-KrbTgtLink", "msDS-NeverRevealGroup", "msDS-RevealOnDemandGroup", "objectGUID", NULL }; ++ const char *rodc_attrs[] = { "msDS-KrbTgtLink", ++ "msDS-NeverRevealGroup", ++ "msDS-RevealOnDemandGroup", ++ "objectGUID", ++ "userAccountControl", ++ NULL }; + const char *obj_attrs[] = { "tokenGroups", "objectSid", "UserAccountControl", "msDS-KrbTgtLinkBL", NULL }; + struct ldb_dn *rodc_dn; + int ret; +-- +2.25.1 diff --git a/backport-0010-CVE-2020-25722-s4-dsdb-cracknames-always-free-tmp_ct.patch b/backport-0010-CVE-2020-25722-s4-dsdb-cracknames-always-free-tmp_ct.patch new file mode 100644 index 0000000..30f1d37 --- /dev/null +++ b/backport-0010-CVE-2020-25722-s4-dsdb-cracknames-always-free-tmp_ct.patch @@ -0,0 +1,54 @@ +From c1973cedbaa5313448a436f86dc4d662efbe497e Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 11 Aug 2021 16:56:07 +1200 +Subject: [PATCH 141/266] CVE-2020-25722 s4/dsdb/cracknames: always free + tmp_ctx in spn_alias + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/c1973cedbaa5313448a436f86dc4d662efbe497e +--- + source4/dsdb/samdb/cracknames.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/source4/dsdb/samdb/cracknames.c b/source4/dsdb/samdb/cracknames.c +index b4bd9d8f9c9..7336778ec53 100644 +--- a/source4/dsdb/samdb/cracknames.c ++++ b/source4/dsdb/samdb/cracknames.c +@@ -99,10 +99,12 @@ static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, stru + + service_dn = ldb_dn_new(tmp_ctx, ldb_ctx, "CN=Directory Service,CN=Windows NT,CN=Services"); + if ( ! ldb_dn_add_base(service_dn, ldb_get_config_basedn(ldb_ctx))) { ++ talloc_free(tmp_ctx); + return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; + } + service_dn_str = ldb_dn_alloc_linearized(tmp_ctx, service_dn); + if ( ! service_dn_str) { ++ talloc_free(tmp_ctx); + return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; + } + +@@ -111,13 +113,15 @@ static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, stru + + if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) { + DEBUG(1, ("ldb_search: dn: %s not found: %s\n", service_dn_str, ldb_errstring(ldb_ctx))); ++ talloc_free(tmp_ctx); + return DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; + } else if (ret == LDB_ERR_NO_SUCH_OBJECT) { + DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str)); ++ talloc_free(tmp_ctx); + return DRSUAPI_DS_NAME_STATUS_NOT_FOUND; + } else if (res->count != 1) { +- talloc_free(res); + DEBUG(1, ("ldb_search: dn: %s not found\n", service_dn_str)); ++ talloc_free(tmp_ctx); + return DRSUAPI_DS_NAME_STATUS_NOT_FOUND; + } + +-- +2.23.0 + diff --git a/backport-0011-CVE-2020-25717-s3-winbindd-make-sure-we-default-to-r.patch b/backport-0011-CVE-2020-25717-s3-winbindd-make-sure-we-default-to-r.patch new file mode 100644 index 0000000..a1bbe6c --- /dev/null +++ b/backport-0011-CVE-2020-25717-s3-winbindd-make-sure-we-default-to-r.patch @@ -0,0 +1,176 @@ +From 5966f8c2d47ed0d6544d7ac242bcbe2c849b474e Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 4 Oct 2021 17:29:34 +0200 +Subject: [PATCH 103/266] CVE-2020-25717: s3:winbindd: make sure we default to + r->out.authoritative = true + +We need to make sure that temporary failures don't trigger a fallback +to the local SAM that silently ignores the domain name part for users. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/winbindd/winbindd_dual_srv.c | 7 +++++++ + source3/winbindd/winbindd_irpc.c | 7 +++++++ + source3/winbindd/winbindd_pam.c | 15 +++++++++++---- + source3/winbindd/winbindd_pam_auth_crap.c | 9 ++++++++- + source3/winbindd/winbindd_util.c | 7 +++++++ + 5 files changed, 40 insertions(+), 4 deletions(-) + +Conflict:{ --> unsigned char local_nt_response[24]; +delete a chunk from previos commit we don't introduce +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=5966f8c2d47ed0d6544d7ac242bcbe2c849b474e + +diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c +index 4a4894c2658..078fa77aed6 100644 +--- a/source3/winbindd/winbindd_dual_srv.c ++++ b/source3/winbindd/winbindd_dual_srv.c +@@ -940,6 +940,13 @@ NTSTATUS _winbind_SamLogon(struct pipes_struct *p, + union netr_Validation *validation = NULL; + bool interactive = false; + ++ /* ++ * Make sure we start with authoritative=true, ++ * it will only set to false if we don't know the ++ * domain. ++ */ ++ r->out.authoritative = true; ++ + domain = wb_child_domain(); + if (domain == NULL) { + return NT_STATUS_REQUEST_NOT_ACCEPTED; +diff --git a/source3/winbindd/winbindd_irpc.c b/source3/winbindd/winbindd_irpc.c +index fda29c7e702..12f4554f9b6 100644 +--- a/source3/winbindd/winbindd_irpc.c ++++ b/source3/winbindd/winbindd_irpc.c +@@ -141,6 +141,13 @@ static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg, + const char *target_domain_name = NULL; + const char *account_name = NULL; + ++ /* ++ * Make sure we start with authoritative=true, ++ * it will only set to false if we don't know the ++ * domain. ++ */ ++ req->out.authoritative = true; ++ + switch (req->in.logon_level) { + case NetlogonInteractiveInformation: + case NetlogonServiceInformation: +diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c +index c49033b375d..59dd18e27b8 100644 +--- a/source3/winbindd/winbindd_pam.c ++++ b/source3/winbindd/winbindd_pam.c +@@ -1797,7 +1797,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon( + unsigned char local_nt_response[24]; + fstring name_namespace, name_domain, name_user; + NTSTATUS result; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uint32_t flags = 0; + uint16_t validation_level = 0; + union netr_Validation *validation = NULL; +@@ -2451,6 +2451,13 @@ done: + result = NT_STATUS_NO_LOGON_SERVERS; + } + ++ /* ++ * Here we don't alter ++ * state->response->data.auth.authoritative based ++ * on the servers response ++ * as we don't want a fallback to the local sam ++ * for interactive PAM logons ++ */ + set_auth_errors(state->response, result); + + DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n", +@@ -2665,7 +2672,7 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain, + const char *name_domain = NULL; + const char *workstation; + uint64_t logon_id = 0; +- uint8_t authoritative = 0; ++ uint8_t authoritative = 1; + uint32_t flags = 0; + uint16_t validation_level; + union netr_Validation *validation = NULL; +@@ -2738,7 +2745,6 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain, + &validation_level, + &validation); + if (!NT_STATUS_IS_OK(result)) { +- state->response->data.auth.authoritative = authoritative; + goto done; + } + +@@ -2792,6 +2797,8 @@ done: + } + + set_auth_errors(state->response, result); ++ state->response->data.auth.authoritative = authoritative; ++ + /* + * Log the winbind pam authentication, the logon_id will tie this to + * any of the logons invoked from this request. +diff --git a/source3/winbindd/winbindd_pam_auth_crap.c b/source3/winbindd/winbindd_pam_auth_crap.c +index b7912db43df..40cab81b5ea 100644 +--- a/source3/winbindd/winbindd_pam_auth_crap.c ++++ b/source3/winbindd/winbindd_pam_auth_crap.c +@@ -24,6 +24,7 @@ + + struct winbindd_pam_auth_crap_state { + struct winbindd_response *response; ++ bool authoritative; + uint32_t flags; + }; + +@@ -45,7 +46,7 @@ struct tevent_req *winbindd_pam_auth_crap_send( + if (req == NULL) { + return NULL; + } +- ++ state->authoritative = true; + state->flags = request->flags; + + if (state->flags & WBFLAG_PAM_AUTH_PAC) { +@@ -124,6 +125,11 @@ struct tevent_req *winbindd_pam_auth_crap_send( + + domain = find_auth_domain(request->flags, auth_domain); + if (domain == NULL) { ++ /* ++ * We don't know the domain so ++ * we're not authoritative ++ */ ++ state->authoritative = false; + tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER); + return tevent_req_post(req, ev); + } +@@ -184,6 +190,7 @@ NTSTATUS winbindd_pam_auth_crap_recv(struct tevent_req *req, + + if (tevent_req_is_nterror(req, &status)) { + set_auth_errors(response, status); ++ response->data.auth.authoritative = state->authoritative; + return status; + } + +diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c +index bec706f87de..ef197310fa0 100644 +--- a/source3/winbindd/winbindd_util.c ++++ b/source3/winbindd/winbindd_util.c +@@ -2092,6 +2092,13 @@ void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain) + + void set_auth_errors(struct winbindd_response *resp, NTSTATUS result) + { ++ /* ++ * Make sure we start with authoritative=true, ++ * it will only set to false if we don't know the ++ * domain. ++ */ ++ resp->data.auth.authoritative = true; ++ + resp->data.auth.nt_status = NT_STATUS_V(result); + fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result)); + +-- +2.23.0 + diff --git a/backport-0011-CVE-2020-25722-s4-provision-add-host-SPNs-at-the-sta.patch b/backport-0011-CVE-2020-25722-s4-provision-add-host-SPNs-at-the-sta.patch new file mode 100644 index 0000000..b6897f5 --- /dev/null +++ b/backport-0011-CVE-2020-25722-s4-provision-add-host-SPNs-at-the-sta.patch @@ -0,0 +1,65 @@ +From 50f5069a73ac689d3b5fb56fdc652aefb57d396a Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Thu, 28 Oct 2021 09:45:36 +1300 +Subject: [PATCH 146/266] 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. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/50f5069a73ac689d3b5fb56fdc652aefb57d396a +--- + selftest/knownfail.d/cve-2020-25722-provision | 4 ++++ + source4/setup/provision_self_join.ldif | 9 +++++++-- + 2 files changed, 11 insertions(+), 2 deletions(-) + create mode 100644 selftest/knownfail.d/cve-2020-25722-provision + +diff --git a/selftest/knownfail.d/cve-2020-25722-provision b/selftest/knownfail.d/cve-2020-25722-provision +new file mode 100644 +index 00000000000..7fd4b4b3763 +--- /dev/null ++++ b/selftest/knownfail.d/cve-2020-25722-provision +@@ -0,0 +1,4 @@ ++samba4.blackbox.dbcheck.release-4-0-0 ++samba4.blackbox.dbcheck.release-4-0-0.quick ++samba4.blackbox.upgradeprovision.release-4-0-0 ++samba4.blackbox.functionalprep.check_databases_same +diff --git a/source4/setup/provision_self_join.ldif b/source4/setup/provision_self_join.ldif +index f77ac5710ec..92bf4d9cf8f 100644 +--- a/source4/setup/provision_self_join.ldif ++++ b/source4/setup/provision_self_join.ldif +@@ -15,11 +15,16 @@ localPolicyFlags: 0 + operatingSystem: Samba + operatingSystemVersion: ${SAMBA_VERSION_STRING} + sAMAccountName: ${NETBIOSNAME}$ +-# The "servicePrincipalName" updates are now handled by the "samba_spnupdate" +-# script + userAccountControl: 532480 + clearTextPassword:: ${MACHINEPASS_B64} + objectSid: ${DOMAINSID}-${DCRID} ++# While some "servicePrincipalName" updates might be handled by the ++# "samba_spnupdate" script, we need to get the basics in here before ++# we add any others. ++servicePrincipalName: HOST/${DNSNAME} ++servicePrincipalName: HOST/${NETBIOSNAME} ++servicePrincipalName: HOST/${DNSNAME}/${DNSNAME} ++ + + dn: CN=RID Set,CN=${NETBIOSNAME},OU=Domain Controllers,${DOMAINDN} + objectClass: rIDSet +-- +2.23.0 + diff --git a/backport-0012-CVE-2020-25717-s4-auth-ntlm-make-sure-auth_check_pas.patch b/backport-0012-CVE-2020-25717-s4-auth-ntlm-make-sure-auth_check_pas.patch new file mode 100644 index 0000000..062684b --- /dev/null +++ b/backport-0012-CVE-2020-25717-s4-auth-ntlm-make-sure-auth_check_pas.patch @@ -0,0 +1,39 @@ +From 66cd97e558cdb57bff2dfc2bf8734b0ee12f648e Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 4 Oct 2021 17:29:34 +0200 +Subject: [PATCH 104/266] CVE-2020-25717: s4:auth/ntlm: make sure + auth_check_password() defaults to r->out.authoritative = true + +We need to make sure that temporary failures don't trigger a fallback +to the local SAM that silently ignores the domain name part for users. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source4/auth/ntlm/auth.c | 5 +++++ + 1 file changed, 5 insertions(+) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=66cd97e558cdb57bff2dfc2bf8734b0ee12f648e + +diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c +index 1aa2e3b065f..e0c4436343c 100644 +--- a/source4/auth/ntlm/auth.c ++++ b/source4/auth/ntlm/auth.c +@@ -169,6 +169,11 @@ _PUBLIC_ NTSTATUS auth_check_password(struct auth4_context *auth_ctx, + /*TODO: create a new event context here! */ + ev = auth_ctx->event_ctx; + ++ /* ++ * We are authoritative by default ++ */ ++ *pauthoritative = 1; ++ + subreq = auth_check_password_send(mem_ctx, + ev, + auth_ctx, +-- +2.23.0 + diff --git a/backport-0012-CVE-2020-25722-s4-dsdb-samldb-add-samldb_get_single_.patch b/backport-0012-CVE-2020-25722-s4-dsdb-samldb-add-samldb_get_single_.patch new file mode 100644 index 0000000..c13c081 --- /dev/null +++ b/backport-0012-CVE-2020-25722-s4-dsdb-samldb-add-samldb_get_single_.patch @@ -0,0 +1,85 @@ +From 935997b92ebea5941a04c553934e203b33f1d7d7 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Fri, 22 Oct 2021 14:12:25 +1300 +Subject: [PATCH 151/266] CVE-2020-25722 s4/dsdb/samldb: add + samldb_get_single_valued_attr() helper + +This takes a string of logic out of samldb_unique_attr_check() that we +are going to need in other places, and that would be very tedious to +repeat. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/935997b92ebea5941a04c553934e203b33f1d7d7 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 49 +++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 6db7840b0c1..40dfab6390b 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -161,6 +161,55 @@ static int samldb_next_step(struct samldb_ctx *ac) + } + } + ++static int samldb_get_single_valued_attr(struct ldb_context *ldb, ++ struct samldb_ctx *ac, ++ const char *attr, ++ const char **value) ++{ ++ /* ++ * The steps we end up going through to get and check a single valued ++ * attribute. ++ */ ++ struct ldb_message_element *el = NULL; ++ ++ *value = NULL; ++ ++ el = dsdb_get_single_valued_attr(ac->msg, attr, ++ ac->req->operation); ++ if (el == NULL) { ++ /* we are not affected */ ++ return LDB_SUCCESS; ++ } ++ ++ if (el->num_values > 1) { ++ ldb_asprintf_errstring( ++ ldb, ++ "samldb: %s has %u values, should be single-valued!", ++ attr, el->num_values); ++ return LDB_ERR_CONSTRAINT_VIOLATION; ++ } else if (el->num_values == 0) { ++ ldb_asprintf_errstring( ++ ldb, ++ "samldb: new value for %s " ++ "not provided for mandatory, single-valued attribute!", ++ attr); ++ return LDB_ERR_OBJECT_CLASS_VIOLATION; ++ } ++ ++ ++ if (el->values[0].length == 0) { ++ ldb_asprintf_errstring( ++ ldb, ++ "samldb: %s is of zero length, should have a value!", ++ attr); ++ return LDB_ERR_OBJECT_CLASS_VIOLATION; ++ } ++ ++ *value = (char *)el->values[0].data; ++ ++ return LDB_SUCCESS; ++} ++ + static int samldb_unique_attr_check(struct samldb_ctx *ac, const char *attr, + const char *attr_conflict, + struct ldb_dn *base_dn) +-- +2.23.0 + diff --git a/backport-0013-CVE-2020-25717-loadparm-Add-new-parameter-min-domain.patch b/backport-0013-CVE-2020-25717-loadparm-Add-new-parameter-min-domain.patch new file mode 100644 index 0000000..70745c7 --- /dev/null +++ b/backport-0013-CVE-2020-25717-loadparm-Add-new-parameter-min-domain.patch @@ -0,0 +1,101 @@ +From b9d8f8025b7122cab64c37e5042866c66b556016 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Tue, 28 Sep 2021 10:43:40 +0200 +Subject: [PATCH 113/266] CVE-2020-25717: loadparm: Add new parameter "min + domain uid" + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Pair-Programmed-With: Stefan Metzmacher + +Signed-off-by: Samuel Cabrero +Signed-off-by: Stefan Metzmacher + +[abartlet@samba.org Backported from master/4.15 due to + conflicts with other new parameters] +--- + docs-xml/smbdotconf/security/mindomainuid.xml | 17 +++++++++++++++++ + docs-xml/smbdotconf/winbind/idmapconfig.xml | 4 ++++ + lib/param/loadparm.c | 4 ++++ + source3/param/loadparm.c | 2 ++ + 4 files changed, 27 insertions(+) + create mode 100644 docs-xml/smbdotconf/security/mindomainuid.xml + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=b9d8f8025b7122cab64c37e5042866c66b556016 + +diff --git a/docs-xml/smbdotconf/security/mindomainuid.xml b/docs-xml/smbdotconf/security/mindomainuid.xml +new file mode 100644 +index 00000000000..46ae795d730 +--- /dev/null ++++ b/docs-xml/smbdotconf/security/mindomainuid.xml +@@ -0,0 +1,17 @@ ++ ++ ++ ++ The integer parameter specifies the minimum uid allowed when mapping a ++ local account to a domain account. ++ ++ ++ ++ Note that this option interacts with the configured idmap ranges! ++ ++ ++ ++1000 ++ +diff --git a/docs-xml/smbdotconf/winbind/idmapconfig.xml b/docs-xml/smbdotconf/winbind/idmapconfig.xml +index 1374040fb29..f70f11df757 100644 +--- a/docs-xml/smbdotconf/winbind/idmapconfig.xml ++++ b/docs-xml/smbdotconf/winbind/idmapconfig.xml +@@ -80,6 +80,9 @@ + authoritative for a unix ID to SID mapping, so it must be set + for each individually configured domain and for the default + configuration. The configured ranges must be mutually disjoint. ++ ++ ++ Note that the low value interacts with the option! + + + +@@ -115,4 +118,5 @@ + + + ++min domain uid + +diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c +index 006caabc092..d2f6e6241ad 100644 +--- a/lib/param/loadparm.c ++++ b/lib/param/loadparm.c +@@ -3079,6 +3079,10 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) + lpcfg_do_global_parameter( + lp_ctx, "ldap max search request size", "256000"); + ++ lpcfg_do_global_parameter(lp_ctx, ++ "min domain uid", ++ "1000"); ++ + for (i = 0; parm_table[i].label; i++) { + if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) { + lp_ctx->flags[i] |= FLAG_DEFAULT; +diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c +index a3abaa2ec67..301e3622ed4 100644 +--- a/source3/param/loadparm.c ++++ b/source3/param/loadparm.c +@@ -960,6 +960,8 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) + Globals.ldap_max_authenticated_request_size = 16777216; + Globals.ldap_max_search_request_size = 256000; + ++ Globals.min_domain_uid = 1000; ++ + /* Now put back the settings that were set with lp_set_cmdline() */ + apply_lp_set_cmdline(); + } +-- +2.23.0 + diff --git a/backport-0013-CVE-2020-25722-s4-dsdb-samldb-check-for-clashes-in-U.patch b/backport-0013-CVE-2020-25722-s4-dsdb-samldb-check-for-clashes-in-U.patch new file mode 100644 index 0000000..d80f136 --- /dev/null +++ b/backport-0013-CVE-2020-25722-s4-dsdb-samldb-check-for-clashes-in-U.patch @@ -0,0 +1,279 @@ +From 4439ac7bb6e8fcb1610fa94923c3daaed3e4c958 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Fri, 22 Oct 2021 13:17:34 +1300 +Subject: [PATCH 153/266] 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. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/4439ac7bb6e8fcb1610fa94923c3daaed3e4c958 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 206 +++++++++++++++++++++- + 1 files changed, 203 insertions(+), 3 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index a03fc6eb07c..0cf00e2b19e 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -235,8 +235,9 @@ static int samldb_unique_attr_check(struct samldb_ctx *ac, const char *attr, + return ldb_module_oom(ac->module); + } + +- /* Make sure that attr (eg) "sAMAccountName" is only used once */ +- ++ /* ++ * No other object should have the attribute with this value. ++ */ + if (attr_conflict != NULL) { + ret = dsdb_module_search(ac->module, ac, &res, + base_dn, +@@ -270,6 +271,193 @@ static int samldb_unique_attr_check(struct samldb_ctx *ac, const char *attr, + return LDB_SUCCESS; + } + ++ ++ ++static inline int samldb_sam_account_upn_clash_sub_search( ++ struct samldb_ctx *ac, ++ TALLOC_CTX *mem_ctx, ++ struct ldb_dn *base_dn, ++ const char *attr, ++ const char *value, ++ const char *err_msg ++ ) ++{ ++ /* ++ * A very specific helper function for samldb_sam_account_upn_clash(), ++ * where we end up doing this same thing several times in a row. ++ */ ++ const char * const no_attrs[] = { NULL }; ++ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); ++ struct ldb_result *res = NULL; ++ int ret; ++ char *enc_value = ldb_binary_encode_string(ac, value); ++ if (enc_value == NULL) { ++ return ldb_module_oom(ac->module); ++ } ++ ret = dsdb_module_search(ac->module, mem_ctx, &res, ++ base_dn, ++ LDB_SCOPE_SUBTREE, no_attrs, ++ DSDB_FLAG_NEXT_MODULE, ac->req, ++ "(%s=%s)", ++ attr, enc_value); ++ talloc_free(enc_value); ++ ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } else if (res->count > 1) { ++ return ldb_operr(ldb); ++ } else if (res->count == 1) { ++ if (ldb_dn_compare(res->msgs[0]->dn, ac->msg->dn) != 0){ ++ ldb_asprintf_errstring(ldb, ++ "samldb: %s '%s' " ++ "is already in use %s", ++ attr, value, err_msg); ++ /* different errors for different attrs */ ++ if (strcasecmp("userPrincipalName", attr) == 0) { ++ return LDB_ERR_CONSTRAINT_VIOLATION; ++ } ++ return LDB_ERR_ENTRY_ALREADY_EXISTS; ++ } ++ } ++ return LDB_SUCCESS; ++} ++ ++static int samldb_sam_account_upn_clash(struct samldb_ctx *ac) ++{ ++ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); ++ int ret; ++ struct ldb_dn *base_dn = ldb_get_default_basedn(ldb); ++ TALLOC_CTX *tmp_ctx = NULL; ++ const char *real_sam = NULL; ++ const char *real_upn = NULL; ++ char *implied_sam = NULL; ++ char *implied_upn = NULL; ++ const char *realm = NULL; ++ ++ ret = samldb_get_single_valued_attr(ldb, ac, ++ "sAMAccountName", ++ &real_sam); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ ret = samldb_get_single_valued_attr(ldb, ac, ++ "userPrincipalName", ++ &real_upn); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ if (real_upn == NULL && real_sam == NULL) { ++ /* Not changing these things, so we're done */ ++ return LDB_SUCCESS; ++ } ++ ++ tmp_ctx = talloc_new(ac); ++ realm = samdb_dn_to_dns_domain(tmp_ctx, base_dn); ++ if (realm == NULL) { ++ talloc_free(tmp_ctx); ++ return ldb_operr(ldb); ++ } ++ ++ if (real_upn != NULL) { ++ /* ++ * note we take the last @ in the upn because the first (i.e. ++ * sAMAccountName equivalent) part can contain @. ++ * ++ * It is also OK (per Windows) for a UPN to have zero @s. ++ */ ++ char *at = NULL; ++ char *upn_realm = NULL; ++ implied_sam = talloc_strdup(tmp_ctx, real_upn); ++ if (implied_sam == NULL) { ++ talloc_free(tmp_ctx); ++ return ldb_module_oom(ac->module); ++ } ++ ++ at = strrchr(implied_sam, '@'); ++ if (at == NULL) { ++ /* ++ * there is no @ in this UPN, so we treat the whole ++ * thing as a sAMAccountName for the purposes of a ++ * clash. ++ */ ++ DBG_INFO("samldb: userPrincipalName '%s' contains " ++ "no '@' character\n", implied_sam); ++ } else { ++ /* ++ * Now, this upn only implies a sAMAccountName if the ++ * realm is our realm. So we need to compare the tail ++ * of the upn to the realm. ++ */ ++ *at = '\0'; ++ upn_realm = at + 1; ++ if (strcasecmp(upn_realm, realm) != 0) { ++ /* implied_sam is not the implied ++ * sAMAccountName after all, because it is ++ * from a different realm. */ ++ TALLOC_FREE(implied_sam); ++ } ++ } ++ } ++ ++ if (real_sam != NULL) { ++ implied_upn = talloc_asprintf(tmp_ctx, "%s@%s", ++ real_sam, realm); ++ if (implied_upn == NULL) { ++ talloc_free(tmp_ctx); ++ return ldb_module_oom(ac->module); ++ } ++ } ++ ++ /* ++ * Now we have all of the actual and implied names, in which to search ++ * for conflicts. ++ */ ++ if (real_sam != NULL) { ++ ret = samldb_sam_account_upn_clash_sub_search( ++ ac, tmp_ctx, base_dn, "sAMAccountName", ++ real_sam, ""); ++ ++ if (ret != LDB_SUCCESS) { ++ talloc_free(tmp_ctx); ++ return ret; ++ } ++ } ++ if (implied_upn != NULL) { ++ ret = samldb_sam_account_upn_clash_sub_search( ++ ac, tmp_ctx, base_dn, "userPrincipalName", implied_upn, ++ "(implied by sAMAccountName)"); ++ ++ if (ret != LDB_SUCCESS) { ++ talloc_free(tmp_ctx); ++ return ret; ++ } ++ } ++ if (real_upn != NULL) { ++ ret = samldb_sam_account_upn_clash_sub_search( ++ ac, tmp_ctx, base_dn, "userPrincipalName", ++ real_upn, ""); ++ ++ if (ret != LDB_SUCCESS) { ++ talloc_free(tmp_ctx); ++ return ret; ++ } ++ } ++ if (implied_sam != NULL) { ++ ret = samldb_sam_account_upn_clash_sub_search( ++ ac, tmp_ctx, base_dn, "sAMAccountName", implied_sam, ++ "(implied by userPrincipalName)"); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(tmp_ctx); ++ return ret; ++ } ++ } ++ ++ talloc_free(tmp_ctx); ++ return LDB_SUCCESS; ++} ++ ++ ++/* This is run during an add or modify */ + static int samldb_sam_accountname_valid_check(struct samldb_ctx *ac) + { + int ret = 0; +@@ -303,7 +491,11 @@ static int samldb_sam_accountname_valid_check(struct samldb_ctx *ac) + } else if (ret == LDB_ERR_OBJECT_CLASS_VIOLATION) { + ret = LDB_ERR_CONSTRAINT_VIOLATION; + } ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } + ++ ret = samldb_sam_account_upn_clash(ac); + if (ret != LDB_SUCCESS) { + return ret; + } +@@ -4175,7 +4367,6 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) + if (ret != LDB_SUCCESS) { + return ret; + } +- + user_account_control + = ldb_msg_find_attr_as_uint(res->msgs[0], + "userAccountControl", +@@ -4199,6 +4390,15 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) + } + } + ++ el = ldb_msg_find_element(ac->msg, "userPrincipalName"); ++ if (el != NULL) { ++ ret = samldb_sam_account_upn_clash(ac); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(ac); ++ return ret; ++ } ++ } ++ + el = ldb_msg_find_element(ac->msg, "ldapDisplayName"); + if (el != NULL) { + ret = samldb_schema_ldapdisplayname_valid_check(ac); +-- +2.23.0 + diff --git a/backport-0014-CVE-2020-25717-s3-auth-Check-minimum-domain-uid.patch b/backport-0014-CVE-2020-25717-s3-auth-Check-minimum-domain-uid.patch new file mode 100644 index 0000000..86be4dd --- /dev/null +++ b/backport-0014-CVE-2020-25717-s3-auth-Check-minimum-domain-uid.patch @@ -0,0 +1,53 @@ +From ce47a81eb5f79dd3f54b300f6a9a7ccac9c1296a Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Tue, 28 Sep 2021 10:45:11 +0200 +Subject: [PATCH 117/266] CVE-2020-25717: s3:auth: Check minimum domain uid + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Pair-Programmed-With: Stefan Metzmacher + +Signed-off-by: Samuel Cabrero +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org Removed knownfail on advice from metze] +--- + source3/auth/auth_util.c | 16 ++++++++++++++++ + 1 files changed, 16 insertions(+) + delete mode 100644 selftest/knownfail.d/min_domain_uid + +Conflict:delete a chunk which delete a file do not exist +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=ce47a81eb5f79dd3f54b300f6a9a7ccac9c1296a + +diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c +index 4686b29111e..4de4bc74374 100644 +--- a/source3/auth/auth_util.c ++++ b/source3/auth/auth_util.c +@@ -2103,6 +2103,22 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, + } + } + goto out; ++ } else if ((lp_security() == SEC_ADS || lp_security() == SEC_DOMAIN) && ++ !is_myname(domain) && pwd->pw_uid < lp_min_domain_uid()) { ++ /* ++ * !is_myname(domain) because when smbd starts tries to setup ++ * the guest user info, calling this function with nobody ++ * username. Nobody is usually uid 65535 but it can be changed ++ * to a regular user with 'guest account' parameter ++ */ ++ nt_status = NT_STATUS_INVALID_TOKEN; ++ DBG_NOTICE("Username '%s%s%s' is invalid on this system, " ++ "it does not meet 'min domain uid' " ++ "restriction (%u < %u): %s\n", ++ nt_domain, lp_winbind_separator(), nt_username, ++ pwd->pw_uid, lp_min_domain_uid(), ++ nt_errstr(nt_status)); ++ goto out; + } + + result = make_server_info(tmp_ctx); +-- +2.23.0 + diff --git a/backport-0014-CVE-2020-25722-s4-dsdb-samldb-check-sAMAccountName-f.patch b/backport-0014-CVE-2020-25722-s4-dsdb-samldb-check-sAMAccountName-f.patch new file mode 100644 index 0000000..028fc57 --- /dev/null +++ b/backport-0014-CVE-2020-25722-s4-dsdb-samldb-check-sAMAccountName-f.patch @@ -0,0 +1,101 @@ +From 9be11622765c060971c4fcc2fba981f760f897d8 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Fri, 22 Oct 2021 15:27:25 +1300 +Subject: [PATCH 154/266] 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. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/9be11622765c060971c4fcc2fba981f760f897d8 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 58 +++++++++++++++++++++++ + 1 files changed, 58 insertions(+), 0 deletion(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 0cf00e2b19e..f420009376c 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -322,6 +322,59 @@ static inline int samldb_sam_account_upn_clash_sub_search( + return LDB_SUCCESS; + } + ++static int samaccountname_bad_chars_check(struct samldb_ctx *ac, ++ const char *name) ++{ ++ /* ++ * The rules here are based on ++ * ++ * https://social.technet.microsoft.com/wiki/contents/articles/11216.active-directory-requirements-for-creating-objects.aspx ++ * ++ * Windows considers UTF-8 sequences that map to "similar" characters ++ * (e.g. 'a', 'ā') to be the same sAMAccountName, and we don't. Names ++ * that are not valid UTF-8 *are* allowed. ++ * ++ * Additionally, Samba collapses multiple spaces, and Windows doesn't. ++ */ ++ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); ++ size_t i; ++ ++ for (i = 0; name[i] != '\0'; i++) { ++ uint8_t c = name[i]; ++ char *p = NULL; ++ if (c < 32 || c == 127) { ++ ldb_asprintf_errstring( ++ ldb, ++ "samldb: sAMAccountName contains invalid " ++ "0x%.2x character\n", c); ++ return LDB_ERR_CONSTRAINT_VIOLATION; ++ } ++ p = strchr("\"[]:;|=+*?<>/\\,", c); ++ if (p != NULL) { ++ ldb_asprintf_errstring( ++ ldb, ++ "samldb: sAMAccountName contains invalid " ++ "'%c' character\n", c); ++ return LDB_ERR_CONSTRAINT_VIOLATION; ++ } ++ } ++ ++ if (i == 0) { ++ ldb_asprintf_errstring( ++ ldb, ++ "samldb: sAMAccountName is empty\n"); ++ return LDB_ERR_CONSTRAINT_VIOLATION; ++ } ++ ++ if (name[i - 1] == '.') { ++ ldb_asprintf_errstring( ++ ldb, ++ "samldb: sAMAccountName ends with '.'"); ++ return LDB_ERR_CONSTRAINT_VIOLATION; ++ } ++ return LDB_SUCCESS; ++} ++ + static int samldb_sam_account_upn_clash(struct samldb_ctx *ac) + { + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); +@@ -421,6 +474,11 @@ static int samldb_sam_account_upn_clash(struct samldb_ctx *ac) + talloc_free(tmp_ctx); + return ret; + } ++ ret = samaccountname_bad_chars_check(ac, real_sam); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(tmp_ctx); ++ return ret; ++ } + } + if (implied_upn != NULL) { + ret = samldb_sam_account_upn_clash_sub_search( +-- +2.23.0 + diff --git a/backport-0015-CVE-2020-25717-s3-auth-we-should-not-try-to-autocrea.patch b/backport-0015-CVE-2020-25717-s3-auth-we-should-not-try-to-autocrea.patch new file mode 100644 index 0000000..f852ac6 --- /dev/null +++ b/backport-0015-CVE-2020-25717-s3-auth-we-should-not-try-to-autocrea.patch @@ -0,0 +1,36 @@ +From 885fe6e31b107b3a6362cde0785e6d886888e0ec Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 8 Oct 2021 17:40:30 +0200 +Subject: [PATCH 118/266] CVE-2020-25717: s3:auth: we should not try to + autocreate the guest account + +We should avoid autocreation of users as much as possible. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/user_krb5.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=885fe6e31b107b3a6362cde0785e6d886888e0ec + +diff --git a/source3/auth/user_krb5.c b/source3/auth/user_krb5.c +index 8998f9c8f8a..074e8c7eb71 100644 +--- a/source3/auth/user_krb5.c ++++ b/source3/auth/user_krb5.c +@@ -155,7 +155,7 @@ NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx, + if (!fuser) { + return NT_STATUS_NO_MEMORY; + } +- pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true); ++ pw = smb_getpwnam(mem_ctx, fuser, &unixuser, false); + } + + /* extra sanity check that the guest account is valid */ +-- +2.23.0 + diff --git a/backport-0015-CVE-2020-25722-s4-dsdb-samldb-check-for-SPN-uniquene.patch b/backport-0015-CVE-2020-25722-s4-dsdb-samldb-check-for-SPN-uniquene.patch new file mode 100644 index 0000000..7ab825a --- /dev/null +++ b/backport-0015-CVE-2020-25722-s4-dsdb-samldb-check-for-SPN-uniquene.patch @@ -0,0 +1,667 @@ +From b121b1920f996fc9c15ec40a63e7cf4dd7159161 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Fri, 22 Oct 2021 13:14:32 +1300 +Subject: [PATCH 155/266] 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. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/b121b1920f996fc9c15ec40a63e7cf4dd7159161 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 588 +++++++++++++++++++++++- + 1 files changed, 585 insertions(+), 3 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index f420009376c..f5141936a60 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -3383,6 +3383,546 @@ static int samldb_description_check(struct samldb_ctx *ac, bool *modified) + return LDB_SUCCESS; + } + ++#define SPN_ALIAS_NONE 0 ++#define SPN_ALIAS_LINK 1 ++#define SPN_ALIAS_TARGET 2 ++ ++static int find_spn_aliases(struct ldb_context *ldb, ++ TALLOC_CTX *mem_ctx, ++ const char *service_class, ++ char ***aliases, ++ size_t *n_aliases, ++ int *direction) ++{ ++ /* ++ * If you change the way this works, you should also look at changing ++ * LDB_lookup_spn_alias() in source4/dsdb/samdb/cracknames.c, which ++ * does some of the same work. ++ * ++ * In particular, note that sPNMappings are resolved on a first come, ++ * first served basis. For example, if we have ++ * ++ * host=ldap,cifs ++ * foo=ldap ++ * cifs=host,alerter ++ * ++ * then 'ldap', 'cifs', and 'host' will resolve to 'host', and ++ * 'alerter' will resolve to 'cifs'. ++ * ++ * If this resolution method is made more complicated, then the ++ * cracknames function should also be changed. ++ */ ++ size_t i, j; ++ int ret; ++ bool ok; ++ struct ldb_result *res = NULL; ++ struct ldb_message_element *spnmappings = NULL; ++ TALLOC_CTX *tmp_ctx = NULL; ++ struct ldb_dn *service_dn = NULL; ++ ++ const char *attrs[] = { ++ "sPNMappings", ++ NULL ++ }; ++ ++ *direction = SPN_ALIAS_NONE; ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ return ldb_oom(ldb); ++ } ++ ++ service_dn = ldb_dn_new( ++ tmp_ctx, ldb, ++ "CN=Directory Service,CN=Windows NT,CN=Services"); ++ if (service_dn == NULL) { ++ talloc_free(tmp_ctx); ++ return ldb_oom(ldb); ++ } ++ ++ ok = ldb_dn_add_base(service_dn, ldb_get_config_basedn(ldb)); ++ if (! ok) { ++ talloc_free(tmp_ctx); ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ ++ ret = ldb_search(ldb, tmp_ctx, &res, service_dn, LDB_SCOPE_BASE, ++ attrs, "(objectClass=nTDSService)"); ++ ++ if (ret != LDB_SUCCESS || res->count != 1) { ++ DBG_WARNING("sPNMappings not found.\n"); ++ talloc_free(tmp_ctx); ++ return ret; ++ } ++ ++ spnmappings = ldb_msg_find_element(res->msgs[0], "sPNMappings"); ++ if (spnmappings == NULL || spnmappings->num_values == 0) { ++ DBG_WARNING("no sPNMappings attribute\n"); ++ talloc_free(tmp_ctx); ++ return LDB_ERR_NO_SUCH_OBJECT; ++ } ++ *n_aliases = 0; ++ ++ for (i = 0; i < spnmappings->num_values; i++) { ++ char *p = NULL; ++ char *mapping = talloc_strndup( ++ tmp_ctx, ++ (char *)spnmappings->values[i].data, ++ spnmappings->values[i].length); ++ if (mapping == NULL) { ++ talloc_free(tmp_ctx); ++ return ldb_oom(ldb); ++ } ++ ++ p = strchr(mapping, '='); ++ if (p == NULL) { ++ talloc_free(tmp_ctx); ++ return LDB_ERR_ALIAS_PROBLEM; ++ } ++ p[0] = '\0'; ++ p++; ++ ++ if (strcasecmp(mapping, service_class) == 0) { ++ /* ++ * We need to return the reverse aliases for this one. ++ * ++ * typically, this means the service_class is "host" ++ * and the mapping is "host=alerter,appmgmt,cisvc,..", ++ * so we get "alerter", "appmgmt", etc in the list of ++ * aliases. ++ */ ++ ++ /* There is one more field than there are commas */ ++ size_t n = 1; ++ ++ for (j = 0; p[j] != '\0'; j++) { ++ if (p[j] == ',') { ++ n++; ++ p[j] = '\0'; ++ } ++ } ++ *aliases = talloc_array(mem_ctx, char*, n); ++ if (*aliases == NULL) { ++ talloc_free(tmp_ctx); ++ return ldb_oom(ldb); ++ } ++ *n_aliases = n; ++ talloc_steal(mem_ctx, mapping); ++ for (j = 0; j < n; j++) { ++ (*aliases)[j] = p; ++ p += strlen(p) + 1; ++ } ++ talloc_free(tmp_ctx); ++ *direction = SPN_ALIAS_LINK; ++ return LDB_SUCCESS; ++ } ++ /* ++ * We need to look along the list to see if service_class is ++ * there; if so, we return a list of one item (probably "host"). ++ */ ++ do { ++ char *str = p; ++ p = strchr(p, ','); ++ if (p != NULL) { ++ p[0] = '\0'; ++ p++; ++ } ++ if (strcasecmp(str, service_class) == 0) { ++ *aliases = talloc_array(mem_ctx, char*, 1); ++ if (*aliases == NULL) { ++ talloc_free(tmp_ctx); ++ return ldb_oom(ldb); ++ } ++ *n_aliases = 1; ++ (*aliases)[0] = mapping; ++ talloc_steal(mem_ctx, mapping); ++ talloc_free(tmp_ctx); ++ *direction = SPN_ALIAS_TARGET; ++ return LDB_SUCCESS; ++ } ++ } while (p != NULL); ++ } ++ DBG_INFO("no sPNMappings alias for '%s'\n", service_class); ++ talloc_free(tmp_ctx); ++ *aliases = NULL; ++ *n_aliases = 0; ++ return LDB_SUCCESS; ++} ++ ++ ++static int get_spn_dn(struct ldb_context *ldb, ++ TALLOC_CTX *tmp_ctx, ++ const char *candidate, ++ struct ldb_dn **dn) ++{ ++ int ret; ++ const char *empty_attrs[] = { NULL }; ++ struct ldb_message *msg = NULL; ++ struct ldb_dn *base_dn = ldb_get_default_basedn(ldb); ++ ++ const char *enc_candidate = NULL; ++ ++ *dn = NULL; ++ ++ enc_candidate = ldb_binary_encode_string(tmp_ctx, candidate); ++ if (enc_candidate == NULL) { ++ return ldb_operr(ldb); ++ } ++ ++ ret = dsdb_search_one(ldb, ++ tmp_ctx, ++ &msg, ++ base_dn, ++ LDB_SCOPE_SUBTREE, ++ empty_attrs, ++ 0, ++ "(servicePrincipalName=%s)", ++ enc_candidate); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ *dn = msg->dn; ++ return LDB_SUCCESS; ++} ++ ++ ++static int check_spn_write_rights(struct ldb_context *ldb, ++ TALLOC_CTX *mem_ctx, ++ const char *spn, ++ struct ldb_dn *dn) ++{ ++ int ret; ++ struct ldb_message *msg = NULL; ++ struct ldb_message_element *del_el = NULL; ++ struct ldb_message_element *add_el = NULL; ++ struct ldb_val val = { ++ .data = discard_const_p(uint8_t, spn), ++ .length = strlen(spn) ++ }; ++ ++ msg = ldb_msg_new(mem_ctx); ++ if (msg == NULL) { ++ return ldb_oom(ldb); ++ } ++ msg->dn = dn; ++ ++ ret = ldb_msg_add_empty(msg, ++ "servicePrincipalName", ++ LDB_FLAG_MOD_DELETE, ++ &del_el); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(msg); ++ return ret; ++ } ++ ++ del_el->values = talloc_array(msg->elements, struct ldb_val, 1); ++ if (del_el->values == NULL) { ++ talloc_free(msg); ++ return ret; ++ } ++ ++ del_el->values[0] = val; ++ del_el->num_values = 1; ++ ++ ret = ldb_msg_add_empty(msg, ++ "servicePrincipalName", ++ LDB_FLAG_MOD_ADD, ++ &add_el); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(msg); ++ return ret; ++ } ++ ++ add_el->values = talloc_array(msg->elements, struct ldb_val, 1); ++ if (add_el->values == NULL) { ++ talloc_free(msg); ++ return ret; ++ } ++ ++ add_el->values[0] = val; ++ add_el->num_values = 1; ++ ++ ret = ldb_modify(ldb, msg); ++ if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { ++ DBG_ERR("hmm I think we're OK, but not sure\n"); ++ } else if (ret != LDB_SUCCESS) { ++ DBG_ERR("SPN write rights check failed with %d\n", ret); ++ talloc_free(msg); ++ return ret; ++ } ++ talloc_free(msg); ++ return LDB_SUCCESS; ++} ++ ++ ++static int check_spn_alias_collision(struct ldb_context *ldb, ++ TALLOC_CTX *mem_ctx, ++ const char *spn, ++ struct ldb_dn *target_dn) ++{ ++ int ret; ++ char *service_class = NULL; ++ char *spn_tail = NULL; ++ char *p = NULL; ++ char **aliases = NULL; ++ size_t n_aliases = 0; ++ size_t i, len; ++ TALLOC_CTX *tmp_ctx = NULL; ++ const char *target_dnstr = ldb_dn_get_linearized(target_dn); ++ int link_direction; ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ return ldb_oom(ldb); ++ } ++ ++ /* ++ * "dns/example.com/xxx" gives ++ * service_class = "dns" ++ * spn_tail = "example.com/xxx" ++ */ ++ p = strchr(spn, '/'); ++ if (p == NULL) { ++ /* bad SPN */ ++ talloc_free(tmp_ctx); ++ return ldb_error(ldb, ++ LDB_ERR_OPERATIONS_ERROR, ++ "malformed servicePrincipalName"); ++ } ++ len = p - spn; ++ ++ service_class = talloc_strndup(tmp_ctx, spn, len); ++ if (service_class == NULL) { ++ talloc_free(tmp_ctx); ++ return ldb_oom(ldb); ++ } ++ spn_tail = p + 1; ++ ++ ret = find_spn_aliases(ldb, ++ tmp_ctx, ++ service_class, ++ &aliases, ++ &n_aliases, ++ &link_direction); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(tmp_ctx); ++ return ret; ++ } ++ ++ /* ++ * we have the list of aliases, and now we need to combined them with ++ * spn_tail and see if we can find the SPN. ++ */ ++ for (i = 0; i < n_aliases; i++) { ++ struct ldb_dn *colliding_dn = NULL; ++ const char *colliding_dnstr = NULL; ++ ++ char *candidate = talloc_asprintf(tmp_ctx, ++ "%s/%s", ++ aliases[i], ++ spn_tail); ++ if (candidate == NULL) { ++ talloc_free(tmp_ctx); ++ return ldb_oom(ldb); ++ } ++ ++ ret = get_spn_dn(ldb, tmp_ctx, candidate, &colliding_dn); ++ if (ret == LDB_ERR_NO_SUCH_OBJECT) { ++ DBG_DEBUG("SPN alias '%s' not found (good)\n", ++ candidate); ++ talloc_free(candidate); ++ continue; ++ } ++ if (ret != LDB_SUCCESS) { ++ DBG_ERR("SPN '%s' search error %d\n", candidate, ret); ++ talloc_free(tmp_ctx); ++ return ret; ++ } ++ ++ target_dnstr = ldb_dn_get_linearized(target_dn); ++ /* ++ * We have found an existing SPN that matches the alias. That ++ * is OK only if it is on the object we are trying to add to, ++ * or if the SPN on the other side is a more generic alias for ++ * this one and we also have rights to modify it. ++ * ++ * That is, we can put "host/X" and "cifs/X" on the same ++ * object, but not on different objects, unless we put the ++ * host/X on first, and could also change that object when we ++ * add cifs/X. It is forbidden to add the objects in the other ++ * order. ++ * ++ * The rationale for this is that adding "cifs/X" effectively ++ * changes "host/X" by diverting traffic. If "host/X" can be ++ * added after "cifs/X", a sneaky person could get "cifs/X" in ++ * first, making "host/X" have less effect than intended. ++ * ++ * Note: we also can't have "host/X" and "Host/X" on the same ++ * object, but that is not relevant here. ++ */ ++ ++ ret = ldb_dn_compare(colliding_dn, target_dn); ++ if (ret != 0) { ++ colliding_dnstr = ldb_dn_get_linearized(colliding_dn); ++ DBG_ERR("trying to add SPN '%s' on '%s' when '%s' is " ++ "on '%s'\n", ++ spn, ++ target_dnstr, ++ candidate, ++ colliding_dnstr); ++ ++ if (link_direction == SPN_ALIAS_LINK) { ++ /* we don't allow host/X if there is a ++ * cifs/X */ ++ talloc_free(tmp_ctx); ++ return LDB_ERR_CONSTRAINT_VIOLATION; ++ } ++ ret = check_spn_write_rights(ldb, ++ tmp_ctx, ++ candidate, ++ colliding_dn); ++ if (ret != LDB_SUCCESS) { ++ DBG_ERR("SPN '%s' is on '%s' so '%s' can't be " ++ "added to '%s'\n", ++ candidate, ++ colliding_dnstr, ++ spn, ++ target_dnstr); ++ talloc_free(tmp_ctx); ++ ldb_asprintf_errstring(ldb, ++ "samldb: spn[%s] would cause a conflict", ++ spn); ++ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; ++ } ++ } else { ++ DBG_INFO("SPNs '%s' and '%s' alias both on '%s'\n", ++ candidate, spn, target_dnstr); ++ } ++ talloc_free(candidate); ++ } ++ ++ talloc_free(tmp_ctx); ++ return LDB_SUCCESS; ++} ++ ++static int check_spn_direct_collision(struct ldb_context *ldb, ++ TALLOC_CTX *mem_ctx, ++ const char *spn, ++ struct ldb_dn *target_dn) ++{ ++ int ret; ++ TALLOC_CTX *tmp_ctx = NULL; ++ struct ldb_dn *colliding_dn = NULL; ++ const char *target_dnstr = NULL; ++ const char *colliding_dnstr = NULL; ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ return ldb_oom(ldb); ++ } ++ ++ ret = get_spn_dn(ldb, tmp_ctx, spn, &colliding_dn); ++ if (ret == LDB_ERR_NO_SUCH_OBJECT) { ++ DBG_DEBUG("SPN '%s' not found (good)\n", spn); ++ talloc_free(tmp_ctx); ++ return LDB_SUCCESS; ++ } ++ if (ret != LDB_SUCCESS) { ++ DBG_ERR("SPN '%s' search error %d\n", spn, ret); ++ talloc_free(tmp_ctx); ++ if (ret == LDB_ERR_COMPARE_TRUE) { ++ /* ++ * COMPARE_TRUE has special meaning here and we don't ++ * want to return it by mistake. ++ */ ++ ret = LDB_ERR_OPERATIONS_ERROR; ++ } ++ return ret; ++ } ++ /* ++ * We have found this exact SPN. This is mostly harmless (depend on ++ * ADD vs REPLACE) when the spn is being put on the object that ++ * already has, so we let it through to succeed or fail as some other ++ * module sees fit. ++ */ ++ target_dnstr = ldb_dn_get_linearized(target_dn); ++ ret = ldb_dn_compare(colliding_dn, target_dn); ++ if (ret != 0) { ++ colliding_dnstr = ldb_dn_get_linearized(colliding_dn); ++ DBG_ERR("SPN '%s' is on '%s' so it can't be " ++ "added to '%s'\n", ++ spn, ++ colliding_dnstr, ++ target_dnstr); ++ ldb_asprintf_errstring(ldb, ++ "samldb: spn[%s] would cause a conflict", ++ spn); ++ talloc_free(tmp_ctx); ++ return LDB_ERR_CONSTRAINT_VIOLATION; ++ } ++ ++ DBG_INFO("SPN '%s' is already on '%s'\n", ++ spn, target_dnstr); ++ talloc_free(tmp_ctx); ++ return LDB_ERR_COMPARE_TRUE; ++} ++ ++ ++/* Check that "servicePrincipalName" changes do not introduce a collision ++ * globally. */ ++static int samldb_spn_uniqueness_check(struct samldb_ctx *ac, ++ struct ldb_message_element *spn_el) ++{ ++ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); ++ int ret; ++ const char *spn = NULL; ++ size_t i; ++ TALLOC_CTX *tmp_ctx = talloc_new(ac->msg); ++ if (tmp_ctx == NULL) { ++ return ldb_oom(ldb); ++ } ++ ++ for (i = 0; i < spn_el->num_values; i++) { ++ spn = (char *)spn_el->values[i].data; ++ ++ ret = check_spn_direct_collision(ldb, ++ tmp_ctx, ++ spn, ++ ac->msg->dn); ++ if (ret == LDB_ERR_COMPARE_TRUE) { ++ DBG_INFO("SPN %s re-added to the same object\n", spn); ++ talloc_free(tmp_ctx); ++ return LDB_SUCCESS; ++ } ++ if (ret != LDB_SUCCESS) { ++ DBG_ERR("SPN %s failed direct uniqueness check\n", spn); ++ talloc_free(tmp_ctx); ++ return ret; ++ } ++ ++ ret = check_spn_alias_collision(ldb, ++ tmp_ctx, ++ spn, ++ ac->msg->dn); ++ ++ if (ret == LDB_ERR_NO_SUCH_OBJECT) { ++ /* we have no sPNMappings, hence no aliases */ ++ break; ++ } ++ if (ret != LDB_SUCCESS) { ++ DBG_ERR("SPN %s failed alias uniqueness check\n", spn); ++ talloc_free(tmp_ctx); ++ return ret; ++ } ++ DBG_INFO("SPN %s seems to be unique\n", spn); ++ } ++ ++ talloc_free(tmp_ctx); ++ return LDB_SUCCESS; ++} ++ ++ ++ + /* This trigger adapts the "servicePrincipalName" attributes if the + * "dNSHostName" and/or "sAMAccountName" attribute change(s) */ + static int samldb_service_principal_names_change(struct samldb_ctx *ac) +@@ -3498,8 +4038,14 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) + return LDB_SUCCESS; + } + +- /* Potential "servicePrincipalName" changes in the same request have to +- * be handled before the update (Windows behaviour). */ ++ /* ++ * Potential "servicePrincipalName" changes in the same request have ++ * to be handled before the update (Windows behaviour). ++ * ++ * We extract the SPN changes into a new message and run it through ++ * the stack from this module, so that it subjects them to the SPN ++ * checks we have here. ++ */ + el = ldb_msg_find_element(ac->msg, "servicePrincipalName"); + if (el != NULL) { + msg = ldb_msg_new(ac->msg); +@@ -3521,7 +4067,7 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) + } while (el != NULL); + + ret = dsdb_module_modify(ac->module, msg, +- DSDB_FLAG_NEXT_MODULE, ac->req); ++ DSDB_FLAG_OWN_MODULE, ac->req); + if (ret != LDB_SUCCESS) { + return ret; + } +@@ -4255,6 +4801,19 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req) + return samldb_fill_object(ac); + } + ++ ++ el = ldb_msg_find_element(ac->msg, "servicePrincipalName"); ++ if ((el != NULL)) { ++ /* ++ * We need to check whether the SPN collides with an existing ++ * one (anywhere) including via aliases. ++ */ ++ ret = samldb_spn_uniqueness_check(ac, el); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ } ++ + if (samdb_find_attribute(ldb, ac->msg, + "objectclass", "subnet") != NULL) { + ret = samldb_verify_subnet(ac, ac->msg->dn); +@@ -4505,12 +5064,35 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) + el2 = ldb_msg_find_element(ac->msg, "sAMAccountName"); + if ((el != NULL) || (el2 != NULL)) { + modified = true; ++ /* ++ * samldb_service_principal_names_change() might add SPN ++ * changes to the request, so this must come before the SPN ++ * uniqueness check below. ++ * ++ * Note we ALSO have to do the SPN uniqueness check inside ++ * samldb_service_principal_names_change(), because it does a ++ * subrequest to do requested SPN modifications *before* its ++ * automatic ones are added. ++ */ + ret = samldb_service_principal_names_change(ac); + if (ret != LDB_SUCCESS) { + return ret; + } + } + ++ el = ldb_msg_find_element(ac->msg, "servicePrincipalName"); ++ if ((el != NULL)) { ++ /* ++ * We need to check whether the SPN collides with an existing ++ * one (anywhere) including via aliases. ++ */ ++ modified = true; ++ ret = samldb_spn_uniqueness_check(ac, el); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ } ++ + el = ldb_msg_find_element(ac->msg, "fSMORoleOwner"); + if (el != NULL) { + ret = samldb_fsmo_role_owner_check(ac); +-- +2.23.0 + diff --git a/backport-0016-CVE-2020-25717-s3-auth-no-longer-let-check_account-a.patch b/backport-0016-CVE-2020-25717-s3-auth-no-longer-let-check_account-a.patch new file mode 100644 index 0000000..3adceb2 --- /dev/null +++ b/backport-0016-CVE-2020-25717-s3-auth-no-longer-let-check_account-a.patch @@ -0,0 +1,42 @@ +From d079628a43f845522598be7efa0abf5e478549c6 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 8 Oct 2021 18:08:20 +0200 +Subject: [PATCH 119/266] CVE-2020-25717: s3:auth: no longer let + check_account() autocreate local users + +So far we autocreated local user accounts based on just the +account_name (just ignoring any domain part). + +This only happens via a possible 'add user script', +which is not typically defined on domain members +and on NT4 DCs local users already exist in the +local passdb anyway. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/auth_util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=d079628a43f845522598be7efa0abf5e478549c6 + +diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c +index 4de4bc74374..99b85d47a5f 100644 +--- a/source3/auth/auth_util.c ++++ b/source3/auth/auth_util.c +@@ -1898,7 +1898,7 @@ static NTSTATUS check_account(TALLOC_CTX *mem_ctx, const char *domain, + return NT_STATUS_NO_MEMORY; + } + +- passwd = smb_getpwnam(mem_ctx, dom_user, &real_username, true ); ++ passwd = smb_getpwnam(mem_ctx, dom_user, &real_username, false); + if (!passwd) { + DEBUG(3, ("Failed to find authenticated user %s via " + "getpwnam(), denying access.\n", dom_user)); +-- +2.23.0 + diff --git a/backport-0016-CVE-2020-25722-s4-dsdb-samldb-reject-SPN-with-too-fe.patch b/backport-0016-CVE-2020-25722-s4-dsdb-samldb-reject-SPN-with-too-fe.patch new file mode 100644 index 0000000..290251f --- /dev/null +++ b/backport-0016-CVE-2020-25722-s4-dsdb-samldb-reject-SPN-with-too-fe.patch @@ -0,0 +1,82 @@ +From 3a4095aec5eb592d4968465930f7fd7e1435e19f Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Fri, 22 Oct 2021 16:03:18 +1300 +Subject: [PATCH 156/266] CVE-2020-25722 s4/dsdb/samldb: reject SPN with too + few/many components + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/3a4095aec5eb592d4968465930f7fd7e1435e19f + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 41 +++++++++++++++++++++++++ + 1 files changed, 41 insertions(+), 0 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index f5141936a60..006658d2bce 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -3868,6 +3868,37 @@ static int check_spn_direct_collision(struct ldb_context *ldb, + } + + ++static int count_spn_components(struct ldb_val val) ++{ ++ /* ++ * a 3 part servicePrincipalName has two slashes, like ++ * ldap/example.com/DomainDNSZones.example.com. ++ * ++ * In krb5_parse_name_flags() we don't count "\/" as a slash (i.e. ++ * escaped by a backslash), but this is not the behaviour of Windows ++ * on setting a servicePrincipalName -- slashes are counted regardless ++ * of backslashes. ++ * ++ * Accordingly, here we ignore backslashes. This will reject ++ * multi-slash SPNs that krb5_parse_name_flags() would accept, and ++ * allow ones in the form "a\/b" that it won't parse. ++ */ ++ size_t i; ++ int slashes = 0; ++ for (i = 0; i < val.length; i++) { ++ char c = val.data[i]; ++ if (c == '/') { ++ slashes++; ++ if (slashes == 3) { ++ /* at this point we don't care */ ++ return 4; ++ } ++ } ++ } ++ return slashes + 1; ++} ++ ++ + /* Check that "servicePrincipalName" changes do not introduce a collision + * globally. */ + static int samldb_spn_uniqueness_check(struct samldb_ctx *ac, +@@ -3883,8 +3914,18 @@ static int samldb_spn_uniqueness_check(struct samldb_ctx *ac, + } + + for (i = 0; i < spn_el->num_values; i++) { ++ int n_components; + spn = (char *)spn_el->values[i].data; + ++ n_components = count_spn_components(spn_el->values[i]); ++ if (n_components > 3 || n_components < 2) { ++ ldb_asprintf_errstring(ldb, ++ "samldb: spn[%s] invalid with %u components", ++ spn, n_components); ++ talloc_free(tmp_ctx); ++ return LDB_ERR_CONSTRAINT_VIOLATION; ++ } ++ + ret = check_spn_direct_collision(ldb, + tmp_ctx, + spn, +-- +2.23.0 + diff --git a/backport-0017-CVE-2020-25717-s3-auth-remove-fallbacks-in-smb_getpw.patch b/backport-0017-CVE-2020-25717-s3-auth-remove-fallbacks-in-smb_getpw.patch new file mode 100644 index 0000000..f01e4bb --- /dev/null +++ b/backport-0017-CVE-2020-25717-s3-auth-remove-fallbacks-in-smb_getpw.patch @@ -0,0 +1,181 @@ +From 844faf2f0ac5d21d65f452fb6f4d1b19bb0a2be2 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Fri, 8 Oct 2021 12:33:16 +0200 +Subject: [PATCH 120/266] CVE-2020-25717: s3:auth: remove fallbacks in + smb_getpwnam() + +So far we tried getpwnam("DOMAIN\account") first and +always did a fallback to getpwnam("account") completely +ignoring the domain part, this just causes problems +as we mix "DOMAIN1\account", "DOMAIN2\account", +and "account"! + +As we require a running winbindd for domain member setups +we should no longer do a fallback to just "account" for +users served by winbindd! + +For users of the local SAM don't use this code path, +as check_sam_security() doesn't call check_account(). + +The only case where smb_getpwnam("account") happens is +when map_username() via ("username map [script]") mapped +"DOMAIN\account" to something without '\', but that is +explicitly desired by the admin. + +Note: use 'git show -w' + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Pair-Programmed-With: Stefan Metzmacher + +Signed-off-by: Ralph Boehme +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + selftest/knownfail.d/ktest | 26 +++++++++++++ + source3/auth/auth_util.c | 77 +++++++++++++++++++++----------------- + 2 files changed, 68 insertions(+), 35 deletions(-) + create mode 100644 selftest/knownfail.d/ktest + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=844faf2f0ac5d21d65f452fb6f4d1b19bb0a2be2 + +diff --git a/selftest/knownfail.d/ktest b/selftest/knownfail.d/ktest +new file mode 100644 +index 00000000000..809612ba0b9 +--- /dev/null ++++ b/selftest/knownfail.d/ktest +@@ -0,0 +1,26 @@ ++^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2...lsa.LookupSidsReply.ktest ++^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2...lsa.LookupSidsReply.ktest ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5...rpcclient.ktest:local ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5...rpcclient.ktest:local ++^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,connect...lsa.LookupSidsReply.ktest ++^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,connect...lsa.LookupSidsReply.ktest ++^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,packet...lsa.LookupSidsReply.ktest ++^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,packet...lsa.LookupSidsReply.ktest ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,packet...rpcclient.ktest:local ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,packet...rpcclient.ktest:local ++^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,sign...lsa.LookupSidsReply.ktest ++^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,sign...lsa.LookupSidsReply.ktest ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,sign...rpcclient.ktest:local ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,sign...rpcclient.ktest:local ++^samba3.rpc.lsa.lookupsids.krb5.with.old.ccache.ncacn_np.with..smb2,seal...lsa.LookupSidsReply.ktest ++^samba3.rpc.lsa.lookupsids.krb5.ncacn_np.with..smb2,seal...lsa.LookupSidsReply.ktest ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..krb5,seal...rpcclient.ktest:local ++^samba3.blackbox.rpcclient.krb5.ncacn_np.with..spnego,krb5,seal...rpcclient.ktest:local ++^samba3.blackbox.smbclient_krb5.old.ccache..smbclient.ktest:local ++^samba3.blackbox.smbclient_krb5.new.ccache..smbclient.ktest:local ++^samba3.blackbox.smbclient_large_file..krb5.smbclient.large.posix.write.read.ktest:local ++^samba3.blackbox.smbclient_large_file..krb5.cmp.of.read.and.written.files.ktest:local ++^samba3.blackbox.smbclient_krb5.old.ccache.--client-protection=encrypt.smbclient.ktest:local ++^samba3.blackbox.smbclient_krb5.new.ccache.--client-protection=encrypt.smbclient.ktest:local ++^samba3.blackbox.smbclient_large_file.--client-protection=encrypt.krb5.smbclient.large.posix.write.read.ktest:local ++^samba3.blackbox.smbclient_large_file.--client-protection=encrypt.krb5.cmp.of.read.and.written.files.ktest:local +diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c +index 99b85d47a5f..d81313a0495 100644 +--- a/source3/auth/auth_util.c ++++ b/source3/auth/auth_util.c +@@ -1933,7 +1933,7 @@ struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, const char *domuser, + { + struct passwd *pw = NULL; + char *p = NULL; +- char *username = NULL; ++ const char *username = NULL; + + /* we only save a copy of the username it has been mangled + by winbindd use default domain */ +@@ -1952,48 +1952,55 @@ struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, const char *domuser, + /* code for a DOMAIN\user string */ + + if ( p ) { +- pw = Get_Pwnam_alloc( mem_ctx, domuser ); +- if ( pw ) { +- /* make sure we get the case of the username correct */ +- /* work around 'winbind use default domain = yes' */ +- +- if ( lp_winbind_use_default_domain() && +- !strchr_m( pw->pw_name, *lp_winbind_separator() ) ) { +- char *domain; +- +- /* split the domain and username into 2 strings */ +- *p = '\0'; +- domain = username; +- +- *p_save_username = talloc_asprintf(mem_ctx, +- "%s%c%s", +- domain, +- *lp_winbind_separator(), +- pw->pw_name); +- if (!*p_save_username) { +- TALLOC_FREE(pw); +- return NULL; +- } +- } else { +- *p_save_username = talloc_strdup(mem_ctx, pw->pw_name); +- } ++ const char *domain = NULL; + +- /* whew -- done! */ +- return pw; ++ /* split the domain and username into 2 strings */ ++ *p = '\0'; ++ domain = username; ++ p++; ++ username = p; ++ ++ if (strequal(domain, get_global_sam_name())) { ++ /* ++ * This typically don't happen ++ * as check_sam_Security() ++ * don't call make_server_info_info3() ++ * and thus check_account(). ++ * ++ * But we better keep this. ++ */ ++ goto username_only; + } + +- /* setup for lookup of just the username */ +- /* remember that p and username are overlapping memory */ +- +- p++; +- username = talloc_strdup(mem_ctx, p); +- if (!username) { ++ pw = Get_Pwnam_alloc( mem_ctx, domuser ); ++ if (pw == NULL) { + return NULL; + } ++ /* make sure we get the case of the username correct */ ++ /* work around 'winbind use default domain = yes' */ ++ ++ if ( lp_winbind_use_default_domain() && ++ !strchr_m( pw->pw_name, *lp_winbind_separator() ) ) { ++ *p_save_username = talloc_asprintf(mem_ctx, ++ "%s%c%s", ++ domain, ++ *lp_winbind_separator(), ++ pw->pw_name); ++ if (!*p_save_username) { ++ TALLOC_FREE(pw); ++ return NULL; ++ } ++ } else { ++ *p_save_username = talloc_strdup(mem_ctx, pw->pw_name); ++ } ++ ++ /* whew -- done! */ ++ return pw; ++ + } + + /* just lookup a plain username */ +- ++username_only: + pw = Get_Pwnam_alloc(mem_ctx, username); + + /* Create local user if requested but only if winbindd +-- +2.23.0 + diff --git a/backport-0017-CVE-2020-25722-s4-dsdb-modules-add-dsdb_get_expected.patch b/backport-0017-CVE-2020-25722-s4-dsdb-modules-add-dsdb_get_expected.patch new file mode 100644 index 0000000..4b6db8f --- /dev/null +++ b/backport-0017-CVE-2020-25722-s4-dsdb-modules-add-dsdb_get_expected.patch @@ -0,0 +1,178 @@ +From 208bbf8cfda200deaeddfad77e4b43d54e692ba5 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:09:21 +1300 +Subject: [PATCH 157/266] CVE-2020-25722 s4/dsdb modules: add + dsdb_get_expected_new_values() + +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. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/208bbf8cfda200deaeddfad77e4b43d54e692ba5 + +--- + source4/dsdb/samdb/ldb_modules/util.c | 121 ++++++++++++++++++++++++++ + 1 file changed, 121 insertions(+) + +diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c +index 9519ecfa928..da152e4d754 100644 +--- a/source4/dsdb/samdb/ldb_modules/util.c ++++ b/source4/dsdb/samdb/ldb_modules/util.c +@@ -1441,6 +1441,127 @@ void dsdb_req_chain_debug(struct ldb_request *req, int level) + talloc_free(s); + } + ++/* ++ * Get all the values that *might* be added by an ldb message, as a composite ++ * ldb element. ++ * ++ * This is useful when we need to check all the possible values against some ++ * criteria. ++ * ++ * In cases where a modify message mixes multiple ADDs, DELETEs, and REPLACES, ++ * the returned element might contain more values than would actually end up ++ * in the database if the message was run to its conclusion. ++ * ++ * If the operation is not LDB_ADD or LDB_MODIFY, an operations error is ++ * returned. ++ * ++ * The returned element might not be new, and should not be modified or freed ++ * before the message is finished. ++ */ ++ ++int dsdb_get_expected_new_values(TALLOC_CTX *mem_ctx, ++ const struct ldb_message *msg, ++ const char *attr_name, ++ struct ldb_message_element **el, ++ enum ldb_request_type operation) ++{ ++ unsigned int i; ++ unsigned int el_count = 0; ++ unsigned int val_count = 0; ++ struct ldb_val *v = NULL; ++ struct ldb_message_element *_el = NULL; ++ *el = NULL; ++ ++ if (operation != LDB_ADD && operation != LDB_MODIFY) { ++ DBG_ERR("inapplicable operation type: %d\n", operation); ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ ++ /* count the adding or replacing elements */ ++ for (i = 0; i < msg->num_elements; i++) { ++ if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) { ++ unsigned int tmp; ++ if ((operation == LDB_MODIFY) && ++ (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) ++ == LDB_FLAG_MOD_DELETE)) { ++ continue; ++ } ++ el_count++; ++ tmp = val_count + msg->elements[i].num_values; ++ if (unlikely(tmp < val_count)) { ++ DBG_ERR("too many values for one element!"); ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ val_count = tmp; ++ } ++ } ++ if (el_count == 0) { ++ /* nothing to see here */ ++ return LDB_SUCCESS; ++ } ++ ++ if (el_count == 1 || val_count == 0) { ++ /* ++ * There is one effective element, which we can return as-is, ++ * OR there are only elements with zero values -- any of which ++ * will do. ++ */ ++ for (i = 0; i < msg->num_elements; i++) { ++ if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) { ++ if ((operation == LDB_MODIFY) && ++ (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) ++ == LDB_FLAG_MOD_DELETE)) { ++ continue; ++ } ++ *el = &msg->elements[i]; ++ return LDB_SUCCESS; ++ } ++ } ++ } ++ ++ _el = talloc_zero(mem_ctx, struct ldb_message_element); ++ if (_el == NULL) { ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ _el->name = attr_name; ++ ++ if (val_count == 0) { ++ /* ++ * Seems unlikely, but sometimes we might be adding zero ++ * values in multiple separate elements. The talloc zero has ++ * already set the expected values = NULL, num_values = 0. ++ */ ++ *el = _el; ++ return LDB_SUCCESS; ++ } ++ ++ _el->values = talloc_array(_el, struct ldb_val, val_count); ++ if (_el->values == NULL) { ++ talloc_free(_el); ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ _el->num_values = val_count; ++ ++ v = _el->values; ++ ++ for (i = 0; i < val_count; i++) { ++ if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) { ++ if ((operation == LDB_MODIFY) && ++ (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) ++ == LDB_FLAG_MOD_DELETE)) { ++ continue; ++ } ++ memcpy(v, ++ msg->elements[i].values, ++ msg->elements[i].num_values); ++ v += msg->elements[i].num_values; ++ } ++ } ++ ++ *el = _el; ++ return LDB_SUCCESS; ++} ++ + /* + * Gets back a single-valued attribute by the rules of the DSDB triggers when + * performing a modify operation. +-- +2.23.0 + diff --git a/backport-0018-CVE-2020-25717-s3-auth-don-t-let-create_local_token-.patch b/backport-0018-CVE-2020-25717-s3-auth-don-t-let-create_local_token-.patch new file mode 100644 index 0000000..1bef963 --- /dev/null +++ b/backport-0018-CVE-2020-25717-s3-auth-don-t-let-create_local_token-.patch @@ -0,0 +1,48 @@ +From e8e0bea9b333315ec1ff9eb1d36d4e810ca95941 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 4 Oct 2021 18:03:55 +0200 +Subject: [PATCH 122/266] CVE-2020-25717: s3:auth: don't let create_local_token + depend on !winbind_ping() + +We always require a running winbindd on a domain member, so +we should better fail a request instead of silently alter +the behaviour, which results in a different unix token, just +because winbindd might be restarted. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/auth_util.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=e8e0bea9b333315ec1ff9eb1d36d4e810ca95941 + +diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c +index d81313a0495..065b525500f 100644 +--- a/source3/auth/auth_util.c ++++ b/source3/auth/auth_util.c +@@ -576,13 +576,11 @@ NTSTATUS create_local_token(TALLOC_CTX *mem_ctx, + } + + /* +- * If winbind is not around, we can not make much use of the SIDs the +- * domain controller provided us with. Likewise if the user name was +- * mapped to some local unix user. ++ * If the user name was mapped to some local unix user, ++ * we can not make much use of the SIDs the ++ * domain controller provided us with. + */ +- +- if (((lp_server_role() == ROLE_DOMAIN_MEMBER) && !winbind_ping()) || +- (server_info->nss_token)) { ++ if (server_info->nss_token) { + char *found_username = NULL; + status = create_token_from_username(session_info, + server_info->unix_name, +-- +2.23.0 + diff --git a/backport-0018-CVE-2020-25722-s4-dsdb-samldb-samldb_get_single_valu.patch b/backport-0018-CVE-2020-25722-s4-dsdb-samldb-samldb_get_single_valu.patch new file mode 100644 index 0000000..da707f8 --- /dev/null +++ b/backport-0018-CVE-2020-25722-s4-dsdb-samldb-samldb_get_single_valu.patch @@ -0,0 +1,49 @@ +From 7913ec038f25b1778dfe545766266c70502e7c63 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:10:44 +1300 +Subject: [PATCH 158/266] CVE-2020-25722 s4/dsdb/samldb: + samldb_get_single_valued_attr() check all values + +using dsdb_get_expected_new_values(). + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/7913ec038f25b1778dfe545766266c70502e7c63 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 006658d2bce..4bd40a5ef1f 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -171,11 +171,19 @@ static int samldb_get_single_valued_attr(struct ldb_context *ldb, + * attribute. + */ + struct ldb_message_element *el = NULL; ++ int ret; + + *value = NULL; + +- el = dsdb_get_single_valued_attr(ac->msg, attr, +- ac->req->operation); ++ ret = dsdb_get_expected_new_values(ac, ++ ac->msg, ++ attr, ++ &el, ++ ac->req->operation); ++ ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } + if (el == NULL) { + /* we are not affected */ + return LDB_SUCCESS; +-- +2.23.0 + diff --git a/backport-0019-CVE-2020-25719-CVE-2020-25717-auth-gensec-always-req.patch b/backport-0019-CVE-2020-25719-CVE-2020-25717-auth-gensec-always-req.patch new file mode 100644 index 0000000..fb6947f --- /dev/null +++ b/backport-0019-CVE-2020-25719-CVE-2020-25717-auth-gensec-always-req.patch @@ -0,0 +1,76 @@ +From eba5e1321830624e6e42d248616f651beb0d3b99 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 5 Oct 2021 18:11:57 +0200 +Subject: [PATCH 124/266] CVE-2020-25719 CVE-2020-25717: auth/gensec: always + require a PAC in domain mode (DC or member) + +AD domains always provide a PAC unless UF_NO_AUTH_DATA_REQUIRED is set +on the service account, which can only be explicitly configured, +but that's an invalid configuration! + +We still try to support standalone servers in an MIT realm, +as legacy setup. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett + +[jsutton@samba.org Removed knownfail entries] +--- + auth/gensec/gensec_util.c | 27 +++++++++++++++++++++++---- + 1 files changed, 23 insertions(+), 4 deletions(-) + delete mode 100644 selftest/knownfail.d/no-pac + +Conflict:delete a chunk which delete a file do not exist +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=eba5e1321830624e6e42d248616f651beb0d3b99 + +diff --git a/auth/gensec/gensec_util.c b/auth/gensec/gensec_util.c +index e185acc0c20..694661b53b5 100644 +--- a/auth/gensec/gensec_util.c ++++ b/auth/gensec/gensec_util.c +@@ -25,6 +25,8 @@ + #include "auth/gensec/gensec_internal.h" + #include "auth/common_auth.h" + #include "../lib/util/asn1.h" ++#include "param/param.h" ++#include "libds/common/roles.h" + + #undef DBGC_CLASS + #define DBGC_CLASS DBGC_AUTH +@@ -46,10 +48,27 @@ NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx, + session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS; + + if (!pac_blob) { +- if (gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) { +- DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access\n", +- principal_string)); +- return NT_STATUS_ACCESS_DENIED; ++ enum server_role server_role = ++ lpcfg_server_role(gensec_security->settings->lp_ctx); ++ ++ /* ++ * For any domain setup (DC or member) we require having ++ * a PAC, as the service ticket comes from an AD DC, ++ * which will always provide a PAC, unless ++ * UF_NO_AUTH_DATA_REQUIRED is configured for our ++ * account, but that's just an invalid configuration, ++ * the admin configured for us! ++ * ++ * As a legacy case, we still allow kerberos tickets from an MIT ++ * realm, but only in standalone mode. In that mode we'll only ++ * ever accept a kerberos authentication with a keytab file ++ * being explicitly configured via the 'keytab method' option. ++ */ ++ if (server_role != ROLE_STANDALONE) { ++ DBG_WARNING("Unable to find PAC in ticket from %s, " ++ "failing to allow access\n", ++ principal_string); ++ return NT_STATUS_NO_IMPERSONATION_TOKEN; + } + DBG_NOTICE("Unable to find PAC for %s, resorting to local " + "user lookup\n", principal_string); +-- +2.23.0 + diff --git a/backport-0019-CVE-2020-25722-s4-dsdb-samldb-samldb_sam_accountname.patch b/backport-0019-CVE-2020-25722-s4-dsdb-samldb-samldb_sam_accountname.patch new file mode 100644 index 0000000..09520e4 --- /dev/null +++ b/backport-0019-CVE-2020-25722-s4-dsdb-samldb-samldb_sam_accountname.patch @@ -0,0 +1,47 @@ +From 437465a90eff051762f347cb5537107f2234af01 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Fri, 22 Oct 2021 14:52:49 +1300 +Subject: [PATCH 159/266] CVE-2020-25722 s4/dsdb/samldb: + samldb_sam_accountname_valid_check() check all values + +Using dsdb_get_expected_new_values(). + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/437465a90eff051762f347cb5537107f2234af01 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 4bd40a5ef1f..5d3e0f9771c 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -530,8 +530,17 @@ static int samldb_sam_accountname_valid_check(struct samldb_ctx *ac) + bool is_admin; + struct security_token *user_token = NULL; + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); +- struct ldb_message_element *el = dsdb_get_single_valued_attr(ac->msg, "samAccountName", +- ac->req->operation); ++ struct ldb_message_element *el = NULL; ++ ++ ret = dsdb_get_expected_new_values(ac, ++ ac->msg, ++ "samAccountName", ++ &el, ++ ac->req->operation); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ + if (el == NULL || el->num_values == 0) { + ldb_asprintf_errstring(ldb, + "%08X: samldb: 'samAccountName' can't be deleted/empty!", +-- +2.23.0 + diff --git a/backport-0020-CVE-2020-25717-s3-ntlm_auth-fix-memory-leaks-in-ntlm.patch b/backport-0020-CVE-2020-25717-s3-ntlm_auth-fix-memory-leaks-in-ntlm.patch new file mode 100644 index 0000000..ac990fd --- /dev/null +++ b/backport-0020-CVE-2020-25717-s3-ntlm_auth-fix-memory-leaks-in-ntlm.patch @@ -0,0 +1,77 @@ +From 9f73360e17d1e519d25cb4b60d7506fca9fd02fe Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 21 Sep 2021 12:27:28 +0200 +Subject: [PATCH 126/266] CVE-2020-25717: s3:ntlm_auth: fix memory leaks in + ntlm_auth_generate_session_info_pac() + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/utils/ntlm_auth.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=9f73360e17d1e519d25cb4b60d7506fca9fd02fe + +diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c +index 1d22a48c57c..e6efdfcec5c 100644 +--- a/source3/utils/ntlm_auth.c ++++ b/source3/utils/ntlm_auth.c +@@ -817,23 +817,27 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c + if (!p) { + DEBUG(3, ("[%s] Doesn't look like a valid principal\n", + princ_name)); +- return NT_STATUS_LOGON_FAILURE; ++ status = NT_STATUS_LOGON_FAILURE; ++ goto done; + } + + user = talloc_strndup(mem_ctx, princ_name, p - princ_name); + if (!user) { +- return NT_STATUS_NO_MEMORY; ++ status = NT_STATUS_NO_MEMORY; ++ goto done; + } + + realm = talloc_strdup(talloc_tos(), p + 1); + if (!realm) { +- return NT_STATUS_NO_MEMORY; ++ status = NT_STATUS_NO_MEMORY; ++ goto done; + } + + if (!strequal(realm, lp_realm())) { + DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm)); + if (!lp_allow_trusted_domains()) { +- return NT_STATUS_LOGON_FAILURE; ++ status = NT_STATUS_LOGON_FAILURE; ++ goto done; + } + } + +@@ -841,7 +845,8 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c + domain = talloc_strdup(mem_ctx, + logon_info->info3.base.logon_domain.string); + if (!domain) { +- return NT_STATUS_NO_MEMORY; ++ status = NT_STATUS_NO_MEMORY; ++ goto done; + } + DEBUG(10, ("Domain is [%s] (using PAC)\n", domain)); + } else { +@@ -871,7 +876,8 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c + domain = talloc_strdup(mem_ctx, realm); + } + if (!domain) { +- return NT_STATUS_NO_MEMORY; ++ status = NT_STATUS_NO_MEMORY; ++ goto done; + } + DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain)); + } +-- +2.23.0 + diff --git a/backport-0020-CVE-2020-25722-s4-dsdb-samldb-samldb_schema_add_hand.patch b/backport-0020-CVE-2020-25722-s4-dsdb-samldb-samldb_schema_add_hand.patch new file mode 100644 index 0000000..8c385eb --- /dev/null +++ b/backport-0020-CVE-2020-25722-s4-dsdb-samldb-samldb_schema_add_hand.patch @@ -0,0 +1,43 @@ +From 466620563bdbb31858e82462cdc0ae62605c9206 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:12:49 +1300 +Subject: [PATCH 160/266] CVE-2020-25722 s4/dsdb/samldb: + samldb_schema_add_handle_linkid() checks all values + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/466620563bdbb31858e82462cdc0ae62605c9206 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 5d3e0f9771c..39533266aeb 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -739,8 +739,15 @@ static int samldb_schema_add_handle_linkid(struct samldb_ctx *ac) + schema = dsdb_get_schema(ldb, ac); + schema_dn = ldb_get_schema_basedn(ldb); + +- el = dsdb_get_single_valued_attr(ac->msg, "linkID", +- ac->req->operation); ++ ret = dsdb_get_expected_new_values(ac, ++ ac->msg, ++ "linkID", ++ &el, ++ ac->req->operation); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ + if (el == NULL) { + return LDB_SUCCESS; + } +-- +2.23.0 + diff --git a/backport-0021-CVE-2020-25717-s3-ntlm_auth-let-ntlm_auth_generate_s.patch b/backport-0021-CVE-2020-25717-s3-ntlm_auth-let-ntlm_auth_generate_s.patch new file mode 100644 index 0000000..66904b1 --- /dev/null +++ b/backport-0021-CVE-2020-25717-s3-ntlm_auth-let-ntlm_auth_generate_s.patch @@ -0,0 +1,145 @@ +From 131d5ceb9deaaa1d8dd478a9b2e2556133c511aa Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 21 Sep 2021 12:44:01 +0200 +Subject: [PATCH 127/266] CVE-2020-25717: s3:ntlm_auth: let + ntlm_auth_generate_session_info_pac() base the name on the PAC LOGON_INFO + only + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14801 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/utils/ntlm_auth.c | 91 ++++++++++++--------------------------- + 1 file changed, 28 insertions(+), 63 deletions(-) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=131d5ceb9deaaa1d8dd478a9b2e2556133c511aa + +diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c +index e6efdfcec5c..5541c58350b 100644 +--- a/source3/utils/ntlm_auth.c ++++ b/source3/utils/ntlm_auth.c +@@ -789,10 +789,8 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c + struct PAC_LOGON_INFO *logon_info = NULL; + char *unixuser; + NTSTATUS status; +- char *domain = NULL; +- char *realm = NULL; +- char *user = NULL; +- char *p; ++ const char *domain = ""; ++ const char *user = ""; + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) { +@@ -809,79 +807,46 @@ static NTSTATUS ntlm_auth_generate_session_info_pac(struct auth4_context *auth_c + if (!NT_STATUS_IS_OK(status)) { + goto done; + } +- } +- +- 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; ++ } else { ++ status = NT_STATUS_ACCESS_DENIED; ++ DBG_WARNING("Kerberos ticket for[%s] has no PAC: %s\n", ++ princ_name, nt_errstr(status)); + goto done; + } + +- user = talloc_strndup(mem_ctx, princ_name, p - princ_name); +- if (!user) { +- status = NT_STATUS_NO_MEMORY; +- goto done; ++ if (logon_info->info3.base.account_name.string != NULL) { ++ user = logon_info->info3.base.account_name.string; ++ } else { ++ user = ""; ++ } ++ if (logon_info->info3.base.logon_domain.string != NULL) { ++ domain = logon_info->info3.base.logon_domain.string; ++ } else { ++ domain = ""; + } + +- realm = talloc_strdup(talloc_tos(), p + 1); +- if (!realm) { +- status = NT_STATUS_NO_MEMORY; ++ if (strlen(user) == 0 || strlen(domain) == 0) { ++ status = NT_STATUS_ACCESS_DENIED; ++ DBG_WARNING("Kerberos ticket for[%s] has invalid " ++ "account_name[%s]/logon_domain[%s]: %s\n", ++ princ_name, ++ logon_info->info3.base.account_name.string, ++ logon_info->info3.base.logon_domain.string, ++ nt_errstr(status)); + goto done; + } + +- if (!strequal(realm, lp_realm())) { +- DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm)); ++ DBG_NOTICE("Kerberos ticket principal name is [%s] " ++ "account_name[%s]/logon_domain[%s]\n", ++ princ_name, user, domain); ++ ++ if (!strequal(domain, lp_workgroup())) { + if (!lp_allow_trusted_domains()) { + status = NT_STATUS_LOGON_FAILURE; + goto done; + } + } + +- if (logon_info && logon_info->info3.base.logon_domain.string) { +- domain = talloc_strdup(mem_ctx, +- logon_info->info3.base.logon_domain.string); +- if (!domain) { +- status = NT_STATUS_NO_MEMORY; +- goto done; +- } +- DEBUG(10, ("Domain is [%s] (using PAC)\n", domain)); +- } else { +- +- /* If we have winbind running, we can (and must) shorten the +- username by using the short netbios name. Otherwise we will +- have inconsistent user names. With Kerberos, we get the +- fully qualified realm, with ntlmssp we get the short +- name. And even w2k3 does use ntlmssp if you for example +- connect to an ip address. */ +- +- wbcErr wbc_status; +- struct wbcDomainInfo *info = NULL; +- +- DEBUG(10, ("Mapping [%s] to short name using winbindd\n", +- realm)); +- +- wbc_status = wbcDomainInfo(realm, &info); +- +- if (WBC_ERROR_IS_OK(wbc_status)) { +- domain = talloc_strdup(mem_ctx, +- info->short_name); +- wbcFreeMemory(info); +- } else { +- DEBUG(3, ("Could not find short name: %s\n", +- wbcErrorString(wbc_status))); +- domain = talloc_strdup(mem_ctx, realm); +- } +- if (!domain) { +- status = NT_STATUS_NO_MEMORY; +- goto done; +- } +- DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain)); +- } +- + unixuser = talloc_asprintf(tmp_ctx, "%s%c%s", domain, winbind_separator(), user); + if (!unixuser) { + status = NT_STATUS_NO_MEMORY; +-- +2.23.0 + diff --git a/backport-0021-CVE-2020-25722-s4-dsdb-samldb-samldb_schema_add_hand.patch b/backport-0021-CVE-2020-25722-s4-dsdb-samldb-samldb_schema_add_hand.patch new file mode 100644 index 0000000..1a88417 --- /dev/null +++ b/backport-0021-CVE-2020-25722-s4-dsdb-samldb-samldb_schema_add_hand.patch @@ -0,0 +1,43 @@ +From 57f7b13f70d6a5802fd31f06f71cfd65347781af Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:13:35 +1300 +Subject: [PATCH 161/266] CVE-2020-25722 s4/dsdb/samldb: + samldb_schema_add_handle_mapiid() checks all values + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/57f7b13f70d6a5802fd31f06f71cfd65347781af + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 39533266aeb..5b2c2fc29aa 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -907,8 +907,15 @@ static int samldb_schema_add_handle_mapiid(struct samldb_ctx *ac) + schema = dsdb_get_schema(ldb, ac); + schema_dn = ldb_get_schema_basedn(ldb); + +- el = dsdb_get_single_valued_attr(ac->msg, "mAPIID", +- ac->req->operation); ++ ret = dsdb_get_expected_new_values(ac, ++ ac->msg, ++ "mAPIID", ++ &el, ++ ac->req->operation); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ + if (el == NULL) { + return LDB_SUCCESS; + } +-- +2.23.0 + diff --git a/backport-0022-CVE-2020-25722-s4-dsdb-samldb-samldb_prim_group_chan.patch b/backport-0022-CVE-2020-25722-s4-dsdb-samldb-samldb_prim_group_chan.patch new file mode 100644 index 0000000..798bebc --- /dev/null +++ b/backport-0022-CVE-2020-25722-s4-dsdb-samldb-samldb_prim_group_chan.patch @@ -0,0 +1,43 @@ +From 18e4c639dfca246d198f2407d39ac5b85bb747f9 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:14:05 +1300 +Subject: [PATCH 162/266] CVE-2020-25722 s4/dsdb/samldb: + samldb_prim_group_change() checks all values + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/18e4c639dfca246d198f2407d39ac5b85bb747f9 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 5b2c2fc29aa..ba56cf8826e 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -2121,8 +2121,15 @@ static int samldb_prim_group_change(struct samldb_ctx *ac) + int ret; + const char * const noattrs[] = { NULL }; + +- el = dsdb_get_single_valued_attr(ac->msg, "primaryGroupID", +- ac->req->operation); ++ ret = dsdb_get_expected_new_values(ac, ++ ac->msg, ++ "primaryGroupID", ++ &el, ++ ac->req->operation); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ + if (el == NULL) { + /* we are not affected */ + return LDB_SUCCESS; +-- +2.23.0 + diff --git a/backport-0022-use-set_current_user_info-in-auth3_generate_session_info_p.patch b/backport-0022-use-set_current_user_info-in-auth3_generate_session_info_p.patch new file mode 100644 index 0000000..9d04bbb --- /dev/null +++ b/backport-0022-use-set_current_user_info-in-auth3_generate_session_info_p.patch @@ -0,0 +1,52 @@ +From dc4b1e39ce1f2201a2d6ae2d4cffef2448f69a62 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Sat, 18 Jan 2020 08:06:45 +0100 +Subject: [PATCH] s3/auth: use set_current_user_info() in + auth3_generate_session_info_pac() + +This delays reloading config slightly, but I don't see how could affect +observable behaviour other then log messages coming from the functions in +between the different locations for lp_load_with_shares() like +make_session_info_krb5() are sent to a different logfile if "log file" uses %U. + +Signed-off-by: Ralph Boehme +Reviewed-by: Andreas Schneider +--- + source3/auth/auth_generic.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +Conflict:NA +Reference:https://github.com/samba-team/samba/commit/dc4b1e39ce1f2201a2d6ae2d4cffef2448f69a62 + +diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c +index 9243a0ba02d3..0e9500ac08d1 100644 +--- a/source3/auth/auth_generic.c ++++ b/source3/auth/auth_generic.c +@@ -159,12 +159,6 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + } + } + +- /* setup the string used by %U */ +- sub_set_smb_name(username); +- +- /* reload services so that the new %U is taken into account */ +- lp_load_with_shares(get_dyn_CONFIGFILE()); +- + status = make_session_info_krb5(mem_ctx, + ntuser, ntdomain, username, pw, + info3_copy, is_guest, is_mapped, NULL /* No session key for now, caller will sort it out */, +@@ -176,6 +170,14 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + goto done; + } + ++ /* setup the string used by %U */ ++ set_current_user_info((*session_info)->unix_info->sanitized_username, ++ (*session_info)->unix_info->unix_name, ++ (*session_info)->info->domain_name); ++ ++ /* reload services so that the new %U is taken into account */ ++ lp_load_with_shares(get_dyn_CONFIGFILE()); ++ + DEBUG(5, (__location__ "OK: user: %s domain: %s client: %s\n", + ntuser, ntdomain, rhost)); + diff --git a/backport-0023-CVE-2020-25717-s3-auth-let-auth3_generate_session_in.patch b/backport-0023-CVE-2020-25717-s3-auth-let-auth3_generate_session_in.patch new file mode 100644 index 0000000..3316e2e --- /dev/null +++ b/backport-0023-CVE-2020-25717-s3-auth-let-auth3_generate_session_in.patch @@ -0,0 +1,319 @@ +From a152f36b0576737e647dbe5f1954039668123c1f Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 4 Oct 2021 19:42:20 +0200 +Subject: [PATCH 128/266] 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 +Reviewed-by: Andrew Bartlett + +--- + source3/auth/auth_generic.c | 137 ++++++++++++++++++++++++++++-------- + 1 file changed, 109 insertions(+), 28 deletions(-) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=a152f36b0576737e647dbe5f1954039668123c1f + +diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c +index 86585ad690c..450c358beeb 100644 +--- a/source3/auth/auth_generic.c ++++ b/source3/auth/auth_generic.c +@@ -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 = {}; + 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; + +-- +2.23.0 + diff --git a/backport-0023-CVE-2020-25722-s4-dsdb-samldb-samldb_user_account_co.patch b/backport-0023-CVE-2020-25722-s4-dsdb-samldb-samldb_user_account_co.patch new file mode 100644 index 0000000..ad84a23 --- /dev/null +++ b/backport-0023-CVE-2020-25722-s4-dsdb-samldb-samldb_user_account_co.patch @@ -0,0 +1,46 @@ +From 2991eedefc19367b57313b72a3b741eae74d049c Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:15:00 +1300 +Subject: [PATCH 163/266] CVE-2020-25722 s4/dsdb/samldb: + samldb_user_account_control_change() checks all values + +There is another call to dsdb_get_expected_new_values() in this function +that we change in the next commit. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/2991eedefc19367b57313b72a3b741eae74d049c + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index ba56cf8826e..b84ef4c26d5 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -2807,8 +2807,15 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) + bool old_is_critical = false; + bool new_is_critical = false; + +- el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl", +- ac->req->operation); ++ ret = dsdb_get_expected_new_values(ac, ++ ac->msg, ++ "userAccountControl", ++ &el, ++ ac->req->operation); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ + if (el == NULL || el->num_values == 0) { + ldb_asprintf_errstring(ldb, + "%08X: samldb: 'userAccountControl' can't be deleted!", +-- +2.23.0 + diff --git a/backport-0024-CVE-2020-25717-s3-auth-let-auth3_generate_session_in.patch b/backport-0024-CVE-2020-25717-s3-auth-let-auth3_generate_session_in.patch new file mode 100644 index 0000000..ff3c5e5 --- /dev/null +++ b/backport-0024-CVE-2020-25717-s3-auth-let-auth3_generate_session_in.patch @@ -0,0 +1,85 @@ +From 9f807fdd8d1a148891d389820c329f44f9ffe965 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 5 Oct 2021 18:12:49 +0200 +Subject: [PATCH 130/266] CVE-2020-25717: s3:auth: let + auth3_generate_session_info_pac() reject a PAC in standalone mode + +We should be strict in standalone mode, that we only support MIT realms +without a PAC in order to keep the code sane. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14556 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +--- + source3/auth/auth_generic.c | 29 +++++++++-------------------- + 1 file changed, 9 insertions(+), 20 deletions(-) + +Conflict:NA +Reference:https://git.samba.org/samba.git/?p=samba.git;a=patch;h=9f807fdd8d1a148891d389820c329f44f9ffe965 + +diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c +index 450c358beeb..7d00cfa95c7 100644 +--- a/source3/auth/auth_generic.c ++++ b/source3/auth/auth_generic.c +@@ -48,8 +48,6 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + { + 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; + bool is_mapped; + bool is_guest; + char *ntuser; +@@ -203,19 +201,20 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + /* 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 +- status = NT_STATUS_ACCESS_DENIED; +-#endif ++ /* ++ * In standalone mode we don't expect a PAC! ++ * we only support MIT realms ++ */ ++ status = NT_STATUS_BAD_TOKEN_TYPE; ++ DBG_WARNING("Unexpected PAC for [%s] in standalone mode - %s\n", ++ princ_name, nt_errstr(status)); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + } + + status = get_user_from_kerberos_info(tmp_ctx, rhost, +- princ_name, logon_info, ++ princ_name, NULL, + &is_mapped, &is_guest, + &ntuser, &ntdomain, + &username, &pw); +@@ -226,19 +225,9 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx, + goto done; + } + +- /* Get the info3 from the PAC data if we have it */ +- if (logon_info) { +- status = create_info3_from_pac_logon_info(tmp_ctx, +- logon_info, +- &info3_copy); +- if (!NT_STATUS_IS_OK(status)) { +- goto done; +- } +- } +- + status = make_session_info_krb5(mem_ctx, + ntuser, ntdomain, username, pw, +- info3_copy, is_guest, is_mapped, NULL /* No session key for now, caller will sort it out */, ++ NULL, is_guest, is_mapped, NULL /* No session key for now, caller will sort it out */, + session_info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to map kerberos pac to server info (%s)\n", +-- +2.23.0 + diff --git a/backport-0024-CVE-2020-25722-s4-dsdb-samldb-_user_account_control_.patch b/backport-0024-CVE-2020-25722-s4-dsdb-samldb-_user_account_control_.patch new file mode 100644 index 0000000..6729b46 --- /dev/null +++ b/backport-0024-CVE-2020-25722-s4-dsdb-samldb-_user_account_control_.patch @@ -0,0 +1,48 @@ +From 96fbfe0edd6307c6cd3c17cabb3473c5775ee656 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:15:43 +1300 +Subject: [PATCH 164/266] 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. + +Instead we just add a replace on the end. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/96fbfe0edd6307c6cd3c17cabb3473c5775ee656 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index b84ef4c26d5..1410e5bc5e6 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -3008,9 +3008,12 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) + return ldb_module_oom(ac->module); + } + +- /* Overwrite "userAccountControl" correctly */ +- el = dsdb_get_single_valued_attr(ac->msg, "userAccountControl", +- ac->req->operation); ++ ret = ldb_msg_add_empty(ac->msg, ++ "userAccountControl", ++ LDB_FLAG_MOD_REPLACE, ++ &el); ++ el->values = talloc(ac->msg, struct ldb_val); ++ el->num_values = 1; + el->values[0].data = (uint8_t *) tempstr; + el->values[0].length = strlen(tempstr); + } else { +-- +2.23.0 + diff --git a/backport-0025-CVE-2020-25722-s4-dsdb-samldb-samldb_pwd_last_set_ch.patch b/backport-0025-CVE-2020-25722-s4-dsdb-samldb-samldb_pwd_last_set_ch.patch new file mode 100644 index 0000000..57c833c --- /dev/null +++ b/backport-0025-CVE-2020-25722-s4-dsdb-samldb-samldb_pwd_last_set_ch.patch @@ -0,0 +1,43 @@ +From 63de509875b5c3426d288a1aad73e5a67bd345f4 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:16:34 +1300 +Subject: [PATCH 165/266] CVE-2020-25722 s4/dsdb/samldb: + samldb_pwd_last_set_change() checks all values + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/63de509875b5c3426d288a1aad73e5a67bd345f4 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 1410e5bc5e6..8e93df221f5 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -3102,8 +3102,15 @@ static int samldb_pwd_last_set_change(struct samldb_ctx *ac) + NULL + }; + +- el = dsdb_get_single_valued_attr(ac->msg, "pwdLastSet", +- ac->req->operation); ++ ret = dsdb_get_expected_new_values(ac, ++ ac->msg, ++ "pwdLastSet", ++ &el, ++ ac->req->operation); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ + if (el == NULL || el->num_values == 0) { + ldb_asprintf_errstring(ldb, + "%08X: samldb: 'pwdLastSet' can't be deleted!", +-- +2.23.0 + diff --git a/backport-0026-CVE-2020-25722-s4-dsdb-samldb-samldb_lockout_time-ch.patch b/backport-0026-CVE-2020-25722-s4-dsdb-samldb-samldb_lockout_time-ch.patch new file mode 100644 index 0000000..7b21b9d --- /dev/null +++ b/backport-0026-CVE-2020-25722-s4-dsdb-samldb-samldb_lockout_time-ch.patch @@ -0,0 +1,43 @@ +From 1deb16de4d1823a653f86be009ab4f9c74c8df7e Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:17:31 +1300 +Subject: [PATCH 166/266] CVE-2020-25722 s4/dsdb/samldb: samldb_lockout_time() + checks all values + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/1deb16de4d1823a653f86be009ab4f9c74c8df7e + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 8e93df221f5..48eb88f728b 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -3164,8 +3164,15 @@ static int samldb_lockout_time(struct samldb_ctx *ac) + struct ldb_message *tmp_msg; + int ret; + +- el = dsdb_get_single_valued_attr(ac->msg, "lockoutTime", +- ac->req->operation); ++ ret = dsdb_get_expected_new_values(ac, ++ ac->msg, ++ "lockoutTime", ++ &el, ++ ac->req->operation); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ + if (el == NULL || el->num_values == 0) { + ldb_asprintf_errstring(ldb, + "%08X: samldb: 'lockoutTime' can't be deleted!", +-- +2.23.0 + diff --git a/backport-0027-CVE-2020-25722-s4-dsdb-samldb-samldb_group_type_chan.patch b/backport-0027-CVE-2020-25722-s4-dsdb-samldb-samldb_group_type_chan.patch new file mode 100644 index 0000000..1786041 --- /dev/null +++ b/backport-0027-CVE-2020-25722-s4-dsdb-samldb-samldb_group_type_chan.patch @@ -0,0 +1,43 @@ +From 485db903ed2bac1470e00948574b97bd9548cae4 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:17:50 +1300 +Subject: [PATCH 167/266] CVE-2020-25722 s4/dsdb/samldb: + samldb_group_type_change() checks all values + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/485db903ed2bac1470e00948574b97bd9548cae4 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 48eb88f728b..391437d759d 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -3221,8 +3221,15 @@ static int samldb_group_type_change(struct samldb_ctx *ac) + struct ldb_result *res; + const char * const attrs[] = { "groupType", NULL }; + +- el = dsdb_get_single_valued_attr(ac->msg, "groupType", +- ac->req->operation); ++ ret = dsdb_get_expected_new_values(ac, ++ ac->msg, ++ "groupType", ++ &el, ++ ac->req->operation); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ + if (el == NULL) { + /* we are not affected */ + return LDB_SUCCESS; +-- +2.23.0 + diff --git a/backport-0028-CVE-2020-25722-s4-dsdb-samldb-samldb_service_princip.patch b/backport-0028-CVE-2020-25722-s4-dsdb-samldb-samldb_service_princip.patch new file mode 100644 index 0000000..06009a2 --- /dev/null +++ b/backport-0028-CVE-2020-25722-s4-dsdb-samldb-samldb_service_princip.patch @@ -0,0 +1,52 @@ +From fdd25972d26455c1b1254de3d1697786ae0678a3 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:18:10 +1300 +Subject: [PATCH 168/266] CVE-2020-25722 s4/dsdb/samldb: + samldb_service_principal_names_change checks values + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/fdd25972d26455c1b1254de3d1697786ae0678a3 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 391437d759d..80ca1e3afc0 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -4047,10 +4047,22 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) + unsigned int i, j; + int ret; + +- el = dsdb_get_single_valued_attr(ac->msg, "dNSHostName", +- ac->req->operation); +- el2 = dsdb_get_single_valued_attr(ac->msg, "sAMAccountName", +- ac->req->operation); ++ ret = dsdb_get_expected_new_values(ac, ++ ac->msg, ++ "dNSHostName", ++ &el, ++ ac->req->operation); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ ret = dsdb_get_expected_new_values(ac, ++ ac->msg, ++ "sAMAccountName", ++ &el2, ++ ac->req->operation); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } + if ((el == NULL) && (el2 == NULL)) { + /* we are not affected */ + return LDB_SUCCESS; +-- +2.23.0 + diff --git a/backport-0029-CVE-2020-25722-s4-dsdb-samldb-samldb_fsmo_role_owner.patch b/backport-0029-CVE-2020-25722-s4-dsdb-samldb-samldb_fsmo_role_owner.patch new file mode 100644 index 0000000..c486b6f --- /dev/null +++ b/backport-0029-CVE-2020-25722-s4-dsdb-samldb-samldb_fsmo_role_owner.patch @@ -0,0 +1,43 @@ +From 3f413fb5813c979c7bdcc15ec4b059dbd533f4d1 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:18:21 +1300 +Subject: [PATCH 169/266] CVE-2020-25722 s4/dsdb/samldb: + samldb_fsmo_role_owner_check checks values + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/3f413fb5813c979c7bdcc15ec4b059dbd533f4d1 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 80ca1e3afc0..d75277b3853 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -4302,9 +4302,15 @@ static int samldb_fsmo_role_owner_check(struct samldb_ctx *ac) + struct ldb_dn *res_dn; + struct ldb_result *res; + int ret; ++ ret = dsdb_get_expected_new_values(ac, ++ ac->msg, ++ "fSMORoleOwner", ++ &el, ++ ac->req->operation); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } + +- el = dsdb_get_single_valued_attr(ac->msg, "fSMORoleOwner", +- ac->req->operation); + if (el == NULL) { + /* we are not affected */ + return LDB_SUCCESS; +-- +2.23.0 + diff --git a/backport-0030-CVE-2020-25722-s4-dsdb-samldb-samldb_fsmo_role_owner.patch b/backport-0030-CVE-2020-25722-s4-dsdb-samldb-samldb_fsmo_role_owner.patch new file mode 100644 index 0000000..a9eefa4 --- /dev/null +++ b/backport-0030-CVE-2020-25722-s4-dsdb-samldb-samldb_fsmo_role_owner.patch @@ -0,0 +1,63 @@ +From 2a57c6e2f6a11698054afb2d9b173e5627eabb89 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Thu, 21 Oct 2021 12:52:07 +1300 +Subject: [PATCH 170/266] CVE-2020-25722 s4/dsdb/samldb: + samldb_fsmo_role_owner_check() wants one value + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/2a57c6e2f6a11698054afb2d9b173e5627eabb89 + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index d75277b3853..810365ca030 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -4315,6 +4315,9 @@ static int samldb_fsmo_role_owner_check(struct samldb_ctx *ac) + /* we are not affected */ + return LDB_SUCCESS; + } ++ if (el->num_values != 1) { ++ goto choose_error_code; ++ } + + /* Create a temporary message for fetching the "fSMORoleOwner" */ + tmp_msg = ldb_msg_new(ac->msg); +@@ -4331,11 +4334,7 @@ static int samldb_fsmo_role_owner_check(struct samldb_ctx *ac) + if (res_dn == NULL) { + ldb_set_errstring(ldb, + "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!"); +- if (ac->req->operation == LDB_ADD) { +- return LDB_ERR_CONSTRAINT_VIOLATION; +- } else { +- return LDB_ERR_UNWILLING_TO_PERFORM; +- } ++ goto choose_error_code; + } + + /* Fetched DN has to reference a "nTDSDSA" entry */ +@@ -4355,6 +4354,14 @@ static int samldb_fsmo_role_owner_check(struct samldb_ctx *ac) + talloc_free(res); + + return LDB_SUCCESS; ++ ++choose_error_code: ++ /* this is just how it is */ ++ if (ac->req->operation == LDB_ADD) { ++ return LDB_ERR_CONSTRAINT_VIOLATION; ++ } else { ++ return LDB_ERR_UNWILLING_TO_PERFORM; ++ } + } + + /* +-- +2.23.0 + diff --git a/backport-0031-CVE-2020-25722-s4-dsdb-pwd_hash-password_hash_bypass.patch b/backport-0031-CVE-2020-25722-s4-dsdb-pwd_hash-password_hash_bypass.patch new file mode 100644 index 0000000..d6b2462 --- /dev/null +++ b/backport-0031-CVE-2020-25722-s4-dsdb-pwd_hash-password_hash_bypass.patch @@ -0,0 +1,70 @@ +From b8424fad4234fa422436b5a704c017bd9d7e3913 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:19:42 +1300 +Subject: [PATCH 171/266] CVE-2020-25722 s4/dsdb/pwd_hash: password_hash_bypass + gets all values + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/b8424fad4234fa422436b5a704c017bd9d7e3913 + +--- + .../dsdb/samdb/ldb_modules/password_hash.c | 30 ++++++++++++------- + 1 file changed, 20 insertions(+), 10 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c +index bb437a3b982..5f033f9622b 100644 +--- a/source4/dsdb/samdb/ldb_modules/password_hash.c ++++ b/source4/dsdb/samdb/ldb_modules/password_hash.c +@@ -201,6 +201,7 @@ static int password_hash_bypass(struct ldb_module *module, struct ldb_request *r + struct ldb_message_element *nthe; + struct ldb_message_element *lmhe; + struct ldb_message_element *sce; ++ int ret; + + switch (request->operation) { + case LDB_ADD: +@@ -214,17 +215,26 @@ static int password_hash_bypass(struct ldb_module *module, struct ldb_request *r + } + + /* nobody must touch password histories and 'supplementalCredentials' */ +- nte = dsdb_get_single_valued_attr(msg, "unicodePwd", +- request->operation); +- lme = dsdb_get_single_valued_attr(msg, "dBCSPwd", +- request->operation); +- nthe = dsdb_get_single_valued_attr(msg, "ntPwdHistory", +- request->operation); +- lmhe = dsdb_get_single_valued_attr(msg, "lmPwdHistory", +- request->operation); +- sce = dsdb_get_single_valued_attr(msg, "supplementalCredentials", +- request->operation); + ++#define GET_VALUES(el, attr) do { \ ++ ret = dsdb_get_expected_new_values(request, \ ++ msg, \ ++ attr, \ ++ &el, \ ++ request->operation); \ ++ \ ++ if (ret != LDB_SUCCESS) { \ ++ return ret; \ ++ } \ ++} while(0) ++ ++ GET_VALUES(nte, "unicodePwd"); ++ GET_VALUES(lme, "dBCSPwd"); ++ GET_VALUES(nthe, "ntPwdHistory"); ++ GET_VALUES(lmhe, "lmPwdHistory"); ++ GET_VALUES(sce, "supplementalCredentials"); ++ ++#undef GET_VALUES + #define CHECK_HASH_ELEMENT(e, min, max) do {\ + if (e && e->num_values) { \ + unsigned int _count; \ +-- +2.23.0 + diff --git a/backport-0032-CVE-2020-25722-s4-dsdb-pwd_hash-rework-pwdLastSet-by.patch b/backport-0032-CVE-2020-25722-s4-dsdb-pwd_hash-rework-pwdLastSet-by.patch new file mode 100644 index 0000000..a86b86c --- /dev/null +++ b/backport-0032-CVE-2020-25722-s4-dsdb-pwd_hash-rework-pwdLastSet-by.patch @@ -0,0 +1,72 @@ +From bed2ea1d378f31e3d071a7a5d4c80cd9cc1c9894 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 20 Oct 2021 17:20:54 +1300 +Subject: [PATCH 172/266] CVE-2020-25722 s4/dsdb/pwd_hash: rework pwdLastSet + bypass + +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(). + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14876 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Conflict:NA +Reference:https://gitlab.com/samba-team/samba/-/commit/bed2ea1d378f31e3d071a7a5d4c80cd9cc1c9894 + +--- + .../dsdb/samdb/ldb_modules/password_hash.c | 28 ++++++++++++------- + 1 file changed, 18 insertions(+), 10 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c +index 5f033f9622b..9fa2e36ba90 100644 +--- a/source4/dsdb/samdb/ldb_modules/password_hash.c ++++ b/source4/dsdb/samdb/ldb_modules/password_hash.c +@@ -2227,23 +2227,31 @@ static int setup_last_set_field(struct setup_password_fields_io *io) + } + + if (io->ac->pwd_last_set_bypass) { +- struct ldb_message_element *el1 = NULL; +- struct ldb_message_element *el2 = NULL; +- ++ struct ldb_message_element *el = NULL; ++ size_t i; ++ size_t count = 0; ++ /* ++ * This is a message from pdb_samba_dsdb_replace_by_sam() ++ * ++ * We want to ensure there is only one pwdLastSet element, and ++ * it isn't deleting. ++ */ + if (msg == NULL) { + return LDB_ERR_CONSTRAINT_VIOLATION; + } + +- el1 = dsdb_get_single_valued_attr(msg, "pwdLastSet", +- io->ac->req->operation); +- if (el1 == NULL) { +- return LDB_ERR_CONSTRAINT_VIOLATION; ++ for (i = 0; i < msg->num_elements; i++) { ++ if (ldb_attr_cmp(msg->elements[i].name, ++ "pwdLastSet") == 0) { ++ count++; ++ el = &msg->elements[i]; ++ } + } +- el2 = ldb_msg_find_element(msg, "pwdLastSet"); +- if (el2 == NULL) { ++ if (count != 1) { + return LDB_ERR_CONSTRAINT_VIOLATION; + } +- if (el1 != el2) { ++ ++ if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) { + return LDB_ERR_CONSTRAINT_VIOLATION; + } + +-- +2.23.0 + diff --git a/backport-0033-CVE-2020-25722-Ensure-the-structural-objectclass-can.patch b/backport-0033-CVE-2020-25722-Ensure-the-structural-objectclass-can.patch new file mode 100644 index 0000000..3c07a8f --- /dev/null +++ b/backport-0033-CVE-2020-25722-Ensure-the-structural-objectclass-can.patch @@ -0,0 +1,90 @@ +From 8513fe9e30a65060fc8908f42756e44550176d7f Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Wed, 20 Oct 2021 11:36:58 +1300 +Subject: [PATCH 228/266] CVE-2020-25722 Ensure the structural objectclass + cannot be changed + +If the structural objectclass is allowed to change, then the restrictions +locking an object to remaining a user or computer will not be enforcable. + +Likewise other LDAP inheritance rules, which allow only certain +child objects can be bypassed, which can in turn allow creation of +(unprivileged) users where only DNS objects were expected. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14753 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14889 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/8513fe9e30a65060fc8908f42756e44550176d7f + +--- + source4/dsdb/samdb/ldb_modules/objectclass.c | 36 +++++++++++++++++++ + 1 files changed, 36 insertions(+), 0 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c +index 36ab76e19fc..d8feff0262c 100644 +--- a/source4/dsdb/samdb/ldb_modules/objectclass.c ++++ b/source4/dsdb/samdb/ldb_modules/objectclass.c +@@ -811,6 +811,7 @@ static int objectclass_do_mod(struct oc_context *ac) + struct ldb_message_element *oc_el_entry, *oc_el_change; + struct ldb_val *vals; + struct ldb_message *msg; ++ const struct dsdb_class *current_structural_objectclass; + const struct dsdb_class *objectclass; + unsigned int i, j, k; + bool found; +@@ -830,6 +831,22 @@ static int objectclass_do_mod(struct oc_context *ac) + return ldb_operr(ldb); + } + ++ /* ++ * Get the current new top-most structural object class ++ * ++ * We must not allow this to change ++ */ ++ ++ current_structural_objectclass ++ = dsdb_get_last_structural_class(ac->schema, ++ oc_el_entry); ++ if (current_structural_objectclass == NULL) { ++ ldb_asprintf_errstring(ldb, ++ "objectclass: cannot find current structural objectclass on %s!", ++ ldb_dn_get_linearized(ac->search_res->message->dn)); ++ return LDB_ERR_OBJECT_CLASS_VIOLATION; ++ } ++ + /* use a new message structure */ + msg = ldb_msg_new(ac); + if (msg == NULL) { +@@ -939,6 +956,25 @@ static int objectclass_do_mod(struct oc_context *ac) + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + ++ /* ++ * Has (so far, we re-check for each and every ++ * "objectclass" in the message) the structural ++ * objectclass changed? ++ */ ++ ++ if (objectclass != current_structural_objectclass) { ++ const char *dn ++ = ldb_dn_get_linearized(ac->search_res->message->dn); ++ ldb_asprintf_errstring(ldb, ++ "objectclass: not permitted " ++ "to change the structural " ++ "objectClass on %s [%s] => [%s]!", ++ dn, ++ current_structural_objectclass->lDAPDisplayName, ++ objectclass->lDAPDisplayName); ++ return LDB_ERR_OBJECT_CLASS_VIOLATION; ++ } ++ + /* Check for unrelated objectclasses */ + ret = check_unrelated_objectclasses(ac->module, ac->schema, + objectclass, +-- +2.23.0 + diff --git a/backport-0034-CVE-2020-25722-kdc-Do-not-honour-a-request-for-a-3-p.patch b/backport-0034-CVE-2020-25722-kdc-Do-not-honour-a-request-for-a-3-p.patch new file mode 100644 index 0000000..317d3b1 --- /dev/null +++ b/backport-0034-CVE-2020-25722-kdc-Do-not-honour-a-request-for-a-3-p.patch @@ -0,0 +1,55 @@ +From b6ab45da636118da83443516eee7d314f19b4e22 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 4 Oct 2021 15:18:34 +1300 +Subject: [PATCH 235/266] CVE-2020-25722 kdc: Do not honour a request for a + 3-part SPN (ending in our domain/realm) unless a DC + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14776 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/b6ab45da636118da83443516eee7d314f19b4e22 + +--- + source4/kdc/db-glue.c | 23 +++++++++++++++++++++++ + 1 files changed, 23 insertions(+), 0 deletions(-) + +diff --git a/source4/kdc/db-glue.c b/source4/kdc/db-glue.c +index d55bf1663d4..0f19e8d1c93 100644 +--- a/source4/kdc/db-glue.c ++++ b/source4/kdc/db-glue.c +@@ -968,6 +968,29 @@ static krb5_error_code samba_kdc_message2entry(krb5_context context, + entry_ex->entry.flags.server = 0; + } + } ++ ++ /* ++ * We restrict a 3-part SPN ending in my domain/realm to full ++ * domain controllers. ++ * ++ * This avoids any cases where (eg) a demoted DC still has ++ * these more restricted SPNs. ++ */ ++ if (krb5_princ_size(context, principal) > 2) { ++ char *third_part ++ = smb_krb5_principal_get_comp_string(mem_ctx, ++ context, ++ principal, ++ 2); ++ bool is_our_realm = ++ lpcfg_is_my_domain_or_realm(lp_ctx, ++ third_part); ++ bool is_dc = userAccountControl & ++ (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT); ++ if (is_our_realm && !is_dc) { ++ entry_ex->entry.flags.server = 0; ++ } ++ } + /* + * To give the correct type of error to the client, we must + * not just return the entry without .server set, we must +-- +2.23.0 + diff --git a/backport-0035-CVE-2020-25722-selftest-Ensure-check-for-duplicate-s.patch b/backport-0035-CVE-2020-25722-selftest-Ensure-check-for-duplicate-s.patch new file mode 100644 index 0000000..93e2319 --- /dev/null +++ b/backport-0035-CVE-2020-25722-selftest-Ensure-check-for-duplicate-s.patch @@ -0,0 +1,67 @@ +From 3ed16e74292058d059ae951317ca8d3b7f1f5d0e Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Tue, 2 Nov 2021 21:00:00 +1300 +Subject: [PATCH 244/266] CVE-2020-25722 selftest: Ensure check for duplicate + servicePrincipalNames is not bypassed for an add operation + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14564 + +If one of the objectClass checks passed, samldb_add() could return +through one of the samldb_fill_*() functions and skip the +servicePrincipalName uniqueness checking. + +Signed-off-by: Joseph Sutton + +Conflict:remove test +Reference:https://gitlab.com/samba-team/samba/-/commit/3ed16e74292058d059ae951317ca8d3b7f1f5d0e + +--- + source4/dsdb/samdb/ldb_modules/samldb.c | 25 ++++++++++++------------- + 1 files changed, 12 insertions(+), 13 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c +index 810365ca030..f0227411ccd 100644 +--- a/source4/dsdb/samdb/ldb_modules/samldb.c ++++ b/source4/dsdb/samdb/ldb_modules/samldb.c +@@ -4838,6 +4838,18 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req) + } + } + ++ el = ldb_msg_find_element(ac->msg, "servicePrincipalName"); ++ if ((el != NULL)) { ++ /* ++ * We need to check whether the SPN collides with an existing ++ * one (anywhere) including via aliases. ++ */ ++ ret = samldb_spn_uniqueness_check(ac, el); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ } ++ + if (samdb_find_attribute(ldb, ac->msg, + "objectclass", "user") != NULL) { + ac->type = SAMLDB_TYPE_USER; +@@ -4936,19 +4948,6 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req) + return samldb_fill_object(ac); + } + +- +- el = ldb_msg_find_element(ac->msg, "servicePrincipalName"); +- if ((el != NULL)) { +- /* +- * We need to check whether the SPN collides with an existing +- * one (anywhere) including via aliases. +- */ +- ret = samldb_spn_uniqueness_check(ac, el); +- if (ret != LDB_SUCCESS) { +- return ret; +- } +- } +- + if (samdb_find_attribute(ldb, ac->msg, + "objectclass", "subnet") != NULL) { + ret = samldb_verify_subnet(ac, ac->msg->dn); +-- +2.23.0 + diff --git a/backport-winbind-Fix-CID-1456624-Uninitialized-scalar-variabl.patch b/backport-winbind-Fix-CID-1456624-Uninitialized-scalar-variabl.patch new file mode 100644 index 0000000..2e368ee --- /dev/null +++ b/backport-winbind-Fix-CID-1456624-Uninitialized-scalar-variabl.patch @@ -0,0 +1,33 @@ +From 33d4d482718fca10030b5a569f17cb1a2637fc8a Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Fri, 3 Jan 2020 12:42:03 +0100 +Subject: [PATCH 2619/6935] winbind: Fix CID 1456624 Uninitialized scalar + variable + +Coverity does not get that for (rc!=0) gnutls_error_to_ntstatus() +never returns NT_STATUS_OK + +Signed-off-by: Volker Lendecke +Reviewed-by: Gary Lockyer +Conflict: NA +Reference: https://git.samba.org/?p=samba.git;a=patch;h=33d4d482718fca10030b5a569f17cb1a2637fc8a +--- + source3/winbindd/winbindd_pam.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c +index 1552eb3ce52..a1c6efe6662 100644 +--- a/source3/winbindd/winbindd_pam.c ++++ b/source3/winbindd/winbindd_pam.c +@@ -1738,7 +1738,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon( + NTSTATUS result; + uint8_t authoritative = 0; + uint32_t flags = 0; +- uint16_t validation_level; ++ uint16_t validation_level = 0; + union netr_Validation *validation = NULL; + struct netr_SamBaseInfo *base_info = NULL; + bool ok; +-- +2.23.0 + diff --git a/samba.spec b/samba.spec index 7429e10..617682f 100644 --- a/samba.spec +++ b/samba.spec @@ -49,7 +49,7 @@ Name: samba Version: 4.11.12 -Release: 5 +Release: 6 Summary: A suite for Linux to interoperate with Windows License: GPLv3+ and LGPLv3+ @@ -80,6 +80,95 @@ Patch10: CVE-2020-27840.patch Patch11: CVE-2021-20254.patch Patch12: backport-CVE-2021-3671.patch +Patch6062: backport-winbind-Fix-CID-1456624-Uninitialized-scalar-variabl.patch + +Patch6157: backport-0001-CVE-2020-25717-winbindd-add-generic-wb_parent_idmap_.patch +Patch6158: backport-0002-CVE-2020-25717-wb_xids2sids-make-use-of-the-new-wb_p.patch +Patch6159: backport-0003-CVE-2020-25717-wb_sids2xids-call-wb_parent_idmap_set.patch +Patch6160: backport-0004-CVE-2020-25717-winbindd-defer-the-setup_child-from-i.patch +Patch6161: backport-0005-CVE-2020-25717-wb_sids2xids-build-state-idmap_doms-b.patch +Patch6162: backport-0006-CVE-2020-25717-winbindd-allow-idmap-backends-to-mark.patch +Patch6163: backport-0007-CVE-2020-25717-s3-idmap_hash-reliable-return-ID_TYPE.patch +Patch6164: backport-0008-CVE-2020-25717-winbindd-call-wb_parent_idmap_setup_s.patch +Patch6165: backport-0009-CVE-2020-25717-winbind-ensure-wb_parent_idmap_setup_.patch +Patch6166: backport-0010-CVE-2020-25717-auth_sam-use-pdb_get_domain_info-to-l.patch +Patch6167: backport-0011-CVE-2020-25717-s3-winbindd-make-sure-we-default-to-r.patch +Patch6168: backport-0012-CVE-2020-25717-s4-auth-ntlm-make-sure-auth_check_pas.patch +Patch6169: backport-0013-CVE-2020-25717-loadparm-Add-new-parameter-min-domain.patch +Patch6170: backport-0014-CVE-2020-25717-s3-auth-Check-minimum-domain-uid.patch +Patch6171: backport-0015-CVE-2020-25717-s3-auth-we-should-not-try-to-autocrea.patch +Patch6172: backport-0016-CVE-2020-25717-s3-auth-no-longer-let-check_account-a.patch +Patch6173: backport-0017-CVE-2020-25717-s3-auth-remove-fallbacks-in-smb_getpw.patch +Patch6174: backport-0018-CVE-2020-25717-s3-auth-don-t-let-create_local_token-.patch +Patch6175: backport-0019-CVE-2020-25719-CVE-2020-25717-auth-gensec-always-req.patch +Patch6176: backport-0020-CVE-2020-25717-s3-ntlm_auth-fix-memory-leaks-in-ntlm.patch +Patch6177: backport-0021-CVE-2020-25717-s3-ntlm_auth-let-ntlm_auth_generate_s.patch +Patch6178: backport-0022-use-set_current_user_info-in-auth3_generate_session_info_p.patch +Patch6179: backport-0023-CVE-2020-25717-s3-auth-let-auth3_generate_session_in.patch +Patch6180: backport-0024-CVE-2020-25717-s3-auth-let-auth3_generate_session_in.patch +Patch6181: backport-0000-CVE-2020-25721-krb5pac-Add-new-buffers-for-samAccoun.patch +Patch6182: backport-0000-CVE-2020-25719-mit-samba-Make-ks_get_principal-inter.patch +Patch6183: backport-0001-CVE-2020-25719-mit-samba-Add-ks_free_principal.patch +Patch6184: backport-0002-CVE-2020-25719-sign-and-verify-PAC-with-ticket-principal.patch +Patch6185: backport-0003-CVE-2020-25719-mit-samba-If-we-use-client_princ-alwa.patch +Patch6186: backport-0004-CVE-2020-25719-mit-samba-Add-mit_samba_princ_needs_p.patch +Patch6187: backport-0005-CVE-2020-25719-mit-samba-Rework-PAC-handling-in-kdb_.patch +Patch6188: backport-0001-CVE-2020-25721-auth-Fill-in-the-new-HAS_SAM_NAME_AND.patch +Patch6189: backport-0000-CVE-2016-2124-s4-libcli-sesssetup-don-t-fallback-to-.patch +Patch6190: backport-0001-CVE-2016-2124-s3-libsmb-don-t-fallback-to-non-spnego.patch +Patch6191: backport-0001-CVE-2020-25722-dsdb-Move-krbtgt-password-setup-after.patch +Patch6192: backport-0002-CVE-2020-25722-dsdb-Restrict-the-setting-of-privileg.patch +Patch6193: backport-0003-CVE-2020-25722-dsdb-objectclass-computer-becomes-UF_.patch +Patch6194: backport-0004-CVE-2020-25722-dsdb-Prohibit-mismatch-between-UF_-ac.patch +Patch6195: backport-0005-CVE-2020-25722-dsdb-Add-restrictions-on-computer-acc.patch +Patch6196: backport-0006-CVE-2020-25722-samdb-Fill-in-isCriticalSystemObject-.patch +Patch6197: backport-0007-CVE-2020-25722-s4-acl-Make-sure-Control-Access-Right.patch +Patch6198: backport-0008-CVE-2020-25722-Check-all-elements-in-acl_check_spn-n.patch +Patch6199: backport-0009-CVE-2020-25722-Check-for-all-errors-from-acl_check_e.patch +Patch6200: backport-0010-CVE-2020-25722-s4-dsdb-cracknames-always-free-tmp_ct.patch +Patch6201: backport-0011-CVE-2020-25722-s4-provision-add-host-SPNs-at-the-sta.patch +Patch6202: backport-0012-CVE-2020-25722-s4-dsdb-samldb-add-samldb_get_single_.patch +Patch6203: backport-0013-CVE-2020-25722-s4-dsdb-samldb-check-for-clashes-in-U.patch +Patch6204: backport-0014-CVE-2020-25722-s4-dsdb-samldb-check-sAMAccountName-f.patch +Patch6205: backport-0015-CVE-2020-25722-s4-dsdb-samldb-check-for-SPN-uniquene.patch +Patch6206: backport-0016-CVE-2020-25722-s4-dsdb-samldb-reject-SPN-with-too-fe.patch +Patch6207: backport-0017-CVE-2020-25722-s4-dsdb-modules-add-dsdb_get_expected.patch +Patch6208: backport-0018-CVE-2020-25722-s4-dsdb-samldb-samldb_get_single_valu.patch +Patch6209: backport-0019-CVE-2020-25722-s4-dsdb-samldb-samldb_sam_accountname.patch +Patch6210: backport-0020-CVE-2020-25722-s4-dsdb-samldb-samldb_schema_add_hand.patch +Patch6211: backport-0021-CVE-2020-25722-s4-dsdb-samldb-samldb_schema_add_hand.patch +Patch6212: backport-0022-CVE-2020-25722-s4-dsdb-samldb-samldb_prim_group_chan.patch +Patch6213: backport-0023-CVE-2020-25722-s4-dsdb-samldb-samldb_user_account_co.patch +Patch6214: backport-0024-CVE-2020-25722-s4-dsdb-samldb-_user_account_control_.patch +Patch6215: backport-0025-CVE-2020-25722-s4-dsdb-samldb-samldb_pwd_last_set_ch.patch +Patch6216: backport-0026-CVE-2020-25722-s4-dsdb-samldb-samldb_lockout_time-ch.patch +Patch6217: backport-0027-CVE-2020-25722-s4-dsdb-samldb-samldb_group_type_chan.patch +Patch6218: backport-0028-CVE-2020-25722-s4-dsdb-samldb-samldb_service_princip.patch +Patch6219: backport-0029-CVE-2020-25722-s4-dsdb-samldb-samldb_fsmo_role_owner.patch +Patch6220: backport-0030-CVE-2020-25722-s4-dsdb-samldb-samldb_fsmo_role_owner.patch +Patch6221: backport-0031-CVE-2020-25722-s4-dsdb-pwd_hash-password_hash_bypass.patch +Patch6222: backport-0032-CVE-2020-25722-s4-dsdb-pwd_hash-rework-pwdLastSet-by.patch +Patch6223: backport-0033-CVE-2020-25722-Ensure-the-structural-objectclass-can.patch +Patch6224: backport-0034-CVE-2020-25722-kdc-Do-not-honour-a-request-for-a-3-p.patch +Patch6225: backport-0035-CVE-2020-25722-selftest-Ensure-check-for-duplicate-s.patch +Patch6226: backport-0000-CVE-2020-25718-simplify.patch +Patch6227: backport-0001-CVE-2020-25718-trailing-chunk-must-match.patch +Patch6228: backport-0002-CVE-2020-25718-fix-ldb_comparison_fold.patch +Patch6229: backport-0003-CVE-2020-25718-catch-potential-overflow-error.patch +Patch6230: backport-0005-CVE-2020-25718-Fix-Message-items-for-a.patch +Patch6231: backport-0006-CVE-2020-25718-Change-sid-list.patch +Patch6232: backport-0007-CVE-2020-25718-Obtain-the-user.patch +Patch6233: backport-0008-CVE-2020-25718-Put-msDS-KrbTgtLinkBL-put-RODC-reveal-never-reveal.patch +Patch6234: backport-0009-CVE-2020-25718-Put-msDS-KrbTgtLinkBL.patch +Patch6235: backport-0010-CVE-2020-25718-Confirm-that-the-RODC.patch +Patch6236: backport-0000-CVE-2021-3738-s4-torture-drsuapi-maintain-priv-admin.patch +Patch6237: backport-0001-CVE-2021-3738-s4-rpc_server-common-provide-assoc_gro.patch +Patch6238: backport-0002-CVE-2021-3738-s4-rpc_server-drsuapi-make-use-of-asso.patch +Patch6239: backport-0003-CVE-2021-3738-s4-rpc_server-dnsserver-make-use-of-dc.patch +Patch6240: backport-0004-CVE-2021-3738-s4-rpc_server-lsa-make-use-of-dcesrv_s.patch +Patch6241: backport-0005-CVE-2021-3738-s4-rpc_server-netlogon-make-use-of-dce.patch +Patch6242: backport-0006-CVE-2021-3738-s4-rpc_server-samr-make-use-of-dcesrv_.patch + BuildRequires: avahi-devel cups-devel dbus-devel docbook-style-xsl e2fsprogs-devel gawk gnupg2 gnutls-devel >= 3.4.7 gpgme-devel BuildRequires: jansson-devel krb5-devel >= %{required_mit_krb5} libacl-devel libaio-devel libarchive-devel libattr-devel BuildRequires: libcap-devel libcmocka-devel libnsl2-devel libtirpc-devel libuuid-devel libxslt lmdb ncurses-devel openldap-devel @@ -3065,6 +3154,12 @@ fi %{_mandir}/man* %changelog +* Thu Dec 09 2021 xihaochen - 4.11.12-6 +- Type:cves +- ID:CVE-2020-25717,CVE-2020-25718,CVE-2020-25719,CVE-2020-25721,CVE-2020-25722,CVE-2016-2124,CVE-2021-3738 +- SUG:NA +- DESC:fix CVE-2020-25717,CVE-2020-25718,CVE-2020-25719,CVE-2020-25721,CVE-2020-25722,CVE-2016-2124,CVE-2021-3738 + * Mon Oct 25 2021 gaihuiying - 4.11.12-5 - Type:cves - ID:CVE-2021-3671 -- Gitee