diff --git a/0001-CVE-2020-14383.patch b/0001-CVE-2020-14383.patch deleted file mode 100644 index 61395bad33ecb91eb81502cd3baddfb192849bc1..0000000000000000000000000000000000000000 --- a/0001-CVE-2020-14383.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 2632e8ebae826a7305fe7d3948ee28b77d2ffbc0 Mon Sep 17 00:00:00 2001 -From: Douglas Bagnall -Date: Fri, 21 Aug 2020 17:10:22 +1200 -Subject: [PATCH] CVE-2020-14383: s4/dns: Ensure variable initialization with - NULL. -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -Based on patches from Francis Brosnan Blázquez -and Jeremy Allison - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14472 -BUG: https://bugzilla.samba.org/show_bug.cgi?id=12795 - -Signed-off-by: Douglas Bagnall -Reviewed-by: Jeremy Allison -(based on commit 7afe449e7201be92bed8e53cbb37b74af720ef4e) ---- - .../rpc_server/dnsserver/dcerpc_dnsserver.c | 24 ++++++++++--------- - 1 file changed, 13 insertions(+), 11 deletions(-) - -diff --git a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c -index b6389f2328a..ec610168266 100644 ---- a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c -+++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c -@@ -1759,15 +1759,17 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, - TALLOC_CTX *tmp_ctx; - char *name; - const char * const attrs[] = { "name", "dnsRecord", NULL }; -- struct ldb_result *res; -- struct DNS_RPC_RECORDS_ARRAY *recs; -+ struct ldb_result *res = NULL; -+ struct DNS_RPC_RECORDS_ARRAY *recs = NULL; - char **add_names = NULL; -- char *rname; -+ char *rname = NULL; - const char *preference_name = NULL; - int add_count = 0; - int i, ret, len; - WERROR status; -- struct dns_tree *tree, *base, *node; -+ struct dns_tree *tree = NULL; -+ struct dns_tree *base = NULL; -+ struct dns_tree *node = NULL; - - tmp_ctx = talloc_new(mem_ctx); - W_ERROR_HAVE_NO_MEMORY(tmp_ctx); -@@ -1850,9 +1852,9 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, - } - } - -- talloc_free(res); -- talloc_free(tree); -- talloc_free(name); -+ TALLOC_FREE(res); -+ TALLOC_FREE(tree); -+ TALLOC_FREE(name); - - /* Add any additional records */ - if (select_flag & DNS_RPC_VIEW_ADDITIONAL_DATA) { -@@ -1870,14 +1872,14 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, - LDB_SCOPE_ONELEVEL, attrs, - "(&(objectClass=dnsNode)(name=%s)(!(dNSTombstoned=TRUE)))", - encoded_name); -- talloc_free(name); -+ TALLOC_FREE(name); - if (ret != LDB_SUCCESS) { - continue; - } - if (res->count == 1) { - break; - } else { -- talloc_free(res); -+ TALLOC_FREE(res); - continue; - } - } -@@ -1892,8 +1894,8 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, - select_flag, rname, - res->msgs[0], 0, recs, - NULL, NULL); -- talloc_free(rname); -- talloc_free(res); -+ TALLOC_FREE(rname); -+ TALLOC_FREE(res); - if (!W_ERROR_IS_OK(status)) { - talloc_free(tmp_ctx); - return status; --- -2.29.2 diff --git a/0002-CVE-2020-14383.patch b/0002-CVE-2020-14383.patch deleted file mode 100644 index f841646d89627cb17c7b21b876922f94912472f1..0000000000000000000000000000000000000000 --- a/0002-CVE-2020-14383.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 8e09649351e9e8143b4bd0b76bcbd2cfb4d2f281 Mon Sep 17 00:00:00 2001 -From: Douglas Bagnall -Date: Fri, 21 Aug 2020 17:23:17 +1200 -Subject: [PATCH] CVE-2020-14383: s4/dns: do not crash when additional data not - found -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -Found by Francis Brosnan Blázquez . - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14472 -BUG: https://bugzilla.samba.org/show_bug.cgi?id=12795 - -Signed-off-by: Douglas Bagnall -Reviewed-by: Jeremy Allison - -Autobuild-User(master): Douglas Bagnall -Autobuild-Date(master): Mon Aug 24 00:21:41 UTC 2020 on sn-devel-184 - -(based on commit df98e7db04c901259dd089e20cd557bdbdeaf379) ---- - source4/rpc_server/dnsserver/dcerpc_dnsserver.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c -index ec610168266..88efc01f154 100644 ---- a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c -+++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c -@@ -1859,8 +1859,8 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, - /* Add any additional records */ - if (select_flag & DNS_RPC_VIEW_ADDITIONAL_DATA) { - for (i=0; izones; z2; z2 = z2->next) { - char *encoded_name; -@@ -1877,6 +1877,7 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, - continue; - } - if (res->count == 1) { -+ msg = res->msgs[0]; - break; - } else { - TALLOC_FREE(res); -@@ -1892,7 +1893,7 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, - } - status = dns_fill_records_array(tmp_ctx, NULL, DNS_TYPE_A, - select_flag, rname, -- res->msgs[0], 0, recs, -+ msg, 0, recs, - NULL, NULL); - TALLOC_FREE(rname); - TALLOC_FREE(res); --- -2.29.2 diff --git a/CVE-2020-14318.patch b/CVE-2020-14318.patch deleted file mode 100644 index 2947bf222dd79ba4ac2e36e5594bc35fdbfda220..0000000000000000000000000000000000000000 --- a/CVE-2020-14318.patch +++ /dev/null @@ -1,159 +0,0 @@ -From 5dd4c789c13035b805fdd2c3a9c38721657b05b3 Mon Sep 17 00:00:00 2001 -From: Jeremy Allison -Date: Tue, 7 Jul 2020 18:25:23 -0700 -Subject: [PATCH] s3: smbd: Ensure change notifies can't get set unless the - directory handle is open for SEC_DIR_LIST. - -Remove knownfail entry. - -CVE-2020-14318 - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14434 - -Signed-off-by: Jeremy Allison ---- - source3/smbd/notify.c | 8 ++++++++ - - 1 files changed, 8 insertions(+) - delete mode 100644 selftest/knownfail.d/smb2_notify_handle_permissions - -diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c -index eb6317b7e8a..5f18b5cf794 100644 ---- a/source3/smbd/notify.c -+++ b/source3/smbd/notify.c -@@ -289,6 +289,14 @@ NTSTATUS change_notify_create(struct files_struct *fsp, - char fullpath[len+1]; - NTSTATUS status = NT_STATUS_NOT_IMPLEMENTED; - -+ /* -+ * Setting a changenotify needs READ/LIST access -+ * on the directory handle. -+ */ -+ if (!(fsp->access_mask & SEC_DIR_LIST)) { -+ return NT_STATUS_ACCESS_DENIED; -+ } -+ - if (fsp->notify != NULL) { - DEBUG(1, ("change_notify_create: fsp->notify != NULL, " - "fname = %s\n", fsp->fsp_name->base_name)); --- -2.29.2 - - -From 22528b76ed6eb6251fdf01875aaa955480e7663d Mon Sep 17 00:00:00 2001 -From: Jeremy Allison -Date: Fri, 10 Jul 2020 15:09:33 -0700 -Subject: [PATCH] s4: torture: Add smb2.notify.handle-permissions test. - -Add knownfail entry. - -CVE-2020-14318 - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14434 - -Signed-off-by: Jeremy Allison ---- - source4/torture/smb2/notify.c | 80 +++++++++++++++++++ - 1 files changed, 80 insertions(+) - create mode 100644 selftest/knownfail.d/smb2_notify_handle_permissions - -diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c -index b65c116b75e..6081d394c6e 100644 ---- a/source4/torture/smb2/notify.c -+++ b/source4/torture/smb2/notify.c -@@ -2649,6 +2649,83 @@ done: - return ok; - } - -+/* -+ Test asking for a change notify on a handle without permissions. -+*/ -+ -+#define BASEDIR_HPERM BASEDIR "_HPERM" -+ -+static bool torture_smb2_notify_handle_permissions( -+ struct torture_context *torture, -+ struct smb2_tree *tree) -+{ -+ bool ret = true; -+ NTSTATUS status; -+ union smb_notify notify; -+ union smb_open io; -+ struct smb2_handle h1 = {{0}}; -+ struct smb2_request *req; -+ -+ smb2_deltree(tree, BASEDIR_HPERM); -+ smb2_util_rmdir(tree, BASEDIR_HPERM); -+ -+ torture_comment(torture, -+ "TESTING CHANGE NOTIFY " -+ "ON A HANDLE WITHOUT PERMISSIONS\n"); -+ -+ /* -+ get a handle on the directory -+ */ -+ ZERO_STRUCT(io.smb2); -+ io.generic.level = RAW_OPEN_SMB2; -+ io.smb2.in.create_flags = 0; -+ io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE; -+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; -+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; -+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | -+ NTCREATEX_SHARE_ACCESS_WRITE; -+ io.smb2.in.alloc_size = 0; -+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; -+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; -+ io.smb2.in.security_flags = 0; -+ io.smb2.in.fname = BASEDIR_HPERM; -+ -+ status = smb2_create(tree, torture, &io.smb2); -+ CHECK_STATUS(status, NT_STATUS_OK); -+ h1 = io.smb2.out.file.handle; -+ -+ /* ask for a change notify, -+ on file or directory name changes */ -+ ZERO_STRUCT(notify.smb2); -+ notify.smb2.level = RAW_NOTIFY_SMB2; -+ notify.smb2.in.buffer_size = 1000; -+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME; -+ notify.smb2.in.file.handle = h1; -+ notify.smb2.in.recursive = true; -+ -+ req = smb2_notify_send(tree, ¬ify.smb2); -+ torture_assert_goto(torture, -+ req != NULL, -+ ret, -+ done, -+ "smb2_notify_send failed\n"); -+ -+ /* -+ * Cancel it, we don't really want to wait. -+ */ -+ smb2_cancel(req); -+ status = smb2_notify_recv(req, torture, ¬ify.smb2); -+ /* Handle h1 doesn't have permissions for ChangeNotify. */ -+ CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); -+ -+done: -+ if (!smb2_util_handle_empty(h1)) { -+ smb2_util_close(tree, h1); -+ } -+ smb2_deltree(tree, BASEDIR_HPERM); -+ return ret; -+} -+ - /* - basic testing of SMB2 change notify - */ -@@ -2682,6 +2759,9 @@ struct torture_suite *torture_smb2_notify_init(TALLOC_CTX *ctx) - torture_smb2_notify_rmdir3); - torture_suite_add_2smb2_test(suite, "rmdir4", - torture_smb2_notify_rmdir4); -+ torture_suite_add_1smb2_test(suite, -+ "handle-permissions", -+ torture_smb2_notify_handle_permissions); - - suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests"); - --- -2.29.2 diff --git a/CVE-2020-14323.patch b/CVE-2020-14323.patch deleted file mode 100644 index 94e03518b29311fba60576cc8549d5c54b0fb816..0000000000000000000000000000000000000000 --- a/CVE-2020-14323.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 595dd9fc4162dd70ad937db8669a0fddbbba9584 Mon Sep 17 00:00:00 2001 -From: Volker Lendecke -Date: Thu, 9 Jul 2020 21:49:25 +0200 -Subject: [PATCH] CVE-2020-14323 winbind: Fix invalid lookupsids DoS - -A lookupsids request without extra_data will lead to "state->domain==NULL", -which makes winbindd_lookupsids_recv trying to dereference it. - -Reported by Bas Alberts of the GitHub Security Lab Team as GHSL-2020-134 - -Bug: https://bugzilla.samba.org/show_bug.cgi?id=14436 -Signed-off-by: Volker Lendecke ---- - source3/winbindd/winbindd_lookupsids.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/source3/winbindd/winbindd_lookupsids.c b/source3/winbindd/winbindd_lookupsids.c -index d28b5fa9f01..a289fd86f0f 100644 ---- a/source3/winbindd/winbindd_lookupsids.c -+++ b/source3/winbindd/winbindd_lookupsids.c -@@ -47,7 +47,7 @@ struct tevent_req *winbindd_lookupsids_send(TALLOC_CTX *mem_ctx, - DEBUG(3, ("lookupsids\n")); - - if (request->extra_len == 0) { -- tevent_req_done(req); -+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); - return tevent_req_post(req, ev); - } - if (request->extra_data.data[request->extra_len-1] != '\0') { --- -2.29.2 - -From 0b259a48a70bde4dfd482e0720e593ae5a9c414a Mon Sep 17 00:00:00 2001 -From: Volker Lendecke -Date: Thu, 9 Jul 2020 21:48:57 +0200 -Subject: [PATCH] CVE-2020-14323 torture4: Add a simple test for invalid - lookup_sids winbind call - -We can't add this test before the fix, add it to knownfail and have the fix -remove the knownfail entry again. As this crashes winbind, many tests after -this one will fail. - -Reported by Bas Alberts of the GitHub Security Lab Team as GHSL-2020-134 - -Bug: https://bugzilla.samba.org/show_bug.cgi?id=14436 -Signed-off-by: Volker Lendecke ---- - source4/torture/winbind/struct_based.c | 27 ++++++++++++++++++++++++++ - 1 file changed, 27 insertions(+) - -diff --git a/source4/torture/winbind/struct_based.c b/source4/torture/winbind/struct_based.c -index 9745b621ca9..71f248c0d61 100644 ---- a/source4/torture/winbind/struct_based.c -+++ b/source4/torture/winbind/struct_based.c -@@ -1110,6 +1110,29 @@ static bool torture_winbind_struct_lookup_name_sid(struct torture_context *tortu - return true; - } - -+static bool torture_winbind_struct_lookup_sids_invalid( -+ struct torture_context *torture) -+{ -+ struct winbindd_request req = {0}; -+ struct winbindd_response rep = {0}; -+ bool strict = torture_setting_bool(torture, "strict mode", false); -+ bool ok; -+ -+ torture_comment(torture, -+ "Running WINBINDD_LOOKUP_SIDS (struct based)\n"); -+ -+ ok = true; -+ DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPSIDS, &req, &rep, -+ NSS_STATUS_NOTFOUND, -+ strict, -+ ok=false, -+ talloc_asprintf( -+ torture, -+ "invalid lookupsids succeeded")); -+ -+ return ok; -+} -+ - struct torture_suite *torture_winbind_struct_init(TALLOC_CTX *ctx) - { - struct torture_suite *suite = torture_suite_create(ctx, "struct"); -@@ -1132,6 +1155,10 @@ struct torture_suite *torture_winbind_struct_init(TALLOC_CTX *ctx) - torture_suite_add_simple_test(suite, "getpwent", torture_winbind_struct_getpwent); - torture_suite_add_simple_test(suite, "endpwent", torture_winbind_struct_endpwent); - torture_suite_add_simple_test(suite, "lookup_name_sid", torture_winbind_struct_lookup_name_sid); -+ torture_suite_add_simple_test( -+ suite, -+ "lookup_sids_invalid", -+ torture_winbind_struct_lookup_sids_invalid); - - suite->description = talloc_strdup(suite, "WINBIND - struct based protocol tests"); - --- -2.29.2 \ No newline at end of file diff --git a/CVE-2020-1472.patch b/CVE-2020-1472.patch deleted file mode 100644 index e61592194a87f5f7e904ccef1dec572832943ba5..0000000000000000000000000000000000000000 --- a/CVE-2020-1472.patch +++ /dev/null @@ -1,1842 +0,0 @@ -From 84b8910da08dfa26440405f5e3916f222801859e Mon Sep 17 00:00:00 2001 -From: Stefan Metzmacher -Date: Wed, 16 Sep 2020 16:04:57 +0200 -Subject: [PATCH 01/19] CVE-2020-1472(ZeroLogon): libcli/auth: add - netlogon_creds_random_challenge() - -It's good to have just a single isolated function that will generate -random challenges, in future we can add some logic in order to -avoid weak values, which are likely to be rejected by a server. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Stefan Metzmacher ---- - libcli/auth/credentials.c | 6 ++++++ - libcli/auth/proto.h | 2 ++ - 2 files changed, 8 insertions(+) - -diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c -index c541eeff470..46259f39306 100644 ---- a/libcli/auth/credentials.c -+++ b/libcli/auth/credentials.c -@@ -33,6 +33,12 @@ - #include - #include - -+void netlogon_creds_random_challenge(struct netr_Credential *challenge) -+{ -+ ZERO_STRUCTP(challenge); -+ generate_random_buffer(challenge->data, sizeof(challenge->data)); -+} -+ - static NTSTATUS netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds, - const struct netr_Credential *in, - struct netr_Credential *out) -diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h -index 88f4a7c6c50..396484a5437 100644 ---- a/libcli/auth/proto.h -+++ b/libcli/auth/proto.h -@@ -13,6 +13,8 @@ - - /* The following definitions come from /home/jeremy/src/samba/git/master/source3/../source4/../libcli/auth/credentials.c */ - -+void netlogon_creds_random_challenge(struct netr_Credential *challenge); -+ - NTSTATUS netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, - struct netr_LMSessionKey *key); - NTSTATUS netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, --- -2.20.1 - - -From 3d9e8bd6735272b528fc10c7d8289044870229d5 Mon Sep 17 00:00:00 2001 -From: Stefan Metzmacher -Date: Wed, 16 Sep 2020 16:07:30 +0200 -Subject: [PATCH 02/19] CVE-2020-1472(ZeroLogon): s4:torture/rpc: make use of - netlogon_creds_random_challenge() - -This will avoid getting flakey tests once our server starts to -reject weak challenges. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Stefan Metzmacher ---- - source4/torture/rpc/lsa.c | 2 +- - source4/torture/rpc/netlogon.c | 34 ++++++++++++---------------------- - 2 files changed, 13 insertions(+), 23 deletions(-) - -diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c -index 548ebf8a090..0b1346e055a 100644 ---- a/source4/torture/rpc/lsa.c -+++ b/source4/torture/rpc/lsa.c -@@ -2872,7 +2872,7 @@ static bool check_pw_with_ServerAuthenticate3(struct dcerpc_pipe *p, - r.in.credentials = &credentials1; - r.out.return_credentials = &credentials2; - -- generate_random_buffer(credentials1.data, sizeof(credentials1.data)); -+ netlogon_creds_random_challenge(&credentials1); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), - "ServerReqChallenge failed"); -diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c -index 65188d2dc85..826793717e7 100644 ---- a/source4/torture/rpc/netlogon.c -+++ b/source4/torture/rpc/netlogon.c -@@ -160,7 +160,7 @@ bool test_SetupCredentials(struct dcerpc_pipe *p, struct torture_context *tctx, - r.in.credentials = &credentials1; - r.out.return_credentials = &credentials2; - -- generate_random_buffer(credentials1.data, sizeof(credentials1.data)); -+ netlogon_creds_random_challenge(&credentials1); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), - "ServerReqChallenge failed"); -@@ -229,7 +229,7 @@ bool test_SetupCredentials2ex(struct dcerpc_pipe *p, struct torture_context *tct - r.in.credentials = &credentials1; - r.out.return_credentials = &credentials2; - -- generate_random_buffer(credentials1.data, sizeof(credentials1.data)); -+ netlogon_creds_random_challenge(&credentials1); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), - "ServerReqChallenge failed"); -@@ -324,7 +324,7 @@ bool test_SetupCredentials3(struct dcerpc_pipe *p, struct torture_context *tctx, - r.in.credentials = &credentials1; - r.out.return_credentials = &credentials2; - -- generate_random_buffer(credentials1.data, sizeof(credentials1.data)); -+ netlogon_creds_random_challenge(&credentials1); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), - "ServerReqChallenge failed"); -@@ -396,7 +396,7 @@ bool test_SetupCredentialsDowngrade(struct torture_context *tctx, - r.in.credentials = &credentials1; - r.out.return_credentials = &credentials2; - -- generate_random_buffer(credentials1.data, sizeof(credentials1.data)); -+ netlogon_creds_random_challenge(&credentials1); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), - "ServerReqChallenge failed"); -@@ -1283,7 +1283,7 @@ static bool test_ServerReqChallengeGlobal(struct torture_context *tctx, - r.in.credentials = &credentials1; - r.out.return_credentials = &credentials2; - -- generate_random_buffer(credentials1.data, sizeof(credentials1.data)); -+ netlogon_creds_random_challenge(&credentials1); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), - "ServerReqChallenge failed on b1"); -@@ -1372,7 +1372,7 @@ static bool test_ServerReqChallengeReuseGlobal(struct torture_context *tctx, - r.in.credentials = &credentials1; - r.out.return_credentials = &credentials2; - -- generate_random_buffer(credentials1.data, sizeof(credentials1.data)); -+ netlogon_creds_random_challenge(&credentials1); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), - "ServerReqChallenge failed on b1"); -@@ -1461,7 +1461,7 @@ static bool test_ServerReqChallengeReuseGlobal2(struct torture_context *tctx, - r.in.credentials = &credentials1; - r.out.return_credentials = &credentials2; - -- generate_random_buffer(credentials1.data, sizeof(credentials1.data)); -+ netlogon_creds_random_challenge(&credentials1); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), - "ServerReqChallenge failed on b1"); -@@ -1551,7 +1551,7 @@ static bool test_ServerReqChallengeReuseGlobal3(struct torture_context *tctx, - r.in.credentials = &credentials1; - r.out.return_credentials = &credentials2; - -- generate_random_buffer(credentials1.data, sizeof(credentials1.data)); -+ netlogon_creds_random_challenge(&credentials1); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), - "ServerReqChallenge failed on b1"); -@@ -1643,8 +1643,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx, - r.in.credentials = &credentials1_random; - r.out.return_credentials = &credentials_discard; - -- generate_random_buffer(credentials1_random.data, -- sizeof(credentials1_random.data)); -+ netlogon_creds_random_challenge(&credentials1_random); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), - "ServerReqChallenge failed on b1"); -@@ -1656,7 +1655,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx, - r.in.credentials = &credentials1; - r.out.return_credentials = &credentials2; - -- generate_random_buffer(credentials1.data, sizeof(credentials1.data)); -+ netlogon_creds_random_challenge(&credentials1); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), - "ServerReqChallenge failed on b1"); -@@ -1667,16 +1666,7 @@ static bool test_ServerReqChallengeReuseGlobal4(struct torture_context *tctx, - r.in.credentials = &credentials1_random; - r.out.return_credentials = &credentials_discard; - -- generate_random_buffer(credentials1_random.data, -- sizeof(credentials1_random.data)); -- -- r.in.server_name = NULL; -- r.in.computer_name = "CHALTEST3"; -- r.in.credentials = &credentials1_random; -- r.out.return_credentials = &credentials_discard; -- -- generate_random_buffer(credentials1_random.data, -- sizeof(credentials1_random.data)); -+ netlogon_creds_random_challenge(&credentials1_random); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b1, tctx, &r), - "ServerReqChallenge failed on b1"); -@@ -1752,7 +1742,7 @@ static bool test_ServerReqChallengeReuse(struct torture_context *tctx, - r.in.credentials = &credentials1; - r.out.return_credentials = &credentials2; - -- generate_random_buffer(credentials1.data, sizeof(credentials1.data)); -+ netlogon_creds_random_challenge(&credentials1); - - torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), - "ServerReqChallenge"); --- -2.20.1 - - -From 8cf3efad0e15c3b001cc23d1e1280a91878f778d Mon Sep 17 00:00:00 2001 -From: Stefan Metzmacher -Date: Wed, 16 Sep 2020 16:08:38 +0200 -Subject: [PATCH 03/19] CVE-2020-1472(ZeroLogon): libcli/auth: make use of - netlogon_creds_random_challenge() in netlogon_creds_cli.c - -This will avoid getting rejected by the server if we generate -a weak challenge. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Stefan Metzmacher ---- - libcli/auth/netlogon_creds_cli.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c -index 407cb471cbc..12cb3149ff6 100644 ---- a/libcli/auth/netlogon_creds_cli.c -+++ b/libcli/auth/netlogon_creds_cli.c -@@ -1177,8 +1177,7 @@ static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req) - - TALLOC_FREE(state->creds); - -- generate_random_buffer(state->client_challenge.data, -- sizeof(state->client_challenge.data)); -+ netlogon_creds_random_challenge(&state->client_challenge); - - subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev, - state->binding_handle, --- -2.20.1 - - -From 2f21d4bd6c68016b1e9c737dc6614131afa2181d Mon Sep 17 00:00:00 2001 -From: Stefan Metzmacher -Date: Wed, 16 Sep 2020 16:10:53 +0200 -Subject: [PATCH 04/19] CVE-2020-1472(ZeroLogon): s3:rpc_server:netlogon: make - use of netlogon_creds_random_challenge() - -This is not strictly needed, but makes things more clear. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Stefan Metzmacher ---- - source3/rpc_server/netlogon/srv_netlog_nt.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c -index 52b17c10e61..516bbd7f6a8 100644 ---- a/source3/rpc_server/netlogon/srv_netlog_nt.c -+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c -@@ -840,8 +840,7 @@ NTSTATUS _netr_ServerReqChallenge(struct pipes_struct *p, - - pipe_state->client_challenge = *r->in.credentials; - -- generate_random_buffer(pipe_state->server_challenge.data, -- sizeof(pipe_state->server_challenge.data)); -+ netlogon_creds_random_challenge(&pipe_state->server_challenge); - - *r->out.return_credentials = pipe_state->server_challenge; - --- -2.20.1 - - -From b4df5225f750e686f742466e28f13c55a261674f Mon Sep 17 00:00:00 2001 -From: Stefan Metzmacher -Date: Wed, 16 Sep 2020 16:10:53 +0200 -Subject: [PATCH 05/19] CVE-2020-1472(ZeroLogon): s4:rpc_server:netlogon: make - use of netlogon_creds_random_challenge() - -This is not strictly needed, but makes things more clear. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Stefan Metzmacher ---- - source4/rpc_server/netlogon/dcerpc_netlogon.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c -index 0ab55afeab0..7d1b9db0b86 100644 ---- a/source4/rpc_server/netlogon/dcerpc_netlogon.c -+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c -@@ -90,8 +90,7 @@ static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_cal - - pipe_state->client_challenge = *r->in.credentials; - -- generate_random_buffer(pipe_state->server_challenge.data, -- sizeof(pipe_state->server_challenge.data)); -+ netlogon_creds_random_challenge(&pipe_state->server_challenge); - - *r->out.return_credentials = pipe_state->server_challenge; - --- -2.20.1 - - -From 18639a64e81866767eaf3e4ea118d932e1cf0d0c Mon Sep 17 00:00:00 2001 -From: Stefan Metzmacher -Date: Wed, 16 Sep 2020 16:15:26 +0200 -Subject: [PATCH 06/19] CVE-2020-1472(ZeroLogon): libcli/auth: add - netlogon_creds_is_random_challenge() to avoid weak values - -This is the check Windows is using, so we won't generate challenges, -which are rejected by Windows DCs (and future Samba DCs). - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Stefan Metzmacher ---- - libcli/auth/credentials.c | 23 ++++++++++++++++++++++- - libcli/auth/proto.h | 1 + - 2 files changed, 23 insertions(+), 1 deletion(-) - -diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c -index 46259f39306..54a20100b51 100644 ---- a/libcli/auth/credentials.c -+++ b/libcli/auth/credentials.c -@@ -33,10 +33,31 @@ - #include - #include - -+bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge) -+{ -+ /* -+ * If none of the first 5 bytes of the client challenge is unique, the -+ * server MUST fail session-key negotiation without further processing -+ * of the following steps. -+ */ -+ -+ if (challenge->data[1] == challenge->data[0] && -+ challenge->data[2] == challenge->data[0] && -+ challenge->data[3] == challenge->data[0] && -+ challenge->data[4] == challenge->data[0]) -+ { -+ return false; -+ } -+ -+ return true; -+} -+ - void netlogon_creds_random_challenge(struct netr_Credential *challenge) - { - ZERO_STRUCTP(challenge); -- generate_random_buffer(challenge->data, sizeof(challenge->data)); -+ while (!netlogon_creds_is_random_challenge(challenge)) { -+ generate_random_buffer(challenge->data, sizeof(challenge->data)); -+ } - } - - static NTSTATUS netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds, -diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h -index 396484a5437..a62668f088f 100644 ---- a/libcli/auth/proto.h -+++ b/libcli/auth/proto.h -@@ -13,6 +13,7 @@ - - /* The following definitions come from /home/jeremy/src/samba/git/master/source3/../source4/../libcli/auth/credentials.c */ - -+bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge); - void netlogon_creds_random_challenge(struct netr_Credential *challenge); - - NTSTATUS netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, --- -2.20.1 - - -From 2eb0f87de8c9d86fad4ca1bd74f05d15af98f56e Mon Sep 17 00:00:00 2001 -From: Stefan Metzmacher -Date: Wed, 16 Sep 2020 16:17:29 +0200 -Subject: [PATCH 07/19] CVE-2020-1472(ZeroLogon): libcli/auth: reject weak - client challenges in netlogon_creds_server_init() - -This implements the note from MS-NRPC 3.1.4.1 Session-Key Negotiation: - - 7. If none of the first 5 bytes of the client challenge is unique, the - server MUST fail session-key negotiation without further processing of - the following steps. - -It lets ./zerologon_tester.py from -https://github.com/SecuraBV/CVE-2020-1472.git -report: "Attack failed. Target is probably patched." - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Stefan Metzmacher ---- - libcli/auth/credentials.c | 17 ++++++++++++++++- - libcli/auth/wscript_build | 2 +- - 2 files changed, 17 insertions(+), 2 deletions(-) - -diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c -index 54a20100b51..23339d98bfa 100644 ---- a/libcli/auth/credentials.c -+++ b/libcli/auth/credentials.c -@@ -24,6 +24,7 @@ - #include "system/time.h" - #include "libcli/auth/libcli_auth.h" - #include "../libcli/security/dom_sid.h" -+#include "lib/util/util_str_escape.h" - - #ifndef HAVE_GNUTLS_AES_CFB8 - #include "lib/crypto/aes.h" -@@ -704,7 +705,7 @@ struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *me - - struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState); - NTSTATUS status; -- -+ bool ok; - - if (!creds) { - return NULL; -@@ -717,6 +718,20 @@ struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *me - dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data)); - dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash)); - -+ ok = netlogon_creds_is_random_challenge(client_challenge); -+ if (!ok) { -+ DBG_WARNING("CVE-2020-1472(ZeroLogon): " -+ "non-random client challenge rejected for " -+ "client_account[%s] client_computer_name[%s]\n", -+ log_escape(mem_ctx, client_account), -+ log_escape(mem_ctx, client_computer_name)); -+ dump_data(DBGLVL_WARNING, -+ client_challenge->data, -+ sizeof(client_challenge->data)); -+ talloc_free(creds); -+ return NULL; -+ } -+ - creds->computer_name = talloc_strdup(creds, client_computer_name); - if (!creds->computer_name) { - talloc_free(creds); -diff --git a/libcli/auth/wscript_build b/libcli/auth/wscript_build -index 41937623630..2a6a7468e45 100644 ---- a/libcli/auth/wscript_build -+++ b/libcli/auth/wscript_build -@@ -18,7 +18,7 @@ bld.SAMBA_SUBSYSTEM('NTLM_CHECK', - - bld.SAMBA_SUBSYSTEM('LIBCLI_AUTH', - source='credentials.c session.c smbencrypt.c smbdes.c', -- public_deps='MSRPC_PARSE gnutls GNUTLS_HELPERS', -+ public_deps='MSRPC_PARSE gnutls GNUTLS_HELPERS util_str_escape', - public_headers='credentials.h:domain_credentials.h' - ) - --- -2.20.1 - - -From 592e8e9acdca472115fdf69a3d0904f1740f4fb0 Mon Sep 17 00:00:00 2001 -From: Stefan Metzmacher -Date: Wed, 16 Sep 2020 19:20:25 +0200 -Subject: [PATCH 08/19] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon: - protect netr_ServerPasswordSet2 against unencrypted passwords - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Stefan Metzmacher ---- - source4/rpc_server/netlogon/dcerpc_netlogon.c | 60 ++++++++++++++++++- - 1 file changed, 59 insertions(+), 1 deletion(-) - -diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c -index 7d1b9db0b86..4aa6f256a07 100644 ---- a/source4/rpc_server/netlogon/dcerpc_netlogon.c -+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c -@@ -724,7 +724,10 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal - struct NL_PASSWORD_VERSION version = {}; - const uint32_t *new_version = NULL; - NTSTATUS nt_status; -- DATA_BLOB new_password; -+ DATA_BLOB new_password = data_blob_null; -+ size_t confounder_len; -+ DATA_BLOB dec_blob = data_blob_null; -+ DATA_BLOB enc_blob = data_blob_null; - int ret; - struct samr_CryptPassword password_buf; - -@@ -790,6 +793,61 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal - return NT_STATUS_WRONG_PASSWORD; - } - -+ /* -+ * Make sure the length field was encrypted, -+ * otherwise we are under attack. -+ */ -+ if (new_password.length == r->in.new_password->length) { -+ DBG_WARNING("Length[%zu] field not encrypted\n", -+ new_password.length); -+ return NT_STATUS_WRONG_PASSWORD; -+ } -+ -+ /* -+ * We don't allow empty passwords for machine accounts. -+ */ -+ if (new_password.length < 2) { -+ DBG_WARNING("Empty password Length[%zu]\n", -+ new_password.length); -+ return NT_STATUS_WRONG_PASSWORD; -+ } -+ -+ /* -+ * Make sure the confounder part of CryptPassword -+ * buffer was encrypted, otherwise we are under attack. -+ */ -+ confounder_len = 512 - new_password.length; -+ enc_blob = data_blob_const(r->in.new_password->data, confounder_len); -+ dec_blob = data_blob_const(password_buf.data, confounder_len); -+ if (data_blob_cmp(&dec_blob, &enc_blob) == 0) { -+ DBG_WARNING("Confounder buffer not encrypted Length[%zu]\n", -+ confounder_len); -+ return NT_STATUS_WRONG_PASSWORD; -+ } -+ -+ /* -+ * Check that the password part was actually encrypted, -+ * otherwise we are under attack. -+ */ -+ enc_blob = data_blob_const(r->in.new_password->data + confounder_len, -+ new_password.length); -+ dec_blob = data_blob_const(password_buf.data + confounder_len, -+ new_password.length); -+ if (data_blob_cmp(&dec_blob, &enc_blob) == 0) { -+ DBG_WARNING("Password buffer not encrypted Length[%zu]\n", -+ new_password.length); -+ return NT_STATUS_WRONG_PASSWORD; -+ } -+ -+ /* -+ * don't allow zero buffers -+ */ -+ if (all_zero(new_password.data, new_password.length)) { -+ DBG_WARNING("Password zero buffer Length[%zu]\n", -+ new_password.length); -+ return NT_STATUS_WRONG_PASSWORD; -+ } -+ - /* fetch the old password hashes (at least one of both has to exist) */ - - ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, --- -2.20.1 - - -From ff66560357d3eb23ce71f6667443e47a0c491833 Mon Sep 17 00:00:00 2001 -From: Jeremy Allison -Date: Wed, 16 Sep 2020 12:48:21 -0700 -Subject: [PATCH 09/19] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon: Fix - mem leak onto p->mem_ctx in error path of _netr_ServerPasswordSet2(). - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Jeremy Allison ---- - source3/rpc_server/netlogon/srv_netlog_nt.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c -index 516bbd7f6a8..b26efb78bab 100644 ---- a/source3/rpc_server/netlogon/srv_netlog_nt.c -+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c -@@ -1385,6 +1385,7 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p, - 516); - } - if (!NT_STATUS_IS_OK(status)) { -+ TALLOC_FREE(creds); - return status; - } - --- -2.20.1 - - -From aa57f084ca2cf16e323d172634eacf34db3ff0d7 Mon Sep 17 00:00:00 2001 -From: Jeremy Allison -Date: Wed, 16 Sep 2020 12:53:50 -0700 -Subject: [PATCH 10/19] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon: - protect netr_ServerPasswordSet2 against unencrypted passwords - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Pair-Programmed-With: Stefan Metzmacher - -Signed-off-by: Jeremy Allison -Signed-off-by: Stefan Metzmacher ---- - source3/rpc_server/netlogon/srv_netlog_nt.c | 98 +++++++++++++++++++-- - 1 file changed, 92 insertions(+), 6 deletions(-) - -diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c -index b26efb78bab..693e254b051 100644 ---- a/source3/rpc_server/netlogon/srv_netlog_nt.c -+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c -@@ -1343,9 +1343,14 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p, - { - NTSTATUS status; - struct netlogon_creds_CredentialState *creds = NULL; -- DATA_BLOB plaintext; -+ DATA_BLOB plaintext = data_blob_null; -+ DATA_BLOB new_password = data_blob_null; -+ size_t confounder_len; -+ DATA_BLOB dec_blob = data_blob_null; -+ DATA_BLOB enc_blob = data_blob_null; - struct samr_CryptPassword password_buf; - struct _samr_Credentials_t cr = { CRED_TYPE_PLAIN_TEXT, {0}}; -+ bool ok; - - become_root(); - status = netr_creds_server_step_check(p, p->mem_ctx, -@@ -1389,18 +1394,99 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p, - return status; - } - -- if (!decode_pw_buffer(p->mem_ctx, -- password_buf.data, -- (char**) &plaintext.data, -- &plaintext.length, -- CH_UTF16)) { -+ if (!extract_pw_from_buffer(p->mem_ctx, password_buf.data, &new_password)) { - DEBUG(2,("_netr_ServerPasswordSet2: unable to extract password " - "from a buffer. Rejecting auth request as a wrong password\n")); - TALLOC_FREE(creds); - return NT_STATUS_WRONG_PASSWORD; - } - -+ /* -+ * Make sure the length field was encrypted, -+ * otherwise we are under attack. -+ */ -+ if (new_password.length == r->in.new_password->length) { -+ DBG_WARNING("Length[%zu] field not encrypted\n", -+ new_password.length); -+ TALLOC_FREE(creds); -+ return NT_STATUS_WRONG_PASSWORD; -+ } -+ -+ /* -+ * We don't allow empty passwords for machine accounts. -+ */ -+ if (new_password.length < 2) { -+ DBG_WARNING("Empty password Length[%zu]\n", -+ new_password.length); -+ TALLOC_FREE(creds); -+ return NT_STATUS_WRONG_PASSWORD; -+ } -+ -+ /* -+ * Make sure the confounder part of CryptPassword -+ * buffer was encrypted, otherwise we are under attack. -+ */ -+ confounder_len = 512 - new_password.length; -+ enc_blob = data_blob_const(r->in.new_password->data, confounder_len); -+ dec_blob = data_blob_const(password_buf.data, confounder_len); -+ if (data_blob_cmp(&dec_blob, &enc_blob) == 0) { -+ DBG_WARNING("Confounder buffer not encrypted Length[%zu]\n", -+ confounder_len); -+ TALLOC_FREE(creds); -+ return NT_STATUS_WRONG_PASSWORD; -+ } -+ -+ /* -+ * Check that the password part was actually encrypted, -+ * otherwise we are under attack. -+ */ -+ enc_blob = data_blob_const(r->in.new_password->data + confounder_len, -+ new_password.length); -+ dec_blob = data_blob_const(password_buf.data + confounder_len, -+ new_password.length); -+ if (data_blob_cmp(&dec_blob, &enc_blob) == 0) { -+ DBG_WARNING("Password buffer not encrypted Length[%zu]\n", -+ new_password.length); -+ TALLOC_FREE(creds); -+ return NT_STATUS_WRONG_PASSWORD; -+ } -+ -+ /* -+ * don't allow zero buffers -+ */ -+ if (all_zero(new_password.data, new_password.length)) { -+ DBG_WARNING("Password zero buffer Length[%zu]\n", -+ new_password.length); -+ TALLOC_FREE(creds); -+ return NT_STATUS_WRONG_PASSWORD; -+ } -+ -+ /* Convert from UTF16 -> plaintext. */ -+ ok = convert_string_talloc(p->mem_ctx, -+ CH_UTF16, -+ CH_UNIX, -+ new_password.data, -+ new_password.length, -+ (void *)&plaintext.data, -+ &plaintext.length); -+ if (!ok) { -+ DBG_WARNING("unable to extract password from a buffer. " -+ "Rejecting auth request as a wrong password\n"); -+ TALLOC_FREE(creds); -+ return NT_STATUS_WRONG_PASSWORD; -+ } -+ -+ /* -+ * We don't allow empty passwords for machine accounts. -+ */ -+ - cr.creds.password = (const char*) plaintext.data; -+ if (strlen(cr.creds.password) == 0) { -+ DBG_WARNING("Empty plaintext password\n"); -+ TALLOC_FREE(creds); -+ return NT_STATUS_WRONG_PASSWORD; -+ } -+ - status = netr_set_machine_account_password(p->mem_ctx, - p->session_info, - p->msg_ctx, --- -2.20.1 - - -From 1c8234f6da6979a063c96c0eb32ddb55a51ce548 Mon Sep 17 00:00:00 2001 -From: Stefan Metzmacher -Date: Wed, 16 Sep 2020 10:18:45 +0200 -Subject: [PATCH 11/19] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon: - refactor dcesrv_netr_creds_server_step_check() - -We should debug more details about the failing request. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Stefan Metzmacher ---- - source4/rpc_server/netlogon/dcerpc_netlogon.c | 45 ++++++++++++++----- - 1 file changed, 33 insertions(+), 12 deletions(-) - -diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c -index 4aa6f256a07..7ccf46ae79b 100644 ---- a/source4/rpc_server/netlogon/dcerpc_netlogon.c -+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c -@@ -624,26 +624,47 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc - NTSTATUS nt_status; - int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx); - bool schannel_global_required = (schannel == true); -+ struct netlogon_creds_CredentialState *creds = NULL; -+ enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; -+ uint16_t opnum = dce_call->pkt.u.request.opnum; -+ const char *opname = ""; - -- if (schannel_global_required) { -- enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; -- -- dcesrv_call_auth_info(dce_call, &auth_type, NULL); -- -- if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { -- DBG_ERR("[%s] is not using schannel\n", -- computer_name); -- return NT_STATUS_ACCESS_DENIED; -- } -+ if (opnum < ndr_table_netlogon.num_calls) { -+ opname = ndr_table_netlogon.calls[opnum].name; - } - -+ dcesrv_call_auth_info(dce_call, &auth_type, NULL); -+ - nt_status = schannel_check_creds_state(mem_ctx, - dce_call->conn->dce_ctx->lp_ctx, - computer_name, - received_authenticator, - return_authenticator, -- creds_out); -- return nt_status; -+ &creds); -+ if (!NT_STATUS_IS_OK(nt_status)) { -+ ZERO_STRUCTP(return_authenticator); -+ return nt_status; -+ } -+ -+ if (schannel_global_required) { -+ if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { -+ *creds_out = creds; -+ return NT_STATUS_OK; -+ } -+ -+ DBG_ERR("CVE-2020-1472(ZeroLogon): " -+ "%s request (opnum[%u]) without schannel from " -+ "client_account[%s] client_computer_name[%s]\n", -+ opname, opnum, -+ log_escape(mem_ctx, creds->account_name), -+ log_escape(mem_ctx, creds->computer_name)); -+ TALLOC_FREE(creds); -+ ZERO_STRUCTP(return_authenticator); -+ return NT_STATUS_ACCESS_DENIED; -+ } -+ -+ *creds_out = creds; -+ return NT_STATUS_OK; - } - - /* --- -2.20.1 - - -From d8e520870c5c8943c289b3f373b1a4bcceefc174 Mon Sep 17 00:00:00 2001 -From: Stefan Metzmacher -Date: Wed, 16 Sep 2020 10:56:53 +0200 -Subject: [PATCH 12/19] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon: - support "server require schannel:WORKSTATION$ = no" - -This allows to add expections for individual workstations, when using "server schannel = yes". -"server schannel = auto" is very insecure and will be removed soon. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Stefan Metzmacher ---- - source4/rpc_server/netlogon/dcerpc_netlogon.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c -index 7ccf46ae79b..7994cb904b7 100644 ---- a/source4/rpc_server/netlogon/dcerpc_netlogon.c -+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c -@@ -624,6 +624,7 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc - NTSTATUS nt_status; - int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx); - bool schannel_global_required = (schannel == true); -+ bool schannel_required = schannel_global_required; - struct netlogon_creds_CredentialState *creds = NULL; - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; - uint16_t opnum = dce_call->pkt.u.request.opnum; -@@ -646,7 +647,13 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc - return nt_status; - } - -- if (schannel_global_required) { -+ schannel_required = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, -+ NULL, -+ "server require schannel", -+ creds->account_name, -+ schannel_global_required); -+ -+ if (schannel_required) { - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - *creds_out = creds; - return NT_STATUS_OK; --- -2.20.1 - - -From 629aeb89877ca7d8aef53b5ea2c507d2f146a23b Mon Sep 17 00:00:00 2001 -From: Stefan Metzmacher -Date: Thu, 17 Sep 2020 13:37:26 +0200 -Subject: [PATCH 13/19] CVE-2020-1472(ZeroLogon): s4:rpc_server/netlogon: log - warnings about unsecure configurations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This should give admins wawrnings until they have a secure -configuration. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Stefan Metzmacher -Reviewed-by: Ralph Boehme -Reviewed-by: Günther Deschner ---- - source4/rpc_server/netlogon/dcerpc_netlogon.c | 66 ++++++++++++++++++- - 1 file changed, 63 insertions(+), 3 deletions(-) - -diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c -index 7994cb904b7..9972138dbde 100644 ---- a/source4/rpc_server/netlogon/dcerpc_netlogon.c -+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c -@@ -625,10 +625,12 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc - int schannel = lpcfg_server_schannel(dce_call->conn->dce_ctx->lp_ctx); - bool schannel_global_required = (schannel == true); - bool schannel_required = schannel_global_required; -+ const char *explicit_opt = NULL; - struct netlogon_creds_CredentialState *creds = NULL; - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; - uint16_t opnum = dce_call->pkt.u.request.opnum; - const char *opname = ""; -+ static bool warned_global_once = false; - - if (opnum < ndr_table_netlogon.num_calls) { - opname = ndr_table_netlogon.calls[opnum].name; -@@ -647,11 +649,18 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc - return nt_status; - } - -- schannel_required = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, -+ /* -+ * We don't use lpcfg_parm_bool(), as we -+ * need the explicit_opt pointer in order to -+ * adjust the debug messages. -+ */ -+ explicit_opt = lpcfg_get_parametric(dce_call->conn->dce_ctx->lp_ctx, - NULL, - "server require schannel", -- creds->account_name, -- schannel_global_required); -+ creds->account_name); -+ if (explicit_opt != NULL) { -+ schannel_required = lp_bool(explicit_opt); -+ } - - if (schannel_required) { - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { -@@ -665,11 +674,62 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dc - opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); -+ DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " -+ "'server require schannel:%s = no' is needed! \n", -+ log_escape(mem_ctx, creds->account_name)); - TALLOC_FREE(creds); - ZERO_STRUCTP(return_authenticator); - return NT_STATUS_ACCESS_DENIED; - } - -+ if (!schannel_global_required && !warned_global_once) { -+ /* -+ * We want admins to notice their misconfiguration! -+ */ -+ DBG_ERR("CVE-2020-1472(ZeroLogon): " -+ "Please configure 'server schannel = yes', " -+ "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n"); -+ warned_global_once = true; -+ } -+ -+ if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { -+ DBG_ERR("CVE-2020-1472(ZeroLogon): " -+ "%s request (opnum[%u]) WITH schannel from " -+ "client_account[%s] client_computer_name[%s]\n", -+ opname, opnum, -+ log_escape(mem_ctx, creds->account_name), -+ log_escape(mem_ctx, creds->computer_name)); -+ DBG_ERR("CVE-2020-1472(ZeroLogon): " -+ "Option 'server require schannel:%s = no' not needed!?\n", -+ log_escape(mem_ctx, creds->account_name)); -+ -+ *creds_out = creds; -+ return NT_STATUS_OK; -+ } -+ -+ -+ if (explicit_opt != NULL) { -+ DBG_INFO("CVE-2020-1472(ZeroLogon): " -+ "%s request (opnum[%u]) without schannel from " -+ "client_account[%s] client_computer_name[%s]\n", -+ opname, opnum, -+ log_escape(mem_ctx, creds->account_name), -+ log_escape(mem_ctx, creds->computer_name)); -+ DBG_INFO("CVE-2020-1472(ZeroLogon): " -+ "Option 'server require schannel:%s = no' still needed!\n", -+ log_escape(mem_ctx, creds->account_name)); -+ } else { -+ DBG_ERR("CVE-2020-1472(ZeroLogon): " -+ "%s request (opnum[%u]) without schannel from " -+ "client_account[%s] client_computer_name[%s]\n", -+ opname, opnum, -+ log_escape(mem_ctx, creds->account_name), -+ log_escape(mem_ctx, creds->computer_name)); -+ DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " -+ "'server require schannel:%s = no' might be needed!\n", -+ log_escape(mem_ctx, creds->account_name)); -+ } -+ - *creds_out = creds; - return NT_STATUS_OK; - } --- -2.20.1 - - -From eab8661ef16856eb0926fe3426f7fe6ac870faae Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?G=C3=BCnther=20Deschner?= -Date: Thu, 17 Sep 2020 14:57:22 +0200 -Subject: [PATCH 14/19] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon: - refactor dcesrv_netr_creds_server_step_check() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We should debug more details about the failing request. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Pair-Programmed-With: Stefan Metzmacher - -Signed-off-by: Günther Deschner -Signed-off-by: Stefan Metzmacher ---- - source3/rpc_server/netlogon/srv_netlog_nt.c | 43 +++++++++++++++++---- - 1 file changed, 35 insertions(+), 8 deletions(-) - -diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c -index 693e254b051..c134e07573c 100644 ---- a/source3/rpc_server/netlogon/srv_netlog_nt.c -+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c -@@ -47,6 +47,7 @@ - #include "../lib/tsocket/tsocket.h" - #include "lib/param/param.h" - #include "libsmb/dsgetdcname.h" -+#include "lib/util/util_str_escape.h" - - extern userdom_struct current_user_info; - -@@ -1073,19 +1074,21 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, - NTSTATUS status; - bool schannel_global_required = (lp_server_schannel() == true) ? true:false; - struct loadparm_context *lp_ctx; -+ struct netlogon_creds_CredentialState *creds = NULL; -+ enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; -+ uint16_t opnum = p->opnum; -+ const char *opname = ""; - - if (creds_out != NULL) { - *creds_out = NULL; - } - -- if (schannel_global_required) { -- if (p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { -- DBG_ERR("[%s] is not using schannel\n", -- computer_name); -- return NT_STATUS_ACCESS_DENIED; -- } -+ if (opnum < ndr_table_netlogon.num_calls) { -+ opname = ndr_table_netlogon.calls[opnum].name; - } - -+ auth_type = p->auth.auth_type; -+ - lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers()); - if (lp_ctx == NULL) { - DEBUG(0, ("loadparm_init_s3 failed\n")); -@@ -1094,9 +1097,33 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, - - status = schannel_check_creds_state(mem_ctx, lp_ctx, - computer_name, received_authenticator, -- return_authenticator, creds_out); -+ return_authenticator, &creds); - talloc_unlink(mem_ctx, lp_ctx); -- return status; -+ -+ if (!NT_STATUS_IS_OK(status)) { -+ ZERO_STRUCTP(return_authenticator); -+ return status; -+ } -+ -+ if (schannel_global_required) { -+ if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { -+ *creds_out = creds; -+ return NT_STATUS_OK; -+ } -+ -+ DBG_ERR("CVE-2020-1472(ZeroLogon): " -+ "%s request (opnum[%u]) without schannel from " -+ "client_account[%s] client_computer_name[%s]\n", -+ opname, opnum, -+ log_escape(mem_ctx, creds->account_name), -+ log_escape(mem_ctx, creds->computer_name)); -+ TALLOC_FREE(creds); -+ ZERO_STRUCTP(return_authenticator); -+ return NT_STATUS_ACCESS_DENIED; -+ } -+ -+ *creds_out = creds; -+ return NT_STATUS_OK; - } - - --- -2.20.1 - - -From db2580705011c996a4feb01c4b6f069a4e013135 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?G=C3=BCnther=20Deschner?= -Date: Thu, 17 Sep 2020 14:23:16 +0200 -Subject: [PATCH 15/19] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon: - support "server require schannel:WORKSTATION$ = no" -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This allows to add expections for individual workstations, when using "server schannel = yes". -"server schannel = auto" is very insecure and will be removed soon. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Pair-Programmed-With: Stefan Metzmacher - -Signed-off-by: Günther Deschner -Signed-off-by: Stefan Metzmacher ---- - source3/rpc_server/netlogon/srv_netlog_nt.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c -index c134e07573c..3327f4bc0a0 100644 ---- a/source3/rpc_server/netlogon/srv_netlog_nt.c -+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c -@@ -1073,6 +1073,7 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, - { - NTSTATUS status; - bool schannel_global_required = (lp_server_schannel() == true) ? true:false; -+ bool schannel_required = schannel_global_required; - struct loadparm_context *lp_ctx; - struct netlogon_creds_CredentialState *creds = NULL; - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; -@@ -1105,7 +1106,11 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, - return status; - } - -- if (schannel_global_required) { -+ schannel_required = lp_parm_bool(GLOBAL_SECTION_SNUM, -+ "server require schannel", -+ creds->account_name, -+ schannel_global_required); -+ if (schannel_required) { - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - *creds_out = creds; - return NT_STATUS_OK; --- -2.20.1 - - -From fa5fc293263150238755fbb8310653550f57049a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?G=C3=BCnther=20Deschner?= -Date: Thu, 17 Sep 2020 14:42:52 +0200 -Subject: [PATCH 16/19] CVE-2020-1472(ZeroLogon): s3:rpc_server/netlogon: log - warnings about unsecure configurations -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Pair-Programmed-With: Stefan Metzmacher - -Signed-off-by: Günther Deschner -Signed-off-by: Stefan Metzmacher ---- - source3/rpc_server/netlogon/srv_netlog_nt.c | 70 +++++++++++++++++++-- - 1 file changed, 66 insertions(+), 4 deletions(-) - -diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c -index 3327f4bc0a0..9ef74447b84 100644 ---- a/source3/rpc_server/netlogon/srv_netlog_nt.c -+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c -@@ -1074,11 +1074,13 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, - NTSTATUS status; - bool schannel_global_required = (lp_server_schannel() == true) ? true:false; - bool schannel_required = schannel_global_required; -+ const char *explicit_opt = NULL; - struct loadparm_context *lp_ctx; - struct netlogon_creds_CredentialState *creds = NULL; - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; - uint16_t opnum = p->opnum; - const char *opname = ""; -+ static bool warned_global_once = false; - - if (creds_out != NULL) { - *creds_out = NULL; -@@ -1106,10 +1108,20 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, - return status; - } - -- schannel_required = lp_parm_bool(GLOBAL_SECTION_SNUM, -- "server require schannel", -- creds->account_name, -- schannel_global_required); -+ /* -+ * We don't use lp_parm_bool(), as we -+ * need the explicit_opt pointer in order to -+ * adjust the debug messages. -+ */ -+ -+ explicit_opt = lp_parm_const_string(GLOBAL_SECTION_SNUM, -+ "server require schannel", -+ creds->account_name, -+ NULL); -+ if (explicit_opt != NULL) { -+ schannel_required = lp_bool(explicit_opt); -+ } -+ - if (schannel_required) { - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - *creds_out = creds; -@@ -1122,11 +1134,61 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, - opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); -+ DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " -+ "'server require schannel:%s = no' is needed! \n", -+ log_escape(mem_ctx, creds->account_name)); - TALLOC_FREE(creds); - ZERO_STRUCTP(return_authenticator); - return NT_STATUS_ACCESS_DENIED; - } - -+ if (!schannel_global_required && !warned_global_once) { -+ /* -+ * We want admins to notice their misconfiguration! -+ */ -+ DBG_ERR("CVE-2020-1472(ZeroLogon): " -+ "Please configure 'server schannel = yes', " -+ "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n"); -+ warned_global_once = true; -+ } -+ -+ if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { -+ DBG_ERR("CVE-2020-1472(ZeroLogon): " -+ "%s request (opnum[%u]) WITH schannel from " -+ "client_account[%s] client_computer_name[%s]\n", -+ opname, opnum, -+ log_escape(mem_ctx, creds->account_name), -+ log_escape(mem_ctx, creds->computer_name)); -+ DBG_ERR("CVE-2020-1472(ZeroLogon): " -+ "Option 'server require schannel:%s = no' not needed!?\n", -+ log_escape(mem_ctx, creds->account_name)); -+ -+ *creds_out = creds; -+ return NT_STATUS_OK; -+ } -+ -+ if (explicit_opt != NULL) { -+ DBG_INFO("CVE-2020-1472(ZeroLogon): " -+ "%s request (opnum[%u]) without schannel from " -+ "client_account[%s] client_computer_name[%s]\n", -+ opname, opnum, -+ log_escape(mem_ctx, creds->account_name), -+ log_escape(mem_ctx, creds->computer_name)); -+ DBG_INFO("CVE-2020-1472(ZeroLogon): " -+ "Option 'server require schannel:%s = no' still needed!\n", -+ log_escape(mem_ctx, creds->account_name)); -+ } else { -+ DBG_ERR("CVE-2020-1472(ZeroLogon): " -+ "%s request (opnum[%u]) without schannel from " -+ "client_account[%s] client_computer_name[%s]\n", -+ opname, opnum, -+ log_escape(mem_ctx, creds->account_name), -+ log_escape(mem_ctx, creds->computer_name)); -+ DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " -+ "'server require schannel:%s = no' might be needed!\n", -+ log_escape(mem_ctx, creds->account_name)); -+ } -+ - *creds_out = creds; - return NT_STATUS_OK; - } --- -2.20.1 - - -From 296a62d1589dbf33aa751e8346ba5721f6314215 Mon Sep 17 00:00:00 2001 -From: Stefan Metzmacher -Date: Thu, 17 Sep 2020 17:27:54 +0200 -Subject: [PATCH 17/19] CVE-2020-1472(ZeroLogon): docs-xml: document 'server - require schannel:COMPUTERACCOUNT' - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Stefan Metzmacher ---- - .../smbdotconf/security/serverschannel.xml | 69 +++++++++++++++---- - 1 file changed, 54 insertions(+), 15 deletions(-) - -diff --git a/docs-xml/smbdotconf/security/serverschannel.xml b/docs-xml/smbdotconf/security/serverschannel.xml -index 489492d79b1..b682d086f76 100644 ---- a/docs-xml/smbdotconf/security/serverschannel.xml -+++ b/docs-xml/smbdotconf/security/serverschannel.xml -@@ -7,26 +7,65 @@ - - - -- This option is deprecated with Samba 4.8 and will be removed in future. -- At the same time the default changed to yes, which will be the -- hardcoded behavior in future. If you have the need for the behavior of "auto" -- to be kept, please file a bug at https://bugzilla.samba.org. -+ This option is deprecated and will be removed in future, -+ as it is a security problem if not set to "yes" (which will be -+ the hardcoded behavior in future). - - - -- This controls whether the server offers or even demands the use of the netlogon schannel. -- no does not offer the schannel, auto offers the schannel but does not enforce it, and yes denies access if the client is not able to speak netlogon schannel. -- This is only the case for Windows NT4 before SP4. -- -- -+ Samba will complain in the log files at log level 0, -+ about the security problem if the option is not set to "yes". -+ - -- Please note that with this set to no, you will have to apply the WindowsXP -- WinXP_SignOrSeal.reg registry patch found in the docs/registry subdirectory of the Samba distribution tarball. -- -+ See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497 -+ -+ -+ If you still have legacy domain members use the option. -+ -+ -+ This option yields precedence to the option. -+ - - - yes --auto -+ -+ -+ -+ -+ -+ If you still have legacy domain members, which required "server schannel = auto" before, -+ it is possible to specify explicit expection per computer account -+ by using 'server require schannel:COMPUTERACCOUNT = no' as option. -+ Note that COMPUTERACCOUNT has to be the sAMAccountName value of -+ the computer account (including the trailing '$' sign). -+ -+ -+ -+ Samba will complain in the log files at log level 0, -+ about the security problem if the option is not set to "no", -+ but the related computer is actually using the netlogon -+ secure channel (schannel) feature. -+ -+ -+ -+ Samba will warn in the log files at log level 5, -+ if a setting is still needed for the specified computer account. -+ -+ -+ -+ See CVE-2020-1472(ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497 -+ -+ -+ This option takes precedence to the option. -+ -+ -+ server require schannel:LEGACYCOMPUTER1$ = no -+ server require schannel:NASBOX$ = no -+ server require schannel:LEGACYCOMPUTER2$ = no -+ -+ -+ - --- -2.20.1 - - -From 3110ca45379309c55f96e97df5d6d010390cd8c6 Mon Sep 17 00:00:00 2001 -From: Gary Lockyer -Date: Fri, 18 Sep 2020 12:39:54 +1200 -Subject: [PATCH 18/19] CVE-2020-1472(ZeroLogon): s4 torture rpc: Test empty - machine acct pwd - -Ensure that an empty machine account password can't be set by -netr_ServerPasswordSet2 - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Gary Lockyer ---- - source4/torture/rpc/netlogon.c | 64 +++++++++++++++------------------- - 1 file changed, 29 insertions(+), 35 deletions(-) - -diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c -index 826793717e7..af9d94b99ff 100644 ---- a/source4/torture/rpc/netlogon.c -+++ b/source4/torture/rpc/netlogon.c -@@ -725,45 +725,39 @@ static bool test_SetPassword2_with_flags(struct torture_context *tctx, - - cli_credentials_set_password(machine_credentials, password, CRED_SPECIFIED); - -- if (!torture_setting_bool(tctx, "dangerous", false)) { -- torture_comment(tctx, -- "Not testing ability to set password to '', enable dangerous tests to perform this test\n"); -+ /* -+ * As a consequence of CVE-2020-1472(ZeroLogon) -+ * Samba explicitly disallows the setting of an empty machine account -+ * password. -+ * -+ * Note that this may fail against Windows, and leave a machine account -+ * with an empty password. -+ */ -+ password = ""; -+ encode_pw_buffer(password_buf.data, password, STR_UNICODE); -+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { -+ netlogon_creds_aes_encrypt(creds, password_buf.data, 516); - } else { -- /* by changing the machine password to "" -- * we check if the server uses password restrictions -- * for ServerPasswordSet2 -- * (win2k3 accepts "") -- */ -- password = ""; -- encode_pw_buffer(password_buf.data, password, STR_UNICODE); -- if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { -- netlogon_creds_aes_encrypt(creds, password_buf.data, 516); -- } else { -- netlogon_creds_arcfour_crypt(creds, password_buf.data, 516); -- } -- memcpy(new_password.data, password_buf.data, 512); -- new_password.length = IVAL(password_buf.data, 512); -- -- torture_comment(tctx, -- "Testing ServerPasswordSet2 on machine account\n"); -- torture_comment(tctx, -- "Changing machine account password to '%s'\n", password); -- -- netlogon_creds_client_authenticator(creds, &credential); -- -- torture_assert_ntstatus_ok(tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r), -- "ServerPasswordSet2 failed"); -- torture_assert_ntstatus_ok(tctx, r.out.result, "ServerPasswordSet2 failed"); -+ netlogon_creds_arcfour_crypt(creds, password_buf.data, 516); -+ } -+ memcpy(new_password.data, password_buf.data, 512); -+ new_password.length = IVAL(password_buf.data, 512); - -- if (!netlogon_creds_client_check(creds, &r.out.return_authenticator->cred)) { -- torture_comment(tctx, "Credential chaining failed\n"); -- } -+ torture_comment(tctx, -+ "Testing ServerPasswordSet2 on machine account\n"); -+ torture_comment(tctx, -+ "Changing machine account password to '%s'\n", password); - -- cli_credentials_set_password(machine_credentials, password, CRED_SPECIFIED); -- } -+ netlogon_creds_client_authenticator(creds, &credential); - -- torture_assert(tctx, test_SetupCredentials(p, tctx, machine_credentials, &creds), -- "ServerPasswordSet failed to actually change the password"); -+ torture_assert_ntstatus_ok( -+ tctx, dcerpc_netr_ServerPasswordSet2_r(b, tctx, &r), -+ "ServerPasswordSet2 failed"); -+ torture_assert_ntstatus_equal( -+ tctx, -+ r.out.result, -+ NT_STATUS_WRONG_PASSWORD, -+ "ServerPasswordSet2 did not return NT_STATUS_WRONG_PASSWORD"); - - /* now try a random password */ - password = generate_random_password(tctx, 8, 255); --- -2.20.1 - - -From a13ddb0fe6ddf29642976f4caff9c2391676645c Mon Sep 17 00:00:00 2001 -From: Gary Lockyer -Date: Fri, 18 Sep 2020 15:57:34 +1200 -Subject: [PATCH 19/19] CVE-2020-1472(ZeroLogon): s4 torture rpc: repeated - bytes in client challenge - -Ensure that client challenges with the first 5 bytes identical are -rejected. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 - -Signed-off-by: Gary Lockyer - -[abartlet@samba.org: backported from master as test order was flipped] ---- - source4/torture/rpc/netlogon.c | 335 +++++++++++++++++++++++++++++++++ - 1 file changed, 335 insertions(+) - -diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c -index af9d94b99ff..c9e614fda30 100644 ---- a/source4/torture/rpc/netlogon.c -+++ b/source4/torture/rpc/netlogon.c -@@ -486,6 +486,325 @@ bool test_SetupCredentialsPipe(const struct dcerpc_pipe *p1, - return true; - } - -+static bool test_ServerReqChallenge( -+ struct torture_context *tctx, -+ struct dcerpc_pipe *p, -+ struct cli_credentials *credentials) -+{ -+ struct netr_ServerReqChallenge r; -+ struct netr_Credential credentials1, credentials2, credentials3; -+ const char *machine_name; -+ struct dcerpc_binding_handle *b = p->binding_handle; -+ struct netr_ServerAuthenticate2 a; -+ uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; -+ uint32_t out_negotiate_flags = 0; -+ const struct samr_Password *mach_password = NULL; -+ enum netr_SchannelType sec_chan_type = 0; -+ struct netlogon_creds_CredentialState *creds = NULL; -+ const char *account_name = NULL; -+ -+ machine_name = cli_credentials_get_workstation(credentials); -+ mach_password = cli_credentials_get_nt_hash(credentials, tctx); -+ account_name = cli_credentials_get_username(credentials); -+ sec_chan_type = cli_credentials_get_secure_channel_type(credentials); -+ -+ torture_comment(tctx, "Testing ServerReqChallenge\n"); -+ -+ r.in.server_name = NULL; -+ r.in.computer_name = machine_name; -+ r.in.credentials = &credentials1; -+ r.out.return_credentials = &credentials2; -+ -+ netlogon_creds_random_challenge(&credentials1); -+ -+ torture_assert_ntstatus_ok( -+ tctx, -+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), -+ "ServerReqChallenge failed"); -+ torture_assert_ntstatus_ok( -+ tctx, -+ r.out.result, -+ "ServerReqChallenge failed"); -+ a.in.server_name = NULL; -+ a.in.account_name = account_name; -+ a.in.secure_channel_type = sec_chan_type; -+ a.in.computer_name = machine_name; -+ a.in.negotiate_flags = &in_negotiate_flags; -+ a.out.negotiate_flags = &out_negotiate_flags; -+ a.in.credentials = &credentials3; -+ a.out.return_credentials = &credentials3; -+ -+ creds = netlogon_creds_client_init(tctx, a.in.account_name, -+ a.in.computer_name, -+ a.in.secure_channel_type, -+ &credentials1, &credentials2, -+ mach_password, &credentials3, -+ in_negotiate_flags); -+ -+ torture_assert(tctx, creds != NULL, "memory allocation"); -+ -+ torture_comment(tctx, "Testing ServerAuthenticate2\n"); -+ -+ torture_assert_ntstatus_ok( -+ tctx, -+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a), -+ "ServerAuthenticate2 failed"); -+ torture_assert_ntstatus_equal( -+ tctx, -+ a.out.result, -+ NT_STATUS_OK, -+ "ServerAuthenticate2 unexpected"); -+ -+ return true; -+} -+ -+static bool test_ServerReqChallenge_zero_challenge( -+ struct torture_context *tctx, -+ struct dcerpc_pipe *p, -+ struct cli_credentials *credentials) -+{ -+ struct netr_ServerReqChallenge r; -+ struct netr_Credential credentials1, credentials2, credentials3; -+ const char *machine_name; -+ struct dcerpc_binding_handle *b = p->binding_handle; -+ struct netr_ServerAuthenticate2 a; -+ uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; -+ uint32_t out_negotiate_flags = 0; -+ const struct samr_Password *mach_password = NULL; -+ enum netr_SchannelType sec_chan_type = 0; -+ struct netlogon_creds_CredentialState *creds = NULL; -+ const char *account_name = NULL; -+ -+ machine_name = cli_credentials_get_workstation(credentials); -+ mach_password = cli_credentials_get_nt_hash(credentials, tctx); -+ account_name = cli_credentials_get_username(credentials); -+ sec_chan_type = cli_credentials_get_secure_channel_type(credentials); -+ -+ torture_comment(tctx, "Testing ServerReqChallenge\n"); -+ -+ r.in.server_name = NULL; -+ r.in.computer_name = machine_name; -+ r.in.credentials = &credentials1; -+ r.out.return_credentials = &credentials2; -+ -+ /* -+ * Set the client challenge to zero, this should fail -+ * CVE-2020-1472(ZeroLogon) -+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 -+ */ -+ ZERO_STRUCT(credentials1); -+ -+ torture_assert_ntstatus_ok( -+ tctx, -+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), -+ "ServerReqChallenge failed"); -+ torture_assert_ntstatus_ok( -+ tctx, -+ r.out.result, -+ "ServerReqChallenge failed"); -+ a.in.server_name = NULL; -+ a.in.account_name = account_name; -+ a.in.secure_channel_type = sec_chan_type; -+ a.in.computer_name = machine_name; -+ a.in.negotiate_flags = &in_negotiate_flags; -+ a.out.negotiate_flags = &out_negotiate_flags; -+ a.in.credentials = &credentials3; -+ a.out.return_credentials = &credentials3; -+ -+ creds = netlogon_creds_client_init(tctx, a.in.account_name, -+ a.in.computer_name, -+ a.in.secure_channel_type, -+ &credentials1, &credentials2, -+ mach_password, &credentials3, -+ in_negotiate_flags); -+ -+ torture_assert(tctx, creds != NULL, "memory allocation"); -+ -+ torture_comment(tctx, "Testing ServerAuthenticate2\n"); -+ -+ torture_assert_ntstatus_ok( -+ tctx, -+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a), -+ "ServerAuthenticate2 failed"); -+ torture_assert_ntstatus_equal( -+ tctx, -+ a.out.result, -+ NT_STATUS_ACCESS_DENIED, -+ "ServerAuthenticate2 unexpected"); -+ -+ return true; -+} -+ -+static bool test_ServerReqChallenge_5_repeats( -+ struct torture_context *tctx, -+ struct dcerpc_pipe *p, -+ struct cli_credentials *credentials) -+{ -+ struct netr_ServerReqChallenge r; -+ struct netr_Credential credentials1, credentials2, credentials3; -+ const char *machine_name; -+ struct dcerpc_binding_handle *b = p->binding_handle; -+ struct netr_ServerAuthenticate2 a; -+ uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; -+ uint32_t out_negotiate_flags = 0; -+ const struct samr_Password *mach_password = NULL; -+ enum netr_SchannelType sec_chan_type = 0; -+ struct netlogon_creds_CredentialState *creds = NULL; -+ const char *account_name = NULL; -+ -+ machine_name = cli_credentials_get_workstation(credentials); -+ mach_password = cli_credentials_get_nt_hash(credentials, tctx); -+ account_name = cli_credentials_get_username(credentials); -+ sec_chan_type = cli_credentials_get_secure_channel_type(credentials); -+ -+ torture_comment(tctx, "Testing ServerReqChallenge\n"); -+ -+ r.in.server_name = NULL; -+ r.in.computer_name = machine_name; -+ r.in.credentials = &credentials1; -+ r.out.return_credentials = &credentials2; -+ -+ /* -+ * Set the first 5 bytes of the client challenge to the same value, -+ * this should fail CVE-2020-1472(ZeroLogon) -+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 -+ */ -+ credentials1.data[0] = 'A'; -+ credentials1.data[1] = 'A'; -+ credentials1.data[2] = 'A'; -+ credentials1.data[3] = 'A'; -+ credentials1.data[4] = 'A'; -+ credentials1.data[5] = 'B'; -+ credentials1.data[6] = 'C'; -+ credentials1.data[7] = 'D'; -+ -+ torture_assert_ntstatus_ok( -+ tctx, -+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), -+ "ServerReqChallenge failed"); -+ torture_assert_ntstatus_ok( -+ tctx, -+ r.out.result, -+ "ServerReqChallenge failed"); -+ a.in.server_name = NULL; -+ a.in.account_name = account_name; -+ a.in.secure_channel_type = sec_chan_type; -+ a.in.computer_name = machine_name; -+ a.in.negotiate_flags = &in_negotiate_flags; -+ a.out.negotiate_flags = &out_negotiate_flags; -+ a.in.credentials = &credentials3; -+ a.out.return_credentials = &credentials3; -+ -+ creds = netlogon_creds_client_init(tctx, a.in.account_name, -+ a.in.computer_name, -+ a.in.secure_channel_type, -+ &credentials1, &credentials2, -+ mach_password, &credentials3, -+ in_negotiate_flags); -+ -+ torture_assert(tctx, creds != NULL, "memory allocation"); -+ -+ torture_comment(tctx, "Testing ServerAuthenticate2\n"); -+ -+ torture_assert_ntstatus_ok( -+ tctx, -+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a), -+ "ServerAuthenticate2 failed"); -+ torture_assert_ntstatus_equal( -+ tctx, -+ a.out.result, -+ NT_STATUS_ACCESS_DENIED, -+ "ServerAuthenticate2 unexpected"); -+ -+ return true; -+} -+ -+static bool test_ServerReqChallenge_4_repeats( -+ struct torture_context *tctx, -+ struct dcerpc_pipe *p, -+ struct cli_credentials *credentials) -+{ -+ struct netr_ServerReqChallenge r; -+ struct netr_Credential credentials1, credentials2, credentials3; -+ const char *machine_name; -+ struct dcerpc_binding_handle *b = p->binding_handle; -+ struct netr_ServerAuthenticate2 a; -+ uint32_t in_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; -+ uint32_t out_negotiate_flags = 0; -+ const struct samr_Password *mach_password = NULL; -+ enum netr_SchannelType sec_chan_type = 0; -+ struct netlogon_creds_CredentialState *creds = NULL; -+ const char *account_name = NULL; -+ -+ machine_name = cli_credentials_get_workstation(credentials); -+ mach_password = cli_credentials_get_nt_hash(credentials, tctx); -+ account_name = cli_credentials_get_username(credentials); -+ sec_chan_type = cli_credentials_get_secure_channel_type(credentials); -+ -+ torture_comment(tctx, "Testing ServerReqChallenge\n"); -+ -+ r.in.server_name = NULL; -+ r.in.computer_name = machine_name; -+ r.in.credentials = &credentials1; -+ r.out.return_credentials = &credentials2; -+ -+ /* -+ * Set the first 4 bytes of the client challenge to the same -+ * value, this should pass as 5 bytes identical are needed to -+ * fail for CVE-2020-1472(ZeroLogon) -+ * -+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14497 -+ */ -+ credentials1.data[0] = 'A'; -+ credentials1.data[1] = 'A'; -+ credentials1.data[2] = 'A'; -+ credentials1.data[3] = 'A'; -+ credentials1.data[4] = 'B'; -+ credentials1.data[5] = 'C'; -+ credentials1.data[6] = 'D'; -+ credentials1.data[7] = 'E'; -+ -+ torture_assert_ntstatus_ok( -+ tctx, -+ dcerpc_netr_ServerReqChallenge_r(b, tctx, &r), -+ "ServerReqChallenge failed"); -+ torture_assert_ntstatus_ok( -+ tctx, -+ r.out.result, -+ "ServerReqChallenge failed"); -+ a.in.server_name = NULL; -+ a.in.account_name = account_name; -+ a.in.secure_channel_type = sec_chan_type; -+ a.in.computer_name = machine_name; -+ a.in.negotiate_flags = &in_negotiate_flags; -+ a.out.negotiate_flags = &out_negotiate_flags; -+ a.in.credentials = &credentials3; -+ a.out.return_credentials = &credentials3; -+ -+ creds = netlogon_creds_client_init(tctx, a.in.account_name, -+ a.in.computer_name, -+ a.in.secure_channel_type, -+ &credentials1, &credentials2, -+ mach_password, &credentials3, -+ in_negotiate_flags); -+ -+ torture_assert(tctx, creds != NULL, "memory allocation"); -+ -+ torture_comment(tctx, "Testing ServerAuthenticate2\n"); -+ -+ torture_assert_ntstatus_ok( -+ tctx, -+ dcerpc_netr_ServerAuthenticate2_r(b, tctx, &a), -+ "ServerAuthenticate2 failed"); -+ torture_assert_ntstatus_equal( -+ tctx, -+ a.out.result, -+ NT_STATUS_OK, -+ "ServerAuthenticate2 unexpected"); -+ -+ return true; -+} -+ - /* - try a change password for our machine account - */ -@@ -4954,6 +5273,22 @@ struct torture_suite *torture_rpc_netlogon(TALLOC_CTX *mem_ctx) - torture_rpc_tcase_add_test(tcase, "lsa_over_netlogon", test_lsa_over_netlogon); - torture_rpc_tcase_add_test_creds(tcase, "SetupCredentialsDowngrade", test_SetupCredentialsDowngrade); - -+ torture_rpc_tcase_add_test_creds( -+ tcase, -+ "ServerReqChallenge", -+ test_ServerReqChallenge); -+ torture_rpc_tcase_add_test_creds( -+ tcase, -+ "ServerReqChallenge_zero_challenge", -+ test_ServerReqChallenge_zero_challenge); -+ torture_rpc_tcase_add_test_creds( -+ tcase, -+ "ServerReqChallenge_5_repeats", -+ test_ServerReqChallenge_5_repeats); -+ torture_rpc_tcase_add_test_creds( -+ tcase, -+ "ServerReqChallenge_4_repeats", -+ test_ServerReqChallenge_4_repeats); - return suite; - } - --- -2.20.1 - diff --git a/CVE-2020-27840.patch b/CVE-2020-27840.patch deleted file mode 100644 index 7fd7b7565b684d9888631be57dd3ec60424ff348..0000000000000000000000000000000000000000 --- a/CVE-2020-27840.patch +++ /dev/null @@ -1,257 +0,0 @@ -From 44ed6c2263c2c969bec4229f99b37d8f2e09dde0 Mon Sep 17 00:00:00 2001 -From: Douglas Bagnall -Date: Thu, 11 Feb 2021 17:05:14 +1300 -Subject: [PATCH 1/3] CVE-2020-27840: pytests:segfault: add ldb.Dn validate - test - -ldb.Dn.validate wraps ldb_dn_explode. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14595 - -Signed-off-by: Douglas Bagnall -Reviewed-by: Andrew Bartlett ---- - python/samba/tests/segfault.py | 6 ++++++ - selftest/knownfail.d/python-segfaults | 1 + - 2 files changed, 7 insertions(+) - -diff --git a/python/samba/tests/segfault.py b/python/samba/tests/segfault.py -index 07e2d46d56a..70bd5b180e3 100644 ---- a/python/samba/tests/segfault.py -+++ b/python/samba/tests/segfault.py -@@ -174,3 +174,9 @@ class SegfaultTests(samba.tests.TestCase): - def test_dcerpc_idl_inline_arrays(self): - """Inline arrays were incorrectly handled.""" - dnsserver.DNS_RPC_SERVER_INFO_DOTNET().pExtensions -+ -+ @segfault_detector -+ def test_ldb_dn_explode_crash(self): -+ for i in range(106, 550, 5): -+ dn = ldb.Dn(ldb.Ldb(), "a=b%s,c= " % (' ' * i)) -+ dn.validate() -diff --git a/selftest/knownfail.d/python-segfaults b/selftest/knownfail.d/python-segfaults -index 1be0566dcb1..524f7dd013b 100644 ---- a/selftest/knownfail.d/python-segfaults -+++ b/selftest/knownfail.d/python-segfaults -@@ -1 +1,2 @@ - samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_init__3 -+samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_ldb_dn_explode_crash --- -2.25.1 - - -From 5fbc51a2cf77ebd7ca42cd7dda58d5fd0ec5127d Mon Sep 17 00:00:00 2001 -From: Douglas Bagnall -Date: Fri, 11 Dec 2020 16:32:25 +1300 -Subject: [PATCH 2/3] CVE-2020-27840 ldb_dn: avoid head corruption in - ldb_dn_explode - -A DN string with lots of trailing space can cause ldb_dn_explode() to -put a zero byte in the wrong place in the heap. - -When a DN string has a value represented with trailing spaces, -like this - - "CN=foo ,DC=bar" - -the whitespace is supposed to be ignored. We keep track of this in the -`t` pointer, which is NULL when we are not walking through trailing -spaces, and points to the first space when we are. We are walking with -the `p` pointer, writing the value to `d`, and keeping the length in -`l`. - - "CN=foo ,DC= " ==> "foo " - ^ ^ ^ - t p d - --l--- - -The value is finished when we encounter a comma or the end of the -string. If `t` is not NULL at that point, we assume there are trailing -spaces and wind `d and `l` back by the correct amount. Then we switch -to expecting an attribute name (e.g. "CN"), until we get to an "=", -which puts us back into looking for a value. - -Unfortunately, we forget to immediately tell `t` that we'd finished -the last value, we can end up like this: - - "CN=foo ,DC= " ==> "" - ^ ^ ^ - t p d - l=0 - -where `p` is pointing to a new value that contains only spaces, while -`t` is still referring to the old value. `p` notices the value ends, -and we subtract `p - t` from `d`: - - "CN=foo ,DC= " ==> ? "" - ^ ^ ^ - t p d - l ~= SIZE_MAX - 8 - -At that point `d` wants to terminate its string with a '\0', but -instead it terminates someone else's byte. This does not crash if the -number of trailing spaces is small, as `d` will point into a previous -value (a copy of "foo" in this example). Corrupting that value will -ultimately not matter, as we will soon try to allocate a buffer `l` -long, which will be greater than the available memory and the whole -operation will fail properly. - -However, with more spaces, `d` will point into memory before the -beginning of the allocated buffer, with the exact offset depending on -the length of the earlier attributes and the number of spaces. - -What about a longer DN with more attributes? For example, -"CN=foo ,DC= ,DC=example,DC=com" -- since `d` has moved out of -bounds, won't we continue to use it and write more DN values into -mystery memory? Fortunately not, because the aforementioned allocation -of `l` bytes must happen first, and `l` is now huge. The allocation -happens in a talloc_memdup(), which is by default restricted to -allocating 256MB. - -So this allows a person who controls a string parsed by ldb_dn_explode -to corrupt heap memory by placing a single zero byte at a chosen -offset before the allocated buffer. - -An LDAP bind request can send a string DN as a username. This DN is -necessarily parsed before the password is checked, so an attacker does -not need proper credentials. The attacker can easily cause a denial of -service and we cannot rule out more subtle attacks. - -The immediate solution is to reset `t` to NULL when a comma is -encountered, indicating that we are no longer looking at trailing -whitespace. - -Found with the help of Honggfuzz. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14595 - -Signed-off-by: Douglas Bagnall -Reviewed-by: Andrew Bartlett ---- - lib/ldb/common/ldb_dn.c | 1 + - selftest/knownfail.d/python-segfaults | 1 - - 2 files changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c -index 83f94e3b913..047244287f5 100644 ---- a/lib/ldb/common/ldb_dn.c -+++ b/lib/ldb/common/ldb_dn.c -@@ -570,6 +570,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) - /* trim back */ - d -= (p - t); - l -= (p - t); -+ t = NULL; - } - - in_attr = true; -diff --git a/selftest/knownfail.d/python-segfaults b/selftest/knownfail.d/python-segfaults -index 524f7dd013b..1be0566dcb1 100644 ---- a/selftest/knownfail.d/python-segfaults -+++ b/selftest/knownfail.d/python-segfaults -@@ -1,2 +1 @@ - samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_net_replicate_init__3 --samba.tests.segfault.samba.tests.segfault.SegfaultTests.test_ldb_dn_explode_crash --- -2.25.1 - - -From 90f08c437ce81f2a96ce0740a93aa00e94eb5f16 Mon Sep 17 00:00:00 2001 -From: Douglas Bagnall -Date: Thu, 11 Feb 2021 16:28:43 +1300 -Subject: [PATCH 3/3] CVE-2020-27840: pytests: move Dn.validate test to ldb - -We had the test in the Samba Python segfault suite because -a) the signal catching infrastructure was there, and -b) the ldb tests lack Samba's knownfail mechanism, which allowed us to - assert the failure. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14595 - -Signed-off-by: Douglas Bagnall -Reviewed-by: Andrew Bartlett ---- - lib/ldb/tests/python/crash.py | 45 ++++++++++++++++++++++++++++++++++ - lib/ldb/wscript | 1 + - python/samba/tests/segfault.py | 6 ----- - 3 files changed, 46 insertions(+), 6 deletions(-) - create mode 100644 lib/ldb/tests/python/crash.py - -diff --git a/lib/ldb/tests/python/crash.py b/lib/ldb/tests/python/crash.py -new file mode 100644 -index 00000000000..32839814552 ---- /dev/null -+++ b/lib/ldb/tests/python/crash.py -@@ -0,0 +1,45 @@ -+#!/usr/bin/env python3 -+# -+# Tests for crashing functions -+ -+import os -+from unittest import TestCase -+import os -+import sys -+import traceback -+ -+import ldb -+ -+ -+def segfault_detector(f): -+ def wrapper(*args, **kwargs): -+ pid = os.fork() -+ if pid == 0: -+ # child, crashing? -+ try: -+ f(*args, **kwargs) -+ except Exception as e: -+ traceback.print_exc() -+ sys.stderr.flush() -+ sys.stdout.flush() -+ os._exit(0) -+ -+ # parent, waiting -+ pid2, status = os.waitpid(pid, 0) -+ if os.WIFSIGNALED(status): -+ signal = os.WTERMSIG(status) -+ raise AssertionError("Failed with signal %d" % signal) -+ -+ return wrapper -+ -+ -+class LdbDnCrashTests(TestCase): -+ @segfault_detector -+ def test_ldb_dn_explode_crash(self): -+ for i in range(106, 150): -+ dn = ldb.Dn(ldb.Ldb(), "a=b%s,c= " % (' ' * i)) -+ dn.validate() -+ -+if __name__ == '__main__': -+ import unittest -+ unittest.TestProgram() -diff --git a/lib/ldb/wscript b/lib/ldb/wscript -index edc3343e827..33265da373a 100644 ---- a/lib/ldb/wscript -+++ b/lib/ldb/wscript -@@ -614,6 +614,7 @@ def test(ctx): - os.mkdir(tmp_dir) - pyret = samba_utils.RUN_PYTHON_TESTS( - ['tests/python/api.py', -+ 'tests/python/crash.py', - 'tests/python/index.py', - 'tests/python/repack.py'], - extra_env={'SELFTEST_PREFIX': test_prefix}) -diff --git a/python/samba/tests/segfault.py b/python/samba/tests/segfault.py -index 70bd5b180e3..07e2d46d56a 100644 ---- a/python/samba/tests/segfault.py -+++ b/python/samba/tests/segfault.py -@@ -174,9 +174,3 @@ class SegfaultTests(samba.tests.TestCase): - def test_dcerpc_idl_inline_arrays(self): - """Inline arrays were incorrectly handled.""" - dnsserver.DNS_RPC_SERVER_INFO_DOTNET().pExtensions -- -- @segfault_detector -- def test_ldb_dn_explode_crash(self): -- for i in range(106, 550, 5): -- dn = ldb.Dn(ldb.Ldb(), "a=b%s,c= " % (' ' * i)) -- dn.validate() --- -2.25.1 diff --git a/CVE-2021-20254.patch b/CVE-2021-20254.patch deleted file mode 100644 index 974e00ad5486e7cae19f628a9584388fb881248f..0000000000000000000000000000000000000000 --- a/CVE-2021-20254.patch +++ /dev/null @@ -1,234 +0,0 @@ -From 75ad84167f5d2379557ec078d17c9a1c244402fc Mon Sep 17 00:00:00 2001 -From: Volker Lendecke -Date: Sat, 20 Feb 2021 15:50:12 +0100 -Subject: [PATCH] CVE-2021-20254 passdb: Simplify sids_to_unixids() - -Best reviewed with "git show -b", there's a "continue" statement that -changes subsequent indentation. - -Decouple lookup status of ids from ID_TYPE_NOT_SPECIFIED - -Add comments to explain the use of the three lookup -loops. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14571 - -Signed-off-by: Volker Lendecke -Reviewed-by: Jeremy Allison - -Autobuild-User(master): Karolin Seeger -Autobuild-Date(master): Thu Apr 29 09:55:51 UTC 2021 on sn-devel-184 ---- - source3/passdb/lookup_sid.c | 123 +++++++++++++++++++++++++++++------- - 1 file changed, 101 insertions(+), 22 deletions(-) - -diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c -index cf80a300189..0e01467b3cb 100644 ---- a/source3/passdb/lookup_sid.c -+++ b/source3/passdb/lookup_sid.c -@@ -29,6 +29,7 @@ - #include "../libcli/security/security.h" - #include "lib/winbind_util.h" - #include "../librpc/gen_ndr/idmap.h" -+#include "lib/util/bitmap.h" - - static bool lookup_unix_user_name(const char *name, struct dom_sid *sid) - { -@@ -1266,7 +1267,9 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, - { - struct wbcDomainSid *wbc_sids = NULL; - struct wbcUnixId *wbc_ids = NULL; -+ struct bitmap *found = NULL; - uint32_t i, num_not_cached; -+ uint32_t wbc_ids_size = 0; - wbcErr err; - bool ret = false; - -@@ -1274,6 +1277,20 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, - if (wbc_sids == NULL) { - return false; - } -+ found = bitmap_talloc(wbc_sids, num_sids); -+ if (found == NULL) { -+ goto fail; -+ } -+ -+ /* -+ * We go through the requested SID array three times. -+ * First time to look for global_sid_Unix_Users -+ * and global_sid_Unix_Groups SIDS, and to look -+ * for mappings cached in the idmap_cache. -+ * -+ * Use bitmap_set() to mark an ids[] array entry as -+ * being mapped. -+ */ - - num_not_cached = 0; - -@@ -1285,17 +1302,20 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, - &sids[i], &rid)) { - ids[i].type = ID_TYPE_UID; - ids[i].id = rid; -+ bitmap_set(found, i); - continue; - } - if (sid_peek_check_rid(&global_sid_Unix_Groups, - &sids[i], &rid)) { - ids[i].type = ID_TYPE_GID; - ids[i].id = rid; -+ bitmap_set(found, i); - continue; - } - if (idmap_cache_find_sid2unixid(&sids[i], &ids[i], &expired) - && !expired) - { -+ bitmap_set(found, i); - continue; - } - ids[i].type = ID_TYPE_NOT_SPECIFIED; -@@ -1306,62 +1326,121 @@ bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids, - if (num_not_cached == 0) { - goto done; - } -- wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, num_not_cached); -+ -+ /* -+ * For the ones that we couldn't map in the loop above, query winbindd -+ * via wbcSidsToUnixIds(). -+ */ -+ -+ wbc_ids_size = num_not_cached; -+ wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, wbc_ids_size); - if (wbc_ids == NULL) { - goto fail; - } -- for (i=0; i id is a union anyway */ -- ids[i].type = (enum id_type)wbc_ids[num_not_cached].type; -- ids[i].id = wbc_ids[num_not_cached].id.gid; -- break; -- } -- num_not_cached += 1; -+ if (bitmap_query(found, i)) { -+ continue; -+ } -+ -+ SMB_ASSERT(num_not_cached < wbc_ids_size); -+ -+ switch (wbc_ids[num_not_cached].type) { -+ case WBC_ID_TYPE_UID: -+ ids[i].type = ID_TYPE_UID; -+ ids[i].id = wbc_ids[num_not_cached].id.uid; -+ bitmap_set(found, i); -+ break; -+ case WBC_ID_TYPE_GID: -+ ids[i].type = ID_TYPE_GID; -+ ids[i].id = wbc_ids[num_not_cached].id.gid; -+ bitmap_set(found, i); -+ break; -+ case WBC_ID_TYPE_BOTH: -+ ids[i].type = ID_TYPE_BOTH; -+ ids[i].id = wbc_ids[num_not_cached].id.uid; -+ bitmap_set(found, i); -+ break; -+ case WBC_ID_TYPE_NOT_SPECIFIED: -+ /* -+ * wbcSidsToUnixIds() wasn't able to map this -+ * so we still need to check legacy_sid_to_XXX() -+ * below. Don't mark the bitmap entry -+ * as being found so the final loop knows -+ * to try and map this entry. -+ */ -+ ids[i].type = ID_TYPE_NOT_SPECIFIED; -+ ids[i].id = (uint32_t)-1; -+ break; -+ default: -+ /* -+ * A successful return from wbcSidsToUnixIds() -+ * cannot return anything other than the values -+ * checked for above. Ensure this is so. -+ */ -+ smb_panic(__location__); -+ break; - } -+ num_not_cached += 1; - } - -+ /* -+ * Third and final time through the SID array, -+ * try legacy_sid_to_gid()/legacy_sid_to_uid() -+ * for entries we haven't already been able to -+ * map. -+ * -+ * Use bitmap_set() to mark an ids[] array entry as -+ * being mapped. -+ */ -+ - for (i=0; i -Date: Tue, 8 Dec 2020 21:32:09 +1300 -Subject: [PATCH] CVE-2021-20277 ldb/attrib_handlers casefold: stay in bounds - -For a string that had N spaces at the beginning, we would -try to move N bytes beyond the end of the string. - -BUG: https://bugzilla.samba.org/show_bug.cgi?id=14655 - -Signed-off-by: Douglas Bagnall -Reviewed-by: Andrew Bartlett - -(cherry-picked from commit for master) ---- - lib/ldb/common/attrib_handlers.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/ldb/common/attrib_handlers.c b/lib/ldb/common/attrib_handlers.c -index b5212b731596..c6ef5ad477b0 100644 ---- a/lib/ldb/common/attrib_handlers.c -+++ b/lib/ldb/common/attrib_handlers.c -@@ -76,7 +76,7 @@ int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx, - - /* remove leading spaces if any */ - if (*s == ' ') { -- for (t = s; *s == ' '; s++) ; -+ for (t = s; *s == ' '; s++, l--) ; - - /* remove leading spaces by moving down the string */ - memmove(t, s, l); diff --git a/backport-0001-CVE-2018-14628.patch b/backport-0001-CVE-2018-14628.patch new file mode 100644 index 0000000000000000000000000000000000000000..51e7857f03d50f97f47cd1728e402fafa5a3540a --- /dev/null +++ b/backport-0001-CVE-2018-14628.patch @@ -0,0 +1,49 @@ +From 890cf42b13b0debea20751a230dd45363523944a Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 29 Jan 2016 23:30:59 +0100 +Subject: [PATCH 1/6] CVE-2018-14628: python:descriptor: add + get_deletedobjects_descriptor() + +samba-tool drs clone-dc-database was quite useful to find +the true value of nTSecurityDescriptor of the CN=Delete Objects +containers. + +Only the auto inherited SACL is available via a ldap search. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13595 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +(cherry picked from commit 3be190dcf7153e479383f7f3d29ddca43fe121b8) + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=18168 +[PATCH 1/6] CVE-2018-14628: python:descriptor: add + get_deletedobjects_descriptor() +--- + python/samba/descriptor.py | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/python/samba/descriptor.py b/python/samba/descriptor.py +index ac4c7e3273de..08c7518f56ab 100644 +--- a/python/samba/descriptor.py ++++ b/python/samba/descriptor.py +@@ -52,6 +52,16 @@ def get_empty_descriptor(domain_sid, name_map={}): + # "get_schema_descriptor" is located in "schema.py" + + ++def get_deletedobjects_descriptor(domain_sid, name_map=None): ++ if name_map is None: ++ name_map = {} ++ ++ sddl = "O:SYG:SYD:PAI" \ ++ "(A;;RPWPCCDCLCRCWOWDSDSW;;;SY)" \ ++ "(A;;RPLC;;;BA)" ++ return sddl2binary(sddl, domain_sid, name_map) ++ ++ + def get_config_descriptor(domain_sid, name_map={}): + sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ + "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \ +-- +2.34.1 diff --git a/backport-0001-CVE-2022-2127.patch b/backport-0001-CVE-2022-2127.patch new file mode 100644 index 0000000000000000000000000000000000000000..55aa50cfec4e41b0f5a97eb93288b3915420511f --- /dev/null +++ b/backport-0001-CVE-2022-2127.patch @@ -0,0 +1,73 @@ +From a3944de6990686bf674e7a9badded501873a7cfa Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Fri, 20 May 2022 10:55:23 +0200 +Subject: [PATCH 01/28] CVE-2022-2127: winbindd: Fix WINBINDD_PAM_AUTH_CRAP + length checks + +With WBFLAG_BIG_NTLMV2_BLOB being set plus lm_resp_len too large you +can crash winbind. We don't independently check lm_resp_len +sufficiently. + +Discovered via Coverity ID 1504444 Out-of-bounds access + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15072 + +Signed-off-by: Volker Lendecke + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/winbindd/winbindd_pam_auth_crap.c | 31 +++++++++++++++-------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/source3/winbindd/winbindd_pam_auth_crap.c b/source3/winbindd/winbindd_pam_auth_crap.c +index 6120522ce3c..e6a32c7ed79 100644 +--- a/source3/winbindd/winbindd_pam_auth_crap.c ++++ b/source3/winbindd/winbindd_pam_auth_crap.c +@@ -52,6 +52,9 @@ struct tevent_req *winbindd_pam_auth_crap_send( + DATA_BLOB chal = data_blob_null; + struct wbint_SidArray *require_membership_of_sid = NULL; + NTSTATUS status; ++ bool lmlength_ok = false; ++ bool ntlength_ok = false; ++ bool pwlength_ok = false; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_pam_auth_crap_state); +@@ -115,16 +118,24 @@ struct tevent_req *winbindd_pam_auth_crap_send( + fstrcpy(request->data.auth_crap.workstation, lp_netbios_name()); + } + +- if (request->data.auth_crap.lm_resp_len > sizeof(request->data.auth_crap.lm_resp) +- || request->data.auth_crap.nt_resp_len > sizeof(request->data.auth_crap.nt_resp)) { +- if (!(request->flags & WBFLAG_BIG_NTLMV2_BLOB) || +- request->extra_len != request->data.auth_crap.nt_resp_len) { +- DBG_ERR("Invalid password length %u/%u\n", +- request->data.auth_crap.lm_resp_len, +- request->data.auth_crap.nt_resp_len); +- tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); +- return tevent_req_post(req, ev); +- } ++ lmlength_ok = (request->data.auth_crap.lm_resp_len <= ++ sizeof(request->data.auth_crap.lm_resp)); ++ ++ ntlength_ok = (request->data.auth_crap.nt_resp_len <= ++ sizeof(request->data.auth_crap.nt_resp)); ++ ++ ntlength_ok |= ++ ((request->flags & WBFLAG_BIG_NTLMV2_BLOB) && ++ (request->extra_len == request->data.auth_crap.nt_resp_len)); ++ ++ pwlength_ok = lmlength_ok && ntlength_ok; ++ ++ if (!pwlength_ok) { ++ DBG_ERR("Invalid password length %u/%u\n", ++ request->data.auth_crap.lm_resp_len, ++ request->data.auth_crap.nt_resp_len); ++ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); ++ return tevent_req_post(req, ev); + } + + state->domain = talloc_strdup(state, request->data.auth_crap.domain); +-- +2.34.1 diff --git a/backport-0001-CVE-2023-0225.patch b/backport-0001-CVE-2023-0225.patch new file mode 100644 index 0000000000000000000000000000000000000000..1f6fe7ddf16a81e9e314ebd55e6ad5652ae205e7 --- /dev/null +++ b/backport-0001-CVE-2023-0225.patch @@ -0,0 +1,93 @@ +From 0bc08daf4c191c370cb218e9a0ecac51b8c36468 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Thu, 28 Apr 2022 20:34:36 +1200 +Subject: [PATCH 1/4] CVE-2023-0225 CVE-2020-25720 s4/dsdb/util: Add functions + for dsHeuristics 28, 29 + +These are the newly-added AttributeAuthorizationOnLDAPAdd and +BlockOwnerImplicitRights. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14810 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15276 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett +(cherry picked from commit 0af5706b559e89c77123ed174b41fd3d01705aa5) + +[abartlet@samba.org This patch is needed for a clean backport of + CVE-2023-0225 as these constants are used in the acl_modify test + even when this behaviour is not itself used.] + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17833 +--- + libds/common/flags.h | 2 ++ + source4/dsdb/samdb/ldb_modules/util.c | 40 +++++++++++++++++++++++++++ + 2 files changed, 42 insertions(+) + +diff --git a/libds/common/flags.h b/libds/common/flags.h +index 75e04b0c488..bee1016b294 100644 +--- a/libds/common/flags.h ++++ b/libds/common/flags.h +@@ -258,6 +258,8 @@ + #define DS_HR_KVNOEMUW2K 0x00000011 + + #define DS_HR_TWENTIETH_CHAR 0x00000014 ++#define DS_HR_ATTR_AUTHZ_ON_LDAP_ADD 0x0000001C ++#define DS_HR_BLOCK_OWNER_IMPLICIT_RIGHTS 0x0000001D + #define DS_HR_THIRTIETH_CHAR 0x0000001E + #define DS_HR_FOURTIETH_CHAR 0x00000028 + #define DS_HR_FIFTIETH_CHAR 0x00000032 +diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c +index 9e00aedd09e..c2949f0734d 100644 +--- a/source4/dsdb/samdb/ldb_modules/util.c ++++ b/source4/dsdb/samdb/ldb_modules/util.c +@@ -1433,6 +1433,46 @@ bool dsdb_do_list_object(struct ldb_module *module, + return result; + } + ++bool dsdb_attribute_authz_on_ldap_add(struct ldb_module *module, ++ TALLOC_CTX *mem_ctx, ++ struct ldb_request *parent) ++{ ++ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); ++ bool result = false; ++ const struct ldb_val *hr_val = dsdb_module_find_dsheuristics(module, ++ tmp_ctx, ++ parent); ++ if (hr_val != NULL && hr_val->length >= DS_HR_ATTR_AUTHZ_ON_LDAP_ADD) { ++ uint8_t val = hr_val->data[DS_HR_ATTR_AUTHZ_ON_LDAP_ADD - 1]; ++ if (val != '0' && val != '2') { ++ result = true; ++ } ++ } ++ ++ talloc_free(tmp_ctx); ++ return result; ++} ++ ++bool dsdb_block_owner_implicit_rights(struct ldb_module *module, ++ TALLOC_CTX *mem_ctx, ++ struct ldb_request *parent) ++{ ++ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); ++ bool result = false; ++ const struct ldb_val *hr_val = dsdb_module_find_dsheuristics(module, ++ tmp_ctx, ++ parent); ++ if (hr_val != NULL && hr_val->length >= DS_HR_BLOCK_OWNER_IMPLICIT_RIGHTS) { ++ uint8_t val = hr_val->data[DS_HR_BLOCK_OWNER_IMPLICIT_RIGHTS - 1]; ++ if (val != '0' && val != '2') { ++ result = true; ++ } ++ } ++ ++ talloc_free(tmp_ctx); ++ return result; ++} ++ + /* + show the chain of requests, useful for debugging async requests + */ +-- +2.25.1 \ No newline at end of file diff --git a/backport-0001-CVE-2023-0614.patch b/backport-0001-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..47c3049e1f068dbebf57f7431ceb0450a1b7fae9 --- /dev/null +++ b/backport-0001-CVE-2023-0614.patch @@ -0,0 +1,174 @@ +From 197d1f09158ee0575cd92c461ed12bdbf4efc074 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 13 Mar 2023 14:25:56 +1300 +Subject: [PATCH 01/35] CVE-2023-0614 lib/ldb: Avoid allocation and memcpy() + for every wildcard match candidate + +The value can be quite large, the allocation will take much +longer than the actual match and is repeated per candidate +record. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15331 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton +(cherry picked from commit cad96f59a08192df927fb1df4e9787c7f70991a2) + +[abartlet@samba.org Included in the security release as this + makes the new large_ldap.py timeout test more reliable] + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb/common/ldb_match.c | 60 +++++++++++++++++++++++++++++++------- + 1 file changed, 50 insertions(+), 10 deletions(-) + +diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c +index 2f4d41f3441..51376871b4c 100644 +--- a/lib/ldb/common/ldb_match.c ++++ b/lib/ldb/common/ldb_match.c +@@ -34,6 +34,7 @@ + + #include "ldb_private.h" + #include "dlinklist.h" ++#include "ldb_handlers.h" + + /* + check if the scope matches in a search result +@@ -259,20 +260,42 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, + return LDB_SUCCESS; + } + +- if (a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) { +- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; ++ /* No need to just copy this value for a binary match */ ++ if (a->syntax->canonicalise_fn != ldb_handler_copy) { ++ if (a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) { ++ return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; ++ } ++ ++ /* ++ * Only set save_p if we allocate (call ++ * a->syntax->canonicalise_fn()), as we ++ * talloc_free(save_p) below to clean up ++ */ ++ save_p = val.data; ++ } else { ++ val = value; + } + +- save_p = val.data; + cnk.data = NULL; + + if ( ! tree->u.substring.start_with_wildcard ) { ++ uint8_t *cnk_to_free = NULL; + + chunk = tree->u.substring.chunks[c]; +- if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch; ++ /* No need to just copy this value for a binary match */ ++ if (a->syntax->canonicalise_fn != ldb_handler_copy) { ++ if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) { ++ goto mismatch; ++ } ++ ++ cnk_to_free = cnk.data; ++ } else { ++ cnk = *chunk; ++ } + + /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */ + if (cnk.length > val.length) { ++ TALLOC_FREE(cnk_to_free); + goto mismatch; + } + /* +@@ -280,32 +303,47 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, + * we can cope with this. + */ + if (cnk.length == 0) { ++ TALLOC_FREE(cnk_to_free); ++ goto mismatch; ++ } ++ ++ if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) { ++ TALLOC_FREE(cnk_to_free); + goto mismatch; + } + +- if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto mismatch; + val.length -= cnk.length; + val.data += cnk.length; + c++; +- talloc_free(cnk.data); ++ TALLOC_FREE(cnk_to_free); + cnk.data = NULL; + } + + while (tree->u.substring.chunks[c]) { + uint8_t *p; ++ uint8_t *cnk_to_free = NULL; + + chunk = tree->u.substring.chunks[c]; +- if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) { +- goto mismatch; ++ /* No need to just copy this value for a binary match */ ++ if (a->syntax->canonicalise_fn != ldb_handler_copy) { ++ if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) { ++ goto mismatch; ++ } ++ ++ cnk_to_free = cnk.data; ++ } else { ++ cnk = *chunk; + } + /* + * Empty strings are returned as length 0. Ensure + * we can cope with this. + */ + if (cnk.length == 0) { ++ TALLOC_FREE(cnk_to_free); + goto mismatch; + } + if (cnk.length > val.length) { ++ TALLOC_FREE(cnk_to_free); + goto mismatch; + } + +@@ -320,6 +358,8 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, + cmp = memcmp(p, + cnk.data, + cnk.length); ++ TALLOC_FREE(cnk_to_free); ++ + if (cmp != 0) { + goto mismatch; + } +@@ -331,15 +371,16 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, + p = memmem((const void *)val.data, val.length, + (const void *)cnk.data, cnk.length); + if (p == NULL) { ++ TALLOC_FREE(cnk_to_free); + goto mismatch; + } + /* move val to the end of the match */ + p += cnk.length; + val.length -= (p - val.data); + val.data = p; ++ TALLOC_FREE(cnk_to_free); + } + c++; +- TALLOC_FREE(cnk.data); + } + + talloc_free(save_p); +@@ -349,7 +390,6 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, + mismatch: + *matched = false; + talloc_free(save_p); +- talloc_free(cnk.data); + return LDB_SUCCESS; + } + +-- +2.25.1 \ No newline at end of file diff --git a/backport-0001-CVE-2023-3347.patch b/backport-0001-CVE-2023-3347.patch new file mode 100644 index 0000000000000000000000000000000000000000..7567a73596a3ca3581f9e8146cd05739621208f8 --- /dev/null +++ b/backport-0001-CVE-2023-3347.patch @@ -0,0 +1,139 @@ +From e67b7e5f88ea29670009eef6a69e3f60ebed3517 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 20 Jun 2023 12:46:31 +0200 +Subject: [PATCH 18/28] CVE-2023-3347: CI: add a test for server-side mandatory + signing + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15397 + +Signed-off-by: Ralph Boehme + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + .../samba3.smb2.session-require-signing | 1 + + selftest/target/Samba3.pm | 1 + + source3/selftest/tests.py | 2 + + source4/torture/smb2/session.c | 64 +++++++++++++++++++ + source4/torture/smb2/smb2.c | 1 + + 5 files changed, 69 insertions(+) + create mode 100644 selftest/knownfail.d/samba3.smb2.session-require-signing + +diff --git a/selftest/knownfail.d/samba3.smb2.session-require-signing b/selftest/knownfail.d/samba3.smb2.session-require-signing +new file mode 100644 +index 00000000000..53b7a7022a8 +--- /dev/null ++++ b/selftest/knownfail.d/samba3.smb2.session-require-signing +@@ -0,0 +1 @@ ++^samba3.smb2.session-require-signing.bug15397 +diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm +index 9c590547c94..3336c5b8e97 100755 +--- a/selftest/target/Samba3.pm ++++ b/selftest/target/Samba3.pm +@@ -1294,6 +1294,7 @@ sub setup_ad_member_idmap_rid + # values required for tests to succeed + create krb5 conf = no + map to guest = bad user ++ server signing = required + "; + + my $ret = $self->provision( +diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py +index 04349c1f1f7..887bf6d5293 100755 +--- a/source3/selftest/tests.py ++++ b/source3/selftest/tests.py +@@ -938,6 +938,8 @@ for t in tests: + # Certain tests fail when run against ad_member with MIT kerberos because the private krb5.conf overrides the provisioned lib/krb5.conf, + # ad_member_idmap_rid sets "create krb5.conf = no" + plansmbtorture4testsuite(t, "ad_member_idmap_rid", '//$SERVER/tmp -k yes -U$DC_USERNAME@$REALM%$DC_PASSWORD', 'krb5') ++ elif t == "smb2.session-require-signing": ++ plansmbtorture4testsuite(t, "ad_member_idmap_rid", '//$SERVER_IP/tmp -U$DC_USERNAME@$REALM%$DC_PASSWORD') + elif t == "rpc.lsa": + plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD', 'over ncacn_np ') + plansmbtorture4testsuite(t, "nt4_dc", 'ncacn_ip_tcp:$SERVER_IP -U$USERNAME%$PASSWORD', 'over ncacn_ip_tcp ') +diff --git a/source4/torture/smb2/session.c b/source4/torture/smb2/session.c +index 92f9e638ff4..e417008cad7 100644 +--- a/source4/torture/smb2/session.c ++++ b/source4/torture/smb2/session.c +@@ -5498,3 +5498,67 @@ struct torture_suite *torture_smb2_session_init(TALLOC_CTX *ctx) + + return suite; + } ++ ++static bool test_session_require_sign_bug15397(struct torture_context *tctx, ++ struct smb2_tree *_tree) ++{ ++ const char *host = torture_setting_string(tctx, "host", NULL); ++ const char *share = torture_setting_string(tctx, "share", NULL); ++ struct cli_credentials *_creds = samba_cmdline_get_creds(); ++ struct cli_credentials *creds = NULL; ++ struct smbcli_options options; ++ struct smb2_tree *tree = NULL; ++ uint8_t security_mode; ++ NTSTATUS status; ++ bool ok = true; ++ ++ /* ++ * Setup our own connection so we can control the signing flags ++ */ ++ ++ creds = cli_credentials_shallow_copy(tctx, _creds); ++ torture_assert(tctx, creds != NULL, "cli_credentials_shallow_copy"); ++ ++ options = _tree->session->transport->options; ++ options.client_guid = GUID_random(); ++ options.signing = SMB_SIGNING_IF_REQUIRED; ++ ++ status = smb2_connect(tctx, ++ host, ++ lpcfg_smb_ports(tctx->lp_ctx), ++ share, ++ lpcfg_resolve_context(tctx->lp_ctx), ++ creds, ++ &tree, ++ tctx->ev, ++ &options, ++ lpcfg_socket_options(tctx->lp_ctx), ++ lpcfg_gensec_settings(tctx, tctx->lp_ctx)); ++ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, ++ "smb2_connect failed"); ++ ++ security_mode = smb2cli_session_security_mode(tree->session->smbXcli); ++ ++ torture_assert_int_equal_goto( ++ tctx, ++ security_mode, ++ SMB2_NEGOTIATE_SIGNING_REQUIRED | SMB2_NEGOTIATE_SIGNING_ENABLED, ++ ok, ++ done, ++ "Signing not required"); ++ ++done: ++ return ok; ++} ++ ++struct torture_suite *torture_smb2_session_req_sign_init(TALLOC_CTX *ctx) ++{ ++ struct torture_suite *suite = ++ torture_suite_create(ctx, "session-require-signing"); ++ ++ torture_suite_add_1smb2_test(suite, "bug15397", ++ test_session_require_sign_bug15397); ++ ++ suite->description = talloc_strdup(suite, "SMB2-SESSION require signing tests"); ++ return suite; ++} +diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c +index c717db50b70..8621f09d820 100644 +--- a/source4/torture/smb2/smb2.c ++++ b/source4/torture/smb2/smb2.c +@@ -189,6 +189,7 @@ NTSTATUS torture_smb2_init(TALLOC_CTX *ctx) + torture_suite_add_suite(suite, torture_smb2_sharemode_init(suite)); + torture_suite_add_1smb2_test(suite, "hold-oplock", test_smb2_hold_oplock); + torture_suite_add_suite(suite, torture_smb2_session_init(suite)); ++ torture_suite_add_suite(suite, torture_smb2_session_req_sign_init(suite)); + torture_suite_add_suite(suite, torture_smb2_replay_init(suite)); + torture_suite_add_simple_test(suite, "dosmode", torture_smb2_dosmode); + torture_suite_add_simple_test(suite, "async_dosmode", torture_smb2_async_dosmode); +-- +2.34.1 diff --git a/backport-0001-CVE-2023-34966.patch b/backport-0001-CVE-2023-34966.patch new file mode 100644 index 0000000000000000000000000000000000000000..98f542968c2d1b8c92e160a7a2f75163c3e9aa57 --- /dev/null +++ b/backport-0001-CVE-2023-34966.patch @@ -0,0 +1,137 @@ +From 6e5e5c7f64eef80e10473e860a1662ce66491e8e Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Wed, 31 May 2023 15:34:26 +0200 +Subject: [PATCH 03/28] CVE-2023-34966: CI: test for sl_unpack_loop() + +Send a maliciously crafted packet where a nil type has a subcount of 0. This +triggers an endless loop in mdssvc sl_unpack_loop(). + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15340 + +Signed-off-by: Ralph Boehme + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source4/torture/rpc/mdssvc.c | 100 +++++++++++++++++++++++++++++++++++ + 1 file changed, 100 insertions(+) + +diff --git a/source4/torture/rpc/mdssvc.c b/source4/torture/rpc/mdssvc.c +index 8f16af66476..d0a2d33cf9e 100644 +--- a/source4/torture/rpc/mdssvc.c ++++ b/source4/torture/rpc/mdssvc.c +@@ -569,6 +569,102 @@ done: + return ok; + } + ++static uint8_t test_sl_unpack_loop_buf[] = { ++ 0x34, 0x33, 0x32, 0x31, 0x33, 0x30, 0x64, 0x6d, ++ 0x1d, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, ++ 0x06, 0x00, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, ++ 0x66, 0x65, 0x74, 0x63, 0x68, 0x41, 0x74, 0x74, ++ 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x3a, ++ 0x66, 0x6f, 0x72, 0x4f, 0x49, 0x44, 0x41, 0x72, ++ 0x72, 0x61, 0x79, 0x3a, 0x63, 0x6f, 0x6e, 0x74, ++ 0x65, 0x78, 0x74, 0x3a, 0x00, 0x00, 0x00, 0xea, ++ 0x02, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, 0x00, ++ 0x0a, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, ++ 0x6b, 0x4d, 0x44, 0x49, 0x74, 0x65, 0x6d, 0x50, ++ 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x02, 0x06, 0x00, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x87, 0x08, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0xdd, 0x0a, 0x20, 0x00, 0x00, 0x6b, ++ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x00, ++ 0x0e, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, ++ 0x0f, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x00, ++ 0x13, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00 ++}; ++ ++static bool test_mdssvc_sl_unpack_loop(struct torture_context *tctx, ++ void *data) ++{ ++ struct torture_mdsscv_state *state = talloc_get_type_abort( ++ data, struct torture_mdsscv_state); ++ struct dcerpc_binding_handle *b = state->p->binding_handle; ++ struct mdssvc_blob request_blob; ++ struct mdssvc_blob response_blob; ++ uint32_t device_id; ++ uint32_t unkn2; ++ uint32_t unkn9; ++ uint32_t fragment; ++ uint32_t flags; ++ NTSTATUS status; ++ bool ok = true; ++ ++ device_id = UINT32_C(0x2f000045); ++ unkn2 = 23; ++ unkn9 = 0; ++ fragment = 0; ++ flags = UINT32_C(0x6b000001); ++ ++ request_blob.spotlight_blob = test_sl_unpack_loop_buf; ++ request_blob.size = sizeof(test_sl_unpack_loop_buf); ++ request_blob.length = sizeof(test_sl_unpack_loop_buf); ++ ++ response_blob.spotlight_blob = talloc_array(state, ++ uint8_t, ++ 0); ++ torture_assert_not_null_goto(tctx, response_blob.spotlight_blob, ++ ok, done, "dalloc_zero failed\n"); ++ response_blob.size = 0; ++ ++ status = dcerpc_mdssvc_cmd(b, ++ state, ++ &state->ph, ++ 0, ++ device_id, ++ unkn2, ++ 0, ++ flags, ++ request_blob, ++ 0, ++ 64 * 1024, ++ 1, ++ 64 * 1024, ++ 0, ++ 0, ++ &fragment, ++ &response_blob, ++ &unkn9); ++ torture_assert_ntstatus_ok_goto( ++ tctx, status, ok, done, ++ "dcerpc_mdssvc_unknown1 failed\n"); ++ ++done: ++ return ok; ++} ++ + static bool test_mdssvc_invalid_ph_close(struct torture_context *tctx, + void *data) + { +@@ -840,5 +936,9 @@ struct torture_suite *torture_rpc_mdssvc(TALLOC_CTX *mem_ctx) + "fetch_unknown_cnid", + test_mdssvc_fetch_attr_unknown_cnid); + ++ torture_tcase_add_simple_test(tcase, ++ "mdssvc_sl_unpack_loop", ++ test_mdssvc_sl_unpack_loop); ++ + return suite; + } +-- +2.34.1 diff --git a/backport-0001-CVE-2023-34967.patch b/backport-0001-CVE-2023-34967.patch new file mode 100644 index 0000000000000000000000000000000000000000..8b0bf3401bfc77a1493537e72da3b81db3a2ddfa --- /dev/null +++ b/backport-0001-CVE-2023-34967.patch @@ -0,0 +1,174 @@ +From 7812c56d4cb44a59a49c68d05a9c38c1d2ebeb19 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Wed, 31 May 2023 16:26:14 +0200 +Subject: [PATCH 05/28] CVE-2023-34967: CI: add a test for type checking of + dalloc_value_for_key() + +Sends a maliciously crafted packet where the value in a key/value style +dictionary for the "scope" key is a simple string object whereas the server +expects an array. As the server doesn't perform type validation on the value, it +crashes when trying to use the "simple" object as a "complex" one. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15341 + +Signed-off-by: Ralph Boehme + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source4/torture/rpc/mdssvc.c | 134 +++++++++++++++++++++++++++++++++++ + 1 file changed, 134 insertions(+) + +diff --git a/source4/torture/rpc/mdssvc.c b/source4/torture/rpc/mdssvc.c +index d0a2d33cf9e..3689692f7de 100644 +--- a/source4/torture/rpc/mdssvc.c ++++ b/source4/torture/rpc/mdssvc.c +@@ -665,6 +665,136 @@ done: + return ok; + } + ++static bool test_sl_dict_type_safety(struct torture_context *tctx, ++ void *data) ++{ ++ struct torture_mdsscv_state *state = talloc_get_type_abort( ++ data, struct torture_mdsscv_state); ++ struct dcerpc_binding_handle *b = state->p->binding_handle; ++ struct mdssvc_blob request_blob; ++ struct mdssvc_blob response_blob; ++ uint64_t ctx1 = 0xdeadbeef; ++ uint64_t ctx2 = 0xcafebabe; ++ uint32_t device_id; ++ uint32_t unkn2; ++ uint32_t unkn9; ++ uint32_t fragment; ++ uint32_t flags; ++ DALLOC_CTX *d = NULL; ++ sl_array_t *array1 = NULL, *array2 = NULL; ++ sl_dict_t *arg = NULL; ++ int result; ++ NTSTATUS status; ++ bool ok = true; ++ ++ device_id = UINT32_C(0x2f000045); ++ unkn2 = 23; ++ unkn9 = 0; ++ fragment = 0; ++ flags = UINT32_C(0x6b000001); ++ ++ d = dalloc_new(tctx); ++ torture_assert_not_null_goto(tctx, d, ++ ok, done, "dalloc_new failed\n"); ++ ++ array1 = dalloc_zero(d, sl_array_t); ++ torture_assert_not_null_goto(tctx, array1, ++ ok, done, "dalloc_zero failed\n"); ++ ++ array2 = dalloc_zero(d, sl_array_t); ++ torture_assert_not_null_goto(tctx, array2, ++ ok, done, "dalloc_new failed\n"); ++ ++ result = dalloc_stradd(array2, "openQueryWithParams:forContext:"); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ result = dalloc_add_copy(array2, &ctx1, uint64_t); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ result = dalloc_add_copy(array2, &ctx2, uint64_t); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ arg = dalloc_zero(array1, sl_dict_t); ++ torture_assert_not_null_goto(tctx, d, ++ ok, done, "dalloc_zero failed\n"); ++ ++ result = dalloc_stradd(arg, "kMDQueryString"); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ result = dalloc_stradd(arg, "*"); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ result = dalloc_stradd(arg, "kMDScopeArray"); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ result = dalloc_stradd(arg, "AAAABBBB"); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ result = dalloc_add(array1, array2, sl_array_t); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_add failed\n"); ++ ++ result = dalloc_add(array1, arg, sl_dict_t); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_add failed\n"); ++ ++ result = dalloc_add(d, array1, sl_array_t); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_add failed\n"); ++ ++ torture_comment(tctx, "%s", dalloc_dump(d, 0)); ++ ++ request_blob.spotlight_blob = talloc_array(tctx, ++ uint8_t, ++ 64 * 1024); ++ torture_assert_not_null_goto(tctx, request_blob.spotlight_blob, ++ ok, done, "dalloc_new failed\n"); ++ request_blob.size = 64 * 1024; ++ ++ request_blob.length = sl_pack(d, ++ (char *)request_blob.spotlight_blob, ++ request_blob.size); ++ torture_assert_goto(tctx, request_blob.length > 0, ++ ok, done, "sl_pack failed\n"); ++ ++ response_blob.spotlight_blob = talloc_array(state, uint8_t, 0); ++ torture_assert_not_null_goto(tctx, response_blob.spotlight_blob, ++ ok, done, "dalloc_zero failed\n"); ++ response_blob.size = 0; ++ ++ status = dcerpc_mdssvc_cmd(b, ++ state, ++ &state->ph, ++ 0, ++ device_id, ++ unkn2, ++ 0, ++ flags, ++ request_blob, ++ 0, ++ 64 * 1024, ++ 1, ++ 64 * 1024, ++ 0, ++ 0, ++ &fragment, ++ &response_blob, ++ &unkn9); ++ torture_assert_ntstatus_ok_goto( ++ tctx, status, ok, done, ++ "dcerpc_mdssvc_cmd failed\n"); ++ ++done: ++ return ok; ++} ++ + static bool test_mdssvc_invalid_ph_close(struct torture_context *tctx, + void *data) + { +@@ -940,5 +1070,9 @@ struct torture_suite *torture_rpc_mdssvc(TALLOC_CTX *mem_ctx) + "mdssvc_sl_unpack_loop", + test_mdssvc_sl_unpack_loop); + ++ torture_tcase_add_simple_test(tcase, ++ "sl_dict_type_safety", ++ test_sl_dict_type_safety); ++ + return suite; + } +-- +2.34.1 diff --git a/backport-0001-CVE-2023-34968.patch b/backport-0001-CVE-2023-34968.patch new file mode 100644 index 0000000000000000000000000000000000000000..a7db9912f5d6f179d29a8e606f44fb7ce7ee5063 --- /dev/null +++ b/backport-0001-CVE-2023-34968.patch @@ -0,0 +1,101 @@ +From 98b2a013bc723cd660978d5a1db40b987816f90e Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 6 Jun 2023 15:17:26 +0200 +Subject: [PATCH 07/28] CVE-2023-34968: mdssvc: cache and reuse stat info in + struct sl_inode_path_map + +Prepare for the "path" being a fake path and not the real server-side +path where we won't be able to vfs_stat_fsp() this fake path. Luckily we already +got stat info for the object in mds_add_result() so we can just pass stat info +from there. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/rpc_server/mdssvc/mdssvc.c | 32 +++++++----------------------- + source3/rpc_server/mdssvc/mdssvc.h | 1 + + 2 files changed, 8 insertions(+), 25 deletions(-) + +diff --git a/source3/rpc_server/mdssvc/mdssvc.c b/source3/rpc_server/mdssvc/mdssvc.c +index 7dd3c84713f..a6d09a43b9c 100644 +--- a/source3/rpc_server/mdssvc/mdssvc.c ++++ b/source3/rpc_server/mdssvc/mdssvc.c +@@ -446,7 +446,10 @@ static int ino_path_map_destr_cb(struct sl_inode_path_map *entry) + * entries by calling talloc_free() on the query slq handles. + **/ + +-static bool inode_map_add(struct sl_query *slq, uint64_t ino, const char *path) ++static bool inode_map_add(struct sl_query *slq, ++ uint64_t ino, ++ const char *path, ++ struct stat_ex *st) + { + NTSTATUS status; + struct sl_inode_path_map *entry; +@@ -493,6 +496,7 @@ static bool inode_map_add(struct sl_query *slq, uint64_t ino, const char *path) + + entry->ino = ino; + entry->mds_ctx = slq->mds_ctx; ++ entry->st = *st; + entry->path = talloc_strdup(entry, path); + if (entry->path == NULL) { + DEBUG(1, ("talloc failed\n")); +@@ -617,7 +621,7 @@ bool mds_add_result(struct sl_query *slq, const char *path) + return false; + } + +- ok = inode_map_add(slq, ino64, path); ++ ok = inode_map_add(slq, ino64, path, &sb); + if (!ok) { + DEBUG(1, ("inode_map_add error\n")); + slq->state = SLQ_STATE_ERROR; +@@ -1340,29 +1344,7 @@ static bool slrpc_fetch_attributes(struct mds_ctx *mds_ctx, + elem = talloc_get_type_abort(p, struct sl_inode_path_map); + path = elem->path; + +- status = synthetic_pathref(talloc_tos(), +- mds_ctx->conn->cwd_fsp, +- path, +- NULL, +- NULL, +- 0, +- 0, +- &smb_fname); +- if (!NT_STATUS_IS_OK(status)) { +- /* This is not an error, the user may lack permissions */ +- DBG_DEBUG("synthetic_pathref [%s]: %s\n", +- smb_fname_str_dbg(smb_fname), +- nt_errstr(status)); +- return true; +- } +- +- status = vfs_stat_fsp(smb_fname->fsp); +- if (!NT_STATUS_IS_OK(status)) { +- TALLOC_FREE(smb_fname); +- return true; +- } +- +- sp = &smb_fname->fsp->fsp_name->st; ++ sp = &elem->st; + } + + ok = add_filemeta(mds_ctx, reqinfo, fm_array, path, sp); +diff --git a/source3/rpc_server/mdssvc/mdssvc.h b/source3/rpc_server/mdssvc/mdssvc.h +index 205417c4be1..ff36b329f2b 100644 +--- a/source3/rpc_server/mdssvc/mdssvc.h ++++ b/source3/rpc_server/mdssvc/mdssvc.h +@@ -105,6 +105,7 @@ struct sl_inode_path_map { + struct mds_ctx *mds_ctx; + uint64_t ino; + char *path; ++ struct stat_ex st; + }; + + /* Per process state */ +-- +2.34.1 diff --git a/backport-0001-CVE-2023-3961.patch b/backport-0001-CVE-2023-3961.patch new file mode 100644 index 0000000000000000000000000000000000000000..53e3cf8f2090323e95c5884b7a78d79a1cdef194 --- /dev/null +++ b/backport-0001-CVE-2023-3961.patch @@ -0,0 +1,52 @@ +From e5a1c1cfb0a73a37001afee530ae09bf5c58b515 Mon Sep 17 00:00:00 2001 +From: Jeremy Allison +Date: Tue, 25 Jul 2023 17:41:04 -0700 +Subject: [PATCH 01/30] CVE-2023-3961:s3:smbd: Catch any incoming pipe path + that could exit socket_dir. + +For now, SMB_ASSERT() to exit the server. We will remove +this once the test code is in place. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15422 + +Signed-off-by: Jeremy Allison + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 01/30] CVE-2023-3961:s3:smbd: Catch any incoming pipe path + that could exit socket_dir. +--- + source3/rpc_client/local_np.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/source3/rpc_client/local_np.c b/source3/rpc_client/local_np.c +index 0b323404f06..95228d5d801 100644 +--- a/source3/rpc_client/local_np.c ++++ b/source3/rpc_client/local_np.c +@@ -542,6 +542,24 @@ struct tevent_req *local_np_connect_send( + return tevent_req_post(req, ev); + } + ++ /* ++ * Ensure we cannot process a path that exits ++ * the socket_dir. ++ */ ++ if (ISDOTDOT(lower_case_pipename) || ++ (strchr(lower_case_pipename, '/')!=NULL)) ++ { ++ DBG_DEBUG("attempt to connect to invalid pipe pathname %s\n", ++ lower_case_pipename); ++ /* ++ * For now, panic the server until we have ++ * the test code in place. ++ */ ++ SMB_ASSERT(false); ++ tevent_req_error(req, ENOENT); ++ return tevent_req_post(req, ev); ++ } ++ + state->socketpath = talloc_asprintf( + state, "%s/np/%s", socket_dir, lower_case_pipename); + if (tevent_req_nomem(state->socketpath, req)) { +-- +2.34.1 diff --git a/backport-0001-CVE-2023-4091.patch b/backport-0001-CVE-2023-4091.patch new file mode 100644 index 0000000000000000000000000000000000000000..a270d693a1ed074d2ebd197549387dcbf4fd0040 --- /dev/null +++ b/backport-0001-CVE-2023-4091.patch @@ -0,0 +1,190 @@ +From b08a60160e6ab8d982d31844bcbf7ab67ff3a8de Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 1 Aug 2023 12:30:00 +0200 +Subject: [PATCH 04/30] CVE-2023-4091: smbtorture: test overwrite dispositions + on read-only file + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15439 + +Signed-off-by: Ralph Boehme + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 04/30] CVE-2023-4091: smbtorture: test overwrite dispositions + on read-only file +--- + selftest/knownfail.d/samba3.smb2.acls | 1 + + source4/torture/smb2/acls.c | 143 ++++++++++++++++++++++++++ + 2 files changed, 144 insertions(+) + create mode 100644 selftest/knownfail.d/samba3.smb2.acls + +diff --git a/selftest/knownfail.d/samba3.smb2.acls b/selftest/knownfail.d/samba3.smb2.acls +new file mode 100644 +index 00000000000..18df260c0e5 +--- /dev/null ++++ b/selftest/knownfail.d/samba3.smb2.acls +@@ -0,0 +1 @@ ++^samba3.smb2.acls.OVERWRITE_READ_ONLY_FILE +diff --git a/source4/torture/smb2/acls.c b/source4/torture/smb2/acls.c +index a27d4e079e6..5a892d004ea 100644 +--- a/source4/torture/smb2/acls.c ++++ b/source4/torture/smb2/acls.c +@@ -2989,6 +2989,148 @@ done: + return ret; + } + ++static bool test_overwrite_read_only_file(struct torture_context *tctx, ++ struct smb2_tree *tree) ++{ ++ NTSTATUS status; ++ struct smb2_create c; ++ const char *fname = BASEDIR "\\test_overwrite_read_only_file.txt"; ++ struct smb2_handle handle = {{0}}; ++ union smb_fileinfo q; ++ union smb_setfileinfo set; ++ struct security_descriptor *sd = NULL, *sd_orig = NULL; ++ const char *owner_sid = NULL; ++ int i; ++ bool ret = true; ++ ++ struct tcase { ++ int disposition; ++ const char *disposition_string; ++ NTSTATUS expected_status; ++ } tcases[] = { ++#define TCASE(d, s) { \ ++ .disposition = d, \ ++ .disposition_string = #d, \ ++ .expected_status = s, \ ++ } ++ TCASE(NTCREATEX_DISP_OPEN, NT_STATUS_OK), ++ TCASE(NTCREATEX_DISP_SUPERSEDE, NT_STATUS_ACCESS_DENIED), ++ TCASE(NTCREATEX_DISP_OVERWRITE, NT_STATUS_ACCESS_DENIED), ++ TCASE(NTCREATEX_DISP_OVERWRITE_IF, NT_STATUS_ACCESS_DENIED), ++ }; ++#undef TCASE ++ ++ ret = smb2_util_setup_dir(tctx, tree, BASEDIR); ++ torture_assert_goto(tctx, ret, ret, done, "smb2_util_setup_dir not ok"); ++ ++ c = (struct smb2_create) { ++ .in.desired_access = SEC_STD_READ_CONTROL | ++ SEC_STD_WRITE_DAC | ++ SEC_STD_WRITE_OWNER, ++ .in.file_attributes = FILE_ATTRIBUTE_NORMAL, ++ .in.share_access = NTCREATEX_SHARE_ACCESS_READ | ++ NTCREATEX_SHARE_ACCESS_WRITE, ++ .in.create_disposition = NTCREATEX_DISP_OPEN_IF, ++ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS, ++ .in.fname = fname, ++ }; ++ ++ status = smb2_create(tree, tctx, &c); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, ++ "smb2_create failed\n"); ++ handle = c.out.file.handle; ++ ++ torture_comment(tctx, "get the original sd\n"); ++ ++ ZERO_STRUCT(q); ++ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; ++ q.query_secdesc.in.file.handle = handle; ++ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER; ++ ++ status = smb2_getinfo_file(tree, tctx, &q); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, ++ "smb2_getinfo_file failed\n"); ++ sd_orig = q.query_secdesc.out.sd; ++ ++ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid); ++ ++ sd = security_descriptor_dacl_create(tctx, ++ 0, NULL, NULL, ++ owner_sid, ++ SEC_ACE_TYPE_ACCESS_ALLOWED, ++ SEC_FILE_READ_DATA, ++ 0, ++ NULL); ++ ++ ZERO_STRUCT(set); ++ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; ++ set.set_secdesc.in.file.handle = handle; ++ set.set_secdesc.in.secinfo_flags = SECINFO_DACL; ++ set.set_secdesc.in.sd = sd; ++ ++ status = smb2_setinfo_file(tree, &set); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, ++ "smb2_setinfo_file failed\n"); ++ ++ smb2_util_close(tree, handle); ++ ZERO_STRUCT(handle); ++ ++ for (i = 0; i < ARRAY_SIZE(tcases); i++) { ++ torture_comment(tctx, "Verify open with %s dispostion\n", ++ tcases[i].disposition_string); ++ ++ c = (struct smb2_create) { ++ .in.create_disposition = tcases[i].disposition, ++ .in.desired_access = SEC_FILE_READ_DATA, ++ .in.file_attributes = FILE_ATTRIBUTE_NORMAL, ++ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, ++ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS, ++ .in.fname = fname, ++ }; ++ ++ status = smb2_create(tree, tctx, &c); ++ smb2_util_close(tree, c.out.file.handle); ++ torture_assert_ntstatus_equal_goto( ++ tctx, status, tcases[i].expected_status, ret, done, ++ "smb2_create failed\n"); ++ }; ++ ++ torture_comment(tctx, "put back original sd\n"); ++ ++ c = (struct smb2_create) { ++ .in.desired_access = SEC_STD_WRITE_DAC, ++ .in.file_attributes = FILE_ATTRIBUTE_NORMAL, ++ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, ++ .in.create_disposition = NTCREATEX_DISP_OPEN_IF, ++ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS, ++ .in.fname = fname, ++ }; ++ ++ status = smb2_create(tree, tctx, &c); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, ++ "smb2_create failed\n"); ++ handle = c.out.file.handle; ++ ++ ZERO_STRUCT(set); ++ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; ++ set.set_secdesc.in.file.handle = handle; ++ set.set_secdesc.in.secinfo_flags = SECINFO_DACL; ++ set.set_secdesc.in.sd = sd_orig; ++ ++ status = smb2_setinfo_file(tree, &set); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, ++ "smb2_setinfo_file failed\n"); ++ ++ smb2_util_close(tree, handle); ++ ZERO_STRUCT(handle); ++ ++done: ++ smb2_util_close(tree, handle); ++ smb2_util_unlink(tree, fname); ++ smb2_deltree(tree, BASEDIR); ++ return ret; ++} ++ + /* + basic testing of SMB2 ACLs + */ +@@ -3017,6 +3159,7 @@ struct torture_suite *torture_smb2_acls_init(TALLOC_CTX *ctx) + test_deny1); + torture_suite_add_1smb2_test(suite, "MXAC-NOT-GRANTED", + test_mxac_not_granted); ++ torture_suite_add_1smb2_test(suite, "OVERWRITE_READ_ONLY_FILE", test_overwrite_read_only_file); + + suite->description = talloc_strdup(suite, "SMB2-ACLS tests"); + +-- +2.34.1 diff --git a/backport-0001-CVE-2023-4154.patch b/backport-0001-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..38dd55fdbc26345afc573b76172e9a9ab79e4c40 --- /dev/null +++ b/backport-0001-CVE-2023-4154.patch @@ -0,0 +1,118 @@ +From 8c0be1d17a5f4e700fe38b5f58d1caa359e8c383 Mon Sep 17 00:00:00 2001 +From: Christian Merten +Date: Mon, 19 Sep 2022 22:47:10 +0200 +Subject: [PATCH 06/30] CVE-2023-4154 libcli security_descriptor: Add function + to delete a given ace from a security descriptor + +Two functions have been added to delete a given ace from the SACL or the DACL of a security descriptor. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Christian Merten +Reviewed-by: Douglas Bagnall +Reviewed-by: Jeremy Allison +(cherry picked from commit 7efe673fbdcd27ddd23f36281c5f5338681a68fe) + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 06/30] CVE-2023-4154 libcli security_descriptor: Add function + to delete a given ace from a security descriptor +--- + libcli/security/security_descriptor.c | 66 +++++++++++++++++++++++++++ + libcli/security/security_descriptor.h | 4 ++ + 2 files changed, 70 insertions(+) + +diff --git a/libcli/security/security_descriptor.c b/libcli/security/security_descriptor.c +index ba142016389..64c2d027876 100644 +--- a/libcli/security/security_descriptor.c ++++ b/libcli/security/security_descriptor.c +@@ -419,6 +419,72 @@ NTSTATUS security_descriptor_sacl_del(struct security_descriptor *sd, + return security_descriptor_acl_del(sd, true, trustee); + } + ++/* ++ delete the given ACE in the SACL or DACL of a security_descriptor ++*/ ++static NTSTATUS security_descriptor_acl_del_ace(struct security_descriptor *sd, ++ bool sacl_del, ++ const struct security_ace *ace) ++{ ++ uint32_t i; ++ bool found = false; ++ struct security_acl *acl = NULL; ++ ++ if (sacl_del) { ++ acl = sd->sacl; ++ } else { ++ acl = sd->dacl; ++ } ++ ++ if (acl == NULL) { ++ return NT_STATUS_OBJECT_NAME_NOT_FOUND; ++ } ++ ++ for (i=0;inum_aces;i++) { ++ if (security_ace_equal(ace, &acl->aces[i])) { ++ ARRAY_DEL_ELEMENT(acl->aces, i, acl->num_aces); ++ acl->num_aces--; ++ if (acl->num_aces == 0) { ++ acl->aces = NULL; ++ } ++ found = true; ++ i--; ++ } ++ } ++ ++ if (!found) { ++ return NT_STATUS_OBJECT_NAME_NOT_FOUND; ++ } ++ ++ acl->revision = SECURITY_ACL_REVISION_NT4; ++ ++ for (i=0;inum_aces;i++) { ++ switch (acl->aces[i].type) { ++ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: ++ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: ++ case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT: ++ case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT: ++ acl->revision = SECURITY_ACL_REVISION_ADS; ++ return NT_STATUS_OK; ++ default: ++ break; /* only for the switch statement */ ++ } ++ } ++ ++ return NT_STATUS_OK; ++} ++ ++NTSTATUS security_descriptor_dacl_del_ace(struct security_descriptor *sd, ++ const struct security_ace *ace) ++{ ++ return security_descriptor_acl_del_ace(sd, false, ace); ++} ++ ++NTSTATUS security_descriptor_sacl_del_ace(struct security_descriptor *sd, ++ const struct security_ace *ace) ++{ ++ return security_descriptor_acl_del_ace(sd, true, ace); ++} + /* + compare two security ace structures + */ +diff --git a/libcli/security/security_descriptor.h b/libcli/security/security_descriptor.h +index 7e6df87fefa..46545321d15 100644 +--- a/libcli/security/security_descriptor.h ++++ b/libcli/security/security_descriptor.h +@@ -39,6 +39,10 @@ NTSTATUS security_descriptor_dacl_del(struct security_descriptor *sd, + const struct dom_sid *trustee); + NTSTATUS security_descriptor_sacl_del(struct security_descriptor *sd, + const struct dom_sid *trustee); ++NTSTATUS security_descriptor_dacl_del_ace(struct security_descriptor *sd, ++ const struct security_ace *ace); ++NTSTATUS security_descriptor_sacl_del_ace(struct security_descriptor *sd, ++ const struct security_ace *ace); + bool security_ace_equal(const struct security_ace *ace1, + const struct security_ace *ace2); + bool security_acl_equal(const struct security_acl *acl1, +-- +2.34.1 diff --git a/backport-0001-CVE-2023-42669.patch b/backport-0001-CVE-2023-42669.patch new file mode 100644 index 0000000000000000000000000000000000000000..7f18cc384350cd2a7607727feb106ed152a29dbf --- /dev/null +++ b/backport-0001-CVE-2023-42669.patch @@ -0,0 +1,93 @@ +From a16b210ec651b535b43c21574ca439238e2f8772 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Tue, 12 Sep 2023 18:59:44 +1200 +Subject: [PATCH 27/30] CVE-2023-42669 s4-rpc_server: Disable rpcecho server by + default + +The rpcecho server is useful in development and testing, but should never +have been allowed into production, as it includes the facility to +do a blocking sleep() in the single-threaded rpc worker. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15474 + +Signed-off-by: Andrew Bartlett + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 27/30] CVE-2023-42669 s4-rpc_server: Disable rpcecho server by + default +--- + docs-xml/smbdotconf/protocol/dcerpcendpointservers.xml | 2 +- + lib/param/loadparm.c | 2 +- + selftest/target/Samba4.pm | 2 +- + source3/param/loadparm.c | 2 +- + source4/rpc_server/wscript_build | 3 ++- + 5 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/docs-xml/smbdotconf/protocol/dcerpcendpointservers.xml b/docs-xml/smbdotconf/protocol/dcerpcendpointservers.xml +index 8a217cc7f11..c6642b795fd 100644 +--- a/docs-xml/smbdotconf/protocol/dcerpcendpointservers.xml ++++ b/docs-xml/smbdotconf/protocol/dcerpcendpointservers.xml +@@ -6,6 +6,6 @@ + Specifies which DCE/RPC endpoint servers should be run. + + +-epmapper, wkssvc, rpcecho, samr, netlogon, lsarpc, drsuapi, dssetup, unixinfo, browser, eventlog6, backupkey, dnsserver ++epmapper, wkssvc, samr, netlogon, lsarpc, drsuapi, dssetup, unixinfo, browser, eventlog6, backupkey, dnsserver + rpcecho + +diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c +index f70823fe366..664fae70c9b 100644 +--- a/lib/param/loadparm.c ++++ b/lib/param/loadparm.c +@@ -2732,7 +2732,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) + lpcfg_do_global_parameter(lp_ctx, "ntvfs handler", "unixuid default"); + lpcfg_do_global_parameter(lp_ctx, "max connections", "0"); + +- lpcfg_do_global_parameter(lp_ctx, "dcerpc endpoint servers", "epmapper wkssvc rpcecho samr netlogon lsarpc drsuapi dssetup unixinfo browser eventlog6 backupkey dnsserver"); ++ lpcfg_do_global_parameter(lp_ctx, "dcerpc endpoint servers", "epmapper wkssvc samr netlogon lsarpc drsuapi dssetup unixinfo browser eventlog6 backupkey dnsserver"); + lpcfg_do_global_parameter(lp_ctx, "server services", "s3fs rpc nbt wrepl ldap cldap kdc drepl winbindd ntp_signd kcc dnsupdate dns"); + lpcfg_do_global_parameter(lp_ctx, "kccsrv:samba_kcc", "true"); + /* the winbind method for domain controllers is for both RODC +diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm +index 5cbc5ccf2b8..7033146f46a 100755 +--- a/selftest/target/Samba4.pm ++++ b/selftest/target/Samba4.pm +@@ -782,7 +782,7 @@ sub provision_raw_step1($$) + wins support = yes + server role = $ctx->{server_role} + server services = +echo $services +- dcerpc endpoint servers = +winreg +srvsvc ++ dcerpc endpoint servers = +winreg +srvsvc +rpcecho + notify:inotify = false + ldb:nosync = true + ldap server require strong auth = yes +diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c +index 97d02037a89..1f7b6d16a78 100644 +--- a/source3/param/loadparm.c ++++ b/source3/param/loadparm.c +@@ -883,7 +883,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) + + Globals.server_services = str_list_make_v3_const(NULL, "s3fs rpc nbt wrepl ldap cldap kdc drepl winbindd ntp_signd kcc dnsupdate dns", NULL); + +- Globals.dcerpc_endpoint_servers = str_list_make_v3_const(NULL, "epmapper wkssvc rpcecho samr netlogon lsarpc drsuapi dssetup unixinfo browser eventlog6 backupkey dnsserver", NULL); ++ Globals.dcerpc_endpoint_servers = str_list_make_v3_const(NULL, "epmapper wkssvc samr netlogon lsarpc drsuapi dssetup unixinfo browser eventlog6 backupkey dnsserver", NULL); + + Globals.tls_enabled = true; + Globals.tls_verify_peer = TLS_VERIFY_PEER_AS_STRICT_AS_POSSIBLE; +diff --git a/source4/rpc_server/wscript_build b/source4/rpc_server/wscript_build +index 0e44a3c2bae..31ec4f60c9a 100644 +--- a/source4/rpc_server/wscript_build ++++ b/source4/rpc_server/wscript_build +@@ -33,7 +33,8 @@ bld.SAMBA_MODULE('dcerpc_rpcecho', + source='echo/rpc_echo.c', + subsystem='dcerpc_server', + init_function='dcerpc_server_rpcecho_init', +- deps='ndr-standard events' ++ deps='ndr-standard events', ++ enabled=bld.CONFIG_GET('ENABLE_SELFTEST') + ) + + +-- +2.34.1 diff --git a/backport-0001-CVE-2023-42670.patch b/backport-0001-CVE-2023-42670.patch new file mode 100644 index 0000000000000000000000000000000000000000..61ffaa1172fddc06f8c4c6cb81ab5acf73130871 --- /dev/null +++ b/backport-0001-CVE-2023-42670.patch @@ -0,0 +1,287 @@ +From 51bc79f85a8d63ed5428c2975f60094157dda2e5 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Tue, 12 Sep 2023 12:28:49 +1200 +Subject: [PATCH 29/30] CVE-2023-42670 s3-rpc_server: Strictly refuse to start + RPC servers in conflict with AD DC + +Just as we refuse to start NETLOGON except on the DC, we must refuse +to start all of the RPC services that are provided by the AD DC. + +Most critically of course this applies to netlogon, lsa and samr. + +This avoids the supression of these services being the result of a +runtime epmapper lookup, as if that fails these services can disrupt +service to end users by listening on the same socket as the AD DC +servers. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15473 + +Signed-off-by: Andrew Bartlett + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 29/30] CVE-2023-42670 s3-rpc_server: Strictly refuse to start + RPC servers in conflict with AD DC +--- + source3/rpc_server/rpcd_classic.c | 45 ++++++++++++++++++++++++++---- + source3/rpc_server/rpcd_epmapper.c | 33 ++++++++++++++++++++-- + source3/rpc_server/rpcd_lsad.c | 21 ++++++++++++++ + source3/rpc_server/rpcd_rpcecho.c | 33 ++++++++++++++++++++-- + 4 files changed, 122 insertions(+), 10 deletions(-) + +diff --git a/source3/rpc_server/rpcd_classic.c b/source3/rpc_server/rpcd_classic.c +index 4f6164c814c..8494af575ec 100644 +--- a/source3/rpc_server/rpcd_classic.c ++++ b/source3/rpc_server/rpcd_classic.c +@@ -42,14 +42,34 @@ static size_t classic_interfaces( + static const struct ndr_interface_table *ifaces[] = { + &ndr_table_srvsvc, + &ndr_table_netdfs, +- &ndr_table_wkssvc, ++ &ndr_table_initshutdown, + &ndr_table_svcctl, + &ndr_table_ntsvcs, + &ndr_table_eventlog, +- &ndr_table_initshutdown, ++ /* ++ * This last item is truncated from the list by the ++ * num_ifaces -= 1 below. Take care when adding new ++ * services. ++ */ ++ &ndr_table_wkssvc, + }; ++ size_t num_ifaces = ARRAY_SIZE(ifaces); ++ ++ switch(lp_server_role()) { ++ case ROLE_ACTIVE_DIRECTORY_DC: ++ /* ++ * On the AD DC wkssvc is provided by the 'samba' ++ * binary from source4/ ++ */ ++ num_ifaces -= 1; ++ break; ++ default: ++ break; ++ } ++ + *pifaces = ifaces; +- return ARRAY_SIZE(ifaces); ++ return num_ifaces; ++ + } + + static size_t classic_servers( +@@ -58,15 +78,28 @@ static size_t classic_servers( + void *private_data) + { + static const struct dcesrv_endpoint_server *ep_servers[7] = { NULL }; ++ size_t num_servers = ARRAY_SIZE(ep_servers); + bool ok; + + ep_servers[0] = srvsvc_get_ep_server(); + ep_servers[1] = netdfs_get_ep_server(); +- ep_servers[2] = wkssvc_get_ep_server(); ++ ep_servers[2] = initshutdown_get_ep_server(); + ep_servers[3] = svcctl_get_ep_server(); + ep_servers[4] = ntsvcs_get_ep_server(); + ep_servers[5] = eventlog_get_ep_server(); +- ep_servers[6] = initshutdown_get_ep_server(); ++ ep_servers[6] = wkssvc_get_ep_server(); ++ ++ switch(lp_server_role()) { ++ case ROLE_ACTIVE_DIRECTORY_DC: ++ /* ++ * On the AD DC wkssvc is provided by the 'samba' ++ * binary from source4/ ++ */ ++ num_servers -= 1; ++ break; ++ default: ++ break; ++ } + + ok = secrets_init(); + if (!ok) { +@@ -85,7 +118,7 @@ static size_t classic_servers( + mangle_reset_cache(); + + *_ep_servers = ep_servers; +- return ARRAY_SIZE(ep_servers); ++ return num_servers; + } + + int main(int argc, const char *argv[]) +diff --git a/source3/rpc_server/rpcd_epmapper.c b/source3/rpc_server/rpcd_epmapper.c +index 950ba7ec12a..455179ccfba 100644 +--- a/source3/rpc_server/rpcd_epmapper.c ++++ b/source3/rpc_server/rpcd_epmapper.c +@@ -19,6 +19,8 @@ + #include "rpc_worker.h" + #include "librpc/gen_ndr/ndr_epmapper.h" + #include "librpc/gen_ndr/ndr_epmapper_scompat.h" ++#include "param/loadparm.h" ++#include "libds/common/roles.h" + + static size_t epmapper_interfaces( + const struct ndr_interface_table ***pifaces, +@@ -27,8 +29,22 @@ static size_t epmapper_interfaces( + static const struct ndr_interface_table *ifaces[] = { + &ndr_table_epmapper, + }; ++ size_t num_ifaces = ARRAY_SIZE(ifaces); ++ ++ switch(lp_server_role()) { ++ case ROLE_ACTIVE_DIRECTORY_DC: ++ /* ++ * On the AD DC epmapper is provided by the 'samba' ++ * binary from source4/ ++ */ ++ num_ifaces = 0; ++ break; ++ default: ++ break; ++ } ++ + *pifaces = ifaces; +- return ARRAY_SIZE(ifaces); ++ return num_ifaces; + } + + static size_t epmapper_servers( +@@ -37,11 +53,24 @@ static size_t epmapper_servers( + void *private_data) + { + static const struct dcesrv_endpoint_server *ep_servers[] = { NULL }; ++ size_t num_servers = ARRAY_SIZE(ep_servers); + + ep_servers[0] = epmapper_get_ep_server(); + ++ switch(lp_server_role()) { ++ case ROLE_ACTIVE_DIRECTORY_DC: ++ /* ++ * On the AD DC epmapper is provided by the 'samba' ++ * binary from source4/ ++ */ ++ num_servers = 0; ++ break; ++ default: ++ break; ++ } ++ + *_ep_servers = ep_servers; +- return ARRAY_SIZE(ep_servers); ++ return num_servers; + } + + int main(int argc, const char *argv[]) +diff --git a/source3/rpc_server/rpcd_lsad.c b/source3/rpc_server/rpcd_lsad.c +index 3ca0ed43fdd..b0e021493e7 100644 +--- a/source3/rpc_server/rpcd_lsad.c ++++ b/source3/rpc_server/rpcd_lsad.c +@@ -36,6 +36,11 @@ static size_t lsad_interfaces( + &ndr_table_lsarpc, + &ndr_table_samr, + &ndr_table_dssetup, ++ /* ++ * This last item is truncated from the list by the ++ * num_ifaces -= 1 below for the fileserver. Take ++ * care when adding new services. ++ */ + &ndr_table_netlogon, + }; + size_t num_ifaces = ARRAY_SIZE(ifaces); +@@ -46,6 +51,14 @@ static size_t lsad_interfaces( + /* no netlogon for non-dc */ + num_ifaces -= 1; + break; ++ case ROLE_ACTIVE_DIRECTORY_DC: ++ /* ++ * All these services are provided by the 'samba' ++ * binary from source4, not this code which is the ++ * source3 / NT4-like "classic" DC implementation ++ */ ++ num_ifaces = 0; ++ break; + default: + break; + } +@@ -80,6 +93,14 @@ static size_t lsad_servers( + /* no netlogon for non-dc */ + num_servers -= 1; + break; ++ case ROLE_ACTIVE_DIRECTORY_DC: ++ /* ++ * All these services are provided by the 'samba' ++ * binary from source4, not this code which is the ++ * source3 / NT4-like "classic" DC implementation ++ */ ++ num_servers = 0; ++ break; + default: + break; + } +diff --git a/source3/rpc_server/rpcd_rpcecho.c b/source3/rpc_server/rpcd_rpcecho.c +index 9176039819f..37391f563db 100644 +--- a/source3/rpc_server/rpcd_rpcecho.c ++++ b/source3/rpc_server/rpcd_rpcecho.c +@@ -19,6 +19,8 @@ + #include "rpc_worker.h" + #include "librpc/gen_ndr/ndr_echo.h" + #include "librpc/gen_ndr/ndr_echo_scompat.h" ++#include "param/loadparm.h" ++#include "libds/common/roles.h" + + static size_t rpcecho_interfaces( + const struct ndr_interface_table ***pifaces, +@@ -27,8 +29,22 @@ static size_t rpcecho_interfaces( + static const struct ndr_interface_table *ifaces[] = { + &ndr_table_rpcecho, + }; ++ size_t num_ifaces = ARRAY_SIZE(ifaces); ++ ++ switch(lp_server_role()) { ++ case ROLE_ACTIVE_DIRECTORY_DC: ++ /* ++ * On the AD DC rpcecho is provided by the 'samba' ++ * binary from source4/ ++ */ ++ num_ifaces = 0; ++ break; ++ default: ++ break; ++ } ++ + *pifaces = ifaces; +- return ARRAY_SIZE(ifaces); ++ return num_ifaces; + } + + static size_t rpcecho_servers( +@@ -37,11 +53,24 @@ static size_t rpcecho_servers( + void *private_data) + { + static const struct dcesrv_endpoint_server *ep_servers[1] = { NULL }; ++ size_t num_servers = ARRAY_SIZE(ep_servers); + + ep_servers[0] = rpcecho_get_ep_server(); + ++ switch(lp_server_role()) { ++ case ROLE_ACTIVE_DIRECTORY_DC: ++ /* ++ * On the AD DC rpcecho is provided by the 'samba' ++ * binary from source4/ ++ */ ++ num_servers = 0; ++ break; ++ default: ++ break; ++ } ++ + *_ep_servers = ep_servers; +- return ARRAY_SIZE(ep_servers); ++ return num_servers; + } + + int main(int argc, const char *argv[]) +-- +2.34.1 diff --git a/backport-0002-CVE-2018-14628.patch b/backport-0002-CVE-2018-14628.patch new file mode 100644 index 0000000000000000000000000000000000000000..acb0b2a98600246a1c698f680a085e3b8366162b --- /dev/null +++ b/backport-0002-CVE-2018-14628.patch @@ -0,0 +1,96 @@ +From 2ee9129c6fe36cb0e363677dee43a2940aa81810 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 29 Jan 2016 23:33:37 +0100 +Subject: [PATCH 2/6] CVE-2018-14628: python:provision: make + DELETEDOBJECTS_DESCRIPTOR available in the ldif files + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13595 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +(cherry picked from commit 0c329a0fda37d87ed737e4b579b6d04ec907604c) + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=18168 +[PATCH 2/6] CVE-2018-14628: python:provision: make + DELETEDOBJECTS_DESCRIPTOR available in the ldif files +--- + python/samba/provision/__init__.py | 5 +++++ + python/samba/provision/sambadns.py | 4 ++++ + 2 files changed, 9 insertions(+) + +diff --git a/python/samba/provision/__init__.py b/python/samba/provision/__init__.py +index ff9b8fac916a..f7d7468e4faf 100644 +--- a/python/samba/provision/__init__.py ++++ b/python/samba/provision/__init__.py +@@ -78,6 +78,7 @@ from samba.provision.backend import ( + LDBBackend, + ) + from samba.descriptor import ( ++ get_deletedobjects_descriptor, + get_empty_descriptor, + get_config_descriptor, + get_config_partitions_descriptor, +@@ -1441,6 +1442,8 @@ def fill_samdb(samdb, lp, names, logger, policyguid, + msg["subRefs"] = ldb.MessageElement(names.configdn, ldb.FLAG_MOD_ADD, + "subRefs") + ++ deletedobjects_descr = b64encode(get_deletedobjects_descriptor(names.domainsid)).decode('utf8') ++ + samdb.invocation_id = invocationid + + # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it +@@ -1472,6 +1475,7 @@ def fill_samdb(samdb, lp, names, logger, policyguid, + "FOREST_FUNCTIONALITY": str(forestFunctionality), + "DOMAIN_FUNCTIONALITY": str(domainFunctionality), + "NTDSQUOTAS_DESCRIPTOR": ntdsquotas_descr, ++ "DELETEDOBJECTS_DESCRIPTOR": deletedobjects_descr, + "LOSTANDFOUND_DESCRIPTOR": protected1wd_descr, + "SERVICES_DESCRIPTOR": protected1_descr, + "PHYSICALLOCATIONS_DESCRIPTOR": protected1wd_descr, +@@ -1536,6 +1540,7 @@ def fill_samdb(samdb, lp, names, logger, policyguid, + "RIDAVAILABLESTART": str(next_rid + 600), + "POLICYGUID_DC": policyguid_dc, + "INFRASTRUCTURE_DESCRIPTOR": infrastructure_desc, ++ "DELETEDOBJECTS_DESCRIPTOR": deletedobjects_descr, + "LOSTANDFOUND_DESCRIPTOR": lostandfound_desc, + "SYSTEM_DESCRIPTOR": system_desc, + "BUILTIN_DESCRIPTOR": builtin_desc, +diff --git a/python/samba/provision/sambadns.py b/python/samba/provision/sambadns.py +index 9184711a7645..d057b7830ada 100644 +--- a/python/samba/provision/sambadns.py ++++ b/python/samba/provision/sambadns.py +@@ -42,6 +42,7 @@ from samba.dsdb import ( + DS_GUID_USERS_CONTAINER + ) + from samba.descriptor import ( ++ get_deletedobjects_descriptor, + get_domain_descriptor, + get_domain_delete_protected1_descriptor, + get_domain_delete_protected2_descriptor, +@@ -256,6 +257,7 @@ def setup_dns_partitions(samdb, domainsid, domaindn, forestdn, configdn, + domainzone_dn = "DC=DomainDnsZones,%s" % domaindn + forestzone_dn = "DC=ForestDnsZones,%s" % forestdn + descriptor = get_dns_partition_descriptor(domainsid) ++ deletedobjects_desc = get_deletedobjects_descriptor(domainsid) + + setup_add_ldif(samdb, setup_path("provision_dnszones_partitions.ldif"), { + "ZONE_DN": domainzone_dn, +@@ -278,6 +280,7 @@ def setup_dns_partitions(samdb, domainsid, domaindn, forestdn, configdn, + "ZONE_DNS": domainzone_dns, + "CONFIGDN": configdn, + "SERVERDN": serverdn, ++ "DELETEDOBJECTS_DESCRIPTOR": b64encode(deletedobjects_desc).decode('utf8'), + "LOSTANDFOUND_DESCRIPTOR": b64encode(protected2_desc).decode('utf8'), + "INFRASTRUCTURE_DESCRIPTOR": b64encode(protected1_desc).decode('utf8'), + }) +@@ -297,6 +300,7 @@ def setup_dns_partitions(samdb, domainsid, domaindn, forestdn, configdn, + "ZONE_DNS": forestzone_dns, + "CONFIGDN": configdn, + "SERVERDN": serverdn, ++ "DELETEDOBJECTS_DESCRIPTOR": b64encode(deletedobjects_desc).decode('utf8'), + "LOSTANDFOUND_DESCRIPTOR": b64encode(protected2_desc).decode('utf8'), + "INFRASTRUCTURE_DESCRIPTOR": b64encode(protected1_desc).decode('utf8'), + }) +-- +2.34.1 diff --git a/backport-0002-CVE-2022-2127.patch b/backport-0002-CVE-2022-2127.patch new file mode 100644 index 0000000000000000000000000000000000000000..b56be07e9a53c385037e441b92366284bbf1ec7a --- /dev/null +++ b/backport-0002-CVE-2022-2127.patch @@ -0,0 +1,42 @@ +From 53838682570135b753fa622dfcde111528563c2d Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Fri, 16 Jun 2023 12:28:47 +0200 +Subject: [PATCH 02/28] CVE-2022-2127: ntlm_auth: cap lanman response length + value + +We already copy at most sizeof(request.data.auth_crap.lm_resp) bytes to the +lm_resp buffer, but we don't cap the length indicator. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15072 + +Signed-off-by: Ralph Boehme + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/utils/ntlm_auth.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c +index 1306951c2a8..62319ccd5b9 100644 +--- a/source3/utils/ntlm_auth.c ++++ b/source3/utils/ntlm_auth.c +@@ -576,10 +576,14 @@ NTSTATUS contact_winbind_auth_crap(const char *username, + memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8)); + + if (lm_response && lm_response->length) { ++ size_t capped_lm_response_len = MIN( ++ lm_response->length, ++ sizeof(request.data.auth_crap.lm_resp)); ++ + memcpy(request.data.auth_crap.lm_resp, + lm_response->data, +- MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp))); +- request.data.auth_crap.lm_resp_len = lm_response->length; ++ capped_lm_response_len); ++ request.data.auth_crap.lm_resp_len = capped_lm_response_len; + } + + if (nt_response && nt_response->length) { +-- +2.34.1 diff --git a/backport-0002-CVE-2023-0225.patch b/backport-0002-CVE-2023-0225.patch new file mode 100644 index 0000000000000000000000000000000000000000..445e1b64a6892b6770264e99f00079a9f27eefc2 --- /dev/null +++ b/backport-0002-CVE-2023-0225.patch @@ -0,0 +1,68 @@ +From 47f8a529885d321c4f787832d5934757656e8094 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Tue, 6 Sep 2022 19:23:13 +1200 +Subject: [PATCH 2/4] CVE-2023-0225 CVE-2020-25720 pydsdb: Add dsHeuristics + constant definitions + +We want to be able to use these values in Python tests. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14810 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15276 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett +(cherry picked from commit cc709077822a39227174b91ed2345c2bd603f61f) + +[abartlet@samba.org This patch is needed for a clean backport of + CVE-2023-0225 as these constants are used in the acl_modify test + even when this behaviour is not itself used.] + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17833 +--- + source4/dsdb/pydsdb.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/source4/dsdb/pydsdb.c b/source4/dsdb/pydsdb.c +index bcfc7e95478..626d849a561 100644 +--- a/source4/dsdb/pydsdb.c ++++ b/source4/dsdb/pydsdb.c +@@ -1665,6 +1665,36 @@ MODULE_INIT_FUNC(dsdb) + ADD_DSDB_FLAG(DS_NTDSDSA_OPT_DISABLE_NTDSCONN_XLATE); + ADD_DSDB_FLAG(DS_NTDSDSA_OPT_DISABLE_SPN_REGISTRATION); + ++ /* dsHeuristics character indexes (see MS-ADTS 7.1.1.2.4.1.2) */ ++ ADD_DSDB_FLAG(DS_HR_SUPFIRSTLASTANR); ++ ADD_DSDB_FLAG(DS_HR_SUPLASTFIRSTANR); ++ ADD_DSDB_FLAG(DS_HR_DOLISTOBJECT); ++ ADD_DSDB_FLAG(DS_HR_DONICKRES); ++ ADD_DSDB_FLAG(DS_HR_LDAP_USEPERMMOD); ++ ADD_DSDB_FLAG(DS_HR_HIDEDSID); ++ ADD_DSDB_FLAG(DS_HR_BLOCK_ANONYMOUS_OPS); ++ ADD_DSDB_FLAG(DS_HR_ALLOW_ANON_NSPI); ++ ADD_DSDB_FLAG(DS_HR_USER_PASSWORD_SUPPORT); ++ ADD_DSDB_FLAG(DS_HR_TENTH_CHAR); ++ ADD_DSDB_FLAG(DS_HR_SPECIFY_GUID_ON_ADD); ++ ADD_DSDB_FLAG(DS_HR_NO_STANDARD_SD); ++ ADD_DSDB_FLAG(DS_HR_ALLOW_NONSECURE_PWD_OPS); ++ ADD_DSDB_FLAG(DS_HR_NO_PROPAGATE_ON_NOCHANGE); ++ ADD_DSDB_FLAG(DS_HR_COMPUTE_ANR_STATS); ++ ADD_DSDB_FLAG(DS_HR_ADMINSDEXMASK); ++ ADD_DSDB_FLAG(DS_HR_KVNOEMUW2K); ++ ++ ADD_DSDB_FLAG(DS_HR_TWENTIETH_CHAR); ++ ADD_DSDB_FLAG(DS_HR_ATTR_AUTHZ_ON_LDAP_ADD); ++ ADD_DSDB_FLAG(DS_HR_BLOCK_OWNER_IMPLICIT_RIGHTS); ++ ADD_DSDB_FLAG(DS_HR_THIRTIETH_CHAR); ++ ADD_DSDB_FLAG(DS_HR_FOURTIETH_CHAR); ++ ADD_DSDB_FLAG(DS_HR_FIFTIETH_CHAR); ++ ADD_DSDB_FLAG(DS_HR_SIXTIETH_CHAR); ++ ADD_DSDB_FLAG(DS_HR_SEVENTIETH_CHAR); ++ ADD_DSDB_FLAG(DS_HR_EIGHTIETH_CHAR); ++ ADD_DSDB_FLAG(DS_HR_NINETIETH_CHAR); ++ + ADD_DSDB_FLAG(NTDSCONN_KCC_GC_TOPOLOGY); + ADD_DSDB_FLAG(NTDSCONN_KCC_RING_TOPOLOGY); + ADD_DSDB_FLAG(NTDSCONN_KCC_MINIMIZE_HOPS_TOPOLOGY); +-- +2.25.1 \ No newline at end of file diff --git a/backport-0002-CVE-2023-0614.patch b/backport-0002-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..1653dec170858d9b3ca1b14e4a22aa5eec9bcabe --- /dev/null +++ b/backport-0002-CVE-2023-0614.patch @@ -0,0 +1,137 @@ +From ba8c9eae1392bf21d3e36530eda1780defd22300 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 13 Mar 2023 17:20:00 +1300 +Subject: [PATCH 02/35] CVE-2023-0614 selftest: Use setUpClass() to reduce + "make test TESTS=large_ldap" time + +This reduces the elapsed time to 6m from 20m on my laptop. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15332 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton + +Autobuild-User(master): Andrew Bartlett +Autobuild-Date(master): Tue Mar 14 07:16:04 UTC 2023 on atb-devel-224 + +(cherry picked from commit b4a6c054ec6acefacd22cb7230a783d20cb07c05) + +[abartlet@samba.org Included in the security release as this + makes working on the large_ldap test practical by reducing + the elapsed time taken] + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/tests/python/large_ldap.py | 69 +++++++++++++------------ + 1 file changed, 36 insertions(+), 33 deletions(-) + +diff --git a/source4/dsdb/tests/python/large_ldap.py b/source4/dsdb/tests/python/large_ldap.py +index 0805119a700..13729052e65 100644 +--- a/source4/dsdb/tests/python/large_ldap.py ++++ b/source4/dsdb/tests/python/large_ldap.py +@@ -66,30 +66,32 @@ creds = credopts.get_credentials(lp) + + class ManyLDAPTest(samba.tests.TestCase): + +- def setUp(self): +- super(ManyLDAPTest, self).setUp() +- self.ldb = SamDB(url, credentials=creds, session_info=system_session(lp), lp=lp) +- self.base_dn = self.ldb.domain_dn() +- self.OU_NAME_MANY="many_ou" + format(random.randint(0, 99999), "05") +- self.ou_dn = ldb.Dn(self.ldb, "ou=" + self.OU_NAME_MANY + "," + str(self.base_dn)) +- +- samba.tests.delete_force(self.ldb, self.ou_dn, ++ @classmethod ++ def setUpClass(cls): ++ super().setUpClass() ++ cls.ldb = SamDB(url, credentials=creds, session_info=system_session(lp), lp=lp) ++ cls.base_dn = self.ldb.domain_dn() ++ cls.OU_NAME_MANY="many_ou" + format(random.randint(0, 99999), "05") ++ cls.ou_dn = ldb.Dn(self.ldb, "ou=" + self.OU_NAME_MANY + "," + str(self.base_dn)) ++ ++ samba.tests.delete_force(cls.ldb, cls.ou_dn, + controls=['tree_delete:1']) + +- self.ldb.add({ +- "dn": self.ou_dn, ++ cls.ldb.add({ ++ "dn": cls.ou_dn, + "objectclass": "organizationalUnit", +- "ou": self.OU_NAME_MANY}) ++ "ou": cls.OU_NAME_MANY}) + + for x in range(2000): +- ou_name = self.OU_NAME_MANY + str(x) +- self.ldb.add({ +- "dn": "ou=" + ou_name + "," + str(self.ou_dn), ++ ou_name = cls.OU_NAME_MANY + str(x) ++ cls.ldb.add({ ++ "dn": "ou=" + ou_name + "," + str(cls.ou_dn), + "objectclass": "organizationalUnit", + "ou": ou_name}) + +- def tearDown(self): +- samba.tests.delete_force(self.ldb, self.ou_dn, ++ @classmethod ++ def tearDownClass(cls): ++ samba.tests.delete_force(cls.ldb, self.ou_dn, + controls=['tree_delete:1']) + + def test_unindexed_iterator_search(self): +@@ -117,34 +119,35 @@ class ManyLDAPTest(samba.tests.TestCase): + + class LargeLDAPTest(samba.tests.TestCase): + +- def setUp(self): +- super(LargeLDAPTest, self).setUp() +- self.ldb = SamDB(url, credentials=creds, session_info=system_session(lp), lp=lp) +- self.base_dn = self.ldb.domain_dn() +- self.USER_NAME = "large_user" + format(random.randint(0, 99999), "05") + "-" +- self.OU_NAME="large_user_ou" + format(random.randint(0, 99999), "05") +- self.ou_dn = ldb.Dn(self.ldb, "ou=" + self.OU_NAME + "," + str(self.base_dn)) ++ @classmethod ++ def setUpClass(cls): ++ cls.ldb = SamDB(url, credentials=creds, session_info=system_session(lp), lp=lp) ++ cls.base_dn = cls.ldb.domain_dn() ++ cls.USER_NAME = "large_user" + format(random.randint(0, 99999), "05") + "-" ++ cls.OU_NAME="large_user_ou" + format(random.randint(0, 99999), "05") ++ cls.ou_dn = ldb.Dn(cls.ldb, "ou=" + cls.OU_NAME + "," + str(cls.base_dn)) + +- samba.tests.delete_force(self.ldb, self.ou_dn, ++ samba.tests.delete_force(cls.ldb, cls.ou_dn, + controls=['tree_delete:1']) + +- self.ldb.add({ +- "dn": self.ou_dn, ++ cls.ldb.add({ ++ "dn": cls.ou_dn, + "objectclass": "organizationalUnit", +- "ou": self.OU_NAME}) ++ "ou": cls.OU_NAME}) + + for x in range(200): +- user_name = self.USER_NAME + format(x, "03") +- self.ldb.add({ +- "dn": "cn=" + user_name + "," + str(self.ou_dn), ++ user_name = cls.USER_NAME + format(x, "03") ++ cls.ldb.add({ ++ "dn": "cn=" + user_name + "," + str(cls.ou_dn), + "objectclass": "user", + "sAMAccountName": user_name, + "jpegPhoto": b'a' * (2 * 1024 * 1024)}) + +- def tearDown(self): ++ @classmethod ++ def tearDownClass(cls): + # Remake the connection for tear-down (old Samba drops the socket) +- self.ldb = SamDB(url, credentials=creds, session_info=system_session(lp), lp=lp) +- samba.tests.delete_force(self.ldb, self.ou_dn, ++ cls.ldb = SamDB(url, credentials=creds, session_info=system_session(lp), lp=lp) ++ samba.tests.delete_force(cls.ldb, cls.ou_dn, + controls=['tree_delete:1']) + + def test_unindexed_iterator_search(self): +-- +2.25.1 \ No newline at end of file diff --git a/backport-0002-CVE-2023-3347.patch b/backport-0002-CVE-2023-3347.patch new file mode 100644 index 0000000000000000000000000000000000000000..112d89cd5af3cd2ee5b68bea7e6abc041851c0b1 --- /dev/null +++ b/backport-0002-CVE-2023-3347.patch @@ -0,0 +1,133 @@ +From e96d5002fc10b3e74c7ed90f8cf7cf234a06a3d1 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Wed, 21 Jun 2023 15:06:12 +0200 +Subject: [PATCH 19/28] CVE-2023-3347: smbd: pass lp_ctx to + smb[1|2]_srv_init_signing() + +No change in behaviour. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15397 + +Signed-off-by: Ralph Boehme + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/smbd/proto.h | 3 ++- + source3/smbd/smb1_signing.c | 10 ++-------- + source3/smbd/smb1_signing.h | 3 ++- + source3/smbd/smb2_signing.c | 25 +++++++++++++++---------- + 4 files changed, 21 insertions(+), 20 deletions(-) + +diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h +index c4a33014515..67cc5e8a380 100644 +--- a/source3/smbd/proto.h ++++ b/source3/smbd/proto.h +@@ -52,7 +52,8 @@ struct dcesrv_context; + + /* The following definitions come from smbd/smb2_signing.c */ + +-bool smb2_srv_init_signing(struct smbXsrv_connection *conn); ++bool smb2_srv_init_signing(struct loadparm_context *lp_ctx, ++ struct smbXsrv_connection *conn); + bool srv_init_signing(struct smbXsrv_connection *conn); + + /* The following definitions come from smbd/aio.c */ +diff --git a/source3/smbd/smb1_signing.c b/source3/smbd/smb1_signing.c +index 6bcb0629c4f..aa3027d5318 100644 +--- a/source3/smbd/smb1_signing.c ++++ b/source3/smbd/smb1_signing.c +@@ -170,18 +170,13 @@ static void smbd_shm_signing_free(TALLOC_CTX *mem_ctx, void *ptr) + Called by server negprot when signing has been negotiated. + ************************************************************/ + +-bool smb1_srv_init_signing(struct smbXsrv_connection *conn) ++bool smb1_srv_init_signing(struct loadparm_context *lp_ctx, ++ struct smbXsrv_connection *conn) + { + bool allowed = true; + bool desired; + bool mandatory = false; + +- struct loadparm_context *lp_ctx = loadparm_init_s3(conn, loadparm_s3_helpers()); +- if (lp_ctx == NULL) { +- DEBUG(10, ("loadparm_init_s3 failed\n")); +- return false; +- } +- + /* + * if the client and server allow signing, + * we desire to use it. +@@ -195,7 +190,6 @@ bool smb1_srv_init_signing(struct smbXsrv_connection *conn) + */ + + desired = lpcfg_server_signing_allowed(lp_ctx, &mandatory); +- talloc_unlink(conn, lp_ctx); + + if (lp_async_smb_echo_handler()) { + struct smbd_shm_signing *s; +diff --git a/source3/smbd/smb1_signing.h b/source3/smbd/smb1_signing.h +index 56c59c5bbc2..26f60420dfa 100644 +--- a/source3/smbd/smb1_signing.h ++++ b/source3/smbd/smb1_signing.h +@@ -33,4 +33,5 @@ bool smb1_srv_is_signing_negotiated(struct smbXsrv_connection *conn); + void smb1_srv_set_signing(struct smbXsrv_connection *conn, + const DATA_BLOB user_session_key, + const DATA_BLOB response); +-bool smb1_srv_init_signing(struct smbXsrv_connection *conn); ++bool smb1_srv_init_signing(struct loadparm_context *lp_ctx, ++ struct smbXsrv_connection *conn); +diff --git a/source3/smbd/smb2_signing.c b/source3/smbd/smb2_signing.c +index 4691ef4d613..c1f876f9cd7 100644 +--- a/source3/smbd/smb2_signing.c ++++ b/source3/smbd/smb2_signing.c +@@ -26,32 +26,37 @@ + #include "lib/param/param.h" + #include "smb2_signing.h" + +-bool smb2_srv_init_signing(struct smbXsrv_connection *conn) ++bool smb2_srv_init_signing(struct loadparm_context *lp_ctx, ++ struct smbXsrv_connection *conn) + { +- struct loadparm_context *lp_ctx = loadparm_init_s3(conn, loadparm_s3_helpers()); +- if (lp_ctx == NULL) { +- DBG_DEBUG("loadparm_init_s3 failed\n"); +- return false; +- } +- + /* + * For SMB2 all we need to know is if signing is mandatory. + * It is always allowed and desired, whatever the smb.conf says. + */ + (void)lpcfg_server_signing_allowed(lp_ctx, &conn->smb2.signing_mandatory); +- talloc_unlink(conn, lp_ctx); + return true; + } + + bool srv_init_signing(struct smbXsrv_connection *conn) + { ++ struct loadparm_context *lp_ctx = NULL; ++ bool ok; ++ ++ lp_ctx = loadparm_init_s3(conn, loadparm_s3_helpers()); ++ if (lp_ctx == NULL) { ++ DBG_DEBUG("loadparm_init_s3 failed\n"); ++ return false; ++ } ++ + #if defined(WITH_SMB1SERVER) + if (conn->protocol >= PROTOCOL_SMB2_02) { + #endif +- return smb2_srv_init_signing(conn); ++ ok = smb2_srv_init_signing(lp_ctx, conn); + #if defined(WITH_SMB1SERVER) + } else { +- return smb1_srv_init_signing(conn); ++ ok = smb1_srv_init_signing(lp_ctx, conn); + } + #endif ++ talloc_unlink(conn, lp_ctx); ++ return ok; + } +-- +2.34.1 diff --git a/backport-0002-CVE-2023-34966.patch b/backport-0002-CVE-2023-34966.patch new file mode 100644 index 0000000000000000000000000000000000000000..d0e93a68c236eb6f879fe25d7ea53cdc05a3d8a4 --- /dev/null +++ b/backport-0002-CVE-2023-34966.patch @@ -0,0 +1,75 @@ +From c77b31f1bcb8778007cfa584e15f3bb2f7135752 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Fri, 26 May 2023 13:06:19 +0200 +Subject: [PATCH 04/28] CVE-2023-34966: mdssvc: harden sl_unpack_loop() + +A malicious client could send a packet where subcount is zero, leading to a busy +loop because + + count -= subcount +=> count -= 0 +=> while (count > 0) + +loops forever. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15340 + +Signed-off-by: Ralph Boehme + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/rpc_server/mdssvc/marshalling.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/source3/rpc_server/mdssvc/marshalling.c b/source3/rpc_server/mdssvc/marshalling.c +index 9ba6ef571f2..d794ba15838 100644 +--- a/source3/rpc_server/mdssvc/marshalling.c ++++ b/source3/rpc_server/mdssvc/marshalling.c +@@ -1119,7 +1119,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX *query, + sl_nil_t nil = 0; + + subcount = tag.count; +- if (subcount > count) { ++ if (subcount < 1 || subcount > count) { + return -1; + } + for (i = 0; i < subcount; i++) { +@@ -1147,7 +1147,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX *query, + + case SQ_TYPE_INT64: + subcount = sl_unpack_ints(query, buf, offset, bufsize, encoding); +- if (subcount == -1 || subcount > count) { ++ if (subcount < 1 || subcount > count) { + return -1; + } + offset += tag.size; +@@ -1156,7 +1156,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX *query, + + case SQ_TYPE_UUID: + subcount = sl_unpack_uuid(query, buf, offset, bufsize, encoding); +- if (subcount == -1 || subcount > count) { ++ if (subcount < 1 || subcount > count) { + return -1; + } + offset += tag.size; +@@ -1165,7 +1165,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX *query, + + case SQ_TYPE_FLOAT: + subcount = sl_unpack_floats(query, buf, offset, bufsize, encoding); +- if (subcount == -1 || subcount > count) { ++ if (subcount < 1 || subcount > count) { + return -1; + } + offset += tag.size; +@@ -1174,7 +1174,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX *query, + + case SQ_TYPE_DATE: + subcount = sl_unpack_date(query, buf, offset, bufsize, encoding); +- if (subcount == -1 || subcount > count) { ++ if (subcount < 1 || subcount > count) { + return -1; + } + offset += tag.size; +-- +2.34.1 diff --git a/backport-0002-CVE-2023-34967.patch b/backport-0002-CVE-2023-34967.patch new file mode 100644 index 0000000000000000000000000000000000000000..ad28e579077b1bb95e337512e973600bfe46835f --- /dev/null +++ b/backport-0002-CVE-2023-34967.patch @@ -0,0 +1,122 @@ +From 049c13245649fab412b61a5b55e5a7dea72d7c72 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Fri, 26 May 2023 15:06:38 +0200 +Subject: [PATCH 06/28] CVE-2023-34967: mdssvc: add type checking to + dalloc_value_for_key() + +Change the dalloc_value_for_key() function to require an additional final +argument which denotes the expected type of the value associated with a key. If +the types don't match, return NULL. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15341 + +Signed-off-by: Ralph Boehme + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/rpc_server/mdssvc/dalloc.c | 14 ++++++++++---- + source3/rpc_server/mdssvc/mdssvc.c | 17 +++++++++++++---- + 2 files changed, 23 insertions(+), 8 deletions(-) + +diff --git a/source3/rpc_server/mdssvc/dalloc.c b/source3/rpc_server/mdssvc/dalloc.c +index 007702d4540..8b79b41fd97 100644 +--- a/source3/rpc_server/mdssvc/dalloc.c ++++ b/source3/rpc_server/mdssvc/dalloc.c +@@ -159,7 +159,7 @@ void *dalloc_value_for_key(const DALLOC_CTX *d, ...) + int result = 0; + void *p = NULL; + va_list args; +- const char *type; ++ const char *type = NULL; + int elem; + size_t array_len; + +@@ -170,7 +170,6 @@ void *dalloc_value_for_key(const DALLOC_CTX *d, ...) + array_len = talloc_array_length(d->dd_talloc_array); + elem = va_arg(args, int); + if (elem >= array_len) { +- va_end(args); + result = -1; + goto done; + } +@@ -178,8 +177,6 @@ void *dalloc_value_for_key(const DALLOC_CTX *d, ...) + type = va_arg(args, const char *); + } + +- va_end(args); +- + array_len = talloc_array_length(d->dd_talloc_array); + + for (elem = 0; elem + 1 < array_len; elem += 2) { +@@ -192,8 +189,17 @@ void *dalloc_value_for_key(const DALLOC_CTX *d, ...) + break; + } + } ++ if (p == NULL) { ++ goto done; ++ } ++ ++ type = va_arg(args, const char *); ++ if (strcmp(talloc_get_name(p), type) != 0) { ++ p = NULL; ++ } + + done: ++ va_end(args); + if (result != 0) { + p = NULL; + } +diff --git a/source3/rpc_server/mdssvc/mdssvc.c b/source3/rpc_server/mdssvc/mdssvc.c +index 9b32c99b8b3..7dd3c84713f 100644 +--- a/source3/rpc_server/mdssvc/mdssvc.c ++++ b/source3/rpc_server/mdssvc/mdssvc.c +@@ -872,7 +872,8 @@ static bool slrpc_open_query(struct mds_ctx *mds_ctx, + + querystring = dalloc_value_for_key(query, "DALLOC_CTX", 0, + "DALLOC_CTX", 1, +- "kMDQueryString"); ++ "kMDQueryString", ++ "char *"); + if (querystring == NULL) { + DEBUG(1, ("missing kMDQueryString\n")); + goto error; +@@ -912,8 +913,11 @@ static bool slrpc_open_query(struct mds_ctx *mds_ctx, + slq->ctx2 = *uint64p; + + path_scope = dalloc_value_for_key(query, "DALLOC_CTX", 0, +- "DALLOC_CTX", 1, "kMDScopeArray"); ++ "DALLOC_CTX", 1, ++ "kMDScopeArray", ++ "sl_array_t"); + if (path_scope == NULL) { ++ DBG_ERR("missing kMDScopeArray\n"); + goto error; + } + +@@ -934,8 +938,11 @@ static bool slrpc_open_query(struct mds_ctx *mds_ctx, + } + + reqinfo = dalloc_value_for_key(query, "DALLOC_CTX", 0, +- "DALLOC_CTX", 1, "kMDAttributeArray"); ++ "DALLOC_CTX", 1, ++ "kMDAttributeArray", ++ "sl_array_t"); + if (reqinfo == NULL) { ++ DBG_ERR("missing kMDAttributeArray\n"); + goto error; + } + +@@ -943,7 +950,9 @@ static bool slrpc_open_query(struct mds_ctx *mds_ctx, + DEBUG(10, ("requested attributes: %s", dalloc_dump(reqinfo, 0))); + + cnids = dalloc_value_for_key(query, "DALLOC_CTX", 0, +- "DALLOC_CTX", 1, "kMDQueryItemArray"); ++ "DALLOC_CTX", 1, ++ "kMDQueryItemArray", ++ "sl_array_t"); + if (cnids) { + ok = sort_cnids(slq, cnids->ca_cnids); + if (!ok) { +-- +2.34.1 diff --git a/backport-0002-CVE-2023-34968.patch b/backport-0002-CVE-2023-34968.patch new file mode 100644 index 0000000000000000000000000000000000000000..d8212a82d7ddeda5a03ddd053a555459ceb482c9 --- /dev/null +++ b/backport-0002-CVE-2023-34968.patch @@ -0,0 +1,36 @@ +From 47a0c1681dd1e7ec407679793966ec8bdc08a24e Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Sat, 17 Jun 2023 13:39:55 +0200 +Subject: [PATCH 08/28] CVE-2023-34968: mdssvc: add missing + "kMDSStoreMetaScopes" dict key in slrpc_fetch_properties() + +We were adding the value, but not the key. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/rpc_server/mdssvc/mdssvc.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/source3/rpc_server/mdssvc/mdssvc.c b/source3/rpc_server/mdssvc/mdssvc.c +index a6d09a43b9c..9c23ef95753 100644 +--- a/source3/rpc_server/mdssvc/mdssvc.c ++++ b/source3/rpc_server/mdssvc/mdssvc.c +@@ -730,6 +730,10 @@ static bool slrpc_fetch_properties(struct mds_ctx *mds_ctx, + } + + /* kMDSStoreMetaScopes array */ ++ result = dalloc_stradd(dict, "kMDSStoreMetaScopes"); ++ if (result != 0) { ++ return false; ++ } + array = dalloc_zero(dict, sl_array_t); + if (array == NULL) { + return NULL; +-- +2.34.1 diff --git a/backport-0002-CVE-2023-3961.patch b/backport-0002-CVE-2023-3961.patch new file mode 100644 index 0000000000000000000000000000000000000000..04169ba65c2bedc1bb07c2460decef6f597a327c --- /dev/null +++ b/backport-0002-CVE-2023-3961.patch @@ -0,0 +1,209 @@ +From 125ce23115b92045a1584f5654669180bea83067 Mon Sep 17 00:00:00 2001 +From: Jeremy Allison +Date: Tue, 25 Jul 2023 17:49:21 -0700 +Subject: [PATCH 02/30] CVE-2023-3961:s3:torture: Add test + SMB2-INVALID-PIPENAME to show we allow bad pipenames with unix separators + through to the UNIX domain socket code. + +The raw SMB2-INVALID-PIPENAME test passes against Windows 2022, +as it just returns NT_STATUS_OBJECT_NAME_NOT_FOUND. + +Add the knownfail. + +BUG:https://bugzilla.samba.org/show_bug.cgi?id=15422 + +Signed-off-by: Jeremy Allison + +[abartlet@samba.org backported to Samba 4.17 due to conflicts from + context of other new torture tests missing in this version and + changes in smb2cli_create() arguments] + +Conflict: context adapt +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 02/30] CVE-2023-3961:s3:torture: Add test + SMB2-INVALID-PIPENAME to show we allow bad pipenames with unix separators +--- + selftest/knownfail.d/badpipename | 1 + + source3/selftest/tests.py | 15 +++++ + source3/torture/proto.h | 1 + + source3/torture/test_smb2.c | 105 +++++++++++++++++++++++++++++++ + source3/torture/torture.c | 4 ++ + 5 files changed, 126 insertions(+) + create mode 100644 selftest/knownfail.d/badpipename + +diff --git a/selftest/knownfail.d/badpipename b/selftest/knownfail.d/badpipename +new file mode 100644 +index 0000000..e69715f +--- /dev/null ++++ b/selftest/knownfail.d/badpipename +@@ -0,0 +1 @@ ++^samba3.smbtorture_s3.smb2.SMB2-INVALID-PIPENAME.smbtorture\(fileserver\) +diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py +index d4f2ea4..1fe17dd 100755 +--- a/source3/selftest/tests.py ++++ b/source3/selftest/tests.py +@@ -229,6 +229,21 @@ plantestsuite("samba3.smbtorture_s3.smb1.MSDFS-ATTRIBUTE", + "-mNT1", + "-f msdfs-src1"]) + ++# ++# BUG: https://bugzilla.samba.org/show_bug.cgi?id=15422 ++# Prevent bad pipenames. ++# ++plantestsuite("samba3.smbtorture_s3.smb2.SMB2-INVALID-PIPENAME", ++ "fileserver", ++ [os.path.join(samba3srcdir, ++ "script/tests/test_smbtorture_s3.sh"), ++ 'SMB2-INVALID-PIPENAME', ++ '//$SERVER_IP/tmp', ++ '$USERNAME', ++ '$PASSWORD', ++ smbtorture3, ++ "-mSMB2"]) ++ + # + # SMB2-STREAM-ACL needs to run against a special share - vfs_wo_fruit + # +diff --git a/source3/torture/proto.h b/source3/torture/proto.h +index 551c4ea..f8d6384 100644 +--- a/source3/torture/proto.h ++++ b/source3/torture/proto.h +@@ -120,6 +120,7 @@ bool run_smb2_path_slash(int dummy); + bool run_smb2_sacl(int dummy); + bool run_smb2_quota1(int dummy); + bool run_smb2_stream_acl(int dummy); ++bool run_smb2_invalid_pipename(int dummy); + bool run_list_dir_async_test(int dummy); + bool run_delete_on_close_non_empty(int dummy); + bool run_delete_on_close_nonwrite_delete_yes_test(int dummy); +diff --git a/source3/torture/test_smb2.c b/source3/torture/test_smb2.c +index c3f0141..f6afdf0 100644 +--- a/source3/torture/test_smb2.c ++++ b/source3/torture/test_smb2.c +@@ -3608,3 +3608,108 @@ bool run_delete_on_close_nonwrite_delete_no_test(int dummy) + } + return ret; + } ++ ++bool run_smb2_invalid_pipename(int dummy) ++{ ++ struct cli_state *cli = NULL; ++ NTSTATUS status; ++ uint64_t fid_persistent = 0; ++ uint64_t fid_volatile = 0; ++ const char *unknown_pipe = "badpipe"; ++ const char *invalid_pipe = "../../../../../../../../../badpipe"; ++ ++ printf("Starting SMB2-INVALID-PIPENAME\n"); ++ ++ if (!torture_init_connection(&cli)) { ++ return false; ++ } ++ ++ status = smbXcli_negprot(cli->conn, ++ cli->timeout, ++ PROTOCOL_SMB2_02, ++ PROTOCOL_SMB3_11); ++ if (!NT_STATUS_IS_OK(status)) { ++ printf("smbXcli_negprot returned %s\n", nt_errstr(status)); ++ return false; ++ } ++ ++ status = cli_session_setup_creds(cli, torture_creds); ++ if (!NT_STATUS_IS_OK(status)) { ++ printf("cli_session_setup returned %s\n", nt_errstr(status)); ++ return false; ++ } ++ ++ status = cli_tree_connect(cli, "IPC$", "?????", NULL); ++ if (!NT_STATUS_IS_OK(status)) { ++ printf("cli_tree_connect returned %s\n", nt_errstr(status)); ++ return false; ++ } ++ ++ /* Try and connect to an unknown pipename. */ ++ status = smb2cli_create(cli->conn, ++ cli->timeout, ++ cli->smb2.session, ++ cli->smb2.tcon, ++ unknown_pipe, ++ SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */ ++ SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */ ++ SEC_STD_SYNCHRONIZE| ++ SEC_FILE_READ_DATA| ++ SEC_FILE_WRITE_DATA| ++ SEC_FILE_READ_ATTRIBUTE, /* desired_access, */ ++ FILE_ATTRIBUTE_NORMAL, /* file_attributes, */ ++ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */ ++ FILE_CREATE, /* create_disposition, */ ++ 0, /* create_options, */ ++ NULL, /* smb2_create_blobs *blobs */ ++ &fid_persistent, ++ &fid_volatile, ++ NULL, /* struct smb_create_returns * */ ++ talloc_tos(), /* mem_ctx. */ ++ NULL); /* struct smb2_create_blobs */ ++ /* We should get NT_STATUS_OBJECT_NAME_NOT_FOUND */ ++ if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { ++ printf("%s:%d smb2cli_create on name %s returned %s\n", ++ __FILE__, ++ __LINE__, ++ unknown_pipe, ++ nt_errstr(status)); ++ return false; ++ } ++ ++ /* Try and connect to an invalid pipename containing unix separators. */ ++ status = smb2cli_create(cli->conn, ++ cli->timeout, ++ cli->smb2.session, ++ cli->smb2.tcon, ++ invalid_pipe, ++ SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */ ++ SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */ ++ SEC_STD_SYNCHRONIZE| ++ SEC_FILE_READ_DATA| ++ SEC_FILE_WRITE_DATA| ++ SEC_FILE_READ_ATTRIBUTE, /* desired_access, */ ++ FILE_ATTRIBUTE_NORMAL, /* file_attributes, */ ++ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */ ++ FILE_CREATE, /* create_disposition, */ ++ 0, /* create_options, */ ++ NULL, /* smb2_create_blobs *blobs */ ++ &fid_persistent, ++ &fid_volatile, ++ NULL, /* struct smb_create_returns * */ ++ talloc_tos(), /* mem_ctx. */ ++ NULL); /* struct smb2_create_blobs */ ++ /* ++ * We should still get NT_STATUS_OBJECT_NAME_NOT_FOUND ++ * (tested against Windows 2022). ++ */ ++ if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { ++ printf("%s:%d smb2cli_create on name %s returned %s\n", ++ __FILE__, ++ __LINE__, ++ invalid_pipe, ++ nt_errstr(status)); ++ return false; ++ } ++ return true; ++} +diff --git a/source3/torture/torture.c b/source3/torture/torture.c +index af28b17..922a1bb 100644 +--- a/source3/torture/torture.c ++++ b/source3/torture/torture.c +@@ -15592,6 +15592,10 @@ static struct { + .name = "readdir-timestamp", + .fn = run_readdir_timestamp, + }, ++ { ++ .name = "SMB2-INVALID-PIPENAME", ++ .fn = run_smb2_invalid_pipename, ++ }, + { + .name = NULL, + }, +-- +2.33.0 + diff --git a/backport-0002-CVE-2023-4091.patch b/backport-0002-CVE-2023-4091.patch new file mode 100644 index 0000000000000000000000000000000000000000..706f34cdc33570ef727645ef5670c69afc7b2ffa --- /dev/null +++ b/backport-0002-CVE-2023-4091.patch @@ -0,0 +1,57 @@ +From 8b26f634372f11edcbea33dfd68a3d57889dfcc5 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 1 Aug 2023 13:04:36 +0200 +Subject: [PATCH 05/30] CVE-2023-4091: smbd: use open_access_mask for access + check in open_file() + +If the client requested FILE_OVERWRITE[_IF], we're implicitly adding +FILE_WRITE_DATA to the open_access_mask in open_file_ntcreate(), but for the +access check we're using access_mask which doesn't contain the additional +right, which means we can end up truncating a file for which the user has +only read-only access via an SD. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15439 + +Signed-off-by: Ralph Boehme + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 05/30] CVE-2023-4091: smbd: use open_access_mask for access + check in open_file() +--- + selftest/knownfail.d/samba3.smb2.acls | 1 - + source3/smbd/open.c | 4 ++-- + 2 files changed, 2 insertions(+), 3 deletions(-) + delete mode 100644 selftest/knownfail.d/samba3.smb2.acls + +diff --git a/selftest/knownfail.d/samba3.smb2.acls b/selftest/knownfail.d/samba3.smb2.acls +deleted file mode 100644 +index 18df260c0e5..00000000000 +--- a/selftest/knownfail.d/samba3.smb2.acls ++++ /dev/null +@@ -1 +0,0 @@ +-^samba3.smb2.acls.OVERWRITE_READ_ONLY_FILE +diff --git a/source3/smbd/open.c b/source3/smbd/open.c +index dbf4e40adf4..704c1d7e312 100644 +--- a/source3/smbd/open.c ++++ b/source3/smbd/open.c +@@ -1442,7 +1442,7 @@ static NTSTATUS open_file(struct smb_request *req, + dirfsp, + fsp, + false, +- access_mask); ++ open_access_mask); + + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("smbd_check_access_rights_fsp" +@@ -1633,7 +1633,7 @@ static NTSTATUS open_file(struct smb_request *req, + status = smbd_check_access_rights_fsp(dirfsp, + fsp, + false, +- access_mask); ++ open_access_mask); + + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) && + posix_open && +-- +2.34.1 diff --git a/backport-0002-CVE-2023-4154.patch b/backport-0002-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..412f34b657ceb4d0befe560ce6268b856b641ce2 --- /dev/null +++ b/backport-0002-CVE-2023-4154.patch @@ -0,0 +1,96 @@ +From d7034c4194a2cec0a88870ea3c7709d2a323653a Mon Sep 17 00:00:00 2001 +From: Christian Merten +Date: Mon, 19 Sep 2022 23:01:34 +0200 +Subject: [PATCH 07/30] CVE-2023-4154 librpc ndr/py_security: Export ACE + deletion functions to python + +Exported security_descriptor_sacl_del and security_descriptor_dacl_del as new methods of the +security descriptor class to python. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Christian Merten +Reviewed-by: Douglas Bagnall +Reviewed-by: Jeremy Allison +(cherry picked from commit 84a54d2fa2b1590fdb4e2ea986ded9c39a82cf78) + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 07/30] CVE-2023-4154 librpc ndr/py_security: Export ACE + deletion functions to python +--- + source4/librpc/ndr/py_security.c | 52 +++++++++++++++++++++++++++++++- + 1 file changed, 51 insertions(+), 1 deletion(-) + +diff --git a/source4/librpc/ndr/py_security.c b/source4/librpc/ndr/py_security.c +index e79e7170812..e61b994d7cb 100644 +--- a/source4/librpc/ndr/py_security.c ++++ b/source4/librpc/ndr/py_security.c +@@ -234,6 +234,52 @@ static PyObject *py_descriptor_sacl_del(PyObject *self, PyObject *args) + Py_RETURN_NONE; + } + ++static PyObject *py_descriptor_dacl_del_ace(PyObject *self, PyObject *args) ++{ ++ struct security_descriptor *desc = pytalloc_get_ptr(self); ++ NTSTATUS status; ++ struct security_ace *ace = NULL; ++ PyObject *py_ace = Py_None; ++ ++ if (!PyArg_ParseTuple(args, "O!", &security_ace_Type, &py_ace)) ++ return NULL; ++ ++ if (!PyObject_TypeCheck(py_ace, &security_ace_Type)) { ++ PyErr_SetString(PyExc_TypeError, ++ "expected security.security_ace " ++ "for first argument to .dacl_del_ace"); ++ return NULL; ++ } ++ ++ ace = pytalloc_get_ptr(py_ace); ++ status = security_descriptor_dacl_del_ace(desc, ace); ++ PyErr_NTSTATUS_IS_ERR_RAISE(status); ++ Py_RETURN_NONE; ++} ++ ++static PyObject *py_descriptor_sacl_del_ace(PyObject *self, PyObject *args) ++{ ++ struct security_descriptor *desc = pytalloc_get_ptr(self); ++ NTSTATUS status; ++ struct security_ace *ace = NULL; ++ PyObject *py_ace = Py_None; ++ ++ if (!PyArg_ParseTuple(args, "O!", &security_ace_Type, &py_ace)) ++ return NULL; ++ ++ if (!PyObject_TypeCheck(py_ace, &security_ace_Type)) { ++ PyErr_SetString(PyExc_TypeError, ++ "expected security.security_ace " ++ "for first argument to .sacl_del_ace"); ++ return NULL; ++ } ++ ++ ace = pytalloc_get_ptr(py_ace); ++ status = security_descriptor_sacl_del_ace(desc, ace); ++ PyErr_NTSTATUS_IS_ERR_RAISE(status); ++ Py_RETURN_NONE; ++} ++ + static PyObject *py_descriptor_new(PyTypeObject *self, PyObject *args, PyObject *kwargs) + { + return pytalloc_steal(self, security_descriptor_initialise(NULL)); +@@ -302,7 +348,11 @@ static PyMethodDef py_descriptor_extra_methods[] = { + NULL }, + { "sacl_del", (PyCFunction)py_descriptor_sacl_del, METH_VARARGS, + NULL }, +- { "from_sddl", (PyCFunction)py_descriptor_from_sddl, METH_VARARGS|METH_CLASS, ++ { "dacl_del_ace", (PyCFunction)py_descriptor_dacl_del_ace, METH_VARARGS, ++ NULL }, ++ { "sacl_del_ace", (PyCFunction)py_descriptor_sacl_del_ace, METH_VARARGS, ++ NULL }, ++ { "from_sddl", (PyCFunction)py_descriptor_from_sddl, METH_VARARGS|METH_CLASS, + NULL }, + { "as_sddl", (PyCFunction)py_descriptor_as_sddl, METH_VARARGS, + NULL }, +-- +2.34.1 diff --git a/backport-0002-CVE-2023-42669.patch b/backport-0002-CVE-2023-42669.patch new file mode 100644 index 0000000000000000000000000000000000000000..bf57e713040a2a683032f92fcb8eddef24703961 --- /dev/null +++ b/backport-0002-CVE-2023-42669.patch @@ -0,0 +1,38 @@ +From d4d49635247ab4bc580899d7c5fb54484b806225 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Tue, 12 Sep 2023 19:01:03 +1200 +Subject: [PATCH 28/30] CVE-2023-42669 s3-rpc_server: Disable rpcecho for + consistency with the AD DC + +The rpcecho server in source3 does have samba the sleep() feature that +the s4 version has, but the task architecture is different, so there +is not the same impact. Hoever equally this is not something that +should be enabled on production builds of Samba, so restrict to +selftest builds. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15474 + +Signed-off-by: Andrew Bartlett + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 28/30] CVE-2023-42669 s3-rpc_server: Disable rpcecho for + consistency with the AD DC +--- + source3/rpc_server/wscript_build | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/source3/rpc_server/wscript_build b/source3/rpc_server/wscript_build +index 341df41a321..5ed81283395 100644 +--- a/source3/rpc_server/wscript_build ++++ b/source3/rpc_server/wscript_build +@@ -38,6 +38,7 @@ bld.SAMBA3_BINARY('rpcd_rpcecho', + RPC_WORKER + RPC_RPCECHO + ''', ++ for_selftest=True, + install_path='${SAMBA_LIBEXECDIR}') + + bld.SAMBA3_BINARY('rpcd_classic', +-- +2.34.1 diff --git a/backport-0002-CVE-2023-42670.patch b/backport-0002-CVE-2023-42670.patch new file mode 100644 index 0000000000000000000000000000000000000000..a597c5ca049836463c1748f3814a56a2891099b2 --- /dev/null +++ b/backport-0002-CVE-2023-42670.patch @@ -0,0 +1,293 @@ +From 2acdaf9860f127c179a3d2e2adb18f901854aebf Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Tue, 12 Sep 2023 16:23:49 +1200 +Subject: [PATCH 30/30] CVE-2023-42670 s3-rpc_server: Remove cross-check with + "samba" EPM lookup + +We now have ensured that no conflicting services attempt to start +so we do not need the runtime lookup and so avoid the risk that +the lookup may fail. + +This means that any duplicates will be noticed early not just +in a race condition. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15473 + +Signed-off-by: Andrew Bartlett + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 30/30] CVE-2023-42670 s3-rpc_server: Remove cross-check with + "samba" EPM lookup +--- + source3/rpc_server/rpc_host.c | 154 +--------------------------------- + 1 file changed, 4 insertions(+), 150 deletions(-) + +diff --git a/source3/rpc_server/rpc_host.c b/source3/rpc_server/rpc_host.c +index 321d30cef2c..810d128d958 100644 +--- a/source3/rpc_server/rpc_host.c ++++ b/source3/rpc_server/rpc_host.c +@@ -214,7 +214,6 @@ struct rpc_server_get_endpoints_state { + char **argl; + char *ncalrpc_endpoint; + enum dcerpc_transport_t only_transport; +- struct dcerpc_binding **existing_bindings; + + struct rpc_host_iface_name *iface_names; + struct rpc_host_endpoint **endpoints; +@@ -235,7 +234,6 @@ static void rpc_server_get_endpoints_done(struct tevent_req *subreq); + * @param[in] ev Event context to run this on + * @param[in] rpc_server_exe Binary to ask with --list-interfaces + * @param[in] only_transport Filter out anything but this +- * @param[in] existing_bindings Filter out endpoints served by "samba" + * @return The tevent_req representing this process + */ + +@@ -243,8 +241,7 @@ static struct tevent_req *rpc_server_get_endpoints_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const char *rpc_server_exe, +- enum dcerpc_transport_t only_transport, +- struct dcerpc_binding **existing_bindings) ++ enum dcerpc_transport_t only_transport) + { + struct tevent_req *req = NULL, *subreq = NULL; + struct rpc_server_get_endpoints_state *state = NULL; +@@ -256,7 +253,6 @@ static struct tevent_req *rpc_server_get_endpoints_send( + return NULL; + } + state->only_transport = only_transport; +- state->existing_bindings = existing_bindings; + + progname = strrchr(rpc_server_exe, '/'); + if (progname != NULL) { +@@ -417,37 +413,17 @@ static bool dcerpc_binding_same_endpoint( + * In member mode, we only serve named pipes. Indicated by NCACN_NP + * passed in via "only_transport". + * +- * In AD mode, the "samba" process already serves many endpoints, +- * passed in via "existing_binding". Don't serve those from +- * samba-dcerpcd. +- * + * @param[in] binding Which binding is in question? + * @param[in] only_transport Exclusive transport to serve +- * @param[in] existing_bindings Endpoints served by "samba" already + * @return Do we want to serve "binding" from samba-dcerpcd? + */ + + static bool rpc_host_serve_endpoint( + struct dcerpc_binding *binding, +- enum dcerpc_transport_t only_transport, +- struct dcerpc_binding **existing_bindings) ++ enum dcerpc_transport_t only_transport) + { + enum dcerpc_transport_t transport = + dcerpc_binding_get_transport(binding); +- size_t i, num_existing_bindings; +- +- num_existing_bindings = talloc_array_length(existing_bindings); +- +- for (i=0; ibinding, state->only_transport, state->existing_bindings); ++ ep->binding, state->only_transport); + if (!serve_this) { + goto fail; + } +@@ -1607,7 +1583,6 @@ static struct tevent_req *rpc_server_setup_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct rpc_host *host, +- struct dcerpc_binding **existing_bindings, + const char *rpc_server_exe) + { + struct tevent_req *req = NULL, *subreq = NULL; +@@ -1639,8 +1614,7 @@ static struct tevent_req *rpc_server_setup_send( + state, + ev, + rpc_server_exe, +- host->np_helper ? NCACN_NP : NCA_UNKNOWN, +- existing_bindings); ++ host->np_helper ? NCACN_NP : NCA_UNKNOWN); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } +@@ -2344,7 +2318,6 @@ static struct tevent_req *rpc_host_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct messaging_context *msg_ctx, +- struct dcerpc_binding **existing_bindings, + char *servers, + int ready_signal_fd, + const char *daemon_ready_progname, +@@ -2465,7 +2438,6 @@ static struct tevent_req *rpc_host_send( + state, + ev, + host, +- existing_bindings, + exe); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); +@@ -2648,117 +2620,6 @@ static int rpc_host_pidfile_create( + return EAGAIN; + } + +-/* +- * Find which interfaces are already being served by the samba AD +- * DC so we know not to serve them. Some interfaces like netlogon +- * are served by "samba", some like srvsvc will be served by the +- * source3 based RPC servers. +- */ +-static NTSTATUS rpc_host_epm_lookup( +- TALLOC_CTX *mem_ctx, +- struct dcerpc_binding ***pbindings) +-{ +- struct rpc_pipe_client *cli = NULL; +- struct pipe_auth_data *auth = NULL; +- struct policy_handle entry_handle = { .handle_type = 0 }; +- struct dcerpc_binding **bindings = NULL; +- NTSTATUS status = NT_STATUS_UNSUCCESSFUL; +- +- status = rpc_pipe_open_ncalrpc(mem_ctx, &ndr_table_epmapper, &cli); +- if (!NT_STATUS_IS_OK(status)) { +- DBG_DEBUG("rpc_pipe_open_ncalrpc failed: %s\n", +- nt_errstr(status)); +- goto fail; +- } +- status = rpccli_ncalrpc_bind_data(cli, &auth); +- if (!NT_STATUS_IS_OK(status)) { +- DBG_DEBUG("rpccli_ncalrpc_bind_data failed: %s\n", +- nt_errstr(status)); +- goto fail; +- } +- status = rpc_pipe_bind(cli, auth); +- if (!NT_STATUS_IS_OK(status)) { +- DBG_DEBUG("rpc_pipe_bind failed: %s\n", nt_errstr(status)); +- goto fail; +- } +- +- for (;;) { +- size_t num_bindings = talloc_array_length(bindings); +- struct dcerpc_binding **tmp = NULL; +- uint32_t num_entries = 0; +- struct epm_entry_t *entry = NULL; +- struct dcerpc_binding *binding = NULL; +- uint32_t result; +- +- entry = talloc(cli, struct epm_entry_t); +- if (entry == NULL) { +- goto fail; +- } +- +- status = dcerpc_epm_Lookup( +- cli->binding_handle, /* binding_handle */ +- cli, /* mem_ctx */ +- 0, /* rpc_c_ep_all */ +- NULL, /* object */ +- NULL, /* interface id */ +- 0, /* rpc_c_vers_all */ +- &entry_handle, /* entry_handle */ +- 1, /* max_ents */ +- &num_entries, /* num_ents */ +- entry, /* entries */ +- &result); /* result */ +- if (!NT_STATUS_IS_OK(status)) { +- DBG_DEBUG("dcerpc_epm_Lookup failed: %s\n", +- nt_errstr(status)); +- goto fail; +- } +- +- if (result == EPMAPPER_STATUS_NO_MORE_ENTRIES) { +- break; +- } +- +- if (result != EPMAPPER_STATUS_OK) { +- DBG_DEBUG("dcerpc_epm_Lookup returned %"PRIu32"\n", +- result); +- break; +- } +- +- if (num_entries != 1) { +- DBG_DEBUG("epm_Lookup returned %"PRIu32" " +- "entries, expected one\n", +- num_entries); +- break; +- } +- +- status = dcerpc_binding_from_tower( +- mem_ctx, &entry->tower->tower, &binding); +- if (!NT_STATUS_IS_OK(status)) { +- break; +- } +- +- tmp = talloc_realloc( +- mem_ctx, +- bindings, +- struct dcerpc_binding *, +- num_bindings+1); +- if (tmp == NULL) { +- status = NT_STATUS_NO_MEMORY; +- goto fail; +- } +- bindings = tmp; +- +- bindings[num_bindings] = talloc_move(bindings, &binding); +- +- TALLOC_FREE(entry); +- } +- +- *pbindings = bindings; +- status = NT_STATUS_OK; +-fail: +- TALLOC_FREE(cli); +- return status; +-} +- + static void samba_dcerpcd_stdin_handler( + struct tevent_context *ev, + struct tevent_fd *fde, +@@ -2788,7 +2649,6 @@ int main(int argc, const char *argv[]) + struct tevent_context *ev_ctx = NULL; + struct messaging_context *msg_ctx = NULL; + struct tevent_req *req = NULL; +- struct dcerpc_binding **existing_bindings = NULL; + char *servers = NULL; + const char *arg = NULL; + size_t num_servers; +@@ -2995,11 +2855,6 @@ int main(int argc, const char *argv[]) + exit(1); + } + +- status = rpc_host_epm_lookup(frame, &existing_bindings); +- DBG_DEBUG("rpc_host_epm_lookup returned %s, %zu bindings\n", +- nt_errstr(status), +- talloc_array_length(existing_bindings)); +- + ret = rpc_host_pidfile_create(msg_ctx, progname, ready_signal_fd); + if (ret != 0) { + DBG_DEBUG("rpc_host_pidfile_create failed: %s\n", +@@ -3013,7 +2868,6 @@ int main(int argc, const char *argv[]) + ev_ctx, + ev_ctx, + msg_ctx, +- existing_bindings, + servers, + ready_signal_fd, + cmdline_daemon_cfg->fork ? NULL : progname, +-- +2.34.1 diff --git a/backport-0003-CVE-2018-14628.patch b/backport-0003-CVE-2018-14628.patch new file mode 100644 index 0000000000000000000000000000000000000000..94948c8c667f7dd3c2f42ade3e6deef0e8eeec9c --- /dev/null +++ b/backport-0003-CVE-2018-14628.patch @@ -0,0 +1,72 @@ +From 96d787c0a5182c24ea51591342b37eb041798afb Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 29 Jan 2016 23:34:15 +0100 +Subject: [PATCH 3/6] CVE-2018-14628: s4:setup: set the correct + nTSecurityDescriptor on the CN=Deleted Objects container + +This revealed a bug in our dirsync code, so we mark +test_search_with_dirsync_deleted_objects as knownfail. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13595 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +(cherry picked from commit 7f8b15faa76d05023c987fac2c4c31f9ac61bb47) + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=18168 +[PATCH 3/6] CVE-2018-14628: s4:setup: set the correct + nTSecurityDescriptor on the CN=Deleted Objects container +--- + selftest/knownfail.d/samba4.ldap.confidential_attr | 1 + + source4/setup/provision.ldif | 1 + + source4/setup/provision_configuration.ldif | 1 + + source4/setup/provision_dnszones_add.ldif | 1 + + 4 files changed, 4 insertions(+) + create mode 100644 selftest/knownfail.d/samba4.ldap.confidential_attr + +diff --git a/selftest/knownfail.d/samba4.ldap.confidential_attr b/selftest/knownfail.d/samba4.ldap.confidential_attr +new file mode 100644 +index 000000000000..46a75ce928b0 +--- /dev/null ++++ b/selftest/knownfail.d/samba4.ldap.confidential_attr +@@ -0,0 +1 @@ ++^samba4.ldap.confidential_attr.python.*.__main__.*.test_search_with_dirsync_deleted_objects +diff --git a/source4/setup/provision.ldif b/source4/setup/provision.ldif +index 5d9eba49f86f..7f966fd57f81 100644 +--- a/source4/setup/provision.ldif ++++ b/source4/setup/provision.ldif +@@ -34,6 +34,7 @@ isDeleted: TRUE + isCriticalSystemObject: TRUE + showInAdvancedViewOnly: TRUE + systemFlags: -1946157056 ++nTSecurityDescriptor:: ${DELETEDOBJECTS_DESCRIPTOR} + + # Computers located in "provision_computers*.ldif" + # Users/Groups located in "provision_users*.ldif" +diff --git a/source4/setup/provision_configuration.ldif b/source4/setup/provision_configuration.ldif +index 53c9c8536de4..8fcbddbdae48 100644 +--- a/source4/setup/provision_configuration.ldif ++++ b/source4/setup/provision_configuration.ldif +@@ -14,6 +14,7 @@ description: Container for deleted objects + isDeleted: TRUE + isCriticalSystemObject: TRUE + systemFlags: -1946157056 ++nTSecurityDescriptor:: ${DELETEDOBJECTS_DESCRIPTOR} + + # Extended rights + +diff --git a/source4/setup/provision_dnszones_add.ldif b/source4/setup/provision_dnszones_add.ldif +index 860aa4b72b30..a2d6b6bab8f2 100644 +--- a/source4/setup/provision_dnszones_add.ldif ++++ b/source4/setup/provision_dnszones_add.ldif +@@ -8,6 +8,7 @@ description: Deleted objects + isDeleted: TRUE + isCriticalSystemObject: TRUE + systemFlags: -1946157056 ++nTSecurityDescriptor:: ${DELETEDOBJECTS_DESCRIPTOR} + + dn: CN=LostAndFound,${ZONE_DN} + objectClass: top +-- +2.34.1 diff --git a/backport-0003-CVE-2023-0225.patch b/backport-0003-CVE-2023-0225.patch new file mode 100644 index 0000000000000000000000000000000000000000..5a997ac894073c33485ecb522f3dcf829e31099a --- /dev/null +++ b/backport-0003-CVE-2023-0225.patch @@ -0,0 +1,291 @@ +From 417fda9bfde2f8db315ea0460fb7da6e780b859c Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Wed, 4 Jan 2023 21:37:49 +1300 +Subject: [PATCH 3/4] CVE-2023-0225 pytest/acl: test deleting dNSHostName as + unprivileged user + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15276 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org The self.set_heuristic(samba.dsdb.DS_HR_ATTR_AUTHZ_ON_LDAP_ADD, b'11') + in the test setUp() is unused in this test but is included as a + clean backport, so the fact that the server does not implement this + is unimportant] + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17833 +--- + selftest/knownfail.d/dns-host-name-deletion | 2 + + source4/dsdb/tests/python/acl_modify.py | 236 ++++++++++++++++++++ + source4/selftest/tests.py | 1 + + 3 files changed, 239 insertions(+) + create mode 100644 selftest/knownfail.d/dns-host-name-deletion + create mode 100755 source4/dsdb/tests/python/acl_modify.py + +diff --git a/selftest/knownfail.d/dns-host-name-deletion b/selftest/knownfail.d/dns-host-name-deletion +new file mode 100644 +index 00000000000..ac11619ffc3 +--- /dev/null ++++ b/selftest/knownfail.d/dns-host-name-deletion +@@ -0,0 +1,2 @@ ++^samba4.ldap.acl_modify.python\(.*\).__main__.AclModifyTests.test_modify_delete_dns_host_name_ldif_unspecified\(.*\) ++^samba4.ldap.acl_modify.python\(.*\).__main__.AclModifyTests.test_modify_delete_dns_host_name_unspecified\(.*\) +diff --git a/source4/dsdb/tests/python/acl_modify.py b/source4/dsdb/tests/python/acl_modify.py +new file mode 100755 +index 00000000000..c85748a764f +--- /dev/null ++++ b/source4/dsdb/tests/python/acl_modify.py +@@ -0,0 +1,236 @@ ++#!/usr/bin/env python3 ++# -*- coding: utf-8 -*- ++ ++ ++import optparse ++import sys ++sys.path.insert(0, "bin/python") ++import samba ++ ++from samba.tests.subunitrun import SubunitOptions, TestProgram ++ ++import samba.getopt as options ++ ++from ldb import ERR_INSUFFICIENT_ACCESS_RIGHTS ++from ldb import Message, MessageElement, Dn ++from ldb import FLAG_MOD_REPLACE, FLAG_MOD_DELETE ++from samba.dcerpc import security ++ ++from samba.auth import system_session ++from samba import gensec, sd_utils ++from samba.samdb import SamDB ++from samba.credentials import Credentials, DONT_USE_KERBEROS ++import samba.tests ++import samba.dsdb ++ ++ ++parser = optparse.OptionParser("acl.py [options] ") ++sambaopts = options.SambaOptions(parser) ++parser.add_option_group(sambaopts) ++parser.add_option_group(options.VersionOptions(parser)) ++ ++# use command line creds if available ++credopts = options.CredentialsOptions(parser) ++parser.add_option_group(credopts) ++subunitopts = SubunitOptions(parser) ++parser.add_option_group(subunitopts) ++ ++opts, args = parser.parse_args() ++ ++if len(args) < 1: ++ parser.print_usage() ++ sys.exit(1) ++ ++host = args[0] ++if "://" not in host: ++ ldaphost = "ldap://%s" % host ++else: ++ ldaphost = host ++ start = host.rindex("://") ++ host = host.lstrip(start + 3) ++ ++lp = sambaopts.get_loadparm() ++creds = credopts.get_credentials(lp) ++creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL) ++ ++# ++# Tests start here ++# ++ ++ ++class AclTests(samba.tests.TestCase): ++ ++ def setUp(self): ++ super(AclTests, self).setUp() ++ ++ strict_checking = samba.tests.env_get_var_value('STRICT_CHECKING', allow_missing=True) ++ if strict_checking is None: ++ strict_checking = '1' ++ self.strict_checking = bool(int(strict_checking)) ++ ++ self.ldb_admin = SamDB(ldaphost, credentials=creds, session_info=system_session(lp), lp=lp) ++ self.base_dn = self.ldb_admin.domain_dn() ++ self.domain_sid = security.dom_sid(self.ldb_admin.get_domain_sid()) ++ self.user_pass = "samba123@" ++ self.configuration_dn = self.ldb_admin.get_config_basedn().get_linearized() ++ self.sd_utils = sd_utils.SDUtils(self.ldb_admin) ++ self.addCleanup(self.delete_admin_connection) ++ # used for anonymous login ++ self.creds_tmp = Credentials() ++ self.creds_tmp.set_username("") ++ self.creds_tmp.set_password("") ++ self.creds_tmp.set_domain(creds.get_domain()) ++ self.creds_tmp.set_realm(creds.get_realm()) ++ self.creds_tmp.set_workstation(creds.get_workstation()) ++ print("baseDN: %s" % self.base_dn) ++ ++ # set AttributeAuthorizationOnLDAPAdd and BlockOwnerImplicitRights ++ self.set_heuristic(samba.dsdb.DS_HR_ATTR_AUTHZ_ON_LDAP_ADD, b'11') ++ ++ def set_heuristic(self, index, values): ++ self.assertGreater(index, 0) ++ self.assertLess(index, 30) ++ self.assertIsInstance(values, bytes) ++ ++ # Get the old "dSHeuristics" if it was set ++ dsheuristics = self.ldb_admin.get_dsheuristics() ++ # Reset the "dSHeuristics" as they were before ++ self.addCleanup(self.ldb_admin.set_dsheuristics, dsheuristics) ++ # Set the "dSHeuristics" to activate the correct behaviour ++ default_heuristics = b"000000000100000000020000000003" ++ if dsheuristics is None: ++ dsheuristics = b"" ++ dsheuristics += default_heuristics[len(dsheuristics):] ++ dsheuristics = (dsheuristics[:index - 1] + ++ values + ++ dsheuristics[index - 1 + len(values):]) ++ self.ldb_admin.set_dsheuristics(dsheuristics) ++ ++ def get_user_dn(self, name): ++ return "CN=%s,CN=Users,%s" % (name, self.base_dn) ++ ++ def get_ldb_connection(self, target_username, target_password): ++ creds_tmp = Credentials() ++ creds_tmp.set_username(target_username) ++ creds_tmp.set_password(target_password) ++ creds_tmp.set_domain(creds.get_domain()) ++ creds_tmp.set_realm(creds.get_realm()) ++ creds_tmp.set_workstation(creds.get_workstation()) ++ creds_tmp.set_gensec_features(creds_tmp.get_gensec_features() ++ | gensec.FEATURE_SEAL) ++ creds_tmp.set_kerberos_state(DONT_USE_KERBEROS) # kinit is too expensive to use in a tight loop ++ ldb_target = SamDB(url=ldaphost, credentials=creds_tmp, lp=lp) ++ return ldb_target ++ ++ # Test if we have any additional groups for users than default ones ++ def assert_user_no_group_member(self, username): ++ res = self.ldb_admin.search(self.base_dn, expression="(distinguishedName=%s)" % self.get_user_dn(username)) ++ try: ++ self.assertEqual(res[0]["memberOf"][0], "") ++ except KeyError: ++ pass ++ else: ++ self.fail() ++ ++ def delete_admin_connection(self): ++ del self.sd_utils ++ del self.ldb_admin ++ ++ ++class AclModifyTests(AclTests): ++ ++ def setup_computer_with_hostname(self, account_name): ++ ou_dn = f'OU={account_name},{self.base_dn}' ++ dn = f'CN={account_name},{ou_dn}' ++ ++ user, password = "mouse", "mus musculus 123!" ++ self.addCleanup(self.ldb_admin.deleteuser, user) ++ ++ self.ldb_admin.newuser(user, password) ++ self.ldb_user = self.get_ldb_connection(user, password) ++ ++ self.addCleanup(self.ldb_admin.delete, ou_dn, ++ controls=["tree_delete:0"]) ++ self.ldb_admin.create_ou(ou_dn) ++ ++ self.ldb_admin.add({ ++ 'dn': dn, ++ 'objectClass': 'computer', ++ 'sAMAccountName': account_name + '$', ++ }) ++ ++ host_name = f'{account_name}.{self.ldb_user.domain_dns_name()}' ++ ++ m = Message(Dn(self.ldb_admin, dn)) ++ m['dNSHostName'] = MessageElement(host_name, ++ FLAG_MOD_REPLACE, ++ 'dNSHostName') ++ ++ self.ldb_admin.modify(m) ++ return host_name, dn ++ ++ def test_modify_delete_dns_host_name_specified(self): ++ '''Test deleting dNSHostName''' ++ account_name = self.id().rsplit(".", 1)[1][:63] ++ host_name, dn = self.setup_computer_with_hostname(account_name) ++ ++ m = Message(Dn(self.ldb_user, dn)) ++ m['dNSHostName'] = MessageElement(host_name, ++ FLAG_MOD_DELETE, ++ 'dNSHostName') ++ ++ self.assertRaisesLdbError( ++ ERR_INSUFFICIENT_ACCESS_RIGHTS, ++ "User able to delete dNSHostName (with specified name)", ++ self.ldb_user.modify, m) ++ ++ def test_modify_delete_dns_host_name_unspecified(self): ++ '''Test deleting dNSHostName''' ++ account_name = self.id().rsplit(".", 1)[1][:63] ++ host_name, dn = self.setup_computer_with_hostname(account_name) ++ ++ m = Message(Dn(self.ldb_user, dn)) ++ m['dNSHostName'] = MessageElement([], ++ FLAG_MOD_DELETE, ++ 'dNSHostName') ++ ++ self.assertRaisesLdbError( ++ ERR_INSUFFICIENT_ACCESS_RIGHTS, ++ "User able to delete dNSHostName (without specified name)", ++ self.ldb_user.modify, m) ++ ++ def test_modify_delete_dns_host_name_ldif_specified(self): ++ '''Test deleting dNSHostName''' ++ account_name = self.id().rsplit(".", 1)[1][:63] ++ host_name, dn = self.setup_computer_with_hostname(account_name) ++ ++ ldif = f""" ++dn: {dn} ++changetype: modify ++delete: dNSHostName ++dNSHostName: {host_name} ++""" ++ self.assertRaisesLdbError( ++ ERR_INSUFFICIENT_ACCESS_RIGHTS, ++ "User able to delete dNSHostName (with specified name)", ++ self.ldb_user.modify_ldif, ldif) ++ ++ def test_modify_delete_dns_host_name_ldif_unspecified(self): ++ '''Test deleting dNSHostName''' ++ account_name = self.id().rsplit(".", 1)[1][:63] ++ host_name, dn = self.setup_computer_with_hostname(account_name) ++ ++ ldif = f""" ++dn: {dn} ++changetype: modify ++delete: dNSHostName ++""" ++ self.assertRaisesLdbError( ++ ERR_INSUFFICIENT_ACCESS_RIGHTS, ++ "User able to delete dNSHostName (without specific name)", ++ self.ldb_user.modify_ldif, ldif) ++ ++ ++ldb = SamDB(ldaphost, credentials=creds, session_info=system_session(lp), lp=lp) ++ ++TestProgram(module=__name__, opts=subunitopts) +diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py +index c6bf668aa9c..9ef9600d886 100755 +--- a/source4/selftest/tests.py ++++ b/source4/selftest/tests.py +@@ -1417,6 +1417,7 @@ for env in all_fl_envs + ["schema_dc"]: + plantestsuite("samba4.ldap.possibleInferiors.python(%s)" % env, env, [python, os.path.join(samba4srcdir, "dsdb/samdb/ldb_modules/tests/possibleinferiors.py"), "ldap://$SERVER", '-U"$USERNAME%$PASSWORD"', "-W$DOMAIN"]) + plantestsuite_loadlist("samba4.ldap.secdesc.python(%s)" % env, env, [python, os.path.join(DSDB_PYTEST_DIR, "sec_descriptor.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) + plantestsuite_loadlist("samba4.ldap.acl.python(%s)" % env, env, ["STRICT_CHECKING=0", python, os.path.join(DSDB_PYTEST_DIR, "acl.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) ++ plantestsuite_loadlist("samba4.ldap.acl_modify.python(%s)" % env, env, ["STRICT_CHECKING=0", python, os.path.join(DSDB_PYTEST_DIR, "acl_modify.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) + + for env in all_fl_envs + ["schema_dc", "ad_dc_no_ntlm"]: + if env != "fl2000dc": +-- +2.25.1 \ No newline at end of file diff --git a/backport-0003-CVE-2023-0614.patch b/backport-0003-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..9608e668ee76b47ffe145308ac52338c4ae6cdd1 --- /dev/null +++ b/backport-0003-CVE-2023-0614.patch @@ -0,0 +1,77 @@ +From e7aa14a5405735234b989bdeba384c7c9249257a Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Fri, 3 Mar 2023 10:31:40 +1300 +Subject: [PATCH 01/34] CVE-2023-0614 dsdb: Alter timeout test in large_ldap.py + to be slower by matching on large objects + +This changes the slow aspect to be the object matching not the filter parsing. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/tests/python/large_ldap.py | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/source4/dsdb/tests/python/large_ldap.py b/source4/dsdb/tests/python/large_ldap.py +index 0805119a700..f7569607cb2 100644 +--- a/source4/dsdb/tests/python/large_ldap.py ++++ b/source4/dsdb/tests/python/large_ldap.py +@@ -32,7 +32,7 @@ from samba.tests.subunitrun import SubunitOptions, TestProgram + import samba.getopt as options + + from samba.auth import system_session +-from samba import ldb ++from samba import ldb, sd_utils + from samba.samdb import SamDB + from samba.ndr import ndr_unpack + from samba import gensec +@@ -123,10 +123,13 @@ class LargeLDAPTest(samba.tests.TestCase): + def setUpClass(cls): + cls.ldb = SamDB(url, credentials=creds, session_info=system_session(lp), lp=lp) + cls.base_dn = cls.ldb.domain_dn() ++ ++ cls.sd_utils = sd_utils.SDUtils(cls.ldb) + cls.USER_NAME = "large_user" + format(random.randint(0, 99999), "05") + "-" + cls.OU_NAME="large_user_ou" + format(random.randint(0, 99999), "05") + cls.ou_dn = ldb.Dn(cls.ldb, "ou=" + cls.OU_NAME + "," + str(cls.base_dn)) + ++ + samba.tests.delete_force(cls.ldb, cls.ou_dn, + controls=['tree_delete:1']) + +@@ -249,6 +252,7 @@ class LargeLDAPTest(samba.tests.TestCase): + self.assertGreater(count, count_jpeg) + + def test_timeout(self): ++ + policy_dn = ldb.Dn(self.ldb, + 'CN=Default Query Policy,CN=Query-Policies,' + 'CN=Directory Service,CN=Windows NT,CN=Services,' +@@ -283,9 +286,19 @@ class LargeLDAPTest(samba.tests.TestCase): + session_info=system_session(lp), + lp=lp) + ++ for x in range(200): ++ user_name = self.USER_NAME + format(x, "03") ++ ace = "(OD;;RP;{6bc69afa-7bd9-4184-88f5-28762137eb6a};;S-1-%d)" % x ++ dn = ldb.Dn(self.ldb, "cn=" + user_name + "," + str(self.ou_dn)) ++ ++ # add an ACE that denies access to the above random attr ++ # for a not-existing user. This makes each SD distinct ++ # and so will slow SD parsing. ++ self.sd_utils.dacl_add_ace(dn, ace) ++ + # Create a large search expression that will take a long time to + # evaluate. +- expression = '(anr=l)' * 10000 ++ expression = f'(jpegPhoto=*X*)' * 1000 + expression = f'(|{expression})' + + # Perform the LDAP search. +-- +2.25.1 \ No newline at end of file diff --git a/backport-0003-CVE-2023-3347.patch b/backport-0003-CVE-2023-3347.patch new file mode 100644 index 0000000000000000000000000000000000000000..10f3e15bb58b8fb88ac31434ab862ddbe23b4ee7 --- /dev/null +++ b/backport-0003-CVE-2023-3347.patch @@ -0,0 +1,75 @@ +From 95cec0dfa2410e667551a1faaef08c8cd2a80074 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Wed, 21 Jun 2023 15:10:58 +0200 +Subject: [PATCH 20/28] CVE-2023-3347: smbd: inline smb2_srv_init_signing() + code in srv_init_signing() + +It's now a one-line function, imho the overall code is simpler if that code is +just inlined. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15397 + +Signed-off-by: Ralph Boehme + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/smbd/proto.h | 2 -- + source3/smbd/smb2_signing.c | 19 ++++++------------- + 2 files changed, 6 insertions(+), 15 deletions(-) + +diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h +index 67cc5e8a380..8075f4e567e 100644 +--- a/source3/smbd/proto.h ++++ b/source3/smbd/proto.h +@@ -52,8 +52,6 @@ struct dcesrv_context; + + /* The following definitions come from smbd/smb2_signing.c */ + +-bool smb2_srv_init_signing(struct loadparm_context *lp_ctx, +- struct smbXsrv_connection *conn); + bool srv_init_signing(struct smbXsrv_connection *conn); + + /* The following definitions come from smbd/aio.c */ +diff --git a/source3/smbd/smb2_signing.c b/source3/smbd/smb2_signing.c +index c1f876f9cd7..ef4a54d5710 100644 +--- a/source3/smbd/smb2_signing.c ++++ b/source3/smbd/smb2_signing.c +@@ -26,21 +26,10 @@ + #include "lib/param/param.h" + #include "smb2_signing.h" + +-bool smb2_srv_init_signing(struct loadparm_context *lp_ctx, +- struct smbXsrv_connection *conn) +-{ +- /* +- * For SMB2 all we need to know is if signing is mandatory. +- * It is always allowed and desired, whatever the smb.conf says. +- */ +- (void)lpcfg_server_signing_allowed(lp_ctx, &conn->smb2.signing_mandatory); +- return true; +-} +- + bool srv_init_signing(struct smbXsrv_connection *conn) + { + struct loadparm_context *lp_ctx = NULL; +- bool ok; ++ bool ok = true; + + lp_ctx = loadparm_init_s3(conn, loadparm_s3_helpers()); + if (lp_ctx == NULL) { +@@ -51,7 +40,11 @@ bool srv_init_signing(struct smbXsrv_connection *conn) + #if defined(WITH_SMB1SERVER) + if (conn->protocol >= PROTOCOL_SMB2_02) { + #endif +- ok = smb2_srv_init_signing(lp_ctx, conn); ++ /* ++ * For SMB2 all we need to know is if signing is mandatory. ++ * It is always allowed and desired, whatever the smb.conf says. ++ */ ++ (void)lpcfg_server_signing_allowed(lp_ctx, &conn->smb2.signing_mandatory); + #if defined(WITH_SMB1SERVER) + } else { + ok = smb1_srv_init_signing(lp_ctx, conn); +-- +2.34.1 diff --git a/backport-0003-CVE-2023-34968.patch b/backport-0003-CVE-2023-34968.patch new file mode 100644 index 0000000000000000000000000000000000000000..ab3137a2a5c6082ac431c6fcae984f03af3e1e60 --- /dev/null +++ b/backport-0003-CVE-2023-34968.patch @@ -0,0 +1,62 @@ +From 56a21b3bc8fb24416ead9061f9305c8122bc7f86 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Mon, 19 Jun 2023 17:14:38 +0200 +Subject: [PATCH 09/28] CVE-2023-34968: mdscli: use correct TALLOC memory + context when allocating spotlight_blob + +d is talloc_free()d at the end of the functions and the buffer was later used +after beeing freed in the DCERPC layer when sending the packet. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/rpc_client/cli_mdssvc_util.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/source3/rpc_client/cli_mdssvc_util.c b/source3/rpc_client/cli_mdssvc_util.c +index fe5092c3790..892a844e71a 100644 +--- a/source3/rpc_client/cli_mdssvc_util.c ++++ b/source3/rpc_client/cli_mdssvc_util.c +@@ -209,7 +209,7 @@ NTSTATUS mdscli_blob_search(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(d, ++ blob->spotlight_blob = talloc_array(mem_ctx, + uint8_t, + ctx->max_fragment_size); + if (blob->spotlight_blob == NULL) { +@@ -293,7 +293,7 @@ NTSTATUS mdscli_blob_get_results(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(d, ++ blob->spotlight_blob = talloc_array(mem_ctx, + uint8_t, + ctx->max_fragment_size); + if (blob->spotlight_blob == NULL) { +@@ -426,7 +426,7 @@ NTSTATUS mdscli_blob_get_path(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(d, ++ blob->spotlight_blob = talloc_array(mem_ctx, + uint8_t, + ctx->max_fragment_size); + if (blob->spotlight_blob == NULL) { +@@ -510,7 +510,7 @@ NTSTATUS mdscli_blob_close_search(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(d, ++ blob->spotlight_blob = talloc_array(mem_ctx, + uint8_t, + ctx->max_fragment_size); + if (blob->spotlight_blob == NULL) { +-- +2.34.1 diff --git a/backport-0003-CVE-2023-3961.patch b/backport-0003-CVE-2023-3961.patch new file mode 100644 index 0000000000000000000000000000000000000000..5bd96cbf39c0579a6c2673c5c5b21212eac708db --- /dev/null +++ b/backport-0003-CVE-2023-3961.patch @@ -0,0 +1,49 @@ +From 4b3e5c2f036f868e38ad5da7faba05db32f624f4 Mon Sep 17 00:00:00 2001 +From: Jeremy Allison +Date: Tue, 25 Jul 2023 17:54:41 -0700 +Subject: [PATCH 03/30] CVE-2023-3961:s3: smbd: Remove the SMB_ASSERT() that + crashes on bad pipenames. + +We correctly handle this and just return ENOENT (NT_STATUS_OBJECT_NAME_NOT_FOUND). + +Remove knowfail. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15422 + +Signed-off-by: Jeremy Allison + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 03/30] CVE-2023-3961:s3: smbd: Remove the SMB_ASSERT() that + crashes on bad pipenames. +--- + selftest/knownfail.d/badpipename | 1 - + source3/rpc_client/local_np.c | 5 ----- + 2 files changed, 6 deletions(-) + delete mode 100644 selftest/knownfail.d/badpipename + +diff --git a/selftest/knownfail.d/badpipename b/selftest/knownfail.d/badpipename +deleted file mode 100644 +index e69715f863d..00000000000 +--- a/selftest/knownfail.d/badpipename ++++ /dev/null +@@ -1 +0,0 @@ +-^samba3.smbtorture_s3.smb2.SMB2-INVALID-PIPENAME.smbtorture\(fileserver\) +diff --git a/source3/rpc_client/local_np.c b/source3/rpc_client/local_np.c +index 95228d5d801..791ded99a47 100644 +--- a/source3/rpc_client/local_np.c ++++ b/source3/rpc_client/local_np.c +@@ -551,11 +551,6 @@ struct tevent_req *local_np_connect_send( + { + DBG_DEBUG("attempt to connect to invalid pipe pathname %s\n", + lower_case_pipename); +- /* +- * For now, panic the server until we have +- * the test code in place. +- */ +- SMB_ASSERT(false); + tevent_req_error(req, ENOENT); + return tevent_req_post(req, ev); + } +-- +2.34.1 diff --git a/backport-0003-CVE-2023-4154.patch b/backport-0003-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..e4a7bd81f62da2db55dfc4c8fb4d22f675a26274 --- /dev/null +++ b/backport-0003-CVE-2023-4154.patch @@ -0,0 +1,251 @@ +From bea7fd5eadccb670d3cfc233fd5cbc6c80d5cf95 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Wed, 1 Mar 2023 14:49:06 +1300 +Subject: [PATCH 08/30] CVE-2023-4154 dsdb: Remove remaining references to + DC_MODE_RETURN_NONE and DC_MODE_RETURN_ALL + +The confidential_attrs test no longer uses DC_MODE_RETURN_NONE we can now +remove the complexity. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton +(cherry picked from commit 82d2ec786f7e75ff6f34eb3357964345b10de091) + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 08/30] CVE-2023-4154 dsdb: Remove remaining references to + DC_MODE_RETURN_NONE and DC_MODE_RETURN_ALL +--- + .../dsdb/tests/python/confidential_attr.py | 86 ++++--------------- + 1 file changed, 16 insertions(+), 70 deletions(-) + +diff --git a/source4/dsdb/tests/python/confidential_attr.py b/source4/dsdb/tests/python/confidential_attr.py +index 6889d5a5560..ac83f488061 100755 +--- a/source4/dsdb/tests/python/confidential_attr.py ++++ b/source4/dsdb/tests/python/confidential_attr.py +@@ -70,20 +70,6 @@ lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL) + +-# When a user does not have access rights to view the objects' attributes, +-# Windows and Samba behave slightly differently. +-# A windows DC will always act as if the hidden attribute doesn't exist AT ALL +-# (for an unprivileged user). So, even for a user that lacks access rights, +-# the inverse/'!' queries should return ALL objects. This is similar to the +-# kludgeaclredacted behaviour on Samba. +-# However, on Samba (for implementation simplicity) we never return a matching +-# result for an unprivileged user. +-# Either approach is OK, so long as it gets applied consistently and we don't +-# disclose any sensitive details by varying what gets returned by the search. +-DC_MODE_RETURN_NONE = 0 +-DC_MODE_RETURN_ALL = 1 +- +- + # + # Tests start here + # +@@ -193,25 +179,6 @@ class ConfidentialAttrCommon(samba.tests.TestCase): + # reset the value after the test completes + self.addCleanup(self.set_attr_search_flags, self.attr_dn, old_value) + +- # The behaviour of the DC can differ in some cases, depending on whether +- # we're talking to a Windows DC or a Samba DC +- def guess_dc_mode(self): +- # if we're in selftest, we can be pretty sure it's a Samba DC +- if os.environ.get('SAMBA_SELFTEST') == '1': +- return DC_MODE_RETURN_NONE +- +- searches = self.get_negative_match_all_searches() +- res = self.ldb_user.search(self.test_dn, expression=searches[0], +- scope=SCOPE_SUBTREE) +- +- # we default to DC_MODE_RETURN_NONE (samba).Update this if it +- # looks like we're talking to a Windows DC +- if len(res) == self.total_objects: +- return DC_MODE_RETURN_ALL +- +- # otherwise assume samba DC behaviour +- return DC_MODE_RETURN_NONE +- + def get_user_dn(self, name): + return "CN={0},{1}".format(name, self.ou) + +@@ -359,7 +326,7 @@ class ConfidentialAttrCommon(samba.tests.TestCase): + return expected_results + + # Returns the expected negative (i.e. '!') search behaviour when talking to +- # a DC with DC_MODE_RETURN_ALL behaviour, i.e. we assert that users ++ # a DC, i.e. we assert that users + # without rights always see ALL objects in '!' searches + def negative_searches_return_all(self, has_rights_to=0, + total_objects=None): +@@ -409,32 +376,24 @@ class ConfidentialAttrCommon(samba.tests.TestCase): + # and what access rights the user has. + # Note we only handle has_rights_to="all", 1 (the test object), or 0 (i.e. + # we don't have rights to any objects) +- def negative_search_expected_results(self, has_rights_to, dc_mode, +- total_objects=None): ++ def negative_search_expected_results(self, has_rights_to, total_objects=None): + + if has_rights_to == "all": + expect_results = self.negative_searches_all_rights(total_objects) + +- # if it's a Samba DC, we only expect the 'match-all' searches to return +- # the objects that we have access rights to (all others are hidden). +- # Whereas Windows 'hides' the objects by always returning all of them +- elif dc_mode == DC_MODE_RETURN_NONE: +- expect_results = self.negative_searches_return_none(has_rights_to) + else: + expect_results = self.negative_searches_return_all(has_rights_to, + total_objects) + return expect_results + +- def assert_negative_searches(self, has_rights_to=0, +- dc_mode=DC_MODE_RETURN_NONE, samdb=None): ++ def assert_negative_searches(self, has_rights_to=0, samdb=None): + """Asserts user without rights cannot see objects in '!' searches""" + + if samdb is None: + samdb = self.ldb_user + + # build a dictionary of key=search-expr, value=expected_num assertions +- expected_results = self.negative_search_expected_results(has_rights_to, +- dc_mode) ++ expected_results = self.negative_search_expected_results(has_rights_to) + + for search, expected_num in expected_results.items(): + self.assert_search_result(expected_num, search, samdb) +@@ -490,8 +449,7 @@ class ConfidentialAttrTest(ConfidentialAttrCommon): + self.make_attr_confidential() + + self.assert_conf_attr_searches(has_rights_to=0) +- dc_mode = DC_MODE_RETURN_ALL +- self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) ++ self.assert_negative_searches(has_rights_to=0) + self.assert_attr_visible(expect_attr=False) + + # sanity-check we haven't hidden the attribute from the admin as well +@@ -503,8 +461,7 @@ class ConfidentialAttrTest(ConfidentialAttrCommon): + self.make_attr_confidential() + + self.assert_conf_attr_searches(has_rights_to=0) +- dc_mode = DC_MODE_RETURN_ALL +- self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) ++ self.assert_negative_searches(has_rights_to=0) + self.assert_attr_visible(expect_attr=False) + + # apply the allow ACE to the object under test +@@ -513,7 +470,7 @@ class ConfidentialAttrTest(ConfidentialAttrCommon): + # the user should now be able to see the attribute for the one object + # we gave it rights to + self.assert_conf_attr_searches(has_rights_to=1) +- self.assert_negative_searches(has_rights_to=1, dc_mode=dc_mode) ++ self.assert_negative_searches(has_rights_to=1) + self.assert_attr_visible(expect_attr=True) + + # sanity-check the admin can still see the attribute +@@ -566,8 +523,7 @@ class ConfidentialAttrTest(ConfidentialAttrCommon): + self.make_attr_confidential() + + self.assert_conf_attr_searches(has_rights_to=0) +- dc_mode = DC_MODE_RETURN_ALL +- self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) ++ self.assert_negative_searches(has_rights_to=0) + self.assert_attr_visible(expect_attr=False) + + # apply the ACE to the object under test +@@ -575,7 +531,7 @@ class ConfidentialAttrTest(ConfidentialAttrCommon): + + # this should make no difference to the user's ability to see the attr + self.assert_conf_attr_searches(has_rights_to=0) +- self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) ++ self.assert_negative_searches(has_rights_to=0) + self.assert_attr_visible(expect_attr=False) + + # sanity-check the admin can still see the attribute +@@ -707,8 +663,7 @@ class ConfidentialAttrTestDenyAcl(ConfidentialAttrCommon): + return expected_results + + # override method specifically for deny ACL test cases +- def assert_negative_searches(self, has_rights_to=0, +- dc_mode=DC_MODE_RETURN_NONE, samdb=None): ++ def assert_negative_searches(self, has_rights_to=0, samdb=None): + """Asserts user without rights cannot see objects in '!' searches""" + + if samdb is None: +@@ -719,12 +674,9 @@ class ConfidentialAttrTestDenyAcl(ConfidentialAttrCommon): + # assert this if the '!'/negative search behaviour is to suppress any + # objects we don't have access rights to) + excl_testobj = False +- if has_rights_to != "all" and dc_mode == DC_MODE_RETURN_NONE: +- excl_testobj = True + + # build a dictionary of key=search-expr, value=expected_num assertions +- expected_results = self.negative_search_expected_results(has_rights_to, +- dc_mode) ++ expected_results = self.negative_search_expected_results(has_rights_to) + + for search, expected_num in expected_results.items(): + self.assert_search_result(expected_num, search, samdb, +@@ -741,9 +693,7 @@ class ConfidentialAttrTestDenyAcl(ConfidentialAttrCommon): + + # the user shouldn't be able to see the attribute anymore + self.assert_conf_attr_searches(has_rights_to="deny-one") +- dc_mode = DC_MODE_RETURN_ALL +- self.assert_negative_searches(has_rights_to="deny-one", +- dc_mode=dc_mode) ++ self.assert_negative_searches(has_rights_to="deny-one") + self.assert_attr_visible(expect_attr=False) + + # sanity-check we haven't hidden the attribute from the admin as well +@@ -887,8 +837,7 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + attrs=['name']) + + # override method specifically for dirsync (total object count differs) +- def assert_negative_searches(self, has_rights_to=0, +- dc_mode=DC_MODE_RETURN_NONE, samdb=None): ++ def assert_negative_searches(self, has_rights_to=0, samdb=None): + """Asserts user without rights cannot see objects in '!' searches""" + + if samdb is None: +@@ -898,7 +847,6 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + # here only includes the user objects (not the parent OU) + total_objects = len(self.all_users) + expected_results = self.negative_search_expected_results(has_rights_to, +- dc_mode, + total_objects) + + for search, expected_num in expected_results.items(): +@@ -917,8 +865,7 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + + self.assert_conf_attr_searches(has_rights_to=0) + self.assert_attr_visible(expect_attr=False) +- dc_mode = DC_MODE_RETURN_ALL +- self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) ++ self.assert_negative_searches(has_rights_to=0) + + # as a final sanity-check, make sure the admin can still see the attr + self.assert_conf_attr_searches(has_rights_to="all", +@@ -1012,8 +959,7 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + # check we can't see the objects now, even with using dirsync controls + self.assert_conf_attr_searches(has_rights_to=0) + self.assert_attr_visible(expect_attr=False) +- dc_mode = DC_MODE_RETURN_ALL +- self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) ++ self.assert_negative_searches(has_rights_to=0) + + # now delete the users (except for the user whose LDB connection + # we're currently using) +@@ -1023,7 +969,7 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + + # check we still can't see the objects + self.assert_conf_attr_searches(has_rights_to=0) +- self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) ++ self.assert_negative_searches(has_rights_to=0) + + def test_timing_attack(self): + # Create the machine account. +-- +2.34.1 diff --git a/backport-0004-CVE-2018-14628.patch b/backport-0004-CVE-2018-14628.patch new file mode 100644 index 0000000000000000000000000000000000000000..0ad8083cd492cb868ecbf3212d080175b874eeb5 --- /dev/null +++ b/backport-0004-CVE-2018-14628.patch @@ -0,0 +1,105 @@ +From a561ec6ebc3676a9f785ddd8d916e1e220a25e35 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 26 Jun 2023 15:14:24 +0200 +Subject: [PATCH 4/6] CVE-2018-14628: s4:dsdb: remove unused code in + dirsync_filter_entry() + +This makes the next change easier to understand. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13595 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +(cherry picked from commit 498542be0bbf4f26558573c1f87b77b8e3509371) + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=18168 +[PATCH 4/6] CVE-2018-14628: s4:dsdb: remove unused code in + dirsync_filter_entry() +--- + source4/dsdb/samdb/ldb_modules/dirsync.c | 53 +++--------------------- + 1 file changed, 5 insertions(+), 48 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/dirsync.c b/source4/dsdb/samdb/ldb_modules/dirsync.c +index fbb75790095b..124cff25e397 100644 +--- a/source4/dsdb/samdb/ldb_modules/dirsync.c ++++ b/source4/dsdb/samdb/ldb_modules/dirsync.c +@@ -151,10 +151,6 @@ static int dirsync_filter_entry(struct ldb_request *req, + * list only the attribute that have been modified since last interogation + * + */ +- newmsg = ldb_msg_new(dsc->req); +- if (newmsg == NULL) { +- return ldb_oom(ldb); +- } + for (i = msg->num_elements - 1; i >= 0; i--) { + if (ldb_attr_cmp(msg->elements[i].name, "uSNChanged") == 0) { + int error = 0; +@@ -201,11 +197,6 @@ static int dirsync_filter_entry(struct ldb_request *req, + */ + return LDB_SUCCESS; + } +- newmsg->dn = ldb_dn_new(newmsg, ldb, ""); +- if (newmsg->dn == NULL) { +- return ldb_oom(ldb); +- } +- + el = ldb_msg_find_element(msg, "objectGUID"); + if ( el != NULL) { + guidfound = true; +@@ -216,48 +207,14 @@ static int dirsync_filter_entry(struct ldb_request *req, + * well will uncomment the code bellow + */ + SMB_ASSERT(guidfound == true); +- /* +- if (guidfound == false) { +- struct GUID guid; +- struct ldb_val *new_val; +- DATA_BLOB guid_blob; +- +- tmp[0] = '\0'; +- txt = strrchr(txt, ':'); +- if (txt == NULL) { +- return ldb_module_done(dsc->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); +- } +- txt++; +- +- status = GUID_from_string(txt, &guid); +- if (!NT_STATUS_IS_OK(status)) { +- return ldb_module_done(dsc->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); +- } +- +- status = GUID_to_ndr_blob(&guid, msg, &guid_blob); +- if (!NT_STATUS_IS_OK(status)) { +- return ldb_module_done(dsc->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); +- } +- +- new_val = talloc(msg, struct ldb_val); +- if (new_val == NULL) { +- return ldb_oom(ldb); +- } +- new_val->data = talloc_steal(new_val, guid_blob.data); +- new_val->length = guid_blob.length; +- if (ldb_msg_add_value(msg, "objectGUID", new_val, NULL) != 0) { +- return ldb_module_done(dsc->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); +- } +- } +- */ +- ldb_msg_add(newmsg, el, LDB_FLAG_MOD_ADD); +- talloc_steal(newmsg->elements, el->name); +- talloc_steal(newmsg->elements, el->values); +- +- talloc_steal(newmsg->elements, msg); + return ldb_module_send_entry(dsc->req, msg, controls); + } + ++ newmsg = ldb_msg_new(dsc->req); ++ if (newmsg == NULL) { ++ return ldb_oom(ldb); ++ } ++ + ndr_err = ndr_pull_struct_blob(replMetaData, dsc, &rmd, + (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { +-- +2.34.1 diff --git a/backport-0004-CVE-2023-0225.patch b/backport-0004-CVE-2023-0225.patch new file mode 100644 index 0000000000000000000000000000000000000000..56384243352b8a43b9f6ce0e1213af8b05b70671 --- /dev/null +++ b/backport-0004-CVE-2023-0225.patch @@ -0,0 +1,67 @@ +From 0d753cc8f2b072175f994ede8b3a541303a8a2d5 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Mon, 9 Jan 2023 11:22:34 +1300 +Subject: [PATCH 4/4] CVE-2023-0225 s4-acl: Don't return early if dNSHostName + element has no values + +This early return would mistakenly allow an unprivileged user to delete +the dNSHostName attribute by making an LDAP modify request with no +values. We should no longer allow this. + +Add or replace operations with no values and no privileges are +disallowed. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15276 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17833 +--- + selftest/knownfail.d/dns-host-name-deletion | 2 -- + source4/dsdb/samdb/ldb_modules/acl.c | 12 +++++++----- + 2 files changed, 7 insertions(+), 7 deletions(-) + delete mode 100644 selftest/knownfail.d/dns-host-name-deletion + +diff --git a/selftest/knownfail.d/dns-host-name-deletion b/selftest/knownfail.d/dns-host-name-deletion +deleted file mode 100644 +index ac11619ffc3..00000000000 +--- a/selftest/knownfail.d/dns-host-name-deletion ++++ /dev/null +@@ -1,2 +0,0 @@ +-^samba4.ldap.acl_modify.python\(.*\).__main__.AclModifyTests.test_modify_delete_dns_host_name_ldif_unspecified\(.*\) +-^samba4.ldap.acl_modify.python\(.*\).__main__.AclModifyTests.test_modify_delete_dns_host_name_unspecified\(.*\) +diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c +index 4098ae2d671..b602520ca2b 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl.c ++++ b/source4/dsdb/samdb/ldb_modules/acl.c +@@ -900,11 +900,6 @@ static int acl_check_dns_host_name(TALLOC_CTX *mem_ctx, + NULL + }; + +- if (el->num_values == 0) { +- return LDB_SUCCESS; +- } +- dnsHostName = &el->values[0]; +- + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return ldb_oom(ldb); +@@ -1050,6 +1045,13 @@ static int acl_check_dns_host_name(TALLOC_CTX *mem_ctx, + --account_name_len; + } + ++ /* Check for add or replace requests with no value. */ ++ if (el->num_values == 0) { ++ talloc_free(tmp_ctx); ++ return ldb_operr(ldb); ++ } ++ dnsHostName = &el->values[0]; ++ + dnsHostName_str = (const char *)dnsHostName->data; + dns_host_name_len = dnsHostName->length; + +-- +2.25.1 + diff --git a/backport-0004-CVE-2023-0614.patch b/backport-0004-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..3b6d2e9b6328c7956f4b97c7edb21dbd570dfd52 --- /dev/null +++ b/backport-0004-CVE-2023-0614.patch @@ -0,0 +1,79 @@ +From ad6945f667329d75174cfb9e90786f811c579355 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 27 Jan 2023 07:57:27 +1300 +Subject: [PATCH 02/34] CVE-2023-0614 libcli/security: Make some parameters + const + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org Updated to add const to sec_access_check_ds() +instead of the sec_access_check_ds_implicit_owner() wrapper +found in 4.18 and later] + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + libcli/security/access_check.c | 10 +++++----- + libcli/security/access_check.h | 2 +- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/libcli/security/access_check.c b/libcli/security/access_check.c +index f5051b0fa93..7dd3798703c 100644 +--- a/libcli/security/access_check.c ++++ b/libcli/security/access_check.c +@@ -394,7 +394,7 @@ NTSTATUS se_file_access_check(const struct security_descriptor *sd, + return NT_STATUS_OK; + } + +-static const struct GUID *get_ace_object_type(struct security_ace *ace) ++static const struct GUID *get_ace_object_type(const struct security_ace *ace) + { + if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) { + return &ace->object.object.type.type; +@@ -412,7 +412,7 @@ static const struct GUID *get_ace_object_type(struct security_ace *ace) + * rights to the object/attribute + * @returns NT_STATUS_OK, unless access was denied + */ +-static NTSTATUS check_object_specific_access(struct security_ace *ace, ++static NTSTATUS check_object_specific_access(const struct security_ace *ace, + struct object_tree *tree, + bool *grant_access) + { +@@ -505,7 +505,7 @@ NTSTATUS sec_access_check_ds(const struct security_descriptor *sd, + uint32_t access_desired, + uint32_t *access_granted, + struct object_tree *tree, +- struct dom_sid *replace_sid) ++ const struct dom_sid *replace_sid) + { + uint32_t i; + uint32_t bits_remaining; +@@ -556,8 +556,8 @@ NTSTATUS sec_access_check_ds(const struct security_descriptor *sd, + + /* check each ace in turn. */ + for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) { +- struct dom_sid *trustee; +- struct security_ace *ace = &sd->dacl->aces[i]; ++ const struct dom_sid *trustee; ++ const struct security_ace *ace = &sd->dacl->aces[i]; + NTSTATUS status; + bool grant_access = false; + +diff --git a/libcli/security/access_check.h b/libcli/security/access_check.h +index 96e33c6624f..37ca078a24e 100644 +--- a/libcli/security/access_check.h ++++ b/libcli/security/access_check.h +@@ -74,7 +74,7 @@ NTSTATUS sec_access_check_ds(const struct security_descriptor *sd, + uint32_t access_desired, + uint32_t *access_granted, + struct object_tree *tree, +- struct dom_sid *replace_sid); ++ const struct dom_sid *replace_sid); + + bool insert_in_object_tree(TALLOC_CTX *mem_ctx, + const struct GUID *guid, +-- +2.25.1 \ No newline at end of file diff --git a/backport-0004-CVE-2023-3347.patch b/backport-0004-CVE-2023-3347.patch new file mode 100644 index 0000000000000000000000000000000000000000..1335f2367e978a9eea5666f093b92bf009377253 --- /dev/null +++ b/backport-0004-CVE-2023-3347.patch @@ -0,0 +1,38 @@ +From a22fcb689187a7b1fa20d008026c91283e222390 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 20 Jun 2023 18:13:23 +0200 +Subject: [PATCH 21/28] CVE-2023-3347: smbd: remove comment in + smbd_smb2_request_process_negprot() + +This is just going to bitrot. Anyone who's interested can just grep for +"signing_mandatory" and look up what it does. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15397 + +Signed-off-by: Ralph Boehme + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/smbd/smb2_negprot.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/source3/smbd/smb2_negprot.c b/source3/smbd/smb2_negprot.c +index baddbecaade..685a1460cef 100644 +--- a/source3/smbd/smb2_negprot.c ++++ b/source3/smbd/smb2_negprot.c +@@ -361,12 +361,6 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req) + } + + security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; +- /* +- * We use xconn->smb2.signing_mandatory set up via +- * srv_init_signing() -> smb2_srv_init_signing(). +- * This calls lpcfg_server_signing_allowed() to get the correct +- * defaults, e.g. signing_required for an ad_dc. +- */ + if (xconn->smb2.signing_mandatory) { + security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED; + } +-- +2.34.1 diff --git a/backport-0004-CVE-2023-34968.patch b/backport-0004-CVE-2023-34968.patch new file mode 100644 index 0000000000000000000000000000000000000000..cb4424b97754c0cb6435f065b9539b972b057f39 --- /dev/null +++ b/backport-0004-CVE-2023-34968.patch @@ -0,0 +1,88 @@ +From 0ae6084d1a9c4eb12e9f1ab1902e00f96bcbea55 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Mon, 19 Jun 2023 18:28:41 +0200 +Subject: [PATCH 10/28] CVE-2023-34968: mdscli: remove response blob allocation + +This is handled by the NDR code transparently. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/rpc_client/cli_mdssvc.c | 36 --------------------------------- + 1 file changed, 36 deletions(-) + +diff --git a/source3/rpc_client/cli_mdssvc.c b/source3/rpc_client/cli_mdssvc.c +index 046d37135cb..474d7c0b150 100644 +--- a/source3/rpc_client/cli_mdssvc.c ++++ b/source3/rpc_client/cli_mdssvc.c +@@ -276,15 +276,6 @@ struct tevent_req *mdscli_search_send(TALLOC_CTX *mem_ctx, + return tevent_req_post(req, ev); + } + +- state->response_blob.spotlight_blob = talloc_array( +- state, +- uint8_t, +- mdscli_ctx->max_fragment_size); +- if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) { +- return tevent_req_post(req, ev); +- } +- state->response_blob.size = mdscli_ctx->max_fragment_size; +- + subreq = dcerpc_mdssvc_cmd_send(state, + ev, + mdscli_ctx->bh, +@@ -457,15 +448,6 @@ struct tevent_req *mdscli_get_results_send( + return tevent_req_post(req, ev); + } + +- state->response_blob.spotlight_blob = talloc_array( +- state, +- uint8_t, +- mdscli_ctx->max_fragment_size); +- if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) { +- return tevent_req_post(req, ev); +- } +- state->response_blob.size = mdscli_ctx->max_fragment_size; +- + subreq = dcerpc_mdssvc_cmd_send(state, + ev, + mdscli_ctx->bh, +@@ -681,15 +663,6 @@ struct tevent_req *mdscli_get_path_send(TALLOC_CTX *mem_ctx, + return tevent_req_post(req, ev); + } + +- state->response_blob.spotlight_blob = talloc_array( +- state, +- uint8_t, +- mdscli_ctx->max_fragment_size); +- if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) { +- return tevent_req_post(req, ev); +- } +- state->response_blob.size = mdscli_ctx->max_fragment_size; +- + subreq = dcerpc_mdssvc_cmd_send(state, + ev, + mdscli_ctx->bh, +@@ -852,15 +825,6 @@ struct tevent_req *mdscli_close_search_send(TALLOC_CTX *mem_ctx, + return tevent_req_post(req, ev); + } + +- state->response_blob.spotlight_blob = talloc_array( +- state, +- uint8_t, +- mdscli_ctx->max_fragment_size); +- if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) { +- return tevent_req_post(req, ev); +- } +- state->response_blob.size = mdscli_ctx->max_fragment_size; +- + subreq = dcerpc_mdssvc_cmd_send(state, + ev, + mdscli_ctx->bh, +-- +2.34.1 diff --git a/backport-0004-CVE-2023-4154.patch b/backport-0004-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..5ef25bf704ab20f7ca03c4d0381f038fc327f5a5 --- /dev/null +++ b/backport-0004-CVE-2023-4154.patch @@ -0,0 +1,182 @@ +From 38d62aa3b2b202d2080b8814f6d9acd8bf99f226 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 27 Jan 2023 07:43:40 +1300 +Subject: [PATCH 09/30] CVE-2023-4154 s4:dsdb:tests: Refactor confidential + attributes test + +Use more specific unittest methods, and remove unused code. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +(cherry picked from commit 2e5d08c908b3fa48b9b374279a331061cb77bce3) + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 09/30] CVE-2023-4154 s4:dsdb:tests: Refactor confidential + attributes test +--- + .../dsdb/tests/python/confidential_attr.py | 69 +++++-------------- + 1 file changed, 16 insertions(+), 53 deletions(-) + +diff --git a/source4/dsdb/tests/python/confidential_attr.py b/source4/dsdb/tests/python/confidential_attr.py +index ac83f488061..eb75da6374f 100755 +--- a/source4/dsdb/tests/python/confidential_attr.py ++++ b/source4/dsdb/tests/python/confidential_attr.py +@@ -24,7 +24,6 @@ import sys + sys.path.insert(0, "bin/python") + + import samba +-import os + import random + import statistics + import time +@@ -136,9 +135,9 @@ class ConfidentialAttrCommon(samba.tests.TestCase): + # sanity-check the flag is not already set (this'll cause problems if + # previous test run didn't clean up properly) + search_flags = self.get_attr_search_flags(self.attr_dn) +- self.assertTrue(int(search_flags) & SEARCH_FLAG_CONFIDENTIAL == 0, +- "{0} searchFlags already {1}".format(self.conf_attr, +- search_flags)) ++ self.assertEqual(0, int(search_flags) & SEARCH_FLAG_CONFIDENTIAL, ++ "{0} searchFlags already {1}".format(self.conf_attr, ++ search_flags)) + + def tearDown(self): + super(ConfidentialAttrCommon, self).tearDown() +@@ -208,9 +207,9 @@ class ConfidentialAttrCommon(samba.tests.TestCase): + for attr in attr_filters: + res = samdb.search(self.test_dn, expression=expr, + scope=SCOPE_SUBTREE, attrs=attr) +- self.assertTrue(len(res) == expected_num, +- "%u results, not %u for search %s, attr %s" % +- (len(res), expected_num, expr, str(attr))) ++ self.assertEqual(len(res), expected_num, ++ "%u results, not %u for search %s, attr %s" % ++ (len(res), expected_num, expr, str(attr))) + + # return a selection of searches that match exactly against the test object + def get_exact_match_searches(self): +@@ -352,25 +351,6 @@ class ConfidentialAttrCommon(samba.tests.TestCase): + + return expected_results + +- # Returns the expected negative (i.e. '!') search behaviour when talking to +- # a DC with DC_MODE_RETURN_NONE behaviour, i.e. we assert that users +- # without rights cannot see objects in '!' searches at all +- def negative_searches_return_none(self, has_rights_to=0): +- expected_results = {} +- +- # the 'match-all' searches should only return the objects we have +- # access rights to (if any) +- for search in self.get_negative_match_all_searches(): +- expected_results[search] = has_rights_to +- +- # for inverse matches, we should NOT be told about any objects at all +- inverse_searches = self.get_inverse_match_searches() +- inverse_searches += ["(!({0}=*))".format(self.conf_attr)] +- for search in inverse_searches: +- expected_results[search] = 0 +- +- return expected_results +- + # Returns the expected negative (i.e. '!') search behaviour. This varies + # depending on what type of DC we're talking to (i.e. Windows or Samba) + # and what access rights the user has. +@@ -403,7 +383,7 @@ class ConfidentialAttrCommon(samba.tests.TestCase): + # checks whether the confidential attribute is present + res = samdb.search(self.conf_dn, expression="(objectClass=*)", + scope=SCOPE_SUBTREE, attrs=attrs) +- self.assertTrue(len(res) == 1) ++ self.assertEqual(1, len(res)) + + attr_returned = False + for msg in res: +@@ -586,9 +566,9 @@ class ConfidentialAttrTestDenyAcl(ConfidentialAttrCommon): + for attr in attr_filters: + res = samdb.search(self.test_dn, expression=expr, + scope=SCOPE_SUBTREE, attrs=attr) +- self.assertTrue(len(res) == expected_num, +- "%u results, not %u for search %s, attr %s" % +- (len(res), expected_num, expr, str(attr))) ++ self.assertEqual(len(res), expected_num, ++ "%u results, not %u for search %s, attr %s" % ++ (len(res), expected_num, expr, str(attr))) + + # assert we haven't revealed the hidden test-object + if excl_testobj: +@@ -604,7 +584,7 @@ class ConfidentialAttrTestDenyAcl(ConfidentialAttrCommon): + + # make sure the test object is not returned if we've been denied rights + # to it via an ACE +- excl_testobj = True if has_rights_to == "deny-one" else False ++ excl_testobj = has_rights_to == "deny-one" + + # these first few searches we just expect to match against the one + # object under test that we're trying to guess the value of +@@ -625,24 +605,6 @@ class ConfidentialAttrTestDenyAcl(ConfidentialAttrCommon): + self.assert_search_result(expected_num, search, samdb, + excl_testobj) + +- # override method specifically for deny ACL test cases. Instead of being +- # granted access to either no objects or only one, we are being denied +- # access to only one object (but can still access the rest). +- def negative_searches_return_none(self, has_rights_to=0): +- expected_results = {} +- +- # on Samba we will see the objects we have rights to, but the one we +- # are denied access to will be hidden +- searches = self.get_negative_match_all_searches() +- searches += self.get_inverse_match_searches() +- for search in searches: +- expected_results[search] = self.total_objects - 1 +- +- # The wildcard returns the objects without this attribute as normal. +- search = "(!({0}=*))".format(self.conf_attr) +- expected_results[search] = self.total_objects - self.objects_with_attr +- return expected_results +- + # override method specifically for deny ACL test cases + def negative_searches_return_all(self, has_rights_to=0, + total_objects=None): +@@ -783,7 +745,7 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + for attr in self.attr_filters: + res = samdb.search(base_dn, expression=search, scope=SCOPE_SUBTREE, + attrs=attr, controls=self.dirsync) +- self.assertTrue(len(res) == expected_num, ++ self.assertEqual(len(res), expected_num, + "%u results, not %u for search %s, attr %s" % + (len(res), expected_num, search, str(attr))) + +@@ -797,7 +759,8 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + expr = self.single_obj_filter + res = samdb.search(self.base_dn, expression=expr, scope=SCOPE_SUBTREE, + attrs=attrs, controls=self.dirsync) +- self.assertTrue(len(res) == 1 or no_result_ok) ++ if not no_result_ok: ++ self.assertEqual(1, len(res)) + + attr_returned = False + for msg in res: +@@ -888,7 +851,7 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + search_flags = int(self.get_attr_search_flags(self.attr_dn)) + + # check we've already set the confidential flag +- self.assertTrue(search_flags & SEARCH_FLAG_CONFIDENTIAL != 0) ++ self.assertNotEqual(0, search_flags & SEARCH_FLAG_CONFIDENTIAL) + search_flags |= SEARCH_FLAG_PRESERVEONDELETE + + self.set_attr_search_flags(self.attr_dn, str(search_flags)) +@@ -964,7 +927,7 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + # now delete the users (except for the user whose LDB connection + # we're currently using) + for user in self.all_users: +- if user != self.user: ++ if user is not self.user: + self.ldb_admin.delete(self.get_user_dn(user)) + + # check we still can't see the objects +-- +2.34.1 diff --git a/backport-0005-CVE-2018-14628.patch b/backport-0005-CVE-2018-14628.patch new file mode 100644 index 0000000000000000000000000000000000000000..a4b51f43c0e89b45b77c3827507580457a08a05f --- /dev/null +++ b/backport-0005-CVE-2018-14628.patch @@ -0,0 +1,71 @@ +From 83dbd0c922640bb1ac244d2855c00d6984625963 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Wed, 7 Jun 2023 18:18:58 +0200 +Subject: [PATCH 5/6] CVE-2018-14628: dbchecker: use + get_deletedobjects_descriptor for missing deleted objects container + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13595 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +(cherry picked from commit 70586061128f90afa33f25e104d4570a1cf778db) + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=18168 +[PATCH 5/6] CVE-2018-14628: dbchecker: use + get_deletedobjects_descriptor for missing deleted objects container +--- + python/samba/dbchecker.py | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py +index 449b0a7d985c..e124b1a0d671 100644 +--- a/python/samba/dbchecker.py ++++ b/python/samba/dbchecker.py +@@ -20,7 +20,7 @@ + import ldb + import samba + import time +-from base64 import b64decode ++from base64 import b64decode, b64encode + from samba import dsdb + from samba import common + from samba.dcerpc import misc +@@ -29,7 +29,11 @@ from samba.ndr import ndr_unpack, ndr_pack + from samba.dcerpc import drsblobs + from samba.samdb import dsdb_Dn + from samba.dcerpc import security +-from samba.descriptor import get_wellknown_sds, get_diff_sds ++from samba.descriptor import ( ++ get_wellknown_sds, ++ get_deletedobjects_descriptor, ++ get_diff_sds ++) + from samba.auth import system_session, admin_session + from samba.netcmd import CommandError + from samba.netcmd.fsmo import get_fsmo_roleowner +@@ -341,6 +345,12 @@ class dbcheck(object): + listwko.append('%s:%s' % (wko_prefix, dn)) + guid_suffix = "" + ++ ++ domain_sid = security.dom_sid(self.samdb.get_domain_sid()) ++ sec_desc = get_deletedobjects_descriptor(domain_sid, ++ name_map=self.name_map) ++ sec_desc_b64 = b64encode(sec_desc).decode('utf8') ++ + # Insert a brand new Deleted Objects container + self.samdb.add_ldif("""dn: %s + objectClass: top +@@ -349,7 +359,8 @@ description: Container for deleted objects + isDeleted: TRUE + isCriticalSystemObject: TRUE + showInAdvancedViewOnly: TRUE +-systemFlags: -1946157056%s""" % (dn, guid_suffix), ++nTSecurityDescriptor:: %s ++systemFlags: -1946157056%s""" % (dn, sec_desc_b64, guid_suffix), + controls=["relax:0", "provision:0"]) + + delta = ldb.Message() +-- +2.34.1 diff --git a/backport-0005-CVE-2023-0614.patch b/backport-0005-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..62df6733d40524c20d1dce242ded426ac31f0ca1 --- /dev/null +++ b/backport-0005-CVE-2023-0614.patch @@ -0,0 +1,86 @@ +From 89f882b49d2669ba8b51e9b5de644164f5c1995e Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Tue, 7 Feb 2023 09:29:51 +1300 +Subject: [PATCH 03/34] CVE-2023-0614 s4:dsdb: Use talloc_get_type_abort() more + consistently + +It is better to explicitly abort than to dereference a NULL pointer or +try to read data cast to the wrong type. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/samdb/ldb_modules/acl_read.c | 4 ++-- + source4/dsdb/samdb/ldb_modules/acl_util.c | 2 +- + source4/dsdb/samdb/ldb_modules/linked_attributes.c | 2 +- + source4/dsdb/samdb/ldb_modules/password_hash.c | 2 +- + 4 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c +index b221dcde445..16a1927183c 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl_read.c ++++ b/source4/dsdb/samdb/ldb_modules/acl_read.c +@@ -268,7 +268,7 @@ static int aclread_get_sd_from_ldb_message(struct aclread_context *ac, + struct ldb_message_element *sd_element; + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + struct aclread_private *private_data +- = talloc_get_type(ldb_module_get_private(ac->module), ++ = talloc_get_type_abort(ldb_module_get_private(ac->module), + struct aclread_private); + enum ndr_err_code ndr_err; + +@@ -568,7 +568,7 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + const struct dsdb_class *objectclass; + bool suppress_result = false; + +- ac = talloc_get_type(req->context, struct aclread_context); ++ ac = talloc_get_type_abort(req->context, struct aclread_context); + ldb = ldb_module_get_ctx(ac->module); + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR ); +diff --git a/source4/dsdb/samdb/ldb_modules/acl_util.c b/source4/dsdb/samdb/ldb_modules/acl_util.c +index 12f00fbff16..367c11d1ba9 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl_util.c ++++ b/source4/dsdb/samdb/ldb_modules/acl_util.c +@@ -298,7 +298,7 @@ uint32_t dsdb_request_sd_flags(struct ldb_request *req, bool *explicit) + + sd_control = ldb_request_get_control(req, LDB_CONTROL_SD_FLAGS_OID); + if (sd_control != NULL && sd_control->data != NULL) { +- struct ldb_sd_flags_control *sdctr = (struct ldb_sd_flags_control *)sd_control->data; ++ struct ldb_sd_flags_control *sdctr = talloc_get_type_abort(sd_control->data, struct ldb_sd_flags_control); + + sd_flags = sdctr->secinfo_flags; + +diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c +index 5ef075f2037..317df9d3e0e 100644 +--- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c ++++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c +@@ -104,7 +104,7 @@ static int handle_verify_name_control(TALLOC_CTX *ctx, struct ldb_context *ldb, + * If we are a GC let's remove the control, + * if there is a specified GC check that is us. + */ +- struct ldb_verify_name_control *lvnc = (struct ldb_verify_name_control *)control->data; ++ struct ldb_verify_name_control *lvnc = talloc_get_type_abort(control->data, struct ldb_verify_name_control); + if (samdb_is_gc(ldb)) { + /* Because we can't easily talloc a struct ldb_dn*/ + struct ldb_dn **dn = talloc_array(ctx, struct ldb_dn *, 1); +diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c +index b308226a9f9..6a713b86736 100644 +--- a/source4/dsdb/samdb/ldb_modules/password_hash.c ++++ b/source4/dsdb/samdb/ldb_modules/password_hash.c +@@ -4066,7 +4066,7 @@ static void ph_apply_controls(struct ph_context *ac) + ctrl = ldb_request_get_control(ac->req, + DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID); + if (ctrl != NULL) { +- ac->change = (struct dsdb_control_password_change *) ctrl->data; ++ ac->change = talloc_get_type_abort(ctrl->data, struct dsdb_control_password_change); + + /* Mark the "change" control as uncritical (done) */ + ctrl->critical = false; +-- +2.25.1 \ No newline at end of file diff --git a/backport-0005-CVE-2023-3347.patch b/backport-0005-CVE-2023-3347.patch new file mode 100644 index 0000000000000000000000000000000000000000..28db6aa9994c4495f33a0ade8cad6ffb5708e5e8 --- /dev/null +++ b/backport-0005-CVE-2023-3347.patch @@ -0,0 +1,62 @@ +From 6c1128b11842d60e3ebd9ee1b5cefcfd99629ba5 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 20 Jun 2023 15:33:02 +0200 +Subject: [PATCH 22/28] CVE-2023-3347: smbd: fix "server signing = mandatory" + +This was broken by commit 1f3f6e20dc086a36de52bffd0bc36e15fb19e1c6 because when +calling srv_init_signing() very early after accepting the connection in +smbd_add_connection(), conn->protocol is still PROTOCOL_NONE. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15397 + +Signed-off-by: Ralph Boehme + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + .../samba3.smb2.session-require-signing | 1 - + source3/smbd/smb2_signing.c | 19 ++++++++----------- + 2 files changed, 8 insertions(+), 12 deletions(-) + delete mode 100644 selftest/knownfail.d/samba3.smb2.session-require-signing + +diff --git a/selftest/knownfail.d/samba3.smb2.session-require-signing b/selftest/knownfail.d/samba3.smb2.session-require-signing +deleted file mode 100644 +index 53b7a7022a8..00000000000 +--- a/selftest/knownfail.d/samba3.smb2.session-require-signing ++++ /dev/null +@@ -1 +0,0 @@ +-^samba3.smb2.session-require-signing.bug15397 +diff --git a/source3/smbd/smb2_signing.c b/source3/smbd/smb2_signing.c +index ef4a54d5710..73d07380dfa 100644 +--- a/source3/smbd/smb2_signing.c ++++ b/source3/smbd/smb2_signing.c +@@ -37,19 +37,16 @@ bool srv_init_signing(struct smbXsrv_connection *conn) + return false; + } + ++ /* ++ * For SMB2 all we need to know is if signing is mandatory. ++ * It is always allowed and desired, whatever the smb.conf says. ++ */ ++ (void)lpcfg_server_signing_allowed(lp_ctx, &conn->smb2.signing_mandatory); ++ + #if defined(WITH_SMB1SERVER) +- if (conn->protocol >= PROTOCOL_SMB2_02) { +-#endif +- /* +- * For SMB2 all we need to know is if signing is mandatory. +- * It is always allowed and desired, whatever the smb.conf says. +- */ +- (void)lpcfg_server_signing_allowed(lp_ctx, &conn->smb2.signing_mandatory); +-#if defined(WITH_SMB1SERVER) +- } else { +- ok = smb1_srv_init_signing(lp_ctx, conn); +- } ++ ok = smb1_srv_init_signing(lp_ctx, conn); + #endif ++ + talloc_unlink(conn, lp_ctx); + return ok; + } +-- +2.34.1 diff --git a/backport-0005-CVE-2023-34968.patch b/backport-0005-CVE-2023-34968.patch new file mode 100644 index 0000000000000000000000000000000000000000..9998f1906e3659268fce50da09856de6b4b752c6 --- /dev/null +++ b/backport-0005-CVE-2023-34968.patch @@ -0,0 +1,79 @@ +From 353a9ccea6ff93ea2cd604dcc2b0372f056f819d Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 20 Jun 2023 11:28:47 +0200 +Subject: [PATCH 11/28] CVE-2023-34968: smbtorture: remove response blob + allocation in mdssvc.c + +This is alreay done by NDR for us. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source4/torture/rpc/mdssvc.c | 26 -------------------------- + 1 file changed, 26 deletions(-) + +diff --git a/source4/torture/rpc/mdssvc.c b/source4/torture/rpc/mdssvc.c +index 3689692f7de..a16bd5b47e3 100644 +--- a/source4/torture/rpc/mdssvc.c ++++ b/source4/torture/rpc/mdssvc.c +@@ -536,13 +536,6 @@ static bool test_mdssvc_invalid_ph_cmd(struct torture_context *tctx, + request_blob.length = 0; + request_blob.size = 0; + +- response_blob.spotlight_blob = talloc_array(state, +- uint8_t, +- 0); +- torture_assert_not_null_goto(tctx, response_blob.spotlight_blob, +- ok, done, "dalloc_zero failed\n"); +- response_blob.size = 0; +- + status = dcerpc_mdssvc_cmd(b, + state, + &ph, +@@ -632,13 +625,6 @@ static bool test_mdssvc_sl_unpack_loop(struct torture_context *tctx, + request_blob.size = sizeof(test_sl_unpack_loop_buf); + request_blob.length = sizeof(test_sl_unpack_loop_buf); + +- response_blob.spotlight_blob = talloc_array(state, +- uint8_t, +- 0); +- torture_assert_not_null_goto(tctx, response_blob.spotlight_blob, +- ok, done, "dalloc_zero failed\n"); +- response_blob.size = 0; +- + status = dcerpc_mdssvc_cmd(b, + state, + &state->ph, +@@ -764,11 +750,6 @@ static bool test_sl_dict_type_safety(struct torture_context *tctx, + torture_assert_goto(tctx, request_blob.length > 0, + ok, done, "sl_pack failed\n"); + +- response_blob.spotlight_blob = talloc_array(state, uint8_t, 0); +- torture_assert_not_null_goto(tctx, response_blob.spotlight_blob, +- ok, done, "dalloc_zero failed\n"); +- response_blob.size = 0; +- + status = dcerpc_mdssvc_cmd(b, + state, + &state->ph, +@@ -926,13 +907,6 @@ static bool test_mdssvc_fetch_attr_unknown_cnid(struct torture_context *tctx, + ret, done, "dalloc_zero failed\n"); + request_blob.size = max_fragment_size; + +- response_blob.spotlight_blob = talloc_array(state, +- uint8_t, +- max_fragment_size); +- torture_assert_not_null_goto(tctx, response_blob.spotlight_blob, +- ret, done, "dalloc_zero failed\n"); +- response_blob.size = max_fragment_size; +- + len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size); + torture_assert_goto(tctx, len != -1, ret, done, "sl_pack failed\n"); + +-- +2.34.1 diff --git a/backport-0005-CVE-2023-4154.patch b/backport-0005-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..31298eff7b027922862697dbd7548f27314dc576 --- /dev/null +++ b/backport-0005-CVE-2023-4154.patch @@ -0,0 +1,429 @@ +From 76091f35016bd6e642237973981b1c88a9e44062 Mon Sep 17 00:00:00 2001 +From: Andreas Schneider +Date: Wed, 2 Aug 2023 10:44:32 +0200 +Subject: [PATCH 10/30] CVE-2023-4154 s4:dsdb:tests: Fix code spelling + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Andreas Schneider +Reviewed-by: Joseph Sutton + +(cherry picked from commit b29793ffdee5d9b9c1c05830622e80f7faec7670) + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 10/30] CVE-2023-4154 s4:dsdb:tests: Fix code spelling +--- + source4/dsdb/tests/python/acl.py | 12 ++++++------ + .../dsdb/tests/python/ad_dc_search_performance.py | 2 +- + source4/dsdb/tests/python/confidential_attr.py | 2 +- + source4/dsdb/tests/python/dirsync.py | 8 ++++---- + source4/dsdb/tests/python/ldap.py | 14 +++++++------- + source4/dsdb/tests/python/ldap_modify_order.py | 4 ++-- + source4/dsdb/tests/python/ldap_syntaxes.py | 4 ++-- + source4/dsdb/tests/python/login_basics.py | 2 +- + source4/dsdb/tests/python/password_settings.py | 4 ++-- + source4/dsdb/tests/python/passwords.py | 4 ++-- + source4/dsdb/tests/python/sam.py | 2 +- + source4/dsdb/tests/python/sec_descriptor.py | 14 +++++++------- + source4/dsdb/tests/python/token_group.py | 4 ++-- + source4/dsdb/tests/python/user_account_control.py | 2 +- + 14 files changed, 39 insertions(+), 39 deletions(-) + +diff --git a/source4/dsdb/tests/python/acl.py b/source4/dsdb/tests/python/acl.py +index 6751934af0c..eb2bafda3e5 100755 +--- a/source4/dsdb/tests/python/acl.py ++++ b/source4/dsdb/tests/python/acl.py +@@ -174,7 +174,7 @@ class AclAddTests(AclTests): + self.assertEqual(len(res), 0) + + def test_add_u1(self): +- """Testing OU with the rights of Doman Admin not creator of the OU """ ++ """Testing OU with the rights of Domain Admin not creator of the OU """ + self.assert_top_ou_deleted() + # Change descriptor for top level OU + self.ldb_owner.create_ou("OU=test_add_ou1," + self.base_dn) +@@ -187,7 +187,7 @@ class AclAddTests(AclTests): + self.ldb_notowner.newgroup("test_add_group1", groupou="OU=test_add_ou2,OU=test_add_ou1", + grouptype=samba.dsdb.GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP) + # Make sure we HAVE created the two objects -- user and group +- # !!! We should not be able to do that, but however beacuse of ACE ordering our inherited Deny ACE ++ # !!! We should not be able to do that, but however because of ACE ordering our inherited Deny ACE + # !!! comes after explicit (A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA) that comes from somewhere + res = self.ldb_admin.search(self.base_dn, expression="(distinguishedName=%s,%s)" % ("CN=test_add_user1,OU=test_add_ou2,OU=test_add_ou1", self.base_dn)) + self.assertTrue(len(res) > 0) +@@ -248,7 +248,7 @@ class AclAddTests(AclTests): + self.assertEqual(len(res), 0) + + def test_add_u4(self): +- """ 4 Testing OU with the rights of Doman Admin creator of the OU""" ++ """ 4 Testing OU with the rights of Domain Admin creator of the OU""" + self.assert_top_ou_deleted() + self.ldb_owner.create_ou("OU=test_add_ou1," + self.base_dn) + self.ldb_owner.create_ou("OU=test_add_ou2,OU=test_add_ou1," + self.base_dn) +@@ -1890,7 +1890,7 @@ class AclDeleteTests(AclTests): + self.assertEqual(len(res), 0) + + def test_delete_u3(self): +- """User indentified by SID has RIGHT_DELETE to another User object""" ++ """User identified by SID has RIGHT_DELETE to another User object""" + user_dn = self.get_user_dn("test_delete_user1") + # Create user that we try to delete + self.ldb_admin.newuser("test_delete_user1", self.user_pass) +@@ -2181,7 +2181,7 @@ class AclCARTests(AclTests): + minPwdAge = self.ldb_admin.get_minPwdAge() + # Reset the "minPwdAge" as it was before + self.addCleanup(self.ldb_admin.set_minPwdAge, minPwdAge) +- # Set it temporarely to "0" ++ # Set it temporarily to "0" + self.ldb_admin.set_minPwdAge("0") + + self.user_with_wp = "acl_car_user1" +@@ -2637,7 +2637,7 @@ class AclUndeleteTests(AclTests): + self.sd_utils.dacl_add_ace(self.deleted_dn2, mod) + self.undelete_deleted(self.deleted_dn2, self.testuser2_dn) + +- # attempt undelete with simultanious addition of url, WP to which is denied ++ # attempt undelete with simultaneous addition of url, WP to which is denied + mod = "(OD;;WP;9a9a0221-4a5b-11d1-a9c3-0000f80367c1;;%s)" % str(self.sid) + self.sd_utils.dacl_add_ace(self.deleted_dn3, mod) + try: +diff --git a/source4/dsdb/tests/python/ad_dc_search_performance.py b/source4/dsdb/tests/python/ad_dc_search_performance.py +index 0afd7a2582e..44e468097d8 100644 +--- a/source4/dsdb/tests/python/ad_dc_search_performance.py ++++ b/source4/dsdb/tests/python/ad_dc_search_performance.py +@@ -180,7 +180,7 @@ class UserTests(samba.tests.TestCase): + maybe_not = ['!(', ''] + joiners = ['&', '|'] + +- # The number of permuations is 18432, which is not huge but ++ # The number of permutations is 18432, which is not huge but + # would take hours to search. So we take a sample. + all_permutations = list(itertools.product(joiners, + classes, classes, +diff --git a/source4/dsdb/tests/python/confidential_attr.py b/source4/dsdb/tests/python/confidential_attr.py +index eb75da6374f..8ca56bd1023 100755 +--- a/source4/dsdb/tests/python/confidential_attr.py ++++ b/source4/dsdb/tests/python/confidential_attr.py +@@ -722,7 +722,7 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + + self.attr_filters = [None, ["*"], ["name"]] + +- # Note dirsync behaviour is slighty different for the attribute under ++ # Note dirsync behaviour is slightly different for the attribute under + # test - when you have full access rights, it only returns the objects + # that actually have this attribute (i.e. it doesn't return an empty + # message with just the DN). So we add the 'name' attribute into the +diff --git a/source4/dsdb/tests/python/dirsync.py b/source4/dsdb/tests/python/dirsync.py +index 1ac719e4332..ca0947e2d21 100755 +--- a/source4/dsdb/tests/python/dirsync.py ++++ b/source4/dsdb/tests/python/dirsync.py +@@ -338,7 +338,7 @@ class SimpleDirsyncTests(DirsyncBaseTests): + self.assertEqual(len(res.msgs[0]), 3) + + def test_dirsync_othernc(self): +- """Check that dirsync return information for entries that are normaly referrals (ie. other NCs)""" ++ """Check that dirsync return information for entries that are normally referrals (ie. other NCs)""" + res = self.ldb_admin.search(self.base_dn, + expression="(objectclass=configuration)", + attrs=["name"], +@@ -459,7 +459,7 @@ class SimpleDirsyncTests(DirsyncBaseTests): + delete_force(self.ldb_admin, ouname) + + def test_dirsync_linkedattributes(self): +- """Check that dirsync returnd deleted objects too""" ++ """Check that dirsync returned deleted objects too""" + # Let's search for members + self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) + res = self.ldb_simple.search(self.base_dn, +@@ -541,7 +541,7 @@ class SimpleDirsyncTests(DirsyncBaseTests): + self.assertEqual(len(res[0].get("member")), 0) + + def test_dirsync_deleted_items(self): +- """Check that dirsync returnd deleted objects too""" ++ """Check that dirsync returned deleted objects too""" + # Let's create an OU + ouname = "OU=testou3,%s" % self.base_dn + self.ouname = ouname +@@ -712,7 +712,7 @@ class ExtendedDirsyncTests(SimpleDirsyncTests): + self.assertIn(b">; +Date: Fri, 29 Jan 2016 23:35:31 +0100 +Subject: [PATCH 6/6] CVE-2018-14628: python:descriptor: let samba-tool dbcheck + fix the nTSecurityDescriptor on CN=Deleted Objects containers + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13595 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +(cherry picked from commit 97e4aab1a6e2feda7c6c6fdeaa7c3e1818c55566) + +Conflict: remove selftest file +source4/selftest/provisions/release-4-5-0-pre1/rootdse-version.final.txt +source4/selftest/provisions/release-4-5-0-pre1/expected-links-after-dbcheck.ldif +source4/selftest/provisions/release-4-5-0-pre1/expected-dbcheck-link-output-missing-link-sid-corruption.txt +Reference: https://attachments.samba.org/attachment.cgi?id=18168 +[PATCH 6/6] CVE-2018-14628: python:descriptor: let samba-tool dbcheck + fix the nTSecurityDescriptor on CN=Deleted Objects containers +--- + python/samba/dbchecker.py | 10 ++++++++-- + python/samba/descriptor.py | 15 ++++++++++++++- + ...ck-link-output-missing-link-sid-corruption.txt | 8 ++++---- + .../expected-links-after-dbcheck.ldif | 2 +- + .../release-4-5-0-pre1/rootdse-version.final.txt | 2 +- + testprogs/blackbox/dbcheck-links.sh | 12 ++++++++++++ + 6 files changed, 40 insertions(+), 9 deletions(-) + +diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py +index e124b1a0d671..28d99c01d044 100644 +--- a/python/samba/dbchecker.py ++++ b/python/samba/dbchecker.py +@@ -2444,7 +2444,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base))) + error_count += 1 + continue + +- if self.reset_well_known_acls: ++ if dn == deleted_objects_dn or self.reset_well_known_acls: + try: + well_known_sd = self.get_wellknown_sd(dn) + except KeyError: +@@ -2453,7 +2453,13 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base))) + current_sd = ndr_unpack(security.descriptor, + obj[attrname][0]) + +- diff = get_diff_sds(well_known_sd, current_sd, security.dom_sid(self.samdb.get_domain_sid())) ++ ignoreAdditionalACEs = False ++ if not self.reset_well_known_acls: ++ ignoreAdditionalACEs = True ++ ++ diff = get_diff_sds(well_known_sd, current_sd, ++ security.dom_sid(self.samdb.get_domain_sid()), ++ ignoreAdditionalACEs=ignoreAdditionalACEs) + if diff != "": + self.err_wrong_default_sd(dn, well_known_sd, diff) + error_count += 1 +diff --git a/python/samba/descriptor.py b/python/samba/descriptor.py +index 08c7518f56ab..34877fa4814a 100644 +--- a/python/samba/descriptor.py ++++ b/python/samba/descriptor.py +@@ -417,6 +417,7 @@ def get_wellknown_sds(samdb): + # Then subcontainers + subcontainers = [ + (ldb.Dn(samdb, "%s" % str(samdb.domain_dn())), get_domain_descriptor), ++ (ldb.Dn(samdb, "CN=Deleted Objects,%s" % str(samdb.domain_dn())), get_deletedobjects_descriptor), + (ldb.Dn(samdb, "CN=LostAndFound,%s" % str(samdb.domain_dn())), get_domain_delete_protected2_descriptor), + (ldb.Dn(samdb, "CN=System,%s" % str(samdb.domain_dn())), get_domain_delete_protected1_descriptor), + (ldb.Dn(samdb, "CN=Infrastructure,%s" % str(samdb.domain_dn())), get_domain_infrastructure_descriptor), +@@ -427,6 +428,7 @@ def get_wellknown_sds(samdb): + (ldb.Dn(samdb, "CN=MicrosoftDNS,CN=System,%s" % str(samdb.domain_dn())), get_dns_domain_microsoft_dns_descriptor), + + (ldb.Dn(samdb, "%s" % str(samdb.get_config_basedn())), get_config_descriptor), ++ (ldb.Dn(samdb, "CN=Deleted Objects,%s" % str(samdb.get_config_basedn())), get_deletedobjects_descriptor), + (ldb.Dn(samdb, "CN=NTDS Quotas,%s" % str(samdb.get_config_basedn())), get_config_ntds_quotas_descriptor), + (ldb.Dn(samdb, "CN=LostAndFoundConfig,%s" % str(samdb.get_config_basedn())), get_config_delete_protected1wd_descriptor), + (ldb.Dn(samdb, "CN=Services,%s" % str(samdb.get_config_basedn())), get_config_delete_protected1_descriptor), +@@ -451,6 +453,9 @@ def get_wellknown_sds(samdb): + if ldb.Dn(samdb, nc.decode('utf8')) == dnsforestdn: + c = (ldb.Dn(samdb, "%s" % str(dnsforestdn)), get_dns_partition_descriptor) + subcontainers.append(c) ++ c = (ldb.Dn(samdb, "CN=Deleted Objects,%s" % str(dnsforestdn)), ++ get_deletedobjects_descriptor) ++ subcontainers.append(c) + c = (ldb.Dn(samdb, "CN=Infrastructure,%s" % str(dnsforestdn)), + get_domain_delete_protected1_descriptor) + subcontainers.append(c) +@@ -466,6 +471,9 @@ def get_wellknown_sds(samdb): + if ldb.Dn(samdb, nc.decode('utf8')) == dnsdomaindn: + c = (ldb.Dn(samdb, "%s" % str(dnsdomaindn)), get_dns_partition_descriptor) + subcontainers.append(c) ++ c = (ldb.Dn(samdb, "CN=Deleted Objects,%s" % str(dnsdomaindn)), ++ get_deletedobjects_descriptor) ++ subcontainers.append(c) + c = (ldb.Dn(samdb, "CN=Infrastructure,%s" % str(dnsdomaindn)), + get_domain_delete_protected1_descriptor) + subcontainers.append(c) +@@ -558,7 +566,8 @@ def get_clean_sd(sd): + return sd_clean + + +-def get_diff_sds(refsd, cursd, domainsid, checkSacl=True): ++def get_diff_sds(refsd, cursd, domainsid, checkSacl=True, ++ ignoreAdditionalACEs=False): + """Get the difference between 2 sd + + This function split the textual representation of ACL into smaller +@@ -613,6 +622,10 @@ def get_diff_sds(refsd, cursd, domainsid, checkSacl=True): + h_ref.remove(k) + + if len(h_cur) + len(h_ref) > 0: ++ if txt == "" and len(h_ref) == 0: ++ if ignoreAdditionalACEs: ++ return "" ++ + txt = "%s\tPart %s is different between reference" \ + " and current here is the detail:\n" % (txt, part) + +diff --git a/testprogs/blackbox/dbcheck-links.sh b/testprogs/blackbox/dbcheck-links.sh +index 29fb5b85abcc..a91ed00fb0f7 100755 +--- a/testprogs/blackbox/dbcheck-links.sh ++++ b/testprogs/blackbox/dbcheck-links.sh +@@ -59,6 +59,16 @@ dbcheck() + fi + } + ++dbcheck_acl_reset() ++{ ++ $PYTHON $BINDIR/samba-tool dbcheck -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb --cross-ncs --fix --yes --attrs=nTSecurityDescriptor ++} ++ ++dbcheck_acl_clean() ++{ ++ $PYTHON $BINDIR/samba-tool dbcheck -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb --cross-ncs --attrs=nTSecurityDescriptor ++} ++ + dbcheck_dangling() + { + dbcheck "" "1" "--selftest-check-expired-tombstones" +@@ -925,6 +935,8 @@ EOF + remove_directory $PREFIX_ABS/${RELEASE} + + testit $RELEASE undump || failed=$(expr $failed + 1) ++testit_expect_failure "dbcheck_acl_reset" dbcheck_acl_reset || failed=$(expr $failed + 1) ++testit "dbcheck_acl_clean" dbcheck_acl_clean || failed=$(expr $failed + 1) + testit "add_two_more_users" add_two_more_users || failed=$(expr $failed + 1) + testit "add_four_more_links" add_four_more_links || failed=$(expr $failed + 1) + testit "remove_one_link" remove_one_link || failed=$(expr $failed + 1) +-- +2.34.1 diff --git a/backport-0006-CVE-2023-0614.patch b/backport-0006-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..f90a1d9a8e0a375fa5a0cda6f74325253cb9ff9d --- /dev/null +++ b/backport-0006-CVE-2023-0614.patch @@ -0,0 +1,36 @@ +From 003c65be1c6d8f8ea853896a75b315ef8e98cfb3 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 27 Jan 2023 08:00:32 +1300 +Subject: [PATCH 04/34] CVE-2023-0614 s4-acl: Make some parameters const + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org Adapted to code without newer + acl_check_access_on_attribute_implicit_owner name] + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/samdb/ldb_modules/acl_util.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/acl_util.c b/source4/dsdb/samdb/ldb_modules/acl_util.c +index 367c11d1ba9..56aa4bd7531 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl_util.c ++++ b/source4/dsdb/samdb/ldb_modules/acl_util.c +@@ -97,8 +97,8 @@ int dsdb_module_check_access_on_dn(struct ldb_module *module, + + int acl_check_access_on_attribute(struct ldb_module *module, + TALLOC_CTX *mem_ctx, +- struct security_descriptor *sd, +- struct dom_sid *rp_sid, ++ const struct security_descriptor *sd, ++ const struct dom_sid *rp_sid, + uint32_t access_mask, + const struct dsdb_attribute *attr, + const struct dsdb_class *objectclass) +-- +2.25.1 \ No newline at end of file diff --git a/backport-0006-CVE-2023-34968.patch b/backport-0006-CVE-2023-34968.patch new file mode 100644 index 0000000000000000000000000000000000000000..ec169a16abd15ddf7a9d09bdc8f44e61e6443a77 --- /dev/null +++ b/backport-0006-CVE-2023-34968.patch @@ -0,0 +1,55 @@ +From 449f1280b718c6da3b8e309fe124be4e9bfd8184 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 20 Jun 2023 11:35:41 +0200 +Subject: [PATCH 12/28] CVE-2023-34968: rpcclient: remove response blob + allocation + +This is alreay done by NDR for us. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/rpcclient/cmd_spotlight.c | 16 ---------------- + 1 file changed, 16 deletions(-) + +diff --git a/source3/rpcclient/cmd_spotlight.c b/source3/rpcclient/cmd_spotlight.c +index 24db9893df6..64fe321089c 100644 +--- a/source3/rpcclient/cmd_spotlight.c ++++ b/source3/rpcclient/cmd_spotlight.c +@@ -144,13 +144,6 @@ static NTSTATUS cmd_mdssvc_fetch_properties( + } + request_blob.size = max_fragment_size; + +- response_blob.spotlight_blob = talloc_array(mem_ctx, uint8_t, max_fragment_size); +- if (response_blob.spotlight_blob == NULL) { +- status = NT_STATUS_INTERNAL_ERROR; +- goto done; +- } +- response_blob.size = max_fragment_size; +- + len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size); + if (len == -1) { + status = NT_STATUS_INTERNAL_ERROR; +@@ -368,15 +361,6 @@ static NTSTATUS cmd_mdssvc_fetch_attributes( + } + request_blob.size = max_fragment_size; + +- response_blob.spotlight_blob = talloc_array(mem_ctx, +- uint8_t, +- max_fragment_size); +- if (response_blob.spotlight_blob == NULL) { +- status = NT_STATUS_INTERNAL_ERROR; +- goto done; +- } +- response_blob.size = max_fragment_size; +- + len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size); + if (len == -1) { + status = NT_STATUS_INTERNAL_ERROR; +-- +2.34.1 diff --git a/backport-0006-CVE-2023-4154.patch b/backport-0006-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..8be3116d32507b401b525d78f71689ebcc1f0846 --- /dev/null +++ b/backport-0006-CVE-2023-4154.patch @@ -0,0 +1,74 @@ +From c7fba7218cd2c271e53268fc857e206aec4f98d7 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Tue, 14 Feb 2023 17:19:27 +1300 +Subject: [PATCH 11/30] CVE-2023-4154 s4-dsdb: Remove + DSDB_ACL_CHECKS_DIRSYNC_FLAG + +It's no longer used anywhere. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +(cherry picked from commit 8b4e6f7b3fb8018cb64deef9b8e1cbc2e5ba12cf) + +Conflict: context adapt for source4/dsdb/samdb/samdb.h +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 11/30] CVE-2023-4154 s4-dsdb: Remove + DSDB_ACL_CHECKS_DIRSYNC_FLAG +--- + source4/dsdb/samdb/ldb_modules/dirsync.c | 11 ++--------- + source4/dsdb/samdb/samdb.h | 1 - + 2 files changed, 2 insertions(+), 10 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/dirsync.c b/source4/dsdb/samdb/ldb_modules/dirsync.c +index fa57af49e8f..b3c463741c8 100644 +--- a/source4/dsdb/samdb/ldb_modules/dirsync.c ++++ b/source4/dsdb/samdb/ldb_modules/dirsync.c +@@ -1005,7 +1005,6 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req + struct dirsync_context *dsc; + struct ldb_context *ldb; + struct ldb_parse_tree *new_tree = req->op.search.tree; +- uint32_t flags = 0; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + const char **attrs; +@@ -1117,13 +1116,8 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req + return ret; + } + talloc_free(acl_res); +- } else { +- flags |= DSDB_ACL_CHECKS_DIRSYNC_FLAG; +- +- if (ret != LDB_SUCCESS) { +- return ret; +- } +- ++ } else if (ret != LDB_SUCCESS) { ++ return ret; + } + + dsc->functional_level = dsdb_functional_level(ldb); +@@ -1394,7 +1388,6 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req + req->controls, + dsc, dirsync_search_callback, + req); +- ldb_req_set_custom_flags(down_req, flags); + LDB_REQ_SET_LOCATION(down_req); + if (ret != LDB_SUCCESS) { + return ret; +diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h +index 5cae2681ed0..7df86e56683 100644 +--- a/source4/dsdb/samdb/samdb.h ++++ b/source4/dsdb/samdb/samdb.h +@@ -362,7 +362,6 @@ struct dsdb_extended_dn_store_format { + + #define DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME "DSDB_OPAQUE_PARTITION_MODULE_MSG" + +-#define DSDB_ACL_CHECKS_DIRSYNC_FLAG 0x1 + #define DSDB_SAMDB_MINIMUM_ALLOWED_RID 1000 + + #define DSDB_METADATA_SCHEMA_SEQ_NUM "SCHEMA_SEQ_NUM" +-- +2.34.1 diff --git a/backport-0007-CVE-2023-0614.patch b/backport-0007-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..cc293a52c1855c6bab7f73e66871d849ccedef64 --- /dev/null +++ b/backport-0007-CVE-2023-0614.patch @@ -0,0 +1,72 @@ +From b01d3ae3261264236504475a26c54ab45dd2175f Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 27 Jan 2023 08:28:36 +1300 +Subject: [PATCH 05/34] CVE-2023-0614 ldb: Add functions for handling + inaccessible message elements + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb/common/ldb_msg.c | 26 ++++++++++++++++++++++++++ + lib/ldb/include/ldb_module.h | 4 ++++ + 2 files changed, 30 insertions(+) + +diff --git a/lib/ldb/common/ldb_msg.c b/lib/ldb/common/ldb_msg.c +index 9cd7998e21c..cbc7e32b2ba 100644 +--- a/lib/ldb/common/ldb_msg.c ++++ b/lib/ldb/common/ldb_msg.c +@@ -795,6 +795,32 @@ int ldb_msg_element_compare_name(struct ldb_message_element *el1, + return ldb_attr_cmp(el1->name, el2->name); + } + ++void ldb_msg_element_mark_inaccessible(struct ldb_message_element *el) ++{ ++ el->flags |= LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE; ++} ++ ++bool ldb_msg_element_is_inaccessible(const struct ldb_message_element *el) ++{ ++ return (el->flags & LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE) != 0; ++} ++ ++void ldb_msg_remove_inaccessible(struct ldb_message *msg) ++{ ++ unsigned i; ++ unsigned num_del = 0; ++ ++ for (i = 0; i < msg->num_elements; ++i) { ++ if (ldb_msg_element_is_inaccessible(&msg->elements[i])) { ++ ++num_del; ++ } else if (num_del) { ++ msg->elements[i - num_del] = msg->elements[i]; ++ } ++ } ++ ++ msg->num_elements -= num_del; ++} ++ + /* + convenience functions to return common types from a message + these return the first value if the attribute is multi-valued +diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h +index 4c7c85a17f0..8481fd3991a 100644 +--- a/lib/ldb/include/ldb_module.h ++++ b/lib/ldb/include/ldb_module.h +@@ -513,6 +513,10 @@ struct ldb_extended_match_rule + int ldb_register_extended_match_rule(struct ldb_context *ldb, + const struct ldb_extended_match_rule *rule); + ++void ldb_msg_element_mark_inaccessible(struct ldb_message_element *el); ++bool ldb_msg_element_is_inaccessible(const struct ldb_message_element *el); ++void ldb_msg_remove_inaccessible(struct ldb_message *msg); ++ + /* + * these pack/unpack functions are exposed in the library for use by + * ldb tools like ldbdump and for use in tests, +-- +2.25.1 \ No newline at end of file diff --git a/backport-0007-CVE-2023-34968.patch b/backport-0007-CVE-2023-34968.patch new file mode 100644 index 0000000000000000000000000000000000000000..b992076355d39a8b75fccc485b7ffe01f1cd2fb3 --- /dev/null +++ b/backport-0007-CVE-2023-34968.patch @@ -0,0 +1,47 @@ +From cc593a6ac531f02f2fe70fd4f7dfe649a02f9206 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 20 Jun 2023 11:42:10 +0200 +Subject: [PATCH 13/28] CVE-2023-34968: mdssvc: remove response blob allocation + +This is alreay done by NDR for us. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/rpc_server/mdssvc/srv_mdssvc_nt.c | 9 --------- + 1 file changed, 9 deletions(-) + +diff --git a/source3/rpc_server/mdssvc/srv_mdssvc_nt.c b/source3/rpc_server/mdssvc/srv_mdssvc_nt.c +index 2fca15cb8a8..2fec2bb6725 100644 +--- a/source3/rpc_server/mdssvc/srv_mdssvc_nt.c ++++ b/source3/rpc_server/mdssvc/srv_mdssvc_nt.c +@@ -164,7 +164,6 @@ void _mdssvc_cmd(struct pipes_struct *p, struct mdssvc_cmd *r) + struct auth_session_info *session_info = + dcesrv_call_session_info(dce_call); + bool ok; +- char *rbuf; + struct mds_ctx *mds_ctx; + NTSTATUS status; + +@@ -221,14 +220,6 @@ void _mdssvc_cmd(struct pipes_struct *p, struct mdssvc_cmd *r) + return; + } + +- rbuf = talloc_zero_array(p->mem_ctx, char, r->in.max_fragment_size1); +- if (rbuf == NULL) { +- p->fault_state = DCERPC_FAULT_CANT_PERFORM; +- return; +- } +- r->out.response_blob->spotlight_blob = (uint8_t *)rbuf; +- r->out.response_blob->size = r->in.max_fragment_size1; +- + /* We currently don't use fragmentation at the mdssvc RPC layer */ + *r->out.fragment = 0; + +-- +2.34.1 diff --git a/backport-0007-CVE-2023-4154.patch b/backport-0007-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..ac2286f41f5cd16031f3a0323b40fe4cff3f2437 --- /dev/null +++ b/backport-0007-CVE-2023-4154.patch @@ -0,0 +1,173 @@ +From 60baeea804aeaf9a2ea618d14985a9b7560e03a7 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 10 Mar 2023 18:25:18 +0100 +Subject: [PATCH 12/30] CVE-2023-4154 python:sd_utils: introduce + update_aces_in_dacl() helper + +This is a more generic api that can be re-used in other places +as well in future. It operates on a security descriptor object instead of +SDDL. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +(cherry picked from commit 8411e6d302e25d10f1035ebbdcbde7308566e930) + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 12/30] CVE-2023-4154 python:sd_utils: introduce + update_aces_in_dacl() helper +--- + python/samba/sd_utils.py | 124 +++++++++++++++++++++++++++++++++++---- + 1 file changed, 112 insertions(+), 12 deletions(-) + +diff --git a/python/samba/sd_utils.py b/python/samba/sd_utils.py +index 26e80ee2f4a..52a78de5d09 100644 +--- a/python/samba/sd_utils.py ++++ b/python/samba/sd_utils.py +@@ -21,8 +21,11 @@ + import samba + from ldb import Message, MessageElement, Dn + from ldb import FLAG_MOD_REPLACE, SCOPE_BASE +-from samba.ndr import ndr_pack, ndr_unpack ++from samba.ndr import ndr_pack, ndr_unpack, ndr_deepcopy + from samba.dcerpc import security ++from samba.ntstatus import ( ++ NT_STATUS_OBJECT_NAME_NOT_FOUND, ++) + + + class SDUtils(object): +@@ -63,19 +66,116 @@ class SDUtils(object): + res = self.ldb.search(object_dn) + return ndr_unpack(security.dom_sid, res[0]["objectSid"][0]) + ++ def update_aces_in_dacl(self, dn, del_aces=None, add_aces=None, ++ sddl_attr=None, controls=None): ++ if del_aces is None: ++ del_aces=[] ++ if add_aces is None: ++ add_aces=[] ++ ++ def ace_from_sddl(ace_sddl): ++ ace_sd = security.descriptor.from_sddl("D:" + ace_sddl, self.domain_sid) ++ assert(len(ace_sd.dacl.aces)==1) ++ return ace_sd.dacl.aces[0] ++ ++ if sddl_attr is None: ++ if controls is None: ++ controls=["sd_flags:1:%d" % security.SECINFO_DACL] ++ sd = self.read_sd_on_dn(dn, controls=controls) ++ if not sd.type & security.SEC_DESC_DACL_PROTECTED: ++ # if the DACL is not protected remove all ++ # inherited aces, as they will be re-inherited ++ # on the server, we need a ndr_deepcopy in order ++ # to avoid reference problems while deleting ++ # the aces while looping over them ++ dacl_copy = ndr_deepcopy(sd.dacl) ++ for ace in dacl_copy.aces: ++ if ace.flags & security.SEC_ACE_FLAG_INHERITED_ACE: ++ try: ++ sd.dacl_del_ace(ace) ++ except samba.NTSTATUSError as err: ++ if err.args[0] != NT_STATUS_OBJECT_NAME_NOT_FOUND: ++ raise err ++ # dacl_del_ace may remove more than ++ # one ace, so we may not find it anymore ++ pass ++ else: ++ if controls is None: ++ controls=[] ++ res = self.ldb.search(dn, SCOPE_BASE, None, ++ [sddl_attr], controls=controls) ++ old_sddl = str(res[0][sddl_attr][0]) ++ sd = security.descriptor.from_sddl(old_sddl, self.domain_sid) ++ ++ num_changes = 0 ++ del_ignored = [] ++ add_ignored = [] ++ inherited_ignored = [] ++ ++ for ace in del_aces: ++ if isinstance(ace, str): ++ ace = ace_from_sddl(ace) ++ assert(isinstance(ace, security.ace)) ++ ++ if ace.flags & security.SEC_ACE_FLAG_INHERITED_ACE: ++ inherited_ignored.append(ace) ++ continue ++ ++ if ace not in sd.dacl.aces: ++ del_ignored.append(ace) ++ continue ++ ++ sd.dacl_del_ace(ace) ++ num_changes += 1 ++ ++ for ace in add_aces: ++ add_idx = -1 ++ if isinstance(ace, dict): ++ if "idx" in ace: ++ add_idx = ace["idx"] ++ ace = ace["ace"] ++ if isinstance(ace, str): ++ ace = ace_from_sddl(ace) ++ assert(isinstance(ace, security.ace)) ++ ++ if ace.flags & security.SEC_ACE_FLAG_INHERITED_ACE: ++ inherited_ignored.append(ace) ++ continue ++ ++ if ace in sd.dacl.aces: ++ add_ignored.append(ace) ++ continue ++ ++ sd.dacl_add(ace, add_idx) ++ num_changes += 1 ++ ++ if num_changes == 0: ++ return del_ignored, add_ignored, inherited_ignored ++ ++ if sddl_attr is None: ++ self.modify_sd_on_dn(dn, sd, controls=controls) ++ else: ++ new_sddl = sd.as_sddl(self.domain_sid) ++ m = Message() ++ m.dn = dn ++ m[sddl_attr] = MessageElement(new_sddl.encode('ascii'), ++ FLAG_MOD_REPLACE, ++ sddl_attr) ++ self.ldb.modify(m, controls=controls) ++ ++ return del_ignored, add_ignored, inherited_ignored ++ + def dacl_add_ace(self, object_dn, ace): +- """Add an ACE to an objects security descriptor ++ """Add an ACE (or more) to an objects security descriptor + """ +- desc = self.read_sd_on_dn(object_dn, ["show_deleted:1"]) +- desc_sddl = desc.as_sddl(self.domain_sid) +- if ace in desc_sddl: +- return +- if desc_sddl.find("(") >= 0: +- desc_sddl = (desc_sddl[:desc_sddl.index("(")] + ace + +- desc_sddl[desc_sddl.index("("):]) +- else: +- desc_sddl = desc_sddl + ace +- self.modify_sd_on_dn(object_dn, desc_sddl, ["show_deleted:1"]) ++ ace_sd = security.descriptor.from_sddl("D:" + ace, self.domain_sid) ++ add_aces = [] ++ add_idx = 0 ++ for ace in ace_sd.dacl.aces: ++ add_aces.append({"idx": add_idx, "ace": ace}) ++ add_idx += 1 ++ _,_,_ = self.update_aces_in_dacl(object_dn, add_aces=add_aces, ++ controls=["show_deleted:1"]) + + def get_sd_as_sddl(self, object_dn, controls=[]): + """Return object nTSecutiryDescriptor in SDDL format +-- +2.34.1 diff --git a/backport-0008-CVE-2023-0614.patch b/backport-0008-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..a56265dcc82c0a4e4bc76cd5c7a4da57768a17a5 --- /dev/null +++ b/backport-0008-CVE-2023-0614.patch @@ -0,0 +1,140 @@ +From c818c16912f5af248b91f0688c3e57012db89011 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 27 Jan 2023 08:29:33 +1300 +Subject: [PATCH 06/34] CVE-2023-0614 s4-acl: Use ldb functions for handling + inaccessible message elements + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/samdb/ldb_modules/acl_read.c | 62 ++++------------------- + 1 file changed, 10 insertions(+), 52 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c +index 16a1927183c..8814a816797 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl_read.c ++++ b/source4/dsdb/samdb/ldb_modules/acl_read.c +@@ -70,14 +70,6 @@ struct aclread_private { + struct ldb_val sd_cached_blob; + }; + +-static void aclread_mark_inaccesslible(struct ldb_message_element *el) { +- el->flags |= LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE; +-} +- +-static bool aclread_is_inaccessible(struct ldb_message_element *el) { +- return el->flags & LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE; +-} +- + /* + * the object has a parent, so we have to check for visibility + * +@@ -557,11 +549,9 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + { + struct ldb_context *ldb; + struct aclread_context *ac; +- struct ldb_message *ret_msg; + struct ldb_message *msg; + int ret; +- size_t num_of_attrs = 0; +- unsigned int i, k = 0; ++ unsigned int i; + struct security_descriptor *sd = NULL; + struct dom_sid *sid = NULL; + TALLOC_CTX *tmp_ctx; +@@ -651,26 +641,26 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + msg->elements[i].name) == 0; + /* these attributes were added to perform access checks and must be removed */ + if (is_objectsid && ac->added_objectSid) { +- aclread_mark_inaccesslible(&msg->elements[i]); ++ ldb_msg_element_mark_inaccessible(&msg->elements[i]); + continue; + } + if (is_instancetype && ac->added_instanceType) { +- aclread_mark_inaccesslible(&msg->elements[i]); ++ ldb_msg_element_mark_inaccessible(&msg->elements[i]); + continue; + } + if (is_objectclass && ac->added_objectClass) { +- aclread_mark_inaccesslible(&msg->elements[i]); ++ ldb_msg_element_mark_inaccessible(&msg->elements[i]); + continue; + } + if (is_sd && ac->added_nTSecurityDescriptor) { +- aclread_mark_inaccesslible(&msg->elements[i]); ++ ldb_msg_element_mark_inaccessible(&msg->elements[i]); + continue; + } + + access_mask = get_attr_access_mask(attr, ac->sd_flags); + + if (access_mask == 0) { +- aclread_mark_inaccesslible(&msg->elements[i]); ++ ldb_msg_element_mark_inaccessible(&msg->elements[i]); + continue; + } + +@@ -714,7 +704,7 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + return LDB_SUCCESS; + } + } else { +- aclread_mark_inaccesslible(&msg->elements[i]); ++ ldb_msg_element_mark_inaccessible(&msg->elements[i]); + } + } else if (ret != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, +@@ -757,44 +747,12 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + } + } + +- for (i=0; i < msg->num_elements; i++) { +- if (!aclread_is_inaccessible(&msg->elements[i])) { +- num_of_attrs++; +- } +- } +- /*create a new message to return*/ +- ret_msg = ldb_msg_new(ac->req); +- ret_msg->dn = msg->dn; +- talloc_steal(ret_msg, msg->dn); +- ret_msg->num_elements = num_of_attrs; +- if (num_of_attrs > 0) { +- ret_msg->elements = talloc_array(ret_msg, +- struct ldb_message_element, +- num_of_attrs); +- if (ret_msg->elements == NULL) { +- return ldb_oom(ldb); +- } +- for (i=0; i < msg->num_elements; i++) { +- bool to_remove = aclread_is_inaccessible(&msg->elements[i]); +- if (!to_remove) { +- ret_msg->elements[k] = msg->elements[i]; +- talloc_steal(ret_msg->elements, msg->elements[i].name); +- talloc_steal(ret_msg->elements, msg->elements[i].values); +- k++; +- } +- } +- /* +- * This should not be needed, but some modules +- * may allocate values on the wrong context... +- */ +- talloc_steal(ret_msg->elements, msg); +- } else { +- ret_msg->elements = NULL; +- } ++ ldb_msg_remove_inaccessible(msg); ++ + talloc_free(tmp_ctx); + + ac->num_entries++; +- return ldb_module_send_entry(ac->req, ret_msg, ares->controls); ++ return ldb_module_send_entry(ac->req, msg, ares->controls); + case LDB_REPLY_REFERRAL: + return ldb_module_send_referral(ac->req, ares->referral); + case LDB_REPLY_DONE: +-- +2.25.1 \ No newline at end of file diff --git a/backport-0008-CVE-2023-34968.patch b/backport-0008-CVE-2023-34968.patch new file mode 100644 index 0000000000000000000000000000000000000000..e2188d786cc71ea0499e1cb1d6235c08c7df2c2e --- /dev/null +++ b/backport-0008-CVE-2023-34968.patch @@ -0,0 +1,59 @@ +From ee428be9c67b1a7c9720c98f4aa67208e1b2938b Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 20 Jun 2023 11:05:22 +0200 +Subject: [PATCH 14/28] CVE-2023-34968: mdssvc: switch to doing an early return + +Just reduce indentation of the code handling the success case. No change in +behaviour. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/rpc_server/mdssvc/mdssvc.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +diff --git a/source3/rpc_server/mdssvc/mdssvc.c b/source3/rpc_server/mdssvc/mdssvc.c +index 9c23ef95753..070503f9eeb 100644 +--- a/source3/rpc_server/mdssvc/mdssvc.c ++++ b/source3/rpc_server/mdssvc/mdssvc.c +@@ -1804,19 +1804,21 @@ bool mds_dispatch(struct mds_ctx *mds_ctx, + } + + ok = slcmd->function(mds_ctx, query, reply); +- if (ok) { +- DBG_DEBUG("%s", dalloc_dump(reply, 0)); +- +- len = sl_pack(reply, +- (char *)response_blob->spotlight_blob, +- response_blob->size); +- if (len == -1) { +- DBG_ERR("error packing Spotlight RPC reply\n"); +- ok = false; +- goto cleanup; +- } +- response_blob->length = len; ++ if (!ok) { ++ goto cleanup; ++ } ++ ++ DBG_DEBUG("%s", dalloc_dump(reply, 0)); ++ ++ len = sl_pack(reply, ++ (char *)response_blob->spotlight_blob, ++ response_blob->size); ++ if (len == -1) { ++ DBG_ERR("error packing Spotlight RPC reply\n"); ++ ok = false; ++ goto cleanup; + } ++ response_blob->length = len; + + cleanup: + talloc_free(query); +-- +2.34.1 diff --git a/backport-0008-CVE-2023-4154.patch b/backport-0008-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..718173ac9ad111a4161bd255c181c855cc18ae00 --- /dev/null +++ b/backport-0008-CVE-2023-4154.patch @@ -0,0 +1,88 @@ +From d038ac36c13b5eb8f17491c9c066d3111a8f7d79 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 16 Mar 2023 18:03:10 +0100 +Subject: [PATCH 13/30] CVE-2023-4154 python:sd_utils: add + dacl_{prepend,append,delete}_aces() helpers + +They better represent what they are doing, we keep dacl_add_ace() +as wrapper of dacl_prepend_aces() in order to let existing callers +work as before. + +In future it would be good to have a dacl_insert_aces() that +would canonicalize the ace order before storing, but that a task +for another day. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +(cherry picked from commit a1109a9bf12e020636b8d66fc54984aac58bfe6b) + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 13/30] CVE-2023-4154 python:sd_utils: add + dacl_{prepend,append,delete}_aces() helpers +--- + python/samba/sd_utils.py | 39 ++++++++++++++++++++++++++++++++++----- + 1 file changed, 34 insertions(+), 5 deletions(-) + +diff --git a/python/samba/sd_utils.py b/python/samba/sd_utils.py +index 52a78de5d09..462bbfbaf18 100644 +--- a/python/samba/sd_utils.py ++++ b/python/samba/sd_utils.py +@@ -165,17 +165,46 @@ class SDUtils(object): + + return del_ignored, add_ignored, inherited_ignored + +- def dacl_add_ace(self, object_dn, ace): +- """Add an ACE (or more) to an objects security descriptor ++ def dacl_prepend_aces(self, object_dn, aces, controls=None): ++ """Prepend an ACE (or more) to an objects security descriptor + """ +- ace_sd = security.descriptor.from_sddl("D:" + ace, self.domain_sid) ++ ace_sd = security.descriptor.from_sddl("D:" + aces, self.domain_sid) + add_aces = [] + add_idx = 0 + for ace in ace_sd.dacl.aces: + add_aces.append({"idx": add_idx, "ace": ace}) + add_idx += 1 +- _,_,_ = self.update_aces_in_dacl(object_dn, add_aces=add_aces, +- controls=["show_deleted:1"]) ++ _,ai,ii = self.update_aces_in_dacl(object_dn, add_aces=add_aces, ++ controls=controls) ++ return ai, ii ++ ++ def dacl_add_ace(self, object_dn, ace): ++ """Add an ACE (or more) to an objects security descriptor ++ """ ++ _,_ = self.dacl_prepend_aces(object_dn, ace, ++ controls=["show_deleted:1"]) ++ ++ def dacl_append_aces(self, object_dn, aces, controls=None): ++ """Append an ACE (or more) to an objects security descriptor ++ """ ++ ace_sd = security.descriptor.from_sddl("D:" + aces, self.domain_sid) ++ add_aces = [] ++ for ace in ace_sd.dacl.aces: ++ add_aces.append(ace) ++ _,ai,ii = self.update_aces_in_dacl(object_dn, add_aces=add_aces, ++ controls=controls) ++ return ai, ii ++ ++ def dacl_delete_aces(self, object_dn, aces, controls=None): ++ """Delete an ACE (or more) to an objects security descriptor ++ """ ++ del_sd = security.descriptor.from_sddl("D:" + aces, self.domain_sid) ++ del_aces = [] ++ for ace in del_sd.dacl.aces: ++ del_aces.append(ace) ++ di,_,ii = self.update_aces_in_dacl(object_dn, del_aces=del_aces, ++ controls=controls) ++ return di, ii + + def get_sd_as_sddl(self, object_dn, controls=[]): + """Return object nTSecutiryDescriptor in SDDL format +-- +2.34.1 diff --git a/backport-0009-CVE-2023-0614.patch b/backport-0009-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..8c5062529c407ca4c7cd74848a1db3fa831aa8a8 --- /dev/null +++ b/backport-0009-CVE-2023-0614.patch @@ -0,0 +1,409 @@ +From e7445d18badee6c3b1bbee48c689eb2629c31681 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Wed, 15 Feb 2023 12:34:51 +1300 +Subject: [PATCH 07/34] CVE-2023-0614 ldb:tests: Ensure ldb_val data is + zero-terminated + +If the value of an ldb message element is not zero-terminated, calling +ldb_msg_find_attr_as_string() will cause the function to read off the +end of the buffer in an attempt to verify that the value is +zero-terminated. This can cause unexpected behaviour and make the test +randomly fail. + +To avoid this, we must have a terminating null byte that is *not* +counted as part of the length, and so we must calculate the length with +strlen() rather than sizeof. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb/tests/ldb_filter_attrs_test.c | 171 +++++++++++++------------- + 1 file changed, 86 insertions(+), 85 deletions(-) + +diff --git a/lib/ldb/tests/ldb_filter_attrs_test.c b/lib/ldb/tests/ldb_filter_attrs_test.c +index 7d555e0da2e..442d9c77ed2 100644 +--- a/lib/ldb/tests/ldb_filter_attrs_test.c ++++ b/lib/ldb/tests/ldb_filter_attrs_test.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -96,10 +97,10 @@ static void test_filter_attrs_one_attr_matched(void **state) + + const char *attrs[] = {"foo", NULL}; + +- uint8_t value[] = "The value.......end"; ++ char value[] = "The value.......end"; + struct ldb_val value_1 = { +- .data = value, +- .length = (sizeof(value)) ++ .data = (uint8_t *)value, ++ .length = strlen(value) + }; + struct ldb_message_element element_1 = { + .name = "foo", +@@ -130,9 +131,9 @@ static void test_filter_attrs_one_attr_matched(void **state) + assert_string_equal(filtered_msg->elements[0].name, "foo"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, +- sizeof(value)); ++ strlen(value)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, +- value, sizeof(value)); ++ value, strlen(value)); + } + + /* +@@ -148,10 +149,10 @@ static void test_filter_attrs_one_attr_matched_of_many(void **state) + + const char *attrs[] = {"foo", "bar", "baz", NULL}; + +- uint8_t value[] = "The value.......end"; ++ char value[] = "The value.......end"; + struct ldb_val value_1 = { +- .data = value, +- .length = (sizeof(value)) ++ .data = (uint8_t *)value, ++ .length = strlen(value) + }; + struct ldb_message_element element_1 = { + .name = "foo", +@@ -182,9 +183,9 @@ static void test_filter_attrs_one_attr_matched_of_many(void **state) + assert_string_equal(filtered_msg->elements[0].name, "foo"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, +- sizeof(value)); ++ strlen(value)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, +- value, sizeof(value)); ++ value, strlen(value)); + } + + /* +@@ -201,15 +202,15 @@ static void test_filter_attrs_two_attr_matched_attrs(void **state) + /* deliberatly the other order */ + const char *attrs[] = {"bar", "foo", NULL}; + +- uint8_t value1[] = "The value.......end"; +- uint8_t value2[] = "The value..MUST.end"; ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { +- .data = value1, +- .length = (sizeof(value1)) ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) + }; + struct ldb_val value_2 = { +- .data = value2, +- .length = (sizeof(value2)) ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) + }; + + /* foo and bar are the other order to in attrs */ +@@ -251,15 +252,15 @@ static void test_filter_attrs_two_attr_matched_attrs(void **state) + assert_string_equal(filtered_msg->elements[0].name, "foo"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, +- sizeof(value1)); ++ strlen(value1)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, +- value1, sizeof(value1)); ++ value1, strlen(value1)); + assert_string_equal(filtered_msg->elements[1].name, "bar"); + assert_int_equal(filtered_msg->elements[1].num_values, 1); + assert_int_equal(filtered_msg->elements[1].values[0].length, +- sizeof(value2)); ++ strlen(value2)); + assert_memory_equal(filtered_msg->elements[1].values[0].data, +- value2, sizeof(value2)); ++ value2, strlen(value2)); + } + + /* +@@ -276,15 +277,15 @@ static void test_filter_attrs_two_attr_matched_one_attr(void **state) + /* deliberatly the other order */ + const char *attrs[] = {"bar", NULL}; + +- uint8_t value1[] = "The value.......end"; +- uint8_t value2[] = "The value..MUST.end"; ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { +- .data = value1, +- .length = (sizeof(value1)) ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) + }; + struct ldb_val value_2 = { +- .data = value2, +- .length = (sizeof(value2)) ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) + }; + + /* foo and bar are the other order to in attrs */ +@@ -326,9 +327,9 @@ static void test_filter_attrs_two_attr_matched_one_attr(void **state) + assert_string_equal(filtered_msg->elements[0].name, "bar"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, +- sizeof(value2)); ++ strlen(value2)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, +- value2, sizeof(value2)); ++ value2, strlen(value2)); + } + + /* +@@ -345,15 +346,15 @@ static void test_filter_attrs_two_dup_attr_matched_one_attr(void **state) + /* deliberatly the other order */ + const char *attrs[] = {"bar", NULL}; + +- uint8_t value1[] = "The value.......end"; +- uint8_t value2[] = "The value..MUST.end"; ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { +- .data = value1, +- .length = (sizeof(value1)) ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) + }; + struct ldb_val value_2 = { +- .data = value2, +- .length = (sizeof(value2)) ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) + }; + + /* foo and bar are the other order to in attrs */ +@@ -400,15 +401,15 @@ static void test_filter_attrs_two_dup_attr_matched_dup(void **state) + + const char *attrs[] = {"bar", "bar", NULL}; + +- uint8_t value1[] = "The value.......end"; +- uint8_t value2[] = "The value..MUST.end"; ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { +- .data = value1, +- .length = (sizeof(value1)) ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) + }; + struct ldb_val value_2 = { +- .data = value2, +- .length = (sizeof(value2)) ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) + }; + + /* foo and bar are the other order to in attrs */ +@@ -445,15 +446,15 @@ static void test_filter_attrs_two_dup_attr_matched_dup(void **state) + assert_string_equal(filtered_msg->elements[0].name, "bar"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, +- sizeof(value1)); ++ strlen(value1)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, +- value1, sizeof(value1)); ++ value1, strlen(value1)); + assert_string_equal(filtered_msg->elements[1].name, "bar"); + assert_int_equal(filtered_msg->elements[1].num_values, 1); + assert_int_equal(filtered_msg->elements[1].values[0].length, +- sizeof(value2)); ++ strlen(value2)); + assert_memory_equal(filtered_msg->elements[1].values[0].data, +- value2, sizeof(value2)); ++ value2, strlen(value2)); + } + + /* +@@ -469,15 +470,15 @@ static void test_filter_attrs_two_dup_attr_matched_one_of_two(void **state) + + const char *attrs[] = {"bar", "foo", NULL}; + +- uint8_t value1[] = "The value.......end"; +- uint8_t value2[] = "The value..MUST.end"; ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { +- .data = value1, +- .length = (sizeof(value1)) ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) + }; + struct ldb_val value_2 = { +- .data = value2, +- .length = (sizeof(value2)) ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) + }; + + /* foo and bar are the other order to in attrs */ +@@ -514,15 +515,15 @@ static void test_filter_attrs_two_dup_attr_matched_one_of_two(void **state) + assert_string_equal(filtered_msg->elements[0].name, "bar"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, +- sizeof(value1)); ++ strlen(value1)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, +- value1, sizeof(value1)); ++ value1, strlen(value1)); + assert_string_equal(filtered_msg->elements[1].name, "bar"); + assert_int_equal(filtered_msg->elements[1].num_values, 1); + assert_int_equal(filtered_msg->elements[1].values[0].length, +- sizeof(value2)); ++ strlen(value2)); + assert_memory_equal(filtered_msg->elements[1].values[0].data, +- value2, sizeof(value2)); ++ value2, strlen(value2)); + } + + /* +@@ -538,15 +539,15 @@ static void test_filter_attrs_two_dup_attr_matched_star(void **state) + + const char *attrs[] = {"*", "foo", NULL}; + +- uint8_t value1[] = "The value.......end"; +- uint8_t value2[] = "The value..MUST.end"; ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { +- .data = value1, +- .length = (sizeof(value1)) ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) + }; + struct ldb_val value_2 = { +- .data = value2, +- .length = (sizeof(value2)) ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) + }; + + /* foo and bar are the other order to in attrs */ +@@ -586,15 +587,15 @@ static void test_filter_attrs_two_dup_attr_matched_star(void **state) + assert_string_equal(filtered_msg->elements[0].name, "bar"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, +- sizeof(value1)); ++ strlen(value1)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, +- value1, sizeof(value1)); ++ value1, strlen(value1)); + assert_string_equal(filtered_msg->elements[1].name, "bar"); + assert_int_equal(filtered_msg->elements[1].num_values, 1); + assert_int_equal(filtered_msg->elements[1].values[0].length, +- sizeof(value2)); ++ strlen(value2)); + assert_memory_equal(filtered_msg->elements[1].values[0].data, +- value2, sizeof(value2)); ++ value2, strlen(value2)); + /* + * assert the ldb_filter_attrs does not modify filtered_msg.dn + * in this case +@@ -619,10 +620,10 @@ static void test_filter_attrs_one_attr_matched_star(void **state) + + const char *attrs[] = {"*", NULL}; + +- uint8_t value[] = "The value.......end"; ++ char value[] = "The value.......end"; + struct ldb_val value_1 = { +- .data = value, +- .length = (sizeof(value)) ++ .data = (uint8_t *)value, ++ .length = strlen(value) + }; + struct ldb_message_element element_1 = { + .name = "foo", +@@ -676,15 +677,15 @@ static void test_filter_attrs_two_attr_matched_star(void **state) + + const char *attrs[] = {"*", NULL}; + +- uint8_t value1[] = "The value.......end"; +- uint8_t value2[] = "The value..MUST.end"; ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { +- .data = value1, +- .length = (sizeof(value1)) ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) + }; + struct ldb_val value_2 = { +- .data = value2, +- .length = (sizeof(value2)) ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) + }; + struct ldb_message_element elements[] = { + { +@@ -750,10 +751,10 @@ static void test_filter_attrs_one_attr_matched_star_no_dn(void **state) + + const char *attrs[] = {"*", NULL}; + +- uint8_t value[] = "The value.......end"; ++ char value[] = "The value.......end"; + struct ldb_val value_1 = { +- .data = value, +- .length = (sizeof(value)) ++ .data = (uint8_t *)value, ++ .length = strlen(value) + }; + struct ldb_message_element element_1 = { + .name = "foo", +@@ -789,10 +790,10 @@ static void test_filter_attrs_one_attr_matched_star_dn(void **state) + + const char *attrs[] = {"*", "distinguishedName", NULL}; + +- uint8_t value[] = "The value.......end"; ++ char value[] = "The value.......end"; + struct ldb_val value_1 = { +- .data = value, +- .length = (sizeof(value)) ++ .data = (uint8_t *)value, ++ .length = strlen(value) + }; + struct ldb_message_element element_1 = { + .name = "foo", +@@ -844,10 +845,10 @@ static void test_filter_attrs_one_attr_matched_dn(void **state) + + const char *attrs[] = {"distinguishedName", NULL}; + +- uint8_t value[] = "The value.......end"; ++ char value[] = "The value.......end"; + struct ldb_val value_1 = { +- .data = value, +- .length = (sizeof(value)) ++ .data = (uint8_t *)value, ++ .length = strlen(value) + }; + struct ldb_message_element element_1 = { + .name = "foo", +@@ -894,10 +895,10 @@ static void test_filter_attrs_one_attr_empty_list(void **state) + + const char *attrs[] = {NULL}; + +- uint8_t value[] = "The value.......end"; ++ char value[] = "The value.......end"; + struct ldb_val value_1 = { +- .data = value, +- .length = (sizeof(value)) ++ .data = (uint8_t *)value, ++ .length = strlen(value) + }; + struct ldb_message_element element_1 = { + .name = "foo", +-- +2.25.1 \ No newline at end of file diff --git a/backport-0009-CVE-2023-34968.patch b/backport-0009-CVE-2023-34968.patch new file mode 100644 index 0000000000000000000000000000000000000000..4009d3a884db142e150bcee7c7898d587c399e9d --- /dev/null +++ b/backport-0009-CVE-2023-34968.patch @@ -0,0 +1,461 @@ +From cb8313e7bee75454ce29d2b2f657927259298f52 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Mon, 19 Jun 2023 18:16:57 +0200 +Subject: [PATCH 15/28] CVE-2023-34968: mdssvc: introduce an allocating wrapper + to sl_pack() + +sl_pack_alloc() does the buffer allocation that previously all callers of +sl_pack() did themselves. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/rpc_client/cli_mdssvc_util.c | 80 +++++------------------ + source3/rpc_server/mdssvc/marshalling.c | 35 ++++++++-- + source3/rpc_server/mdssvc/marshalling.h | 9 ++- + source3/rpc_server/mdssvc/mdssvc.c | 18 ++--- + source3/rpc_server/mdssvc/mdssvc.h | 5 +- + source3/rpc_server/mdssvc/srv_mdssvc_nt.c | 5 +- + source3/rpcclient/cmd_spotlight.c | 32 ++------- + source4/torture/rpc/mdssvc.c | 24 ++----- + 8 files changed, 80 insertions(+), 128 deletions(-) + +diff --git a/source3/rpc_client/cli_mdssvc_util.c b/source3/rpc_client/cli_mdssvc_util.c +index 892a844e71a..a39202d0c99 100644 +--- a/source3/rpc_client/cli_mdssvc_util.c ++++ b/source3/rpc_client/cli_mdssvc_util.c +@@ -42,7 +42,7 @@ NTSTATUS mdscli_blob_search(TALLOC_CTX *mem_ctx, + sl_array_t *scope_array = NULL; + double dval; + uint64_t uint64val; +- ssize_t len; ++ NTSTATUS status; + int ret; + + d = dalloc_new(mem_ctx); +@@ -209,23 +209,11 @@ NTSTATUS mdscli_blob_search(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(mem_ctx, +- uint8_t, +- ctx->max_fragment_size); +- if (blob->spotlight_blob == NULL) { +- TALLOC_FREE(d); +- return NT_STATUS_NO_MEMORY; +- } +- blob->size = ctx->max_fragment_size; +- +- len = sl_pack(d, (char *)blob->spotlight_blob, blob->size); ++ status = sl_pack_alloc(mem_ctx, d, blob, ctx->max_fragment_size); + TALLOC_FREE(d); +- if (len == -1) { +- return NT_STATUS_NO_MEMORY; ++ if (!NT_STATUS_IS_OK(status)) { ++ return status; + } +- +- blob->length = len; +- blob->size = len; + return NT_STATUS_OK; + } + +@@ -238,7 +226,7 @@ NTSTATUS mdscli_blob_get_results(TALLOC_CTX *mem_ctx, + uint64_t *uint64p = NULL; + sl_array_t *array = NULL; + sl_array_t *cmd_array = NULL; +- ssize_t len; ++ NTSTATUS status; + int ret; + + d = dalloc_new(mem_ctx); +@@ -293,23 +281,11 @@ NTSTATUS mdscli_blob_get_results(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(mem_ctx, +- uint8_t, +- ctx->max_fragment_size); +- if (blob->spotlight_blob == NULL) { +- TALLOC_FREE(d); +- return NT_STATUS_NO_MEMORY; +- } +- blob->size = ctx->max_fragment_size; +- +- len = sl_pack(d, (char *)blob->spotlight_blob, blob->size); ++ status = sl_pack_alloc(mem_ctx, d, blob, ctx->max_fragment_size); + TALLOC_FREE(d); +- if (len == -1) { +- return NT_STATUS_NO_MEMORY; ++ if (!NT_STATUS_IS_OK(status)) { ++ return status; + } +- +- blob->length = len; +- blob->size = len; + return NT_STATUS_OK; + } + +@@ -325,7 +301,7 @@ NTSTATUS mdscli_blob_get_path(TALLOC_CTX *mem_ctx, + sl_array_t *cmd_array = NULL; + sl_array_t *attr_array = NULL; + sl_cnids_t *cnids = NULL; +- ssize_t len; ++ NTSTATUS status; + int ret; + + d = dalloc_new(mem_ctx); +@@ -426,23 +402,11 @@ NTSTATUS mdscli_blob_get_path(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(mem_ctx, +- uint8_t, +- ctx->max_fragment_size); +- if (blob->spotlight_blob == NULL) { +- TALLOC_FREE(d); +- return NT_STATUS_NO_MEMORY; +- } +- blob->size = ctx->max_fragment_size; +- +- len = sl_pack(d, (char *)blob->spotlight_blob, blob->size); ++ status = sl_pack_alloc(mem_ctx, d, blob, ctx->max_fragment_size); + TALLOC_FREE(d); +- if (len == -1) { +- return NT_STATUS_NO_MEMORY; ++ if (!NT_STATUS_IS_OK(status)) { ++ return status; + } +- +- blob->length = len; +- blob->size = len; + return NT_STATUS_OK; + } + +@@ -455,7 +419,7 @@ NTSTATUS mdscli_blob_close_search(TALLOC_CTX *mem_ctx, + uint64_t *uint64p = NULL; + sl_array_t *array = NULL; + sl_array_t *cmd_array = NULL; +- ssize_t len; ++ NTSTATUS status; + int ret; + + d = dalloc_new(mem_ctx); +@@ -510,22 +474,10 @@ NTSTATUS mdscli_blob_close_search(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(mem_ctx, +- uint8_t, +- ctx->max_fragment_size); +- if (blob->spotlight_blob == NULL) { +- TALLOC_FREE(d); +- return NT_STATUS_NO_MEMORY; +- } +- blob->size = ctx->max_fragment_size; +- +- len = sl_pack(d, (char *)blob->spotlight_blob, blob->size); ++ status = sl_pack_alloc(mem_ctx, d, blob, ctx->max_fragment_size); + TALLOC_FREE(d); +- if (len == -1) { +- return NT_STATUS_NO_MEMORY; ++ if (!NT_STATUS_IS_OK(status)) { ++ return status; + } +- +- blob->length = len; +- blob->size = len; + return NT_STATUS_OK; + } +diff --git a/source3/rpc_server/mdssvc/marshalling.c b/source3/rpc_server/mdssvc/marshalling.c +index d794ba15838..5f866d7fb6e 100644 +--- a/source3/rpc_server/mdssvc/marshalling.c ++++ b/source3/rpc_server/mdssvc/marshalling.c +@@ -78,6 +78,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX *query, const char *buf, + ssize_t offset, size_t bufsize, + int count, ssize_t toc_offset, + int encoding); ++static ssize_t sl_pack(DALLOC_CTX *query, char *buf, size_t bufsize); + + /****************************************************************************** + * Wrapper functions for the *VAL macros with bound checking +@@ -1190,11 +1191,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX *query, + return offset; + } + +-/****************************************************************************** +- * Global functions for packing und unpacking +- ******************************************************************************/ +- +-ssize_t sl_pack(DALLOC_CTX *query, char *buf, size_t bufsize) ++static ssize_t sl_pack(DALLOC_CTX *query, char *buf, size_t bufsize) + { + ssize_t result; + char *toc_buf; +@@ -1274,6 +1271,34 @@ ssize_t sl_pack(DALLOC_CTX *query, char *buf, size_t bufsize) + return len; + } + ++/****************************************************************************** ++ * Global functions for packing und unpacking ++ ******************************************************************************/ ++ ++NTSTATUS sl_pack_alloc(TALLOC_CTX *mem_ctx, ++ DALLOC_CTX *d, ++ struct mdssvc_blob *b, ++ size_t max_fragment_size) ++{ ++ ssize_t len; ++ ++ b->spotlight_blob = talloc_zero_array(mem_ctx, ++ uint8_t, ++ max_fragment_size); ++ if (b->spotlight_blob == NULL) { ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ len = sl_pack(d, (char *)b->spotlight_blob, max_fragment_size); ++ if (len == -1) { ++ return NT_STATUS_DATA_ERROR; ++ } ++ ++ b->length = len; ++ b->size = len; ++ return NT_STATUS_OK; ++} ++ + bool sl_unpack(DALLOC_CTX *query, const char *buf, size_t bufsize) + { + ssize_t result; +diff --git a/source3/rpc_server/mdssvc/marshalling.h b/source3/rpc_server/mdssvc/marshalling.h +index 086ca740604..2cc1b44712c 100644 +--- a/source3/rpc_server/mdssvc/marshalling.h ++++ b/source3/rpc_server/mdssvc/marshalling.h +@@ -22,6 +22,9 @@ + #define _MDSSVC_MARSHALLING_H + + #include "dalloc.h" ++#include "libcli/util/ntstatus.h" ++#include "lib/util/data_blob.h" ++#include "librpc/gen_ndr/mdssvc.h" + + #define MAX_SL_FRAGMENT_SIZE 0xFFFFF + +@@ -49,7 +52,11 @@ typedef struct { + * Function declarations + ******************************************************************************/ + +-extern ssize_t sl_pack(DALLOC_CTX *query, char *buf, size_t bufsize); ++extern NTSTATUS sl_pack_alloc(TALLOC_CTX *mem_ctx, ++ DALLOC_CTX *d, ++ struct mdssvc_blob *b, ++ size_t max_fragment_size); ++ + extern bool sl_unpack(DALLOC_CTX *query, const char *buf, size_t bufsize); + + #endif +diff --git a/source3/rpc_server/mdssvc/mdssvc.c b/source3/rpc_server/mdssvc/mdssvc.c +index 070503f9eeb..9b814f51fc3 100644 +--- a/source3/rpc_server/mdssvc/mdssvc.c ++++ b/source3/rpc_server/mdssvc/mdssvc.c +@@ -1732,11 +1732,11 @@ error: + **/ + bool mds_dispatch(struct mds_ctx *mds_ctx, + struct mdssvc_blob *request_blob, +- struct mdssvc_blob *response_blob) ++ struct mdssvc_blob *response_blob, ++ size_t max_fragment_size) + { + bool ok; + int ret; +- ssize_t len; + DALLOC_CTX *query = NULL; + DALLOC_CTX *reply = NULL; + char *rpccmd; +@@ -1744,6 +1744,7 @@ bool mds_dispatch(struct mds_ctx *mds_ctx, + const struct smb_filename conn_basedir = { + .base_name = mds_ctx->conn->connectpath, + }; ++ NTSTATUS status; + + if (CHECK_DEBUGLVL(10)) { + const struct sl_query *slq; +@@ -1810,15 +1811,14 @@ bool mds_dispatch(struct mds_ctx *mds_ctx, + + DBG_DEBUG("%s", dalloc_dump(reply, 0)); + +- len = sl_pack(reply, +- (char *)response_blob->spotlight_blob, +- response_blob->size); +- if (len == -1) { +- DBG_ERR("error packing Spotlight RPC reply\n"); +- ok = false; ++ status = sl_pack_alloc(response_blob, ++ reply, ++ response_blob, ++ max_fragment_size); ++ if (!NT_STATUS_IS_OK(status)) { ++ DBG_ERR("sl_pack_alloc() failed\n"); + goto cleanup; + } +- response_blob->length = len; + + cleanup: + talloc_free(query); +diff --git a/source3/rpc_server/mdssvc/mdssvc.h b/source3/rpc_server/mdssvc/mdssvc.h +index ff36b329f2b..e1fc0709ab1 100644 +--- a/source3/rpc_server/mdssvc/mdssvc.h ++++ b/source3/rpc_server/mdssvc/mdssvc.h +@@ -158,9 +158,10 @@ NTSTATUS mds_init_ctx(TALLOC_CTX *mem_ctx, + const char *sharename, + const char *path, + struct mds_ctx **_mds_ctx); +-extern bool mds_dispatch(struct mds_ctx *query_ctx, ++extern bool mds_dispatch(struct mds_ctx *mds_ctx, + struct mdssvc_blob *request_blob, +- struct mdssvc_blob *response_blob); ++ struct mdssvc_blob *response_blob, ++ size_t max_fragment_size); + bool mds_add_result(struct sl_query *slq, const char *path); + + #endif /* _MDSSVC_H */ +diff --git a/source3/rpc_server/mdssvc/srv_mdssvc_nt.c b/source3/rpc_server/mdssvc/srv_mdssvc_nt.c +index 2fec2bb6725..ae6a73605e1 100644 +--- a/source3/rpc_server/mdssvc/srv_mdssvc_nt.c ++++ b/source3/rpc_server/mdssvc/srv_mdssvc_nt.c +@@ -223,7 +223,10 @@ void _mdssvc_cmd(struct pipes_struct *p, struct mdssvc_cmd *r) + /* We currently don't use fragmentation at the mdssvc RPC layer */ + *r->out.fragment = 0; + +- ok = mds_dispatch(mds_ctx, &r->in.request_blob, r->out.response_blob); ++ ok = mds_dispatch(mds_ctx, ++ &r->in.request_blob, ++ r->out.response_blob, ++ r->in.max_fragment_size1); + if (ok) { + *r->out.unkn9 = 0; + } else { +diff --git a/source3/rpcclient/cmd_spotlight.c b/source3/rpcclient/cmd_spotlight.c +index 64fe321089c..ba3f61fd4b0 100644 +--- a/source3/rpcclient/cmd_spotlight.c ++++ b/source3/rpcclient/cmd_spotlight.c +@@ -43,7 +43,6 @@ static NTSTATUS cmd_mdssvc_fetch_properties( + uint32_t unkn3; /* server always returns 0 ? */ + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; +- ssize_t len; + uint32_t max_fragment_size = 64 * 1024; + DALLOC_CTX *d, *mds_reply; + uint64_t *uint64var; +@@ -137,20 +136,10 @@ static NTSTATUS cmd_mdssvc_fetch_properties( + goto done; + } + +- request_blob.spotlight_blob = talloc_array(mem_ctx, uint8_t, max_fragment_size); +- if (request_blob.spotlight_blob == NULL) { +- status = NT_STATUS_INTERNAL_ERROR; +- goto done; +- } +- request_blob.size = max_fragment_size; +- +- len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size); +- if (len == -1) { +- status = NT_STATUS_INTERNAL_ERROR; ++ status = sl_pack_alloc(mem_ctx, d, &request_blob, max_fragment_size); ++ if (!NT_STATUS_IS_OK(status)) { + goto done; + } +- request_blob.length = len; +- request_blob.size = len; + + status = dcerpc_mdssvc_cmd(b, mem_ctx, + &share_handle, +@@ -204,7 +193,6 @@ static NTSTATUS cmd_mdssvc_fetch_attributes( + uint32_t unkn3; /* server always returns 0 ? */ + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; +- ssize_t len; + uint32_t max_fragment_size = 64 * 1024; + DALLOC_CTX *d, *mds_reply; + uint64_t *uint64var; +@@ -352,22 +340,10 @@ static NTSTATUS cmd_mdssvc_fetch_attributes( + goto done; + } + +- request_blob.spotlight_blob = talloc_array(mem_ctx, +- uint8_t, +- max_fragment_size); +- if (request_blob.spotlight_blob == NULL) { +- status = NT_STATUS_INTERNAL_ERROR; +- goto done; +- } +- request_blob.size = max_fragment_size; +- +- len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size); +- if (len == -1) { +- status = NT_STATUS_INTERNAL_ERROR; ++ status = sl_pack_alloc(mem_ctx, d, &request_blob, max_fragment_size); ++ if (!NT_STATUS_IS_OK(status)) { + goto done; + } +- request_blob.length = len; +- request_blob.size = len; + + status = dcerpc_mdssvc_cmd(b, mem_ctx, + &share_handle, +diff --git a/source4/torture/rpc/mdssvc.c b/source4/torture/rpc/mdssvc.c +index a16bd5b47e3..afe7068ee1b 100644 +--- a/source4/torture/rpc/mdssvc.c ++++ b/source4/torture/rpc/mdssvc.c +@@ -744,11 +744,9 @@ static bool test_sl_dict_type_safety(struct torture_context *tctx, + ok, done, "dalloc_new failed\n"); + request_blob.size = 64 * 1024; + +- request_blob.length = sl_pack(d, +- (char *)request_blob.spotlight_blob, +- request_blob.size); +- torture_assert_goto(tctx, request_blob.length > 0, +- ok, done, "sl_pack failed\n"); ++ status = sl_pack_alloc(tctx, d, &request_blob, 64 * 1024); ++ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, ++ "sl_pack_alloc() failed\n"); + + status = dcerpc_mdssvc_cmd(b, + state, +@@ -835,7 +833,6 @@ static bool test_mdssvc_fetch_attr_unknown_cnid(struct torture_context *tctx, + const char *path_type = NULL; + uint64_t ino64; + NTSTATUS status; +- ssize_t len; + int ret; + bool ok = true; + +@@ -900,18 +897,9 @@ static bool test_mdssvc_fetch_attr_unknown_cnid(struct torture_context *tctx, + ret = dalloc_add(array, cnids, sl_cnids_t); + torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n"); + +- request_blob.spotlight_blob = talloc_array(state, +- uint8_t, +- max_fragment_size); +- torture_assert_not_null_goto(tctx, request_blob.spotlight_blob, +- ret, done, "dalloc_zero failed\n"); +- request_blob.size = max_fragment_size; +- +- len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size); +- torture_assert_goto(tctx, len != -1, ret, done, "sl_pack failed\n"); +- +- request_blob.length = len; +- request_blob.size = len; ++ status = sl_pack_alloc(tctx, d, &request_blob, max_fragment_size); ++ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, ++ "sl_pack_alloc() failed\n"); + + status = dcerpc_mdssvc_cmd(b, + state, +-- +2.34.1 diff --git a/backport-0009-CVE-2023-4154.patch b/backport-0009-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..ffe1fa3315a7e759517802b67a69cadc8cd191a4 --- /dev/null +++ b/backport-0009-CVE-2023-4154.patch @@ -0,0 +1,61 @@ +From ebd421306e7b1ec37e7a477937d04a27de838cff Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 16 Mar 2023 10:11:05 +0100 +Subject: [PATCH 14/30] CVE-2023-4154 py_security: allow idx argument to + descriptor.[s|d]acl_add() + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +(cherry picked from commit 9ea06aaf9f57e3c7094553d9ac40fb73057a9b74) + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 14/30] CVE-2023-4154 py_security: allow idx argument to + descriptor.[s|d]acl_add() +--- + source4/librpc/ndr/py_security.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/source4/librpc/ndr/py_security.c b/source4/librpc/ndr/py_security.c +index e61b994d7cb..4a8271a11db 100644 +--- a/source4/librpc/ndr/py_security.c ++++ b/source4/librpc/ndr/py_security.c +@@ -175,12 +175,13 @@ static PyObject *py_descriptor_sacl_add(PyObject *self, PyObject *args) + NTSTATUS status; + struct security_ace *ace; + PyObject *py_ace; ++ Py_ssize_t idx = -1; + +- if (!PyArg_ParseTuple(args, "O", &py_ace)) ++ if (!PyArg_ParseTuple(args, "O|n", &py_ace, &idx)) + return NULL; + + ace = pytalloc_get_ptr(py_ace); +- status = security_descriptor_sacl_add(desc, ace); ++ status = security_descriptor_sacl_insert(desc, ace, idx); + PyErr_NTSTATUS_IS_ERR_RAISE(status); + Py_RETURN_NONE; + } +@@ -191,13 +192,14 @@ static PyObject *py_descriptor_dacl_add(PyObject *self, PyObject *args) + NTSTATUS status; + struct security_ace *ace; + PyObject *py_ace; ++ Py_ssize_t idx = -1; + +- if (!PyArg_ParseTuple(args, "O", &py_ace)) ++ if (!PyArg_ParseTuple(args, "O|n", &py_ace, &idx)) + return NULL; + + ace = pytalloc_get_ptr(py_ace); + +- status = security_descriptor_dacl_add(desc, ace); ++ status = security_descriptor_dacl_insert(desc, ace, idx); + PyErr_NTSTATUS_IS_ERR_RAISE(status); + Py_RETURN_NONE; + } +-- +2.34.1 diff --git a/backport-0010-CVE-2023-0614.patch b/backport-0010-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..4e79b61682f3de291aa1aa5daff7f700156ca1fd --- /dev/null +++ b/backport-0010-CVE-2023-0614.patch @@ -0,0 +1,48 @@ +From 936bfcb6ef804d2224072f3770ca09fe2596ee1f Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Wed, 15 Feb 2023 14:08:57 +1300 +Subject: [PATCH 08/34] CVE-2023-0614 ldb:tests: Ensure all tests are accounted + for + +Add ldb_filter_attrs_test to the list of tests so that it actually gets +run. + +Remove a duplicate ldb_msg_test that was accidentally added in commit +5ca90e758ade97fb5e335029c7a1768094e70564. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb/wscript | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/lib/ldb/wscript b/lib/ldb/wscript +index 60bb7cf48b3..c862229822d 100644 +--- a/lib/ldb/wscript ++++ b/lib/ldb/wscript +@@ -627,7 +627,6 @@ def test(ctx): + 'ldb_msg_test', + 'ldb_tdb_mod_op_test', + 'ldb_tdb_guid_mod_op_test', +- 'ldb_msg_test', + 'ldb_tdb_kv_ops_test', + 'ldb_tdb_test', + 'ldb_match_test', +@@ -637,7 +636,9 @@ def test(ctx): + # on operations which the TDB backend does not currently + # support + # 'ldb_key_value_sub_txn_tdb_test' +- 'ldb_parse_test'] ++ 'ldb_parse_test', ++ 'ldb_filter_attrs_test', ++ ] + + # if LIB_LDAP and LIB_LBER defined, then we can test ldb_ldap backend + # behavior regression for bz#14413 +-- +2.25.1 \ No newline at end of file diff --git a/backport-0010-CVE-2023-34968.patch b/backport-0010-CVE-2023-34968.patch new file mode 100644 index 0000000000000000000000000000000000000000..80624722bd05115c9580b365b87a028d8b61150c --- /dev/null +++ b/backport-0010-CVE-2023-34968.patch @@ -0,0 +1,506 @@ +From a5c570e262911874e43e82de601d809aa5b1b729 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Sat, 17 Jun 2023 13:53:27 +0200 +Subject: [PATCH 16/28] CVE-2023-34968: mdscli: return share relative paths +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The next commit will change the Samba Spotlight server to return absolute paths +that start with the sharename as "/SHARENAME/..." followed by the share path +relative appended. + +So given a share + + [spotlight] + path = /foo/bar + spotlight = yes + +and a file inside this share with a full path of + + /foo/bar/dir/file + +previously a search that matched this file would returns the absolute +server-side pato of the file, ie + + /foo/bar/dir/file + +This will be change to + + /spotlight/dir/file + +As currently the mdscli library and hence the mdsearch tool print out these +paths returned from the server, we have to change the output to accomodate these +fake paths. The only way to do this sensibly is by makeing the paths relative to +the containing share, so just + + dir/file + +in the example above. + +The client learns about the share root path prefix 鈥� real server-side of fake in +the future 鈥� in an initial handshake in the "share_path" out argument of the +mdssvc_open() RPC call, so the client can use this path to convert the absolute +path to relative. + +There is however an additional twist: the macOS Spotlight server prefixes this +absolute path with another prefix, typically "/System/Volumes/Data", so in the +example above the full path for the same search would be + + /System/Volumes/Data/foo/bar/dir/file + +So macOS does return the full server-side path too, just prefixed with an +additional path. This path prefixed can be queried by the client in the +mdssvc_cmd() RPC call with an Spotlight command of "fetchPropertiesForContext:" +and the path is returned in a dictionary with key "kMDSStorePathScopes". Samba +just returns "/" for this. + +Currently the mdscli library doesn't issue this Spotlight RPC +request (fetchPropertiesForContext), so this is added in this commit. In the +end, all search result paths are stripped of the combined prefix + + kMDSStorePathScopes + share_path (from mdssvc_open). + +eg + + kMDSStorePathScopes = /System/Volumes/Data + share_path = /foo/bar + search result = /System/Volumes/Data/foo/bar/dir/file + relative path returned by mdscli = dir/file + +Makes sense? :) + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + python/samba/tests/blackbox/mdsearch.py | 8 +- + python/samba/tests/dcerpc/mdssvc.py | 26 ++-- + source3/rpc_client/cli_mdssvc.c | 155 +++++++++++++++++++++++- + source3/rpc_client/cli_mdssvc_private.h | 4 + + source3/rpc_client/cli_mdssvc_util.c | 68 +++++++++++ + source3/rpc_client/cli_mdssvc_util.h | 4 + + 6 files changed, 245 insertions(+), 20 deletions(-) + +diff --git a/python/samba/tests/blackbox/mdsearch.py b/python/samba/tests/blackbox/mdsearch.py +index c9156ae6e0e..c8e75661f15 100644 +--- a/python/samba/tests/blackbox/mdsearch.py ++++ b/python/samba/tests/blackbox/mdsearch.py +@@ -76,10 +76,7 @@ class MdfindBlackboxTests(BlackboxTestCase): + self.t.start() + time.sleep(1) + +- pipe = mdssvc.mdssvc('ncacn_np:fileserver[/pipe/mdssvc]', self.get_loadparm()) +- conn = mdscli.conn(pipe, 'spotlight', '/foo') +- self.sharepath = conn.sharepath() +- conn.disconnect(pipe) ++ self.sharepath = os.environ["LOCAL_PATH"] + + for file in testfiles: + f = open("%s/%s" % (self.sharepath, file), "w") +@@ -126,5 +123,4 @@ class MdfindBlackboxTests(BlackboxTestCase): + output = self.check_output("mdsearch --configfile=%s -U %s%%%s fileserver spotlight '*==\"samba*\"'" % (config, username, password)) + + actual = output.decode('utf-8').splitlines() +- expected = ["%s/%s" % (self.sharepath, file) for file in testfiles] +- self.assertEqual(expected, actual) ++ self.assertEqual(testfiles, actual) +diff --git a/python/samba/tests/dcerpc/mdssvc.py b/python/samba/tests/dcerpc/mdssvc.py +index b0df509ddc7..5002e5d26d6 100644 +--- a/python/samba/tests/dcerpc/mdssvc.py ++++ b/python/samba/tests/dcerpc/mdssvc.py +@@ -84,10 +84,11 @@ class MdssvcTests(RpcInterfaceTestCase): + self.t = threading.Thread(target=MdssvcTests.http_server, args=(self,)) + self.t.setDaemon(True) + self.t.start() ++ self.sharepath = os.environ["LOCAL_PATH"] + time.sleep(1) + + conn = mdscli.conn(self.pipe, 'spotlight', '/foo') +- self.sharepath = conn.sharepath() ++ self.fakepath = conn.sharepath() + conn.disconnect(self.pipe) + + for file in testfiles: +@@ -105,12 +106,11 @@ class MdssvcTests(RpcInterfaceTestCase): + self.server.serve_forever() + + def run_test(self, query, expect, json_in, json_out): +- expect = [s.replace("%BASEPATH%", self.sharepath) for s in expect] + self.server.json_in = json_in.replace("%BASEPATH%", self.sharepath) + self.server.json_out = json_out.replace("%BASEPATH%", self.sharepath) + + self.conn = mdscli.conn(self.pipe, 'spotlight', '/foo') +- search = self.conn.search(self.pipe, query, self.sharepath) ++ search = self.conn.search(self.pipe, query, self.fakepath) + + # Give it some time, the get_results() below returns immediately + # what's available, so if we ask to soon, we might get back no results +@@ -141,7 +141,7 @@ class MdssvcTests(RpcInterfaceTestCase): + ] + } + }''' +- exp_results = ["%BASEPATH%/foo", "%BASEPATH%/bar"] ++ exp_results = ["foo", "bar"] + self.run_test('*=="samba*"', exp_results, exp_json_query, fake_json_response) + + def test_mdscli_search_escapes(self): +@@ -181,14 +181,14 @@ class MdssvcTests(RpcInterfaceTestCase): + } + }''' + exp_results = [ +- r"%BASEPATH%/x+x", +- r"%BASEPATH%/x*x", +- r"%BASEPATH%/x=x", +- r"%BASEPATH%/x'x", +- r"%BASEPATH%/x?x", +- r"%BASEPATH%/x x", +- r"%BASEPATH%/x(x", +- "%BASEPATH%/x\"x", +- r"%BASEPATH%/x\x", ++ r"x+x", ++ r"x*x", ++ r"x=x", ++ r"x'x", ++ r"x?x", ++ r"x x", ++ r"x(x", ++ "x\"x", ++ r"x\x", + ] + self.run_test(sl_query, exp_results, exp_json_query, fake_json_response) +diff --git a/source3/rpc_client/cli_mdssvc.c b/source3/rpc_client/cli_mdssvc.c +index 474d7c0b150..753bc2e52ed 100644 +--- a/source3/rpc_client/cli_mdssvc.c ++++ b/source3/rpc_client/cli_mdssvc.c +@@ -43,10 +43,12 @@ char *mdscli_get_basepath(TALLOC_CTX *mem_ctx, + struct mdscli_connect_state { + struct tevent_context *ev; + struct mdscli_ctx *mdscli_ctx; ++ struct mdssvc_blob response_blob; + }; + + static void mdscli_connect_open_done(struct tevent_req *subreq); + static void mdscli_connect_unknown1_done(struct tevent_req *subreq); ++static void mdscli_connect_fetch_props_done(struct tevent_req *subreq); + + struct tevent_req *mdscli_connect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +@@ -111,6 +113,7 @@ static void mdscli_connect_open_done(struct tevent_req *subreq) + struct mdscli_connect_state *state = tevent_req_data( + req, struct mdscli_connect_state); + struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx; ++ size_t share_path_len; + NTSTATUS status; + + status = dcerpc_mdssvc_open_recv(subreq, state); +@@ -120,6 +123,18 @@ static void mdscli_connect_open_done(struct tevent_req *subreq) + return; + } + ++ share_path_len = strlen(mdscli_ctx->mdscmd_open.share_path); ++ if (share_path_len < 1 || share_path_len > UINT16_MAX) { ++ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); ++ return; ++ } ++ mdscli_ctx->mdscmd_open.share_path_len = share_path_len; ++ ++ if (mdscli_ctx->mdscmd_open.share_path[share_path_len-1] == '/') { ++ mdscli_ctx->mdscmd_open.share_path[share_path_len-1] = '\0'; ++ mdscli_ctx->mdscmd_open.share_path_len--; ++ } ++ + subreq = dcerpc_mdssvc_unknown1_send( + state, + state->ev, +@@ -146,6 +161,8 @@ static void mdscli_connect_unknown1_done(struct tevent_req *subreq) + subreq, struct tevent_req); + struct mdscli_connect_state *state = tevent_req_data( + req, struct mdscli_connect_state); ++ struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx; ++ struct mdssvc_blob request_blob; + NTSTATUS status; + + status = dcerpc_mdssvc_unknown1_recv(subreq, state); +@@ -154,6 +171,108 @@ static void mdscli_connect_unknown1_done(struct tevent_req *subreq) + return; + } + ++ status = mdscli_blob_fetch_props(state, ++ state->mdscli_ctx, ++ &request_blob); ++ if (tevent_req_nterror(req, status)) { ++ return; ++ } ++ ++ subreq = dcerpc_mdssvc_cmd_send(state, ++ state->ev, ++ mdscli_ctx->bh, ++ &mdscli_ctx->ph, ++ 0, ++ mdscli_ctx->dev, ++ mdscli_ctx->mdscmd_open.unkn2, ++ 0, ++ mdscli_ctx->flags, ++ request_blob, ++ 0, ++ mdscli_ctx->max_fragment_size, ++ 1, ++ mdscli_ctx->max_fragment_size, ++ 0, ++ 0, ++ &mdscli_ctx->mdscmd_cmd.fragment, ++ &state->response_blob, ++ &mdscli_ctx->mdscmd_cmd.unkn9); ++ if (tevent_req_nomem(subreq, req)) { ++ return; ++ } ++ tevent_req_set_callback(subreq, mdscli_connect_fetch_props_done, req); ++ mdscli_ctx->async_pending++; ++ return; ++} ++ ++static void mdscli_connect_fetch_props_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data( ++ subreq, struct tevent_req); ++ struct mdscli_connect_state *state = tevent_req_data( ++ req, struct mdscli_connect_state); ++ struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx; ++ DALLOC_CTX *d = NULL; ++ sl_array_t *path_scope_array = NULL; ++ char *path_scope = NULL; ++ NTSTATUS status; ++ bool ok; ++ ++ status = dcerpc_mdssvc_cmd_recv(subreq, state); ++ TALLOC_FREE(subreq); ++ state->mdscli_ctx->async_pending--; ++ if (tevent_req_nterror(req, status)) { ++ return; ++ } ++ ++ d = dalloc_new(state); ++ if (tevent_req_nomem(d, req)) { ++ return; ++ } ++ ++ ok = sl_unpack(d, ++ (char *)state->response_blob.spotlight_blob, ++ state->response_blob.length); ++ if (!ok) { ++ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); ++ return; ++ } ++ ++ path_scope_array = dalloc_value_for_key(d, ++ "DALLOC_CTX", 0, ++ "kMDSStorePathScopes", ++ "sl_array_t"); ++ if (path_scope_array == NULL) { ++ DBG_ERR("Missing kMDSStorePathScopes\n"); ++ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); ++ return; ++ } ++ ++ path_scope = dalloc_get(path_scope_array, "char *", 0); ++ if (path_scope == NULL) { ++ DBG_ERR("Missing path in kMDSStorePathScopes\n"); ++ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); ++ return; ++ } ++ ++ mdscli_ctx->path_scope_len = strlen(path_scope); ++ if (mdscli_ctx->path_scope_len < 1 || ++ mdscli_ctx->path_scope_len > UINT16_MAX) ++ { ++ DBG_ERR("Bad path_scope: %s\n", path_scope); ++ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); ++ return; ++ } ++ mdscli_ctx->path_scope = talloc_strdup(mdscli_ctx, path_scope); ++ if (tevent_req_nomem(mdscli_ctx->path_scope, req)) { ++ return; ++ } ++ ++ if (mdscli_ctx->path_scope[mdscli_ctx->path_scope_len-1] == '/') { ++ mdscli_ctx->path_scope[mdscli_ctx->path_scope_len-1] = '\0'; ++ mdscli_ctx->path_scope_len--; ++ } ++ + tevent_req_done(req); + } + +@@ -697,7 +816,10 @@ static void mdscli_get_path_done(struct tevent_req *subreq) + struct mdscli_get_path_state *state = tevent_req_data( + req, struct mdscli_get_path_state); + DALLOC_CTX *d = NULL; ++ size_t pathlen; ++ size_t prefixlen; + char *path = NULL; ++ const char *p = NULL; + NTSTATUS status; + bool ok; + +@@ -732,7 +854,38 @@ static void mdscli_get_path_done(struct tevent_req *subreq) + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } +- state->path = talloc_move(state, &path); ++ ++ /* Path is prefixed by /PATHSCOPE/SHARENAME/, strip it */ ++ pathlen = strlen(path); ++ ++ /* ++ * path_scope_len and share_path_len are already checked to be smaller ++ * then UINT16_MAX so this can't overflow ++ */ ++ prefixlen = state->mdscli_ctx->path_scope_len ++ + state->mdscli_ctx->mdscmd_open.share_path_len; ++ ++ if (pathlen < prefixlen) { ++ DBG_DEBUG("Bad path: %s\n", path); ++ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); ++ return; ++ } ++ ++ p = path + prefixlen; ++ while (*p == '/') { ++ p++; ++ } ++ if (*p == '\0') { ++ DBG_DEBUG("Bad path: %s\n", path); ++ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); ++ return; ++ } ++ ++ state->path = talloc_strdup(state, p); ++ if (state->path == NULL) { ++ tevent_req_nterror(req, NT_STATUS_NO_MEMORY); ++ return; ++ } + DBG_DEBUG("path: %s\n", state->path); + + tevent_req_done(req); +diff --git a/source3/rpc_client/cli_mdssvc_private.h b/source3/rpc_client/cli_mdssvc_private.h +index 031af85bf58..77f300c09cc 100644 +--- a/source3/rpc_client/cli_mdssvc_private.h ++++ b/source3/rpc_client/cli_mdssvc_private.h +@@ -42,6 +42,7 @@ struct mdscli_ctx { + /* cmd specific or unknown fields */ + struct { + char share_path[1025]; ++ size_t share_path_len; + uint32_t unkn2; + uint32_t unkn3; + } mdscmd_open; +@@ -56,6 +57,9 @@ struct mdscli_ctx { + struct { + uint32_t status; + } mdscmd_close; ++ ++ char *path_scope; ++ size_t path_scope_len; + }; + + struct mdscli_search_ctx { +diff --git a/source3/rpc_client/cli_mdssvc_util.c b/source3/rpc_client/cli_mdssvc_util.c +index a39202d0c99..1eaaca715a8 100644 +--- a/source3/rpc_client/cli_mdssvc_util.c ++++ b/source3/rpc_client/cli_mdssvc_util.c +@@ -28,6 +28,74 @@ + #include "rpc_server/mdssvc/dalloc.h" + #include "rpc_server/mdssvc/marshalling.h" + ++NTSTATUS mdscli_blob_fetch_props(TALLOC_CTX *mem_ctx, ++ struct mdscli_ctx *ctx, ++ struct mdssvc_blob *blob) ++{ ++ DALLOC_CTX *d = NULL; ++ uint64_t *uint64p = NULL; ++ sl_array_t *array = NULL; ++ sl_array_t *cmd_array = NULL; ++ NTSTATUS status; ++ int ret; ++ ++ d = dalloc_new(mem_ctx); ++ if (d == NULL) { ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ array = dalloc_zero(d, sl_array_t); ++ if (array == NULL) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ ret = dalloc_add(d, array, sl_array_t); ++ if (ret != 0) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ cmd_array = dalloc_zero(d, sl_array_t); ++ if (cmd_array == NULL) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ ret = dalloc_add(array, cmd_array, sl_array_t); ++ if (ret != 0) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ ret = dalloc_stradd(cmd_array, "fetchPropertiesForContext:"); ++ if (ret != 0) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ uint64p = talloc_zero_array(cmd_array, uint64_t, 2); ++ if (uint64p == NULL) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ talloc_set_name(uint64p, "uint64_t *"); ++ ++ ret = dalloc_add(cmd_array, uint64p, uint64_t *); ++ if (ret != 0) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ status = sl_pack_alloc(mem_ctx, d, blob, ctx->max_fragment_size); ++ TALLOC_FREE(d); ++ if (!NT_STATUS_IS_OK(status)) { ++ return status; ++ } ++ return NT_STATUS_OK; ++} ++ + NTSTATUS mdscli_blob_search(TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx *search, + struct mdssvc_blob *blob) +diff --git a/source3/rpc_client/cli_mdssvc_util.h b/source3/rpc_client/cli_mdssvc_util.h +index 7a98c854526..3f324758c70 100644 +--- a/source3/rpc_client/cli_mdssvc_util.h ++++ b/source3/rpc_client/cli_mdssvc_util.h +@@ -21,6 +21,10 @@ + #ifndef _MDSCLI_UTIL_H_ + #define _MDSCLI_UTIL_H_ + ++NTSTATUS mdscli_blob_fetch_props(TALLOC_CTX *mem_ctx, ++ struct mdscli_ctx *ctx, ++ struct mdssvc_blob *blob); ++ + NTSTATUS mdscli_blob_search(TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx *search, + struct mdssvc_blob *blob); +-- +2.34.1 diff --git a/backport-0010-CVE-2023-4154.patch b/backport-0010-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..741ffa7bf6bf3ea6b7db6f61e52268e71feb9f2a --- /dev/null +++ b/backport-0010-CVE-2023-4154.patch @@ -0,0 +1,57 @@ +From 92cf3328a00cacb07fe7c6b7abf5335dc8235e86 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 17 Mar 2023 14:08:34 +0100 +Subject: [PATCH 15/30] CVE-2023-4154 python/samba/ndr: add ndr_deepcopy() + helper + +This uses ndr_pack/unpack in order to create a deep copy +of the given object. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +(cherry picked from commit 4627997ddae44265ad35b3234232eb74458c6c34) + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 15/30] CVE-2023-4154 python/samba/ndr: add ndr_deepcopy() + helper +--- + python/samba/ndr.py | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/python/samba/ndr.py b/python/samba/ndr.py +index 35b2414e8ae..8369abfb2d0 100644 +--- a/python/samba/ndr.py ++++ b/python/samba/ndr.py +@@ -56,6 +56,25 @@ def ndr_print(object): + return ndr_print() + + ++def ndr_deepcopy(object): ++ """Create a deep copy of a NDR object, using pack/unpack ++ ++ :param object: Object to copy ++ :return: The object copy ++ """ ++ ndr_pack = getattr(object, "__ndr_pack__", None) ++ if ndr_pack is None: ++ raise TypeError("%r is not a NDR object" % object) ++ data = ndr_pack() ++ cls = type(object) ++ copy = cls() ++ ndr_unpack = getattr(copy, "__ndr_unpack__", None) ++ if ndr_unpack is None: ++ raise TypeError("%r is not a NDR object" % copy) ++ ndr_unpack(data, allow_remaining=False) ++ return copy ++ ++ + def ndr_pack_in(object, bigendian=False, ndr64=False): + """Pack the input of an NDR function object. + +-- +2.34.1 diff --git a/backport-0011-CVE-2023-0614.patch b/backport-0011-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..95423624ecd2d508281aa8a94d01469464481d46 --- /dev/null +++ b/backport-0011-CVE-2023-0614.patch @@ -0,0 +1,104 @@ +From 83217ce77381f8faa3cde948e15a36db234d3033 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 3 Mar 2023 17:23:42 +1300 +Subject: [PATCH 09/34] CVE-2023-0614 ldb: Add function to take ownership of an + ldb message + +Many places in Samba depend upon various components of an ldb message +being talloc allocated, and hence able to be used as talloc contexts. +The elements and values of an unpacked ldb message point to unowned data +inside the memory-mapped database, and this function ensures that such +messages have talloc ownership of said elements and values. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb/common/ldb_pack.c | 41 ++++++++++++++++++++++++++++++++++++ + lib/ldb/include/ldb_module.h | 4 ++++ + 2 files changed, 45 insertions(+) + +diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c +index e7dd364008a..028d96a619a 100644 +--- a/lib/ldb/common/ldb_pack.c ++++ b/lib/ldb/common/ldb_pack.c +@@ -690,6 +690,7 @@ static int ldb_unpack_data_flags_v1(struct ldb_context *ldb, + element->values = NULL; + if ((flags & LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC) && element->num_values == 1) { + element->values = &ldb_val_single_array[nelem]; ++ element->flags |= LDB_FLAG_INTERNAL_SHARED_VALUES; + } else if (element->num_values != 0) { + element->values = talloc_array(message->elements, + struct ldb_val, +@@ -932,6 +933,7 @@ static int ldb_unpack_data_flags_v2(struct ldb_context *ldb, + if ((flags & LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC) && + element->num_values == 1) { + element->values = &ldb_val_single_array[nelem]; ++ element->flags |= LDB_FLAG_INTERNAL_SHARED_VALUES; + } else if (element->num_values != 0) { + element->values = talloc_array(message->elements, + struct ldb_val, +@@ -1259,3 +1261,42 @@ failed: + TALLOC_FREE(filtered_msg->elements); + return -1; + } ++ ++/* Have an unpacked ldb message take talloc ownership of its elements. */ ++int ldb_msg_elements_take_ownership(struct ldb_message *msg) ++{ ++ unsigned int i = 0; ++ ++ for (i = 0; i < msg->num_elements; i++) { ++ struct ldb_message_element *el = &msg->elements[i]; ++ const char *name; ++ unsigned int j; ++ ++ name = talloc_strdup(msg->elements, ++ el->name); ++ if (name == NULL) { ++ return -1; ++ } ++ el->name = name; ++ ++ if (el->flags & LDB_FLAG_INTERNAL_SHARED_VALUES) { ++ struct ldb_val *values = talloc_memdup(msg->elements, el->values, ++ sizeof(struct ldb_val) * el->num_values); ++ if (values == NULL) { ++ return -1; ++ } ++ el->values = values; ++ el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES; ++ } ++ ++ for (j = 0; j < el->num_values; j++) { ++ struct ldb_val val = ldb_val_dup(el->values, &el->values[j]); ++ if (val.data == NULL && el->values[j].length != 0) { ++ return -1; ++ } ++ el->values[j] = val; ++ } ++ } ++ ++ return LDB_SUCCESS; ++} +diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h +index 8481fd3991a..8c7f33496fb 100644 +--- a/lib/ldb/include/ldb_module.h ++++ b/lib/ldb/include/ldb_module.h +@@ -542,6 +542,10 @@ int ldb_filter_attrs(struct ldb_context *ldb, + const struct ldb_message *msg, + const char *const *attrs, + struct ldb_message *filtered_msg); ++ ++/* Have an unpacked ldb message take talloc ownership of its elements. */ ++int ldb_msg_elements_take_ownership(struct ldb_message *msg); ++ + /* + * Unpack a ldb message from a linear buffer in ldb_val + * +-- +2.25.1 \ No newline at end of file diff --git a/backport-0011-CVE-2023-34968.patch b/backport-0011-CVE-2023-34968.patch new file mode 100644 index 0000000000000000000000000000000000000000..f5c23326b823f4e4babbaa3b7960bf4e8a8c3f3e --- /dev/null +++ b/backport-0011-CVE-2023-34968.patch @@ -0,0 +1,224 @@ +From 091b0265fe42878d676def5d4f5b4f8f3977b0e2 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Mon, 5 Jun 2023 18:02:20 +0200 +Subject: [PATCH 17/28] CVE-2023-34968: mdssvc: return a fake share path + +Instead of returning the real server-side absolute path of shares and search +results, return a fake absolute path replacing the path of the share with the +share name, iow for a share "test" with a server-side path of "/foo/bar", we +previously returned + + /foo/bar and + /foo/bar/search/result + +and now return + + /test and + /test/search/result + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.10-security-2023-07-19.patch +--- + source3/rpc_server/mdssvc/mdssvc.c | 61 +++++++++++++++++++++-- + source3/rpc_server/mdssvc/mdssvc.h | 1 + + source3/rpc_server/mdssvc/srv_mdssvc_nt.c | 18 +++++-- + 3 files changed, 73 insertions(+), 7 deletions(-) + +diff --git a/source3/rpc_server/mdssvc/mdssvc.c b/source3/rpc_server/mdssvc/mdssvc.c +index 9b814f51fc3..22cc7abd153 100644 +--- a/source3/rpc_server/mdssvc/mdssvc.c ++++ b/source3/rpc_server/mdssvc/mdssvc.c +@@ -520,10 +520,13 @@ static bool inode_map_add(struct sl_query *slq, + bool mds_add_result(struct sl_query *slq, const char *path) + { + struct smb_filename *smb_fname = NULL; ++ const char *relative = NULL; ++ char *fake_path = NULL; + struct stat_ex sb; + uint64_t ino64; + int result; + NTSTATUS status; ++ bool sub; + bool ok; + + /* +@@ -598,6 +601,17 @@ bool mds_add_result(struct sl_query *slq, const char *path) + } + } + ++ sub = subdir_of(slq->mds_ctx->spath, ++ slq->mds_ctx->spath_len, ++ path, ++ &relative); ++ if (!sub) { ++ DBG_ERR("[%s] is not inside [%s]\n", ++ path, slq->mds_ctx->spath); ++ slq->state = SLQ_STATE_ERROR; ++ return false; ++ } ++ + /* + * Add inode number and filemeta to result set, this is what + * we return as part of the result set of a query +@@ -610,18 +624,30 @@ bool mds_add_result(struct sl_query *slq, const char *path) + slq->state = SLQ_STATE_ERROR; + return false; + } ++ ++ fake_path = talloc_asprintf(slq, ++ "/%s/%s", ++ slq->mds_ctx->sharename, ++ relative); ++ if (fake_path == NULL) { ++ slq->state = SLQ_STATE_ERROR; ++ return false; ++ } ++ + ok = add_filemeta(slq->mds_ctx, + slq->reqinfo, + slq->query_results->fm_array, +- path, ++ fake_path, + &sb); + if (!ok) { + DBG_ERR("add_filemeta error\n"); ++ TALLOC_FREE(fake_path); + slq->state = SLQ_STATE_ERROR; + return false; + } + +- ok = inode_map_add(slq, ino64, path, &sb); ++ ok = inode_map_add(slq, ino64, fake_path, &sb); ++ TALLOC_FREE(fake_path); + if (!ok) { + DEBUG(1, ("inode_map_add error\n")); + slq->state = SLQ_STATE_ERROR; +@@ -828,6 +854,32 @@ static void slq_close_timer(struct tevent_context *ev, + } + } + ++/** ++ * Translate a fake scope from the client like /sharename/dir ++ * to the real server-side path, replacing the "/sharename" part ++ * with the absolute server-side path of the share. ++ **/ ++static bool mdssvc_real_scope(struct sl_query *slq, const char *fake_scope) ++{ ++ size_t sname_len = strlen(slq->mds_ctx->sharename); ++ size_t fake_scope_len = strlen(fake_scope); ++ ++ if (fake_scope_len < sname_len + 1) { ++ DBG_ERR("Short scope [%s] for share [%s]\n", ++ fake_scope, slq->mds_ctx->sharename); ++ return false; ++ } ++ ++ slq->path_scope = talloc_asprintf(slq, ++ "%s%s", ++ slq->mds_ctx->spath, ++ fake_scope + sname_len + 1); ++ if (slq->path_scope == NULL) { ++ return false; ++ } ++ return true; ++} ++ + /** + * Begin a search query + **/ +@@ -940,8 +992,8 @@ static bool slrpc_open_query(struct mds_ctx *mds_ctx, + goto error; + } + +- slq->path_scope = talloc_strdup(slq, scope); +- if (slq->path_scope == NULL) { ++ ok = mdssvc_real_scope(slq, scope); ++ if (!ok) { + goto error; + } + +@@ -1662,6 +1714,7 @@ NTSTATUS mds_init_ctx(TALLOC_CTX *mem_ctx, + status = NT_STATUS_NO_MEMORY; + goto error; + } ++ mds_ctx->spath_len = strlen(path); + + mds_ctx->snum = snum; + mds_ctx->pipe_session_info = session_info; +diff --git a/source3/rpc_server/mdssvc/mdssvc.h b/source3/rpc_server/mdssvc/mdssvc.h +index e1fc0709ab1..3b2ce250f1f 100644 +--- a/source3/rpc_server/mdssvc/mdssvc.h ++++ b/source3/rpc_server/mdssvc/mdssvc.h +@@ -127,6 +127,7 @@ struct mds_ctx { + int snum; + const char *sharename; + const char *spath; ++ size_t spath_len; + struct connection_struct *conn; + struct sl_query *query_list; /* list of active queries */ + struct db_context *ino_path_map; /* dbwrap rbt for storing inode->path mappings */ +diff --git a/source3/rpc_server/mdssvc/srv_mdssvc_nt.c b/source3/rpc_server/mdssvc/srv_mdssvc_nt.c +index ae6a73605e1..c77e7185521 100644 +--- a/source3/rpc_server/mdssvc/srv_mdssvc_nt.c ++++ b/source3/rpc_server/mdssvc/srv_mdssvc_nt.c +@@ -81,6 +81,7 @@ void _mdssvc_open(struct pipes_struct *p, struct mdssvc_open *r) + loadparm_s3_global_substitution(); + int snum; + char *outpath = discard_const_p(char, r->out.share_path); ++ char *fake_path = NULL; + char *path; + NTSTATUS status; + +@@ -98,12 +99,21 @@ void _mdssvc_open(struct pipes_struct *p, struct mdssvc_open *r) + + path = lp_path(talloc_tos(), lp_sub, snum); + if (path == NULL) { +- DBG_ERR("Couldn't create policy handle for %s\n", ++ DBG_ERR("Couldn't create path for %s\n", + r->in.share_name); + p->fault_state = DCERPC_FAULT_CANT_PERFORM; + return; + } + ++ fake_path = talloc_asprintf(p->mem_ctx, "/%s", r->in.share_name); ++ if (fake_path == NULL) { ++ DBG_ERR("Couldn't create fake share path for %s\n", ++ r->in.share_name); ++ talloc_free(path); ++ p->fault_state = DCERPC_FAULT_CANT_PERFORM; ++ return; ++ } ++ + status = create_mdssvc_policy_handle(p->mem_ctx, p, + snum, + r->in.share_name, +@@ -112,18 +122,20 @@ void _mdssvc_open(struct pipes_struct *p, struct mdssvc_open *r) + if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_VOLUME)) { + ZERO_STRUCTP(r->out.handle); + talloc_free(path); ++ talloc_free(fake_path); + return; + } + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("Couldn't create policy handle for %s\n", + r->in.share_name); + talloc_free(path); ++ talloc_free(fake_path); + p->fault_state = DCERPC_FAULT_CANT_PERFORM; + return; + } + +- strlcpy(outpath, path, 1024); +- talloc_free(path); ++ strlcpy(outpath, fake_path, 1024); ++ talloc_free(fake_path); + return; + } + +-- +2.34.1 diff --git a/backport-0011-CVE-2023-4154.patch b/backport-0011-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..7bc41fb7f905e620643551f429f9b6412c7b726f --- /dev/null +++ b/backport-0011-CVE-2023-4154.patch @@ -0,0 +1,50 @@ +From 2c7710bd5bc979d5fa601d2ee841592694bb14df Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 16 Mar 2023 09:57:43 +0100 +Subject: [PATCH 16/30] CVE-2023-4154 replace: add ARRAY_INSERT_ELEMENT() + helper + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +(cherry picked from commit 9d8ff0d1e0b2ba7c84af36e1931f5bc99902a44b) + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 16/30] CVE-2023-4154 replace: add ARRAY_INSERT_ELEMENT() + helper +--- + lib/replace/replace.h | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/lib/replace/replace.h b/lib/replace/replace.h +index bd7f6e53e81..bcd5c09bf7c 100644 +--- a/lib/replace/replace.h ++++ b/lib/replace/replace.h +@@ -889,6 +889,21 @@ typedef unsigned long long ptrdiff_t ; + #define ARRAY_DEL_ELEMENT(a,i,n) \ + if((i)<((n)-1)){memmove(&((a)[(i)]),&((a)[(i)+1]),(sizeof(*(a))*((n)-(i)-1)));} + ++/** ++ * Insert an array element by moving the rest one up ++ * ++ */ ++#define ARRAY_INSERT_ELEMENT(__array,__old_last_idx,__new_elem,__new_idx) do { \ ++ if ((__new_idx) < (__old_last_idx)) { \ ++ const void *__src = &((__array)[(__new_idx)]); \ ++ void *__dst = &((__array)[(__new_idx)+1]); \ ++ size_t __num = (__old_last_idx)-(__new_idx); \ ++ size_t __len = sizeof(*(__array)) * __num; \ ++ memmove(__dst, __src, __len); \ ++ } \ ++ (__array)[(__new_idx)] = (__new_elem); \ ++} while(0) ++ + /** + * Pointer difference macro + */ +-- +2.34.1 diff --git a/backport-0012-CVE-2023-0614.patch b/backport-0012-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..7861a1cc84f0d65ff33ae4523a288fede6c908fe --- /dev/null +++ b/backport-0012-CVE-2023-0614.patch @@ -0,0 +1,62 @@ +From a9b625bc8ab00b83b55bcd21ba0df48e73e4df29 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 3 Mar 2023 17:26:04 +1300 +Subject: [PATCH 10/34] CVE-2023-0614 ldb: Add function to remove excess + capacity from an ldb message + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org Adapted to conflict from lack of new +ldb_ascii_toupper() in ldb_private.h] + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb/common/ldb_msg.c | 16 ++++++++++++++++ + lib/ldb/include/ldb_private.h | 3 +++ + 2 files changed, 19 insertions(+) + +diff --git a/lib/ldb/common/ldb_msg.c b/lib/ldb/common/ldb_msg.c +index cbc7e32b2ba..2ea2cce2e83 100644 +--- a/lib/ldb/common/ldb_msg.c ++++ b/lib/ldb/common/ldb_msg.c +@@ -1497,6 +1497,22 @@ void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr) + } + } + ++/* Reallocate elements to drop any excess capacity. */ ++void ldb_msg_shrink_to_fit(struct ldb_message *msg) ++{ ++ if (msg->num_elements > 0) { ++ struct ldb_message_element *elements = talloc_realloc(msg, ++ msg->elements, ++ struct ldb_message_element, ++ msg->num_elements); ++ if (elements != NULL) { ++ msg->elements = elements; ++ } ++ } else { ++ TALLOC_FREE(msg->elements); ++ } ++} ++ + /* + return a LDAP formatted GeneralizedTime string + */ +diff --git a/lib/ldb/include/ldb_private.h b/lib/ldb/include/ldb_private.h +index 4deb24691ca..338e71def6d 100644 +--- a/lib/ldb/include/ldb_private.h ++++ b/lib/ldb/include/ldb_private.h +@@ -317,4 +317,7 @@ int ldb_match_message(struct ldb_context *ldb, + const struct ldb_parse_tree *tree, + enum ldb_scope scope, bool *matched); + ++/* Reallocate elements to drop any excess capacity. */ ++void ldb_msg_shrink_to_fit(struct ldb_message *msg); ++ + #endif +-- +2.25.1 \ No newline at end of file diff --git a/backport-0012-CVE-2023-4154.patch b/backport-0012-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..131c9eefb8a08fa39a026533f3d0d44e8845e7fe --- /dev/null +++ b/backport-0012-CVE-2023-4154.patch @@ -0,0 +1,103 @@ +From 3c34a51da12c4b1fb446f9a384ff57cdc6019632 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 16 Mar 2023 10:00:11 +0100 +Subject: [PATCH 17/30] CVE-2023-4154 libcli/security: prepare + security_descriptor_acl_add() to place the ace at a position + +Often it is important to insert an ace at a specific position in the +ACL. As a default we still append by default by using -1, which is the +generic version of passing the number of existing aces. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +(cherry picked from commit c3cb915a67aff6739b72b86d7d139609df309ada) + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 17/30] CVE-2023-4154 libcli/security: prepare + security_descriptor_acl_add() to place the ace at a position +--- + libcli/security/security_descriptor.c | 27 ++++++++++++++++++++------- + 1 file changed, 20 insertions(+), 7 deletions(-) + +diff --git a/libcli/security/security_descriptor.c b/libcli/security/security_descriptor.c +index 64c2d027876..8657c797364 100644 +--- a/libcli/security/security_descriptor.c ++++ b/libcli/security/security_descriptor.c +@@ -267,9 +267,11 @@ NTSTATUS security_descriptor_for_client(TALLOC_CTX *mem_ctx, + + static NTSTATUS security_descriptor_acl_add(struct security_descriptor *sd, + bool add_to_sacl, +- const struct security_ace *ace) ++ const struct security_ace *ace, ++ ssize_t _idx) + { + struct security_acl *acl = NULL; ++ ssize_t idx; + + if (add_to_sacl) { + acl = sd->sacl; +@@ -288,15 +290,28 @@ static NTSTATUS security_descriptor_acl_add(struct security_descriptor *sd, + acl->aces = NULL; + } + ++ if (_idx < 0) { ++ idx = (acl->num_aces + 1) + _idx; ++ } else { ++ idx = _idx; ++ } ++ ++ if (idx < 0) { ++ return NT_STATUS_ARRAY_BOUNDS_EXCEEDED; ++ } else if (idx > acl->num_aces) { ++ return NT_STATUS_ARRAY_BOUNDS_EXCEEDED; ++ } ++ + acl->aces = talloc_realloc(acl, acl->aces, + struct security_ace, acl->num_aces+1); + if (acl->aces == NULL) { + return NT_STATUS_NO_MEMORY; + } + +- acl->aces[acl->num_aces] = *ace; ++ ARRAY_INSERT_ELEMENT(acl->aces, acl->num_aces, *ace, idx); ++ acl->num_aces++; + +- switch (acl->aces[acl->num_aces].type) { ++ switch (acl->aces[idx].type) { + case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: + case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: + case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT: +@@ -307,8 +322,6 @@ static NTSTATUS security_descriptor_acl_add(struct security_descriptor *sd, + break; + } + +- acl->num_aces++; +- + if (add_to_sacl) { + sd->sacl = acl; + sd->type |= SEC_DESC_SACL_PRESENT; +@@ -327,7 +340,7 @@ static NTSTATUS security_descriptor_acl_add(struct security_descriptor *sd, + NTSTATUS security_descriptor_sacl_add(struct security_descriptor *sd, + const struct security_ace *ace) + { +- return security_descriptor_acl_add(sd, true, ace); ++ return security_descriptor_acl_add(sd, true, ace, -1); + } + + /* +@@ -337,7 +350,7 @@ NTSTATUS security_descriptor_sacl_add(struct security_descriptor *sd, + NTSTATUS security_descriptor_dacl_add(struct security_descriptor *sd, + const struct security_ace *ace) + { +- return security_descriptor_acl_add(sd, false, ace); ++ return security_descriptor_acl_add(sd, false, ace, -1); + } + + /* +-- +2.34.1 diff --git a/backport-0013-CVE-2023-0614.patch b/backport-0013-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..c0f961b16435be1b81b7669f207804eebfe10331 --- /dev/null +++ b/backport-0013-CVE-2023-0614.patch @@ -0,0 +1,68 @@ +From 8b7374780e3e7b67e51a1b54a09bf48d89fa9f26 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 3 Mar 2023 17:27:38 +1300 +Subject: [PATCH 11/34] CVE-2023-0614 ldb: Add function to add + distinguishedName to message + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org Adapted to conflict from lack of new +ldb_ascii_toupper() in ldb_private.h] + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb/common/ldb_pack.c | 6 +++--- + lib/ldb/include/ldb_private.h | 5 +++++ + 2 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c +index 028d96a619a..b0b0d64a5ba 100644 +--- a/lib/ldb/common/ldb_pack.c ++++ b/lib/ldb/common/ldb_pack.c +@@ -1098,7 +1098,7 @@ int ldb_unpack_data(struct ldb_context *ldb, + /* + add the special distinguishedName element + */ +-static int msg_add_distinguished_name(struct ldb_message *msg) ++int ldb_msg_add_distinguished_name(struct ldb_message *msg) + { + const char *dn_attr = "distinguishedName"; + char *dn = NULL; +@@ -1158,7 +1158,7 @@ int ldb_filter_attrs(struct ldb_context *ldb, + + /* Shortcuts for the simple cases */ + } else if (add_dn && i == 1) { +- if (msg_add_distinguished_name(filtered_msg) != 0) { ++ if (ldb_msg_add_distinguished_name(filtered_msg) != 0) { + goto failed; + } + return 0; +@@ -1238,7 +1238,7 @@ int ldb_filter_attrs(struct ldb_context *ldb, + filtered_msg->num_elements = num_elements; + + if (add_dn) { +- if (msg_add_distinguished_name(filtered_msg) != 0) { ++ if (ldb_msg_add_distinguished_name(filtered_msg) != 0) { + goto failed; + } + } +diff --git a/lib/ldb/include/ldb_private.h b/lib/ldb/include/ldb_private.h +index 338e71def6d..ca43817d07a 100644 +--- a/lib/ldb/include/ldb_private.h ++++ b/lib/ldb/include/ldb_private.h +@@ -320,4 +320,9 @@ int ldb_match_message(struct ldb_context *ldb, + /* Reallocate elements to drop any excess capacity. */ + void ldb_msg_shrink_to_fit(struct ldb_message *msg); + ++/* ++ add the special distinguishedName element ++*/ ++int ldb_msg_add_distinguished_name(struct ldb_message *msg); ++ + #endif +-- +2.25.1 \ No newline at end of file diff --git a/backport-0013-CVE-2023-4154.patch b/backport-0013-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..59371fbc1520ba3a6b75768ad1c54bd637dbdc3b --- /dev/null +++ b/backport-0013-CVE-2023-4154.patch @@ -0,0 +1,90 @@ +From 3de5d8a01163bfa70464d7532069ed467e4ffd10 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 16 Mar 2023 10:03:44 +0100 +Subject: [PATCH 18/30] CVE-2023-4154 libcli/security: add + security_descriptor_[s|d]acl_insert() helpers + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +(cherry picked from commit 2c02378029fff6636b8f19e45af78b265f2210ed) + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 18/30] CVE-2023-4154 libcli/security: add + security_descriptor_[s|d]acl_insert() helpers +--- + libcli/security/security_descriptor.c | 28 +++++++++++++++++++++++++++ + libcli/security/security_descriptor.h | 6 ++++++ + 2 files changed, 34 insertions(+) + +diff --git a/libcli/security/security_descriptor.c b/libcli/security/security_descriptor.c +index 8657c797364..08f2cf19ee8 100644 +--- a/libcli/security/security_descriptor.c ++++ b/libcli/security/security_descriptor.c +@@ -343,6 +343,20 @@ NTSTATUS security_descriptor_sacl_add(struct security_descriptor *sd, + return security_descriptor_acl_add(sd, true, ace, -1); + } + ++/* ++ insert an ACE at a given index to the SACL of a security_descriptor ++ ++ idx can be negative, which means it's related to the new size from the ++ end, so -1 means the ace is appended at the end. ++*/ ++ ++NTSTATUS security_descriptor_sacl_insert(struct security_descriptor *sd, ++ const struct security_ace *ace, ++ ssize_t idx) ++{ ++ return security_descriptor_acl_add(sd, true, ace, idx); ++} ++ + /* + add an ACE to the DACL of a security_descriptor + */ +@@ -353,6 +367,20 @@ NTSTATUS security_descriptor_dacl_add(struct security_descriptor *sd, + return security_descriptor_acl_add(sd, false, ace, -1); + } + ++/* ++ insert an ACE at a given index to the DACL of a security_descriptor ++ ++ idx can be negative, which means it's related to the new size from the ++ end, so -1 means the ace is appended at the end. ++*/ ++ ++NTSTATUS security_descriptor_dacl_insert(struct security_descriptor *sd, ++ const struct security_ace *ace, ++ ssize_t idx) ++{ ++ return security_descriptor_acl_add(sd, false, ace, idx); ++} ++ + /* + delete the ACE corresponding to the given trustee in an ACL of a + security_descriptor +diff --git a/libcli/security/security_descriptor.h b/libcli/security/security_descriptor.h +index 46545321d15..354bc17e925 100644 +--- a/libcli/security/security_descriptor.h ++++ b/libcli/security/security_descriptor.h +@@ -33,8 +33,14 @@ NTSTATUS security_descriptor_for_client(TALLOC_CTX *mem_ctx, + struct security_descriptor **_csd); + NTSTATUS security_descriptor_sacl_add(struct security_descriptor *sd, + const struct security_ace *ace); ++NTSTATUS security_descriptor_sacl_insert(struct security_descriptor *sd, ++ const struct security_ace *ace, ++ ssize_t idx); + NTSTATUS security_descriptor_dacl_add(struct security_descriptor *sd, + const struct security_ace *ace); ++NTSTATUS security_descriptor_dacl_insert(struct security_descriptor *sd, ++ const struct security_ace *ace, ++ ssize_t idx); + NTSTATUS security_descriptor_dacl_del(struct security_descriptor *sd, + const struct dom_sid *trustee); + NTSTATUS security_descriptor_sacl_del(struct security_descriptor *sd, +-- +2.34.1 diff --git a/backport-0014-CVE-2023-0614.patch b/backport-0014-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..ed63e9fd14318dedbffe2a78c44e8859e58ab677 --- /dev/null +++ b/backport-0014-CVE-2023-0614.patch @@ -0,0 +1,1224 @@ +From 4f8b4ce403ff68ca26d33d7272276052829c96f7 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 3 Mar 2023 17:29:03 +1300 +Subject: [PATCH 12/34] CVE-2023-0614 ldb: Add function to filter message in + place + +At present this function is an exact duplicate of ldb_filter_attrs(), +but in the next commit we shall modify it to work in place, without the +need for the allocation of a second message. + +The test is a near duplicate of the existing test for +ldb_filter_attrs(). + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb/common/ldb_pack.c | 143 +++ + lib/ldb/include/ldb_module.h | 10 + + .../tests/ldb_filter_attrs_in_place_test.c | 989 ++++++++++++++++++ + lib/ldb/wscript | 6 + + 4 files changed, 1148 insertions(+) + create mode 100644 lib/ldb/tests/ldb_filter_attrs_in_place_test.c + +diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c +index b0b0d64a5ba..f19ac73fa5e 100644 +--- a/lib/ldb/common/ldb_pack.c ++++ b/lib/ldb/common/ldb_pack.c +@@ -1262,6 +1262,149 @@ failed: + return -1; + } + ++/* ++ * filter the specified list of attributes from msg, ++ * adding requested attributes, and perhaps all for *, ++ * but not the DN to filtered_msg. ++ */ ++int ldb_filter_attrs_in_place(struct ldb_context *ldb, ++ const struct ldb_message *msg, ++ const char *const *attrs, ++ struct ldb_message *filtered_msg) ++{ ++ unsigned int i; ++ bool keep_all = false; ++ bool add_dn = false; ++ uint32_t num_elements; ++ uint32_t elements_size; ++ ++ if (attrs) { ++ /* check for special attrs */ ++ for (i = 0; attrs[i]; i++) { ++ int cmp = strcmp(attrs[i], "*"); ++ if (cmp == 0) { ++ keep_all = true; ++ break; ++ } ++ cmp = ldb_attr_cmp(attrs[i], "distinguishedName"); ++ if (cmp == 0) { ++ add_dn = true; ++ } ++ } ++ } else { ++ keep_all = true; ++ } ++ ++ if (keep_all) { ++ add_dn = true; ++ elements_size = msg->num_elements + 1; ++ ++ /* Shortcuts for the simple cases */ ++ } else if (add_dn && i == 1) { ++ if (ldb_msg_add_distinguished_name(filtered_msg) != 0) { ++ goto failed; ++ } ++ return 0; ++ } else if (i == 0) { ++ return 0; ++ ++ /* ++ * Otherwise we are copying at most as many elements as we ++ * have attributes ++ */ ++ } else { ++ elements_size = i; ++ } ++ ++ filtered_msg->elements = talloc_array(filtered_msg, ++ struct ldb_message_element, ++ elements_size); ++ if (filtered_msg->elements == NULL) goto failed; ++ ++ num_elements = 0; ++ ++ for (i = 0; i < msg->num_elements; i++) { ++ struct ldb_message_element *el = &msg->elements[i]; ++ ++ /* ++ * el2 is assigned after the Pigeonhole principle ++ * check below for clarity ++ */ ++ struct ldb_message_element *el2 = NULL; ++ unsigned int j; ++ ++ if (keep_all == false) { ++ bool found = false; ++ for (j = 0; attrs[j]; j++) { ++ int cmp = ldb_attr_cmp(el->name, attrs[j]); ++ if (cmp == 0) { ++ found = true; ++ break; ++ } ++ } ++ if (found == false) { ++ continue; ++ } ++ } ++ ++ /* ++ * Pigeonhole principle: we can't have more elements ++ * than the number of attributes if they are unique in ++ * the DB. ++ */ ++ if (num_elements >= elements_size) { ++ goto failed; ++ } ++ ++ el2 = &filtered_msg->elements[num_elements]; ++ ++ *el2 = *el; ++ el2->name = talloc_strdup(filtered_msg->elements, ++ el->name); ++ if (el2->name == NULL) { ++ goto failed; ++ } ++ el2->values = talloc_array(filtered_msg->elements, ++ struct ldb_val, el->num_values); ++ if (el2->values == NULL) { ++ goto failed; ++ } ++ for (j=0;jnum_values;j++) { ++ el2->values[j] = ldb_val_dup(el2->values, &el->values[j]); ++ if (el2->values[j].data == NULL && el->values[j].length != 0) { ++ goto failed; ++ } ++ } ++ num_elements++; ++ } ++ ++ filtered_msg->num_elements = num_elements; ++ ++ if (add_dn) { ++ if (ldb_msg_add_distinguished_name(filtered_msg) != 0) { ++ goto failed; ++ } ++ } ++ ++ if (filtered_msg->num_elements > 0) { ++ filtered_msg->elements ++ = talloc_realloc(filtered_msg, ++ filtered_msg->elements, ++ struct ldb_message_element, ++ filtered_msg->num_elements); ++ if (filtered_msg->elements == NULL) { ++ goto failed; ++ } ++ } else { ++ TALLOC_FREE(filtered_msg->elements); ++ } ++ ++ return 0; ++failed: ++ TALLOC_FREE(filtered_msg->elements); ++ return -1; ++} ++ + /* Have an unpacked ldb message take talloc ownership of its elements. */ + int ldb_msg_elements_take_ownership(struct ldb_message *msg) + { +diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h +index 8c7f33496fb..105093cf38c 100644 +--- a/lib/ldb/include/ldb_module.h ++++ b/lib/ldb/include/ldb_module.h +@@ -543,6 +543,16 @@ int ldb_filter_attrs(struct ldb_context *ldb, + const char *const *attrs, + struct ldb_message *filtered_msg); + ++/* ++ * filter the specified list of attributes from msg, ++ * adding requested attributes, and perhaps all for *, ++ * but not the DN to filtered_msg. ++ */ ++int ldb_filter_attrs_in_place(struct ldb_context *ldb, ++ const struct ldb_message *msg, ++ const char *const *attrs, ++ struct ldb_message *filtered_msg); ++ + /* Have an unpacked ldb message take talloc ownership of its elements. */ + int ldb_msg_elements_take_ownership(struct ldb_message *msg); + +diff --git a/lib/ldb/tests/ldb_filter_attrs_in_place_test.c b/lib/ldb/tests/ldb_filter_attrs_in_place_test.c +new file mode 100644 +index 00000000000..bef961f8f9c +--- /dev/null ++++ b/lib/ldb/tests/ldb_filter_attrs_in_place_test.c +@@ -0,0 +1,989 @@ ++/* ++ * Tests exercising ldb_filter_attrs_in_place(). ++ * ++ * ++ * Copyright (C) Catalyst.NET Ltd 2017 ++ * Copyright (C) Andrew Bartlett 2019 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++ ++/* ++ * from cmocka.c: ++ * These headers or their equivalents should be included prior to ++ * including ++ * this header file. ++ * ++ * #include ++ * #include ++ * #include ++ * ++ * This allows test applications to use custom definitions of C standard ++ * library functions and types. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../include/ldb.h" ++#include "../include/ldb_module.h" ++ ++struct ldbtest_ctx { ++ struct tevent_context *ev; ++ struct ldb_context *ldb; ++}; ++ ++/* ++ * NOTE WELL: ++ * ++ * This test checks the current behaviour of the function, however ++ * this is not in a public ABI and many of the tested behaviours are ++ * not ideal. If the behaviour is deliberatly improved, this test ++ * should be updated without worry to the new better behaviour. ++ * ++ * In particular the test is particularly to ensure the current ++ * behaviour is memory-safe. ++ */ ++ ++static int setup(void **state) ++{ ++ struct ldbtest_ctx *test_ctx; ++ ++ test_ctx = talloc_zero(NULL, struct ldbtest_ctx); ++ assert_non_null(test_ctx); ++ ++ test_ctx->ev = tevent_context_init(test_ctx); ++ assert_non_null(test_ctx->ev); ++ ++ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev); ++ assert_non_null(test_ctx->ldb); ++ ++ *state = test_ctx; ++ return 0; ++} ++ ++static int teardown(void **state) ++{ ++ talloc_free(*state); ++ return 0; ++} ++ ++ ++/* ++ * Test against a record with only one attribute, matching the one in ++ * the list ++ */ ++static void test_filter_attrs_one_attr_matched(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ const char *attrs[] = {"foo", NULL}; ++ ++ char value[] = "The value.......end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value, ++ .length = strlen(value) ++ }; ++ struct ldb_message_element element_1 = { ++ .name = "foo", ++ .num_values = 1, ++ .values = &value_1 ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 1, ++ .elements = &element_1, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_non_null(filtered_msg); ++ ++ /* ++ * assert the ldb_filter_attrs_in_place does not read or modify ++ * filtered_msg.dn in this case ++ */ ++ assert_null(filtered_msg->dn); ++ assert_int_equal(filtered_msg->num_elements, 1); ++ assert_string_equal(filtered_msg->elements[0].name, "foo"); ++ assert_int_equal(filtered_msg->elements[0].num_values, 1); ++ assert_int_equal(filtered_msg->elements[0].values[0].length, ++ strlen(value)); ++ assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ value, strlen(value)); ++} ++ ++/* ++ * Test against a record with only one attribute, matching the one of ++ * the multiple attributes in the list ++ */ ++static void test_filter_attrs_one_attr_matched_of_many(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ const char *attrs[] = {"foo", "bar", "baz", NULL}; ++ ++ char value[] = "The value.......end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value, ++ .length = strlen(value) ++ }; ++ struct ldb_message_element element_1 = { ++ .name = "foo", ++ .num_values = 1, ++ .values = &value_1 ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 1, ++ .elements = &element_1, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_non_null(filtered_msg); ++ ++ /* ++ * assert the ldb_filter_attrs_in_place does not read or modify ++ * filtered_msg.dn in this case ++ */ ++ assert_null(filtered_msg->dn); ++ assert_int_equal(filtered_msg->num_elements, 1); ++ assert_string_equal(filtered_msg->elements[0].name, "foo"); ++ assert_int_equal(filtered_msg->elements[0].num_values, 1); ++ assert_int_equal(filtered_msg->elements[0].values[0].length, ++ strlen(value)); ++ assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ value, strlen(value)); ++} ++ ++/* ++ * Test against a record with only one attribute, matching both ++ * attributes in the list ++ */ ++static void test_filter_attrs_two_attr_matched_attrs(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ /* deliberatly the other order */ ++ const char *attrs[] = {"bar", "foo", NULL}; ++ ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) ++ }; ++ struct ldb_val value_2 = { ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) ++ }; ++ ++ /* foo and bar are the other order to in attrs */ ++ struct ldb_message_element elements[] = { ++ { ++ .name = "foo", ++ .num_values = 1, ++ .values = &value_1 ++ }, ++ { ++ .name = "bar", ++ .num_values = 1, ++ .values = &value_2 ++ } ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 2, ++ .elements = elements, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_non_null(filtered_msg); ++ assert_int_equal(filtered_msg->num_elements, 2); ++ ++ /* ++ * assert the ldb_filter_attrs_in_place does not read or modify ++ * filtered_msg.dn in this case ++ */ ++ assert_null(filtered_msg->dn); ++ ++ /* Assert that DB order is preserved */ ++ assert_string_equal(filtered_msg->elements[0].name, "foo"); ++ assert_int_equal(filtered_msg->elements[0].num_values, 1); ++ assert_int_equal(filtered_msg->elements[0].values[0].length, ++ strlen(value1)); ++ assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ value1, strlen(value1)); ++ assert_string_equal(filtered_msg->elements[1].name, "bar"); ++ assert_int_equal(filtered_msg->elements[1].num_values, 1); ++ assert_int_equal(filtered_msg->elements[1].values[0].length, ++ strlen(value2)); ++ assert_memory_equal(filtered_msg->elements[1].values[0].data, ++ value2, strlen(value2)); ++} ++ ++/* ++ * Test against a record with two attributes, only of which is in ++ * the list ++ */ ++static void test_filter_attrs_two_attr_matched_one_attr(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ /* deliberatly the other order */ ++ const char *attrs[] = {"bar", NULL}; ++ ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) ++ }; ++ struct ldb_val value_2 = { ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) ++ }; ++ ++ /* foo and bar are the other order to in attrs */ ++ struct ldb_message_element elements[] = { ++ { ++ .name = "foo", ++ .num_values = 1, ++ .values = &value_1 ++ }, ++ { ++ .name = "bar", ++ .num_values = 1, ++ .values = &value_2 ++ } ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 2, ++ .elements = elements, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_non_null(filtered_msg); ++ assert_int_equal(filtered_msg->num_elements, 1); ++ ++ /* ++ * assert the ldb_filter_attrs_in_place does not read or modify ++ * filtered_msg.dn in this case ++ */ ++ assert_null(filtered_msg->dn); ++ ++ /* Assert that DB order is preserved */ ++ assert_string_equal(filtered_msg->elements[0].name, "bar"); ++ assert_int_equal(filtered_msg->elements[0].num_values, 1); ++ assert_int_equal(filtered_msg->elements[0].values[0].length, ++ strlen(value2)); ++ assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ value2, strlen(value2)); ++} ++ ++/* ++ * Test against a record with two attributes, both matching the one ++ * specified attribute in the list (a corrupt record) ++ */ ++static void test_filter_attrs_two_dup_attr_matched_one_attr(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ /* deliberatly the other order */ ++ const char *attrs[] = {"bar", NULL}; ++ ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) ++ }; ++ struct ldb_val value_2 = { ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) ++ }; ++ ++ /* foo and bar are the other order to in attrs */ ++ struct ldb_message_element elements[] = { ++ { ++ .name = "bar", ++ .num_values = 1, ++ .values = &value_1 ++ }, ++ { ++ .name = "bar", ++ .num_values = 1, ++ .values = &value_2 ++ } ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 2, ++ .elements = elements, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ ++ /* This should fail the pidgenhole test */ ++ assert_int_equal(ret, -1); ++ assert_null(filtered_msg->elements); ++} ++ ++/* ++ * Test against a record with two attributes, both matching the one ++ * specified attribute in the list (a corrupt record) ++ */ ++static void test_filter_attrs_two_dup_attr_matched_dup(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ const char *attrs[] = {"bar", "bar", NULL}; ++ ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) ++ }; ++ struct ldb_val value_2 = { ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) ++ }; ++ ++ /* foo and bar are the other order to in attrs */ ++ struct ldb_message_element elements[] = { ++ { ++ .name = "bar", ++ .num_values = 1, ++ .values = &value_1 ++ }, ++ { ++ .name = "bar", ++ .num_values = 1, ++ .values = &value_2 ++ } ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 2, ++ .elements = elements, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ ++ /* This does not fail the pidgenhole test */ ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_int_equal(filtered_msg->num_elements, 2); ++ ++ /* Assert that DB order is preserved */ ++ assert_string_equal(filtered_msg->elements[0].name, "bar"); ++ assert_int_equal(filtered_msg->elements[0].num_values, 1); ++ assert_int_equal(filtered_msg->elements[0].values[0].length, ++ strlen(value1)); ++ assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ value1, strlen(value1)); ++ assert_string_equal(filtered_msg->elements[1].name, "bar"); ++ assert_int_equal(filtered_msg->elements[1].num_values, 1); ++ assert_int_equal(filtered_msg->elements[1].values[0].length, ++ strlen(value2)); ++ assert_memory_equal(filtered_msg->elements[1].values[0].data, ++ value2, strlen(value2)); ++} ++ ++/* ++ * Test against a record with two attributes, both matching one of the ++ * specified attributes in the list (a corrupt record) ++ */ ++static void test_filter_attrs_two_dup_attr_matched_one_of_two(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ const char *attrs[] = {"bar", "foo", NULL}; ++ ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) ++ }; ++ struct ldb_val value_2 = { ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) ++ }; ++ ++ /* foo and bar are the other order to in attrs */ ++ struct ldb_message_element elements[] = { ++ { ++ .name = "bar", ++ .num_values = 1, ++ .values = &value_1 ++ }, ++ { ++ .name = "bar", ++ .num_values = 1, ++ .values = &value_2 ++ } ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 2, ++ .elements = elements, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ ++ /* This does not fail the pidgenhole test */ ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_int_equal(filtered_msg->num_elements, 2); ++ ++ /* Assert that DB order is preserved */ ++ assert_string_equal(filtered_msg->elements[0].name, "bar"); ++ assert_int_equal(filtered_msg->elements[0].num_values, 1); ++ assert_int_equal(filtered_msg->elements[0].values[0].length, ++ strlen(value1)); ++ assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ value1, strlen(value1)); ++ assert_string_equal(filtered_msg->elements[1].name, "bar"); ++ assert_int_equal(filtered_msg->elements[1].num_values, 1); ++ assert_int_equal(filtered_msg->elements[1].values[0].length, ++ strlen(value2)); ++ assert_memory_equal(filtered_msg->elements[1].values[0].data, ++ value2, strlen(value2)); ++} ++ ++/* ++ * Test against a record with two attributes against * (but not the ++ * other named attribute) (a corrupt record) ++ */ ++static void test_filter_attrs_two_dup_attr_matched_star(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ const char *attrs[] = {"*", "foo", NULL}; ++ ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) ++ }; ++ struct ldb_val value_2 = { ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) ++ }; ++ ++ /* foo and bar are the other order to in attrs */ ++ struct ldb_message_element elements[] = { ++ { ++ .name = "bar", ++ .num_values = 1, ++ .values = &value_1 ++ }, ++ { ++ .name = "bar", ++ .num_values = 1, ++ .values = &value_2 ++ } ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 2, ++ .elements = elements, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ /* Needed as * implies distinguishedName */ ++ filtered_msg->dn = in.dn; ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ ++ /* This does not fail the pidgenhole test */ ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_int_equal(filtered_msg->num_elements, 3); ++ ++ /* Assert that DB order is preserved */ ++ assert_string_equal(filtered_msg->elements[0].name, "bar"); ++ assert_int_equal(filtered_msg->elements[0].num_values, 1); ++ assert_int_equal(filtered_msg->elements[0].values[0].length, ++ strlen(value1)); ++ assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ value1, strlen(value1)); ++ assert_string_equal(filtered_msg->elements[1].name, "bar"); ++ assert_int_equal(filtered_msg->elements[1].num_values, 1); ++ assert_int_equal(filtered_msg->elements[1].values[0].length, ++ strlen(value2)); ++ assert_memory_equal(filtered_msg->elements[1].values[0].data, ++ value2, strlen(value2)); ++ /* ++ * assert the ldb_filter_attrs_in_place does not modify filtered_msg.dn ++ * in this case ++ */ ++ assert_ptr_equal(filtered_msg->dn, in.dn); ++ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ "distinguishedName", ++ NULL), ++ ldb_dn_get_linearized(in.dn)); ++} ++ ++/* ++ * Test against a record with only one attribute, matching the * in ++ * the list ++ */ ++static void test_filter_attrs_one_attr_matched_star(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ const char *attrs[] = {"*", NULL}; ++ ++ char value[] = "The value.......end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value, ++ .length = strlen(value) ++ }; ++ struct ldb_message_element element_1 = { ++ .name = "foo", ++ .num_values = 1, ++ .values = &value_1 ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 1, ++ .elements = &element_1, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ /* Needed as * implies distinguishedName */ ++ filtered_msg->dn = in.dn; ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_non_null(filtered_msg); ++ assert_int_equal(filtered_msg->num_elements, 2); ++ ++ /* ++ * assert the ldb_filter_attrs_in_place does not modify filtered_msg.dn ++ * in this case ++ */ ++ assert_ptr_equal(filtered_msg->dn, in.dn); ++ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ "distinguishedName", ++ NULL), ++ ldb_dn_get_linearized(in.dn)); ++ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ "foo", ++ NULL), ++ value); ++} ++ ++/* ++ * Test against a record with two attributes, matching the * in ++ * the list ++ */ ++static void test_filter_attrs_two_attr_matched_star(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ const char *attrs[] = {"*", NULL}; ++ ++ char value1[] = "The value.......end"; ++ char value2[] = "The value..MUST.end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value1, ++ .length = strlen(value1) ++ }; ++ struct ldb_val value_2 = { ++ .data = (uint8_t *)value2, ++ .length = strlen(value2) ++ }; ++ struct ldb_message_element elements[] = { ++ { ++ .name = "foo", ++ .num_values = 1, ++ .values = &value_1 ++ }, ++ { ++ .name = "bar", ++ .num_values = 1, ++ .values = &value_2 ++ } ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 2, ++ .elements = elements, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ /* Needed as * implies distinguishedName */ ++ filtered_msg->dn = in.dn; ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_non_null(filtered_msg); ++ assert_int_equal(filtered_msg->num_elements, 3); ++ ++ /* ++ * assert the ldb_filter_attrs_in_place does not modify filtered_msg.dn ++ * in this case ++ */ ++ assert_ptr_equal(filtered_msg->dn, in.dn); ++ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ "distinguishedName", ++ NULL), ++ ldb_dn_get_linearized(in.dn)); ++ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ "foo", ++ NULL), ++ value1); ++ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ "bar", ++ NULL), ++ value2); ++} ++ ++/* ++ * Test against a record with only one attribute, matching the * in ++ * the list, but without the DN being pre-filled. Fails due to need ++ * to contstruct the distinguishedName ++ */ ++static void test_filter_attrs_one_attr_matched_star_no_dn(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ const char *attrs[] = {"*", NULL}; ++ ++ char value[] = "The value.......end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value, ++ .length = strlen(value) ++ }; ++ struct ldb_message_element element_1 = { ++ .name = "foo", ++ .num_values = 1, ++ .values = &value_1 ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 1, ++ .elements = &element_1, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ assert_int_equal(ret, -1); ++ assert_null(filtered_msg->elements); ++} ++ ++/* ++ * Test against a record with only one attribute, matching the * in ++ * the list plus requsesting distinguishedName ++ */ ++static void test_filter_attrs_one_attr_matched_star_dn(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ const char *attrs[] = {"*", "distinguishedName", NULL}; ++ ++ char value[] = "The value.......end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value, ++ .length = strlen(value) ++ }; ++ struct ldb_message_element element_1 = { ++ .name = "foo", ++ .num_values = 1, ++ .values = &value_1 ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 1, ++ .elements = &element_1, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ /* Needed for distinguishedName */ ++ filtered_msg->dn = in.dn; ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_non_null(filtered_msg); ++ assert_int_equal(filtered_msg->num_elements, 2); ++ ++ /* show that ldb_filter_attrs_in_place does not modify in.dn */ ++ assert_ptr_equal(filtered_msg->dn, in.dn); ++ ++ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ "distinguishedName", ++ NULL), ++ ldb_dn_get_linearized(in.dn)); ++ assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ "foo", ++ NULL), ++ value); ++} ++ ++/* ++ * Test against a record with only one attribute, but returning ++ * distinguishedName from the list (only) ++ */ ++static void test_filter_attrs_one_attr_matched_dn(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ const char *attrs[] = {"distinguishedName", NULL}; ++ ++ char value[] = "The value.......end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value, ++ .length = strlen(value) ++ }; ++ struct ldb_message_element element_1 = { ++ .name = "foo", ++ .num_values = 1, ++ .values = &value_1 ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 1, ++ .elements = &element_1, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ /* Needed for distinguishedName */ ++ filtered_msg->dn = in.dn; ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_non_null(filtered_msg); ++ assert_int_equal(filtered_msg->num_elements, 1); ++ ++ /* show that ldb_filter_attrs_in_place does not modify in.dn */ ++ assert_ptr_equal(filtered_msg->dn, in.dn); ++ assert_string_equal(filtered_msg->elements[0].name, "distinguishedName"); ++ assert_int_equal(filtered_msg->elements[0].num_values, 1); ++ assert_string_equal(filtered_msg->elements[0].values[0].data, ++ ldb_dn_get_linearized(in.dn)); ++} ++ ++/* ++ * Test against a record with only one attribute, not matching the ++ * empty attribute list ++ */ ++static void test_filter_attrs_one_attr_empty_list(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ int ret; ++ ++ struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ ++ const char *attrs[] = {NULL}; ++ ++ char value[] = "The value.......end"; ++ struct ldb_val value_1 = { ++ .data = (uint8_t *)value, ++ .length = strlen(value) ++ }; ++ struct ldb_message_element element_1 = { ++ .name = "foo", ++ .num_values = 1, ++ .values = &value_1 ++ }; ++ struct ldb_message in = { ++ .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), ++ .num_elements = 1, ++ .elements = &element_1, ++ }; ++ ++ assert_non_null(in.dn); ++ ++ ret = ldb_filter_attrs_in_place(ctx->ldb, ++ &in, ++ attrs, ++ filtered_msg); ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_non_null(filtered_msg); ++ assert_int_equal(filtered_msg->num_elements, 0); ++ assert_null(filtered_msg->dn); ++ assert_null(filtered_msg->elements); ++} ++ ++int main(int argc, const char **argv) ++{ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_one_attr_matched, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_one_attr_matched_of_many, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_two_attr_matched_attrs, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_two_attr_matched_one_attr, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_two_dup_attr_matched_one_attr, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_two_dup_attr_matched_dup, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_two_dup_attr_matched_one_of_two, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_two_dup_attr_matched_star, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_one_attr_matched_star, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_two_attr_matched_star, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_one_attr_matched_star_no_dn, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_one_attr_matched_star_dn, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_one_attr_matched_dn, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_filter_attrs_one_attr_empty_list, ++ setup, ++ teardown), ++ }; ++ ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} +diff --git a/lib/ldb/wscript b/lib/ldb/wscript +index c862229822d..7e02309c1d5 100644 +--- a/lib/ldb/wscript ++++ b/lib/ldb/wscript +@@ -518,6 +518,11 @@ def build(bld): + deps='cmocka ldb ldb_tdb_err_map', + install=False) + ++ bld.SAMBA_BINARY('ldb_filter_attrs_in_place_test', ++ source='tests/ldb_filter_attrs_in_place_test.c', ++ deps='cmocka ldb ldb_tdb_err_map', ++ install=False) ++ + bld.SAMBA_BINARY('ldb_key_value_sub_txn_tdb_test', + bld.SUBDIR('ldb_key_value', + '''ldb_kv_search.c +@@ -638,6 +643,7 @@ def test(ctx): + # 'ldb_key_value_sub_txn_tdb_test' + 'ldb_parse_test', + 'ldb_filter_attrs_test', ++ 'ldb_filter_attrs_in_place_test', + ] + + # if LIB_LDAP and LIB_LBER defined, then we can test ldb_ldap backend +-- +2.25.1 \ No newline at end of file diff --git a/backport-0014-CVE-2023-4154.patch b/backport-0014-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..30425427d74cb7c1d72b91349e9d2135613c9b60 --- /dev/null +++ b/backport-0014-CVE-2023-4154.patch @@ -0,0 +1,71 @@ +From d7ab8d4c2ea390d4d4f9be55f7072fa875457721 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 7 Aug 2023 11:55:55 +1200 +Subject: [PATCH 19/30] CVE-2023-4154 dsdb/tests: Do not run SimpleDirsyncTests + twice + +To re-use setup code, the super-class must have no test_*() methods +otherwise these will be run as well as the class-local tests. + +We rename tests that would otherwise have duplicate names + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Andrew Bartlett + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 19/30] CVE-2023-4154 dsdb/tests: Do not run SimpleDirsyncTests + twice +--- + selftest/knownfail | 2 +- + source4/dsdb/tests/python/dirsync.py | 7 ++----- + 2 files changed, 3 insertions(+), 6 deletions(-) + +diff --git a/selftest/knownfail b/selftest/knownfail +index f9ca4984176..a89616c1dbe 100644 +--- a/selftest/knownfail ++++ b/selftest/knownfail +@@ -151,7 +151,7 @@ + ^samba4.smb2.acls.*.inheritflags + ^samba4.smb2.acls.*.owner + ^samba4.smb2.acls.*.ACCESSBASED +-^samba4.ldap.dirsync.python.ad_dc_ntvfs..__main__.ExtendedDirsyncTests.test_dirsync_deleted_items ++^samba4.ldap.dirsync.python.ad_dc_ntvfs..__main__.SimpleDirsyncTests.test_dirsync_deleted_items_OBJECT_SECURITY + #^samba4.ldap.dirsync.python.ad_dc_ntvfs..__main__.ExtendedDirsyncTests.* + ^samba4.libsmbclient.opendir.(NT1|SMB3).opendir # This requires netbios browsing + ^samba4.rpc.drsuapi.*.drsuapi.DsGetDomainControllerInfo\(.*\)$ +diff --git a/source4/dsdb/tests/python/dirsync.py b/source4/dsdb/tests/python/dirsync.py +index ca0947e2d21..ad136b7efee 100755 +--- a/source4/dsdb/tests/python/dirsync.py ++++ b/source4/dsdb/tests/python/dirsync.py +@@ -458,7 +458,7 @@ class SimpleDirsyncTests(DirsyncBaseTests): + self.assertTrue(res[0].get("name") is not None) + delete_force(self.ldb_admin, ouname) + +- def test_dirsync_linkedattributes(self): ++ def test_dirsync_linkedattributes_OBJECT_SECURITY(self): + """Check that dirsync returned deleted objects too""" + # Let's search for members + self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) +@@ -585,9 +585,6 @@ class SimpleDirsyncTests(DirsyncBaseTests): + expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))", + controls=controls) + +- +-class ExtendedDirsyncTests(SimpleDirsyncTests): +- + def test_dirsync_linkedattributes_range(self): + self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) + res = self.ldb_admin.search(self.base_dn, +@@ -711,7 +708,7 @@ class ExtendedDirsyncTests(SimpleDirsyncTests): + self.assertIn(b"; +Date: Fri, 3 Mar 2023 17:30:19 +1300 +Subject: [PATCH 13/34] CVE-2023-0614 ldb: Make ldb_filter_attrs_in_place() + work in place + +ldb_filter_attrs() previously did too much. Now its replacement, +ldb_filter_attrs_in_place(), only does the actual filtering, while +taking ownership of each element's values is handled in a separate +function, ldb_msg_elements_take_ownership(). + +Also, ldb_filter_attrs_in_place() no longer adds the distinguishedName +to the message if it is missing. That is handled in another function, +ldb_msg_add_distinguished_name(). + +As we're now modifying the original message rather than copying it into +a new one, we no longer need the filtered_msg parameter. + +We adapt a test, based on ldb_filter_attrs_test, to exercise the new +function. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb/common/ldb_pack.c | 129 +--- + lib/ldb/include/ldb_module.h | 11 +- + .../tests/ldb_filter_attrs_in_place_test.c | 609 ++++++++---------- + 3 files changed, 307 insertions(+), 442 deletions(-) + +diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c +index f19ac73fa5e..28b9a8dfe07 100644 +--- a/lib/ldb/common/ldb_pack.c ++++ b/lib/ldb/common/ldb_pack.c +@@ -1264,19 +1264,16 @@ failed: + + /* + * filter the specified list of attributes from msg, +- * adding requested attributes, and perhaps all for *, +- * but not the DN to filtered_msg. ++ * adding requested attributes, and perhaps all for *. ++ * Unlike ldb_filter_attrs(), the DN will not be added ++ * if it is missing. + */ +-int ldb_filter_attrs_in_place(struct ldb_context *ldb, +- const struct ldb_message *msg, +- const char *const *attrs, +- struct ldb_message *filtered_msg) ++int ldb_filter_attrs_in_place(struct ldb_message *msg, ++ const char *const *attrs) + { +- unsigned int i; ++ unsigned int i = 0; + bool keep_all = false; +- bool add_dn = false; +- uint32_t num_elements; +- uint32_t elements_size; ++ unsigned int num_del = 0; + + if (attrs) { + /* check for special attrs */ +@@ -1286,123 +1283,41 @@ int ldb_filter_attrs_in_place(struct ldb_context *ldb, + keep_all = true; + break; + } +- cmp = ldb_attr_cmp(attrs[i], "distinguishedName"); +- if (cmp == 0) { +- add_dn = true; +- } + } +- } else { +- keep_all = true; +- } +- +- if (keep_all) { +- add_dn = true; +- elements_size = msg->num_elements + 1; +- +- /* Shortcuts for the simple cases */ +- } else if (add_dn && i == 1) { +- if (ldb_msg_add_distinguished_name(filtered_msg) != 0) { +- goto failed; ++ if (!keep_all && i == 0) { ++ msg->num_elements = 0; ++ return LDB_SUCCESS; + } +- return 0; +- } else if (i == 0) { +- return 0; +- +- /* +- * Otherwise we are copying at most as many elements as we +- * have attributes +- */ + } else { +- elements_size = i; ++ keep_all = true; + } + +- filtered_msg->elements = talloc_array(filtered_msg, +- struct ldb_message_element, +- elements_size); +- if (filtered_msg->elements == NULL) goto failed; +- +- num_elements = 0; +- + for (i = 0; i < msg->num_elements; i++) { +- struct ldb_message_element *el = &msg->elements[i]; +- +- /* +- * el2 is assigned after the Pigeonhole principle +- * check below for clarity +- */ +- struct ldb_message_element *el2 = NULL; ++ bool found = false; + unsigned int j; + +- if (keep_all == false) { +- bool found = false; ++ if (keep_all) { ++ found = true; ++ } else { + for (j = 0; attrs[j]; j++) { +- int cmp = ldb_attr_cmp(el->name, attrs[j]); ++ int cmp = ldb_attr_cmp(msg->elements[i].name, attrs[j]); + if (cmp == 0) { + found = true; + break; + } + } +- if (found == false) { +- continue; +- } +- } +- +- /* +- * Pigeonhole principle: we can't have more elements +- * than the number of attributes if they are unique in +- * the DB. +- */ +- if (num_elements >= elements_size) { +- goto failed; + } + +- el2 = &filtered_msg->elements[num_elements]; +- +- *el2 = *el; +- el2->name = talloc_strdup(filtered_msg->elements, +- el->name); +- if (el2->name == NULL) { +- goto failed; +- } +- el2->values = talloc_array(filtered_msg->elements, +- struct ldb_val, el->num_values); +- if (el2->values == NULL) { +- goto failed; ++ if (!found) { ++ ++num_del; ++ } else if (num_del != 0) { ++ msg->elements[i - num_del] = msg->elements[i]; + } +- for (j=0;jnum_values;j++) { +- el2->values[j] = ldb_val_dup(el2->values, &el->values[j]); +- if (el2->values[j].data == NULL && el->values[j].length != 0) { +- goto failed; +- } +- } +- num_elements++; + } + +- filtered_msg->num_elements = num_elements; +- +- if (add_dn) { +- if (ldb_msg_add_distinguished_name(filtered_msg) != 0) { +- goto failed; +- } +- } ++ msg->num_elements -= num_del; + +- if (filtered_msg->num_elements > 0) { +- filtered_msg->elements +- = talloc_realloc(filtered_msg, +- filtered_msg->elements, +- struct ldb_message_element, +- filtered_msg->num_elements); +- if (filtered_msg->elements == NULL) { +- goto failed; +- } +- } else { +- TALLOC_FREE(filtered_msg->elements); +- } +- +- return 0; +-failed: +- TALLOC_FREE(filtered_msg->elements); +- return -1; ++ return LDB_SUCCESS; + } + + /* Have an unpacked ldb message take talloc ownership of its elements. */ +diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h +index 105093cf38c..4ae381ba5be 100644 +--- a/lib/ldb/include/ldb_module.h ++++ b/lib/ldb/include/ldb_module.h +@@ -545,13 +545,12 @@ int ldb_filter_attrs(struct ldb_context *ldb, + + /* + * filter the specified list of attributes from msg, +- * adding requested attributes, and perhaps all for *, +- * but not the DN to filtered_msg. ++ * adding requested attributes, and perhaps all for *. ++ * Unlike ldb_filter_attrs(), the DN will not be added ++ * if it is missing. + */ +-int ldb_filter_attrs_in_place(struct ldb_context *ldb, +- const struct ldb_message *msg, +- const char *const *attrs, +- struct ldb_message *filtered_msg); ++int ldb_filter_attrs_in_place(struct ldb_message *msg, ++ const char *const *attrs); + + /* Have an unpacked ldb message take talloc ownership of its elements. */ + int ldb_msg_elements_take_ownership(struct ldb_message *msg); +diff --git a/lib/ldb/tests/ldb_filter_attrs_in_place_test.c b/lib/ldb/tests/ldb_filter_attrs_in_place_test.c +index bef961f8f9c..da333c73c99 100644 +--- a/lib/ldb/tests/ldb_filter_attrs_in_place_test.c ++++ b/lib/ldb/tests/ldb_filter_attrs_in_place_test.c +@@ -83,17 +83,41 @@ static int teardown(void **state) + return 0; + } + ++static void msg_add_dn(struct ldb_message *msg) ++{ ++ const char *dn_attr = "distinguishedName"; ++ char *dn = NULL; ++ int ret; ++ ++ assert_null(ldb_msg_find_element(msg, dn_attr)); ++ ++ assert_non_null(msg->dn); ++ dn = ldb_dn_alloc_linearized(msg, msg->dn); ++ assert_non_null(dn); ++ ++ /* ++ * The message's elements must be talloc allocated to call ++ * ldb_msg_add_steal_string(). ++ */ ++ msg->elements = talloc_memdup(msg, ++ msg->elements, ++ msg->num_elements * sizeof(msg->elements[0])); ++ assert_non_null(msg->elements); ++ ++ ret = ldb_msg_add_steal_string(msg, dn_attr, dn); ++ assert_int_equal(ret, LDB_SUCCESS); ++} + + /* + * Test against a record with only one attribute, matching the one in + * the list + */ +-static void test_filter_attrs_one_attr_matched(void **state) ++static void test_filter_attrs_in_place_one_attr_matched(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + + const char *attrs[] = {"foo", NULL}; + +@@ -107,32 +131,25 @@ static void test_filter_attrs_one_attr_matched(void **state) + .num_values = 1, + .values = &value_1 + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 1, +- .elements = &element_1, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 1; ++ msg->elements = &element_1; + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); ++ ++ ret = ldb_filter_attrs_in_place(msg, attrs); + assert_int_equal(ret, LDB_SUCCESS); +- assert_non_null(filtered_msg); + +- /* +- * assert the ldb_filter_attrs_in_place does not read or modify +- * filtered_msg.dn in this case +- */ +- assert_null(filtered_msg->dn); +- assert_int_equal(filtered_msg->num_elements, 1); +- assert_string_equal(filtered_msg->elements[0].name, "foo"); +- assert_int_equal(filtered_msg->elements[0].num_values, 1); +- assert_int_equal(filtered_msg->elements[0].values[0].length, ++ assert_non_null(msg->dn); ++ assert_int_equal(msg->num_elements, 1); ++ assert_string_equal(msg->elements[0].name, "foo"); ++ assert_int_equal(msg->elements[0].num_values, 1); ++ assert_int_equal(msg->elements[0].values[0].length, + strlen(value)); +- assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ assert_memory_equal(msg->elements[0].values[0].data, + value, strlen(value)); + } + +@@ -140,12 +157,12 @@ static void test_filter_attrs_one_attr_matched(void **state) + * Test against a record with only one attribute, matching the one of + * the multiple attributes in the list + */ +-static void test_filter_attrs_one_attr_matched_of_many(void **state) ++static void test_filter_attrs_in_place_one_attr_matched_of_many(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + + const char *attrs[] = {"foo", "bar", "baz", NULL}; + +@@ -159,32 +176,25 @@ static void test_filter_attrs_one_attr_matched_of_many(void **state) + .num_values = 1, + .values = &value_1 + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 1, +- .elements = &element_1, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 1; ++ msg->elements = &element_1; + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); ++ ++ ret = ldb_filter_attrs_in_place(msg, attrs); + assert_int_equal(ret, LDB_SUCCESS); +- assert_non_null(filtered_msg); + +- /* +- * assert the ldb_filter_attrs_in_place does not read or modify +- * filtered_msg.dn in this case +- */ +- assert_null(filtered_msg->dn); +- assert_int_equal(filtered_msg->num_elements, 1); +- assert_string_equal(filtered_msg->elements[0].name, "foo"); +- assert_int_equal(filtered_msg->elements[0].num_values, 1); +- assert_int_equal(filtered_msg->elements[0].values[0].length, ++ assert_non_null(msg->dn); ++ assert_int_equal(msg->num_elements, 1); ++ assert_string_equal(msg->elements[0].name, "foo"); ++ assert_int_equal(msg->elements[0].num_values, 1); ++ assert_int_equal(msg->elements[0].values[0].length, + strlen(value)); +- assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ assert_memory_equal(msg->elements[0].values[0].data, + value, strlen(value)); + } + +@@ -192,12 +202,12 @@ static void test_filter_attrs_one_attr_matched_of_many(void **state) + * Test against a record with only one attribute, matching both + * attributes in the list + */ +-static void test_filter_attrs_two_attr_matched_attrs(void **state) ++static void test_filter_attrs_in_place_two_attr_matched_attrs(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + + /* deliberatly the other order */ + const char *attrs[] = {"bar", "foo", NULL}; +@@ -226,40 +236,33 @@ static void test_filter_attrs_two_attr_matched_attrs(void **state) + .values = &value_2 + } + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 2, +- .elements = elements, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 2; ++ msg->elements = elements; + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); ++ ++ ret = ldb_filter_attrs_in_place(msg, attrs); + assert_int_equal(ret, LDB_SUCCESS); +- assert_non_null(filtered_msg); +- assert_int_equal(filtered_msg->num_elements, 2); ++ assert_int_equal(msg->num_elements, 2); + +- /* +- * assert the ldb_filter_attrs_in_place does not read or modify +- * filtered_msg.dn in this case +- */ +- assert_null(filtered_msg->dn); ++ assert_non_null(msg->dn); + + /* Assert that DB order is preserved */ +- assert_string_equal(filtered_msg->elements[0].name, "foo"); +- assert_int_equal(filtered_msg->elements[0].num_values, 1); +- assert_int_equal(filtered_msg->elements[0].values[0].length, ++ assert_string_equal(msg->elements[0].name, "foo"); ++ assert_int_equal(msg->elements[0].num_values, 1); ++ assert_int_equal(msg->elements[0].values[0].length, + strlen(value1)); +- assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ assert_memory_equal(msg->elements[0].values[0].data, + value1, strlen(value1)); +- assert_string_equal(filtered_msg->elements[1].name, "bar"); +- assert_int_equal(filtered_msg->elements[1].num_values, 1); +- assert_int_equal(filtered_msg->elements[1].values[0].length, ++ assert_string_equal(msg->elements[1].name, "bar"); ++ assert_int_equal(msg->elements[1].num_values, 1); ++ assert_int_equal(msg->elements[1].values[0].length, + strlen(value2)); +- assert_memory_equal(filtered_msg->elements[1].values[0].data, ++ assert_memory_equal(msg->elements[1].values[0].data, + value2, strlen(value2)); + } + +@@ -267,14 +270,13 @@ static void test_filter_attrs_two_attr_matched_attrs(void **state) + * Test against a record with two attributes, only of which is in + * the list + */ +-static void test_filter_attrs_two_attr_matched_one_attr(void **state) ++static void test_filter_attrs_in_place_two_attr_matched_one_attr(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + +- /* deliberatly the other order */ + const char *attrs[] = {"bar", NULL}; + + char value1[] = "The value.......end"; +@@ -288,7 +290,6 @@ static void test_filter_attrs_two_attr_matched_one_attr(void **state) + .length = strlen(value2) + }; + +- /* foo and bar are the other order to in attrs */ + struct ldb_message_element elements[] = { + { + .name = "foo", +@@ -301,34 +302,27 @@ static void test_filter_attrs_two_attr_matched_one_attr(void **state) + .values = &value_2 + } + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 2, +- .elements = elements, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 2; ++ msg->elements = elements; + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); ++ ++ ret = ldb_filter_attrs_in_place(msg, attrs); + assert_int_equal(ret, LDB_SUCCESS); +- assert_non_null(filtered_msg); +- assert_int_equal(filtered_msg->num_elements, 1); ++ assert_int_equal(msg->num_elements, 1); + +- /* +- * assert the ldb_filter_attrs_in_place does not read or modify +- * filtered_msg.dn in this case +- */ +- assert_null(filtered_msg->dn); ++ assert_non_null(msg->dn); + + /* Assert that DB order is preserved */ +- assert_string_equal(filtered_msg->elements[0].name, "bar"); +- assert_int_equal(filtered_msg->elements[0].num_values, 1); +- assert_int_equal(filtered_msg->elements[0].values[0].length, ++ assert_string_equal(msg->elements[0].name, "bar"); ++ assert_int_equal(msg->elements[0].num_values, 1); ++ assert_int_equal(msg->elements[0].values[0].length, + strlen(value2)); +- assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ assert_memory_equal(msg->elements[0].values[0].data, + value2, strlen(value2)); + } + +@@ -336,14 +330,13 @@ static void test_filter_attrs_two_attr_matched_one_attr(void **state) + * Test against a record with two attributes, both matching the one + * specified attribute in the list (a corrupt record) + */ +-static void test_filter_attrs_two_dup_attr_matched_one_attr(void **state) ++static void test_filter_attrs_in_place_two_dup_attr_matched_one_attr(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + +- /* deliberatly the other order */ + const char *attrs[] = {"bar", NULL}; + + char value1[] = "The value.......end"; +@@ -357,7 +350,6 @@ static void test_filter_attrs_two_dup_attr_matched_one_attr(void **state) + .length = strlen(value2) + }; + +- /* foo and bar are the other order to in attrs */ + struct ldb_message_element elements[] = { + { + .name = "bar", +@@ -370,34 +362,49 @@ static void test_filter_attrs_two_dup_attr_matched_one_attr(void **state) + .values = &value_2 + } + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 2, +- .elements = elements, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 2; ++ msg->elements = elements; ++ ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); ++ ++ ret = ldb_filter_attrs_in_place(msg, attrs); + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ /* Both elements match the filter */ ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_int_equal(msg->num_elements, 2); ++ ++ assert_non_null(msg->dn); + +- /* This should fail the pidgenhole test */ +- assert_int_equal(ret, -1); +- assert_null(filtered_msg->elements); ++ /* Assert that DB order is preserved */ ++ assert_string_equal(msg->elements[0].name, "bar"); ++ assert_int_equal(msg->elements[0].num_values, 1); ++ assert_int_equal(msg->elements[0].values[0].length, ++ strlen(value1)); ++ assert_memory_equal(msg->elements[0].values[0].data, ++ value1, strlen(value1)); ++ ++ assert_string_equal(msg->elements[1].name, "bar"); ++ assert_int_equal(msg->elements[1].num_values, 1); ++ assert_int_equal(msg->elements[1].values[0].length, ++ strlen(value2)); ++ assert_memory_equal(msg->elements[1].values[0].data, ++ value2, strlen(value2)); + } + + /* + * Test against a record with two attributes, both matching the one + * specified attribute in the list (a corrupt record) + */ +-static void test_filter_attrs_two_dup_attr_matched_dup(void **state) ++static void test_filter_attrs_in_place_two_dup_attr_matched_dup(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + + const char *attrs[] = {"bar", "bar", NULL}; + +@@ -412,7 +419,6 @@ static void test_filter_attrs_two_dup_attr_matched_dup(void **state) + .length = strlen(value2) + }; + +- /* foo and bar are the other order to in attrs */ + struct ldb_message_element elements[] = { + { + .name = "bar", +@@ -425,35 +431,33 @@ static void test_filter_attrs_two_dup_attr_matched_dup(void **state) + .values = &value_2 + } + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 2, +- .elements = elements, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 2; ++ msg->elements = elements; ++ ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ ret = ldb_filter_attrs_in_place(msg, attrs); + + /* This does not fail the pidgenhole test */ + assert_int_equal(ret, LDB_SUCCESS); +- assert_int_equal(filtered_msg->num_elements, 2); ++ assert_int_equal(msg->num_elements, 2); + + /* Assert that DB order is preserved */ +- assert_string_equal(filtered_msg->elements[0].name, "bar"); +- assert_int_equal(filtered_msg->elements[0].num_values, 1); +- assert_int_equal(filtered_msg->elements[0].values[0].length, ++ assert_string_equal(msg->elements[0].name, "bar"); ++ assert_int_equal(msg->elements[0].num_values, 1); ++ assert_int_equal(msg->elements[0].values[0].length, + strlen(value1)); +- assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ assert_memory_equal(msg->elements[0].values[0].data, + value1, strlen(value1)); +- assert_string_equal(filtered_msg->elements[1].name, "bar"); +- assert_int_equal(filtered_msg->elements[1].num_values, 1); +- assert_int_equal(filtered_msg->elements[1].values[0].length, ++ assert_string_equal(msg->elements[1].name, "bar"); ++ assert_int_equal(msg->elements[1].num_values, 1); ++ assert_int_equal(msg->elements[1].values[0].length, + strlen(value2)); +- assert_memory_equal(filtered_msg->elements[1].values[0].data, ++ assert_memory_equal(msg->elements[1].values[0].data, + value2, strlen(value2)); + } + +@@ -461,12 +465,12 @@ static void test_filter_attrs_two_dup_attr_matched_dup(void **state) + * Test against a record with two attributes, both matching one of the + * specified attributes in the list (a corrupt record) + */ +-static void test_filter_attrs_two_dup_attr_matched_one_of_two(void **state) ++static void test_filter_attrs_in_place_two_dup_attr_matched_one_of_two(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + + const char *attrs[] = {"bar", "foo", NULL}; + +@@ -481,7 +485,6 @@ static void test_filter_attrs_two_dup_attr_matched_one_of_two(void **state) + .length = strlen(value2) + }; + +- /* foo and bar are the other order to in attrs */ + struct ldb_message_element elements[] = { + { + .name = "bar", +@@ -494,35 +497,33 @@ static void test_filter_attrs_two_dup_attr_matched_one_of_two(void **state) + .values = &value_2 + } + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 2, +- .elements = elements, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 2; ++ msg->elements = elements; + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); ++ ++ ret = ldb_filter_attrs_in_place(msg, attrs); + + /* This does not fail the pidgenhole test */ + assert_int_equal(ret, LDB_SUCCESS); +- assert_int_equal(filtered_msg->num_elements, 2); ++ assert_int_equal(msg->num_elements, 2); + + /* Assert that DB order is preserved */ +- assert_string_equal(filtered_msg->elements[0].name, "bar"); +- assert_int_equal(filtered_msg->elements[0].num_values, 1); +- assert_int_equal(filtered_msg->elements[0].values[0].length, ++ assert_string_equal(msg->elements[0].name, "bar"); ++ assert_int_equal(msg->elements[0].num_values, 1); ++ assert_int_equal(msg->elements[0].values[0].length, + strlen(value1)); +- assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ assert_memory_equal(msg->elements[0].values[0].data, + value1, strlen(value1)); +- assert_string_equal(filtered_msg->elements[1].name, "bar"); +- assert_int_equal(filtered_msg->elements[1].num_values, 1); +- assert_int_equal(filtered_msg->elements[1].values[0].length, ++ assert_string_equal(msg->elements[1].name, "bar"); ++ assert_int_equal(msg->elements[1].num_values, 1); ++ assert_int_equal(msg->elements[1].values[0].length, + strlen(value2)); +- assert_memory_equal(filtered_msg->elements[1].values[0].data, ++ assert_memory_equal(msg->elements[1].values[0].data, + value2, strlen(value2)); + } + +@@ -530,12 +531,12 @@ static void test_filter_attrs_two_dup_attr_matched_one_of_two(void **state) + * Test against a record with two attributes against * (but not the + * other named attribute) (a corrupt record) + */ +-static void test_filter_attrs_two_dup_attr_matched_star(void **state) ++static void test_filter_attrs_in_place_two_dup_attr_matched_star(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + + const char *attrs[] = {"*", "foo", NULL}; + +@@ -550,7 +551,6 @@ static void test_filter_attrs_two_dup_attr_matched_star(void **state) + .length = strlen(value2) + }; + +- /* foo and bar are the other order to in attrs */ + struct ldb_message_element elements[] = { + { + .name = "bar", +@@ -563,60 +563,52 @@ static void test_filter_attrs_two_dup_attr_matched_star(void **state) + .values = &value_2 + } + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 2, +- .elements = elements, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 2; ++ msg->elements = elements; + +- /* Needed as * implies distinguishedName */ +- filtered_msg->dn = in.dn; ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ ret = ldb_filter_attrs_in_place(msg, attrs); + + /* This does not fail the pidgenhole test */ + assert_int_equal(ret, LDB_SUCCESS); +- assert_int_equal(filtered_msg->num_elements, 3); ++ assert_int_equal(msg->num_elements, 3); + + /* Assert that DB order is preserved */ +- assert_string_equal(filtered_msg->elements[0].name, "bar"); +- assert_int_equal(filtered_msg->elements[0].num_values, 1); +- assert_int_equal(filtered_msg->elements[0].values[0].length, ++ assert_string_equal(msg->elements[0].name, "bar"); ++ assert_int_equal(msg->elements[0].num_values, 1); ++ assert_int_equal(msg->elements[0].values[0].length, + strlen(value1)); +- assert_memory_equal(filtered_msg->elements[0].values[0].data, ++ assert_memory_equal(msg->elements[0].values[0].data, + value1, strlen(value1)); +- assert_string_equal(filtered_msg->elements[1].name, "bar"); +- assert_int_equal(filtered_msg->elements[1].num_values, 1); +- assert_int_equal(filtered_msg->elements[1].values[0].length, ++ assert_string_equal(msg->elements[1].name, "bar"); ++ assert_int_equal(msg->elements[1].num_values, 1); ++ assert_int_equal(msg->elements[1].values[0].length, + strlen(value2)); +- assert_memory_equal(filtered_msg->elements[1].values[0].data, ++ assert_memory_equal(msg->elements[1].values[0].data, + value2, strlen(value2)); +- /* +- * assert the ldb_filter_attrs_in_place does not modify filtered_msg.dn +- * in this case +- */ +- assert_ptr_equal(filtered_msg->dn, in.dn); +- assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ ++ assert_non_null(msg->dn); ++ assert_string_equal(ldb_msg_find_attr_as_string(msg, + "distinguishedName", + NULL), +- ldb_dn_get_linearized(in.dn)); ++ ldb_dn_get_linearized(msg->dn)); + } + + /* + * Test against a record with only one attribute, matching the * in + * the list + */ +-static void test_filter_attrs_one_attr_matched_star(void **state) ++static void test_filter_attrs_in_place_one_attr_matched_star(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + + const char *attrs[] = {"*", NULL}; + +@@ -630,35 +622,25 @@ static void test_filter_attrs_one_attr_matched_star(void **state) + .num_values = 1, + .values = &value_1 + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 1, +- .elements = &element_1, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 1; ++ msg->elements = &element_1; + +- /* Needed as * implies distinguishedName */ +- filtered_msg->dn = in.dn; ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ ret = ldb_filter_attrs_in_place(msg, attrs); + assert_int_equal(ret, LDB_SUCCESS); +- assert_non_null(filtered_msg); +- assert_int_equal(filtered_msg->num_elements, 2); ++ assert_int_equal(msg->num_elements, 2); + +- /* +- * assert the ldb_filter_attrs_in_place does not modify filtered_msg.dn +- * in this case +- */ +- assert_ptr_equal(filtered_msg->dn, in.dn); +- assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ assert_non_null(msg->dn); ++ assert_string_equal(ldb_msg_find_attr_as_string(msg, + "distinguishedName", + NULL), +- ldb_dn_get_linearized(in.dn)); +- assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ ldb_dn_get_linearized(msg->dn)); ++ assert_string_equal(ldb_msg_find_attr_as_string(msg, + "foo", + NULL), + value); +@@ -668,12 +650,12 @@ static void test_filter_attrs_one_attr_matched_star(void **state) + * Test against a record with two attributes, matching the * in + * the list + */ +-static void test_filter_attrs_two_attr_matched_star(void **state) ++static void test_filter_attrs_in_place_two_attr_matched_star(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + + const char *attrs[] = {"*", NULL}; + +@@ -699,39 +681,29 @@ static void test_filter_attrs_two_attr_matched_star(void **state) + .values = &value_2 + } + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 2, +- .elements = elements, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 2; ++ msg->elements = elements; + +- /* Needed as * implies distinguishedName */ +- filtered_msg->dn = in.dn; ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ ret = ldb_filter_attrs_in_place(msg, attrs); + assert_int_equal(ret, LDB_SUCCESS); +- assert_non_null(filtered_msg); +- assert_int_equal(filtered_msg->num_elements, 3); ++ assert_int_equal(msg->num_elements, 3); + +- /* +- * assert the ldb_filter_attrs_in_place does not modify filtered_msg.dn +- * in this case +- */ +- assert_ptr_equal(filtered_msg->dn, in.dn); +- assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ assert_non_null(msg->dn); ++ assert_string_equal(ldb_msg_find_attr_as_string(msg, + "distinguishedName", + NULL), +- ldb_dn_get_linearized(in.dn)); +- assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ ldb_dn_get_linearized(msg->dn)); ++ assert_string_equal(ldb_msg_find_attr_as_string(msg, + "foo", + NULL), + value1); +- assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ assert_string_equal(ldb_msg_find_attr_as_string(msg, + "bar", + NULL), + value2); +@@ -739,15 +711,15 @@ static void test_filter_attrs_two_attr_matched_star(void **state) + + /* + * Test against a record with only one attribute, matching the * in +- * the list, but without the DN being pre-filled. Fails due to need +- * to contstruct the distinguishedName ++ * the list, but without the DN being pre-filled. Succeeds, but the ++ * distinguishedName is not added. + */ +-static void test_filter_attrs_one_attr_matched_star_no_dn(void **state) ++static void test_filter_attrs_in_place_one_attr_matched_star_no_dn(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + + const char *attrs[] = {"*", NULL}; + +@@ -761,32 +733,29 @@ static void test_filter_attrs_one_attr_matched_star_no_dn(void **state) + .num_values = 1, + .values = &value_1 + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 1, +- .elements = &element_1, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = NULL; ++ msg->num_elements = 1; ++ msg->elements = &element_1; ++ ++ assert_null(msg->dn); + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); +- assert_int_equal(ret, -1); +- assert_null(filtered_msg->elements); ++ ret = ldb_filter_attrs_in_place(msg, attrs); ++ assert_int_equal(ret, LDB_SUCCESS); ++ assert_int_equal(msg->num_elements, 1); + } + + /* + * Test against a record with only one attribute, matching the * in + * the list plus requsesting distinguishedName + */ +-static void test_filter_attrs_one_attr_matched_star_dn(void **state) ++static void test_filter_attrs_in_place_one_attr_matched_star_dn(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + + const char *attrs[] = {"*", "distinguishedName", NULL}; + +@@ -800,33 +769,26 @@ static void test_filter_attrs_one_attr_matched_star_dn(void **state) + .num_values = 1, + .values = &value_1 + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 1, +- .elements = &element_1, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 1; ++ msg->elements = &element_1; + +- /* Needed for distinguishedName */ +- filtered_msg->dn = in.dn; ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ ret = ldb_filter_attrs_in_place(msg, attrs); + assert_int_equal(ret, LDB_SUCCESS); +- assert_non_null(filtered_msg); +- assert_int_equal(filtered_msg->num_elements, 2); ++ assert_int_equal(msg->num_elements, 2); + +- /* show that ldb_filter_attrs_in_place does not modify in.dn */ +- assert_ptr_equal(filtered_msg->dn, in.dn); ++ assert_non_null(msg->dn); + +- assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ assert_string_equal(ldb_msg_find_attr_as_string(msg, + "distinguishedName", + NULL), +- ldb_dn_get_linearized(in.dn)); +- assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, ++ ldb_dn_get_linearized(msg->dn)); ++ assert_string_equal(ldb_msg_find_attr_as_string(msg, + "foo", + NULL), + value); +@@ -836,12 +798,12 @@ static void test_filter_attrs_one_attr_matched_star_dn(void **state) + * Test against a record with only one attribute, but returning + * distinguishedName from the list (only) + */ +-static void test_filter_attrs_one_attr_matched_dn(void **state) ++static void test_filter_attrs_in_place_one_attr_matched_dn(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + + const char *attrs[] = {"distinguishedName", NULL}; + +@@ -855,43 +817,36 @@ static void test_filter_attrs_one_attr_matched_dn(void **state) + .num_values = 1, + .values = &value_1 + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 1, +- .elements = &element_1, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 1; ++ msg->elements = &element_1; + +- /* Needed for distinguishedName */ +- filtered_msg->dn = in.dn; ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ ret = ldb_filter_attrs_in_place(msg, attrs); + assert_int_equal(ret, LDB_SUCCESS); +- assert_non_null(filtered_msg); +- assert_int_equal(filtered_msg->num_elements, 1); +- +- /* show that ldb_filter_attrs_in_place does not modify in.dn */ +- assert_ptr_equal(filtered_msg->dn, in.dn); +- assert_string_equal(filtered_msg->elements[0].name, "distinguishedName"); +- assert_int_equal(filtered_msg->elements[0].num_values, 1); +- assert_string_equal(filtered_msg->elements[0].values[0].data, +- ldb_dn_get_linearized(in.dn)); ++ assert_int_equal(msg->num_elements, 1); ++ ++ assert_non_null(msg->dn); ++ assert_string_equal(msg->elements[0].name, "distinguishedName"); ++ assert_int_equal(msg->elements[0].num_values, 1); ++ assert_string_equal(msg->elements[0].values[0].data, ++ ldb_dn_get_linearized(msg->dn)); + } + + /* + * Test against a record with only one attribute, not matching the + * empty attribute list + */ +-static void test_filter_attrs_one_attr_empty_list(void **state) ++static void test_filter_attrs_in_place_one_attr_empty_list(void **state) + { + struct ldbtest_ctx *ctx = *state; + int ret; + +- struct ldb_message *filtered_msg = ldb_msg_new(ctx); ++ struct ldb_message *msg = ldb_msg_new(ctx); + + const char *attrs[] = {NULL}; + +@@ -905,82 +860,78 @@ static void test_filter_attrs_one_attr_empty_list(void **state) + .num_values = 1, + .values = &value_1 + }; +- struct ldb_message in = { +- .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), +- .num_elements = 1, +- .elements = &element_1, +- }; + +- assert_non_null(in.dn); ++ assert_non_null(msg); ++ msg->dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"); ++ msg->num_elements = 1; ++ msg->elements = &element_1; ++ ++ assert_non_null(msg->dn); ++ msg_add_dn(msg); + +- ret = ldb_filter_attrs_in_place(ctx->ldb, +- &in, +- attrs, +- filtered_msg); ++ ret = ldb_filter_attrs_in_place(msg, attrs); + assert_int_equal(ret, LDB_SUCCESS); +- assert_non_null(filtered_msg); +- assert_int_equal(filtered_msg->num_elements, 0); +- assert_null(filtered_msg->dn); +- assert_null(filtered_msg->elements); ++ assert_int_equal(msg->num_elements, 0); ++ assert_non_null(msg->dn); + } + + int main(int argc, const char **argv) + { + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown( +- test_filter_attrs_one_attr_matched, ++ test_filter_attrs_in_place_one_attr_matched, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_one_attr_matched_of_many, ++ test_filter_attrs_in_place_one_attr_matched_of_many, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_two_attr_matched_attrs, ++ test_filter_attrs_in_place_two_attr_matched_attrs, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_two_attr_matched_one_attr, ++ test_filter_attrs_in_place_two_attr_matched_one_attr, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_two_dup_attr_matched_one_attr, ++ test_filter_attrs_in_place_two_dup_attr_matched_one_attr, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_two_dup_attr_matched_dup, ++ test_filter_attrs_in_place_two_dup_attr_matched_dup, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_two_dup_attr_matched_one_of_two, ++ test_filter_attrs_in_place_two_dup_attr_matched_one_of_two, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_two_dup_attr_matched_star, ++ test_filter_attrs_in_place_two_dup_attr_matched_star, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_one_attr_matched_star, ++ test_filter_attrs_in_place_one_attr_matched_star, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_two_attr_matched_star, ++ test_filter_attrs_in_place_two_attr_matched_star, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_one_attr_matched_star_no_dn, ++ test_filter_attrs_in_place_one_attr_matched_star_no_dn, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_one_attr_matched_star_dn, ++ test_filter_attrs_in_place_one_attr_matched_star_dn, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_one_attr_matched_dn, ++ test_filter_attrs_in_place_one_attr_matched_dn, + setup, + teardown), + cmocka_unit_test_setup_teardown( +- test_filter_attrs_one_attr_empty_list, ++ test_filter_attrs_in_place_one_attr_empty_list, + setup, + teardown), + }; +-- +2.25.1 \ No newline at end of file diff --git a/backport-0015-CVE-2023-4154.patch b/backport-0015-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..3a5ae6e74761ad7f919a6dc7f8261b41d87db3ad --- /dev/null +++ b/backport-0015-CVE-2023-4154.patch @@ -0,0 +1,80 @@ +From 23b867c70bd995ca6eedcf0b72a24c043e8e7fb0 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 7 Aug 2023 13:15:40 +1200 +Subject: [PATCH 20/30] CVE-2023-4154 dsdb/tests: Use self.addCleanup() and + delete_force() + +Thie helps ensure this test is reliable even in spite of errors while +running. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Andrew Bartlett + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 20/30] CVE-2023-4154 dsdb/tests: Use self.addCleanup() and + delete_force() +--- + source4/dsdb/tests/python/confidential_attr.py | 6 ++---- + source4/dsdb/tests/python/dirsync.py | 6 +----- + 2 files changed, 3 insertions(+), 9 deletions(-) + +diff --git a/source4/dsdb/tests/python/confidential_attr.py b/source4/dsdb/tests/python/confidential_attr.py +index 8ca56bd1023..3997848f8f9 100755 +--- a/source4/dsdb/tests/python/confidential_attr.py ++++ b/source4/dsdb/tests/python/confidential_attr.py +@@ -98,7 +98,9 @@ class ConfidentialAttrCommon(samba.tests.TestCase): + + userou = "OU=conf-attr-test" + self.ou = "{0},{1}".format(userou, self.base_dn) ++ samba.tests.delete_force(self.ldb_admin, self.ou, controls=['tree_delete:1']) + self.ldb_admin.create_ou(self.ou) ++ self.addCleanup(samba.tests.delete_force, self.ldb_admin, self.ou, controls=['tree_delete:1']) + + # use a common username prefix, so we can use sAMAccountName=CATC-* as + # a search filter to only return the users we're interested in +@@ -139,10 +141,6 @@ class ConfidentialAttrCommon(samba.tests.TestCase): + "{0} searchFlags already {1}".format(self.conf_attr, + search_flags)) + +- def tearDown(self): +- super(ConfidentialAttrCommon, self).tearDown() +- self.ldb_admin.delete(self.ou, ["tree_delete:1"]) +- + def add_attr(self, dn, attr, value): + m = Message() + m.dn = Dn(self.ldb_admin, dn) +diff --git a/source4/dsdb/tests/python/dirsync.py b/source4/dsdb/tests/python/dirsync.py +index ad136b7efee..e06b85bc749 100755 +--- a/source4/dsdb/tests/python/dirsync.py ++++ b/source4/dsdb/tests/python/dirsync.py +@@ -137,10 +137,6 @@ class SimpleDirsyncTests(DirsyncBaseTests): + if self.ouname: + delete_force(self.ldb_admin, self.ouname) + self.sd_utils.modify_sd_on_dn(self.base_dn, self.desc_sddl) +- try: +- self.ldb_admin.deletegroup("testgroup") +- except Exception: +- pass + + # def test_dirsync_errors(self): + +@@ -499,6 +495,7 @@ class SimpleDirsyncTests(DirsyncBaseTests): + self.assertEqual(len(res[0].get("member")), size) + + self.ldb_admin.newgroup("testgroup") ++ self.addCleanup(self.ldb_admin.deletegroup, "testgroup") + self.ldb_admin.add_remove_group_members("testgroup", [self.simple_user], + add_members_operation=True) + +@@ -537,7 +534,6 @@ class SimpleDirsyncTests(DirsyncBaseTests): + attrs=["member"], + controls=[control1]) + +- self.ldb_admin.deletegroup("testgroup") + self.assertEqual(len(res[0].get("member")), 0) + + def test_dirsync_deleted_items(self): +-- +2.34.1 diff --git a/backport-0016-CVE-2023-0614.patch b/backport-0016-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..0b8c1d8f549dff003402b0261c9e11b51990704e --- /dev/null +++ b/backport-0016-CVE-2023-0614.patch @@ -0,0 +1,293 @@ +From 8e84201f508b2893b6ec9383c656cccb08b148ef Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Mon, 27 Feb 2023 10:31:52 +1300 +Subject: [PATCH 14/34] CVE-2023-0614 ldb: Make use of + ldb_filter_attrs_in_place() + +Change all uses of ldb_kv_filter_attrs() to use +ldb_filter_attrs_in_place() instead. This function does less work than +its predecessor, and no longer requires the allocation of a second ldb +message. Some of the work is able to be split out into separate +functions that each accomplish a single task, with a purpose to make the +code clearer. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb/ldb_key_value/ldb_kv.h | 6 +- + lib/ldb/ldb_key_value/ldb_kv_index.c | 27 +++++---- + lib/ldb/ldb_key_value/ldb_kv_search.c | 86 ++++++++++++++------------- + source4/torture/ldb/ldb.c | 12 ++-- + 4 files changed, 66 insertions(+), 65 deletions(-) + +diff --git a/lib/ldb/ldb_key_value/ldb_kv.h b/lib/ldb/ldb_key_value/ldb_kv.h +index ac474b04b4c..7d5a40e76e9 100644 +--- a/lib/ldb/ldb_key_value/ldb_kv.h ++++ b/lib/ldb/ldb_key_value/ldb_kv.h +@@ -301,10 +301,8 @@ int ldb_kv_search_key(struct ldb_module *module, + const struct ldb_val ldb_key, + struct ldb_message *msg, + unsigned int unpack_flags); +-int ldb_kv_filter_attrs(struct ldb_context *ldb, +- const struct ldb_message *msg, +- const char *const *attrs, +- struct ldb_message *filtered_msg); ++int ldb_kv_filter_attrs_in_place(struct ldb_message *msg, ++ const char *const *attrs); + int ldb_kv_search(struct ldb_kv_context *ctx); + + /* +diff --git a/lib/ldb/ldb_key_value/ldb_kv_index.c b/lib/ldb/ldb_key_value/ldb_kv_index.c +index d70e5f619ef..203266ea8c9 100644 +--- a/lib/ldb/ldb_key_value/ldb_kv_index.c ++++ b/lib/ldb/ldb_key_value/ldb_kv_index.c +@@ -2264,7 +2264,6 @@ static int ldb_kv_index_filter(struct ldb_kv_private *ldb_kv, + { + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + struct ldb_message *msg; +- struct ldb_message *filtered_msg; + unsigned int i; + unsigned int num_keys = 0; + uint8_t previous_guid_key[LDB_KV_GUID_KEY_SIZE] = {0}; +@@ -2456,27 +2455,31 @@ static int ldb_kv_index_filter(struct ldb_kv_private *ldb_kv, + continue; + } + +- filtered_msg = ldb_msg_new(ac); +- if (filtered_msg == NULL) { +- TALLOC_FREE(keys); +- TALLOC_FREE(msg); ++ ret = ldb_msg_add_distinguished_name(msg); ++ if (ret == -1) { ++ talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + +- filtered_msg->dn = talloc_steal(filtered_msg, msg->dn); +- + /* filter the attributes that the user wants */ +- ret = ldb_kv_filter_attrs(ldb, msg, ac->attrs, filtered_msg); ++ ret = ldb_kv_filter_attrs_in_place(msg, ac->attrs); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(keys); ++ talloc_free(msg); ++ return LDB_ERR_OPERATIONS_ERROR; ++ } + +- talloc_free(msg); ++ ldb_msg_shrink_to_fit(msg); + +- if (ret == -1) { +- TALLOC_FREE(filtered_msg); ++ /* Ensure the message elements are all talloc'd. */ ++ ret = ldb_msg_elements_take_ownership(msg); ++ if (ret != LDB_SUCCESS) { + talloc_free(keys); ++ talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + +- ret = ldb_module_send_entry(ac->req, filtered_msg, NULL); ++ ret = ldb_module_send_entry(ac->req, msg, NULL); + if (ret != LDB_SUCCESS) { + /* Regardless of success or failure, the msg + * is the callbacks responsiblity, and should +diff --git a/lib/ldb/ldb_key_value/ldb_kv_search.c b/lib/ldb/ldb_key_value/ldb_kv_search.c +index 46031b99c16..f3333510eab 100644 +--- a/lib/ldb/ldb_key_value/ldb_kv_search.c ++++ b/lib/ldb/ldb_key_value/ldb_kv_search.c +@@ -292,15 +292,13 @@ int ldb_kv_search_dn1(struct ldb_module *module, + + /* + * filter the specified list of attributes from msg, +- * adding requested attributes, and perhaps all for *, +- * but not the DN to filtered_msg. ++ * adding requested attributes, and perhaps all for *. ++ * The DN will not be added if it is missing. + */ +-int ldb_kv_filter_attrs(struct ldb_context *ldb, +- const struct ldb_message *msg, +- const char *const *attrs, +- struct ldb_message *filtered_msg) ++int ldb_kv_filter_attrs_in_place(struct ldb_message *msg, ++ const char *const *attrs) + { +- return ldb_filter_attrs(ldb, msg, attrs, filtered_msg); ++ return ldb_filter_attrs_in_place(msg, attrs); + } + + /* +@@ -313,7 +311,7 @@ static int search_func(_UNUSED_ struct ldb_kv_private *ldb_kv, + { + struct ldb_context *ldb; + struct ldb_kv_context *ac; +- struct ldb_message *msg, *filtered_msg; ++ struct ldb_message *msg; + struct timeval now; + int ret, timeval_cmp; + bool matched; +@@ -410,25 +408,31 @@ static int search_func(_UNUSED_ struct ldb_kv_private *ldb_kv, + return 0; + } + +- filtered_msg = ldb_msg_new(ac); +- if (filtered_msg == NULL) { +- TALLOC_FREE(msg); ++ ret = ldb_msg_add_distinguished_name(msg); ++ if (ret == -1) { ++ talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + +- filtered_msg->dn = talloc_steal(filtered_msg, msg->dn); +- + /* filter the attributes that the user wants */ +- ret = ldb_kv_filter_attrs(ldb, msg, ac->attrs, filtered_msg); +- talloc_free(msg); ++ ret = ldb_kv_filter_attrs_in_place(msg, ac->attrs); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(msg); ++ ac->error = LDB_ERR_OPERATIONS_ERROR; ++ return -1; ++ } + +- if (ret == -1) { +- TALLOC_FREE(filtered_msg); ++ ldb_msg_shrink_to_fit(msg); ++ ++ /* Ensure the message elements are all talloc'd. */ ++ ret = ldb_msg_elements_take_ownership(msg); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(msg); + ac->error = LDB_ERR_OPERATIONS_ERROR; + return -1; + } + +- ret = ldb_module_send_entry(ac->req, filtered_msg, NULL); ++ ret = ldb_module_send_entry(ac->req, msg, NULL); + if (ret != LDB_SUCCESS) { + ac->request_terminated = true; + /* the callback failed, abort the operation */ +@@ -491,7 +495,7 @@ static int ldb_kv_search_full(struct ldb_kv_context *ctx) + static int ldb_kv_search_and_return_base(struct ldb_kv_private *ldb_kv, + struct ldb_kv_context *ctx) + { +- struct ldb_message *msg, *filtered_msg; ++ struct ldb_message *msg; + struct ldb_context *ldb = ldb_module_get_ctx(ctx->module); + const char *dn_linearized; + const char *msg_dn_linearized; +@@ -549,12 +553,6 @@ static int ldb_kv_search_and_return_base(struct ldb_kv_private *ldb_kv, + dn_linearized = ldb_dn_get_linearized(ctx->base); + msg_dn_linearized = ldb_dn_get_linearized(msg->dn); + +- filtered_msg = ldb_msg_new(ctx); +- if (filtered_msg == NULL) { +- talloc_free(msg); +- return LDB_ERR_OPERATIONS_ERROR; +- } +- + if (strcmp(dn_linearized, msg_dn_linearized) == 0) { + /* + * If the DN is exactly the same string, then +@@ -562,36 +560,42 @@ static int ldb_kv_search_and_return_base(struct ldb_kv_private *ldb_kv, + * returned result, as it has already been + * casefolded + */ +- filtered_msg->dn = ldb_dn_copy(filtered_msg, ctx->base); ++ struct ldb_dn *dn = ldb_dn_copy(msg, ctx->base); ++ if (dn != NULL) { ++ msg->dn = dn; ++ } + } + +- /* +- * If the ldb_dn_copy() failed, or if we did not choose that +- * optimisation (filtered_msg is zeroed at allocation), +- * steal the one from the unpack +- */ +- if (filtered_msg->dn == NULL) { +- filtered_msg->dn = talloc_steal(filtered_msg, msg->dn); ++ ret = ldb_msg_add_distinguished_name(msg); ++ if (ret == -1) { ++ talloc_free(msg); ++ return LDB_ERR_OPERATIONS_ERROR; + } + + /* + * filter the attributes that the user wants. + */ +- ret = ldb_kv_filter_attrs(ldb, msg, ctx->attrs, filtered_msg); +- if (ret == -1) { ++ ret = ldb_kv_filter_attrs_in_place(msg, ctx->attrs); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(msg); ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ ++ ldb_msg_shrink_to_fit(msg); ++ ++ /* Ensure the message elements are all talloc'd. */ ++ ret = ldb_msg_elements_take_ownership(msg); ++ if (ret != LDB_SUCCESS) { + talloc_free(msg); +- filtered_msg = NULL; + return LDB_ERR_OPERATIONS_ERROR; + } + + /* +- * Remove any extended components possibly copied in from +- * msg->dn, we just want the casefold components ++ * Remove any extended components, we just want the casefold components + */ +- ldb_dn_remove_extended_components(filtered_msg->dn); +- talloc_free(msg); ++ ldb_dn_remove_extended_components(msg->dn); + +- ret = ldb_module_send_entry(ctx->req, filtered_msg, NULL); ++ ret = ldb_module_send_entry(ctx->req, msg, NULL); + if (ret != LDB_SUCCESS) { + /* Regardless of success or failure, the msg + * is the callbacks responsiblity, and should +diff --git a/source4/torture/ldb/ldb.c b/source4/torture/ldb/ldb.c +index bd0ae3a382a..c170416bec4 100644 +--- a/source4/torture/ldb/ldb.c ++++ b/source4/torture/ldb/ldb.c +@@ -1634,7 +1634,6 @@ static bool torture_ldb_unpack_and_filter(struct torture_context *torture, + TALLOC_CTX *mem_ctx = talloc_new(torture); + struct ldb_context *ldb; + struct ldb_val data = *discard_const_p(struct ldb_val, data_p); +- struct ldb_message *unpack_msg = ldb_msg_new(mem_ctx); + struct ldb_message *msg = ldb_msg_new(mem_ctx); + const char *lookup_names[] = {"instanceType", "nonexistent", + "whenChanged", "objectClass", +@@ -1649,18 +1648,15 @@ static bool torture_ldb_unpack_and_filter(struct torture_context *torture, + "Failed to init samba"); + + torture_assert_int_equal(torture, +- ldb_unpack_data(ldb, &data, unpack_msg), ++ ldb_unpack_data(ldb, &data, msg), + 0, "ldb_unpack_data failed"); + +- torture_assert_int_equal(torture, unpack_msg->num_elements, 13, ++ torture_assert_int_equal(torture, msg->num_elements, 13, + "Got wrong count of elements"); + +- msg->dn = talloc_steal(msg, unpack_msg->dn); +- + torture_assert_int_equal(torture, +- ldb_filter_attrs(ldb, unpack_msg, +- lookup_names, msg), +- 0, "ldb_kv_filter_attrs failed"); ++ ldb_filter_attrs_in_place(msg, lookup_names), ++ 0, "ldb_filter_attrs_in_place failed"); + + /* Compare data in binary form */ + torture_assert_int_equal(torture, msg->num_elements, 6, +-- +2.25.1 \ No newline at end of file diff --git a/backport-0016-CVE-2023-4154.patch b/backport-0016-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..884ca8edc62bf26596900601f8301a55d3dcfd34 --- /dev/null +++ b/backport-0016-CVE-2023-4154.patch @@ -0,0 +1,44 @@ +From c18f819f8ce285e014cfb51279e144eb4d141d9e Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 7 Aug 2023 14:44:28 +1200 +Subject: [PATCH 21/30] CVE-2023-4154 dsdb/tests: Force the test attribute to + be not-confidential at the start + +Rather than fail, if the last run failed to reset things, just force +the DC into the required state. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Andrew Bartlett + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 21/30] CVE-2023-4154 dsdb/tests: Force the test attribute to + be not-confidential at the start +--- + source4/dsdb/tests/python/confidential_attr.py | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/source4/dsdb/tests/python/confidential_attr.py b/source4/dsdb/tests/python/confidential_attr.py +index 3997848f8f9..ee7f554a008 100755 +--- a/source4/dsdb/tests/python/confidential_attr.py ++++ b/source4/dsdb/tests/python/confidential_attr.py +@@ -136,10 +136,12 @@ class ConfidentialAttrCommon(samba.tests.TestCase): + + # sanity-check the flag is not already set (this'll cause problems if + # previous test run didn't clean up properly) +- search_flags = self.get_attr_search_flags(self.attr_dn) +- self.assertEqual(0, int(search_flags) & SEARCH_FLAG_CONFIDENTIAL, +- "{0} searchFlags already {1}".format(self.conf_attr, +- search_flags)) ++ search_flags = int(self.get_attr_search_flags(self.attr_dn)) ++ if search_flags & SEARCH_FLAG_CONFIDENTIAL: ++ self.set_attr_search_flags(self.attr_dn, str(search_flags &~ SEARCH_FLAG_CONFIDENTIAL)) ++ search_flags = int(self.get_attr_search_flags(self.attr_dn)) ++ self.assertEqual(0, search_flags & SEARCH_FLAG_CONFIDENTIAL, ++ f"{self.conf_attr} searchFlags did not reset to omit SEARCH_FLAG_CONFIDENTIAL ({search_flags})") + + def add_attr(self, dn, attr, value): + m = Message() +-- +2.34.1 diff --git a/backport-0017-CVE-2023-0614.patch b/backport-0017-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..fcd8daa2292198cc62b2e7117e1db6d6fd89d949 --- /dev/null +++ b/backport-0017-CVE-2023-0614.patch @@ -0,0 +1,143 @@ +From 9e07df4e268fd49358382e8d90c2d151efb66569 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Tue, 7 Feb 2023 09:35:24 +1300 +Subject: [PATCH 15/34] CVE-2023-0614 s4:dsdb/extended_dn_in: Don't modify a + search tree we don't own + +In extended_dn_fix_filter() we had: + + req->op.search.tree = ldb_parse_tree_copy_shallow(req, req->op.search.tree); + +which overwrote the parse tree on an existing ldb request with a fixed +up tree. This became a problem if a module performed another search with +that same request structure, as extended_dn_in would try to fix up the +already-modified tree for a second time. The fixed-up tree element now +having an extended DN, it would fall foul of the ldb_dn_match_allowed() +check in extended_dn_filter_callback(), and be replaced with an +ALWAYS_FALSE match rule. In practice this meant that searches +would only work for one search in an ldb request, and fail for +subsequent ones. + +Fix this by creating a new request with the modified tree, and leaving +the original request unmodified. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + .../dsdb/samdb/ldb_modules/extended_dn_in.c | 40 +++++++++++++++---- + 1 file changed, 32 insertions(+), 8 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c +index 2d0513a738b..1dc1e1f2d42 100644 +--- a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c ++++ b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c +@@ -48,6 +48,7 @@ + struct extended_search_context { + struct ldb_module *module; + struct ldb_request *req; ++ struct ldb_parse_tree *tree; + struct ldb_dn *basedn; + struct ldb_dn *dn; + char *wellknown_object; +@@ -200,7 +201,7 @@ static int extended_base_callback(struct ldb_request *req, struct ldb_reply *are + ldb_module_get_ctx(ac->module), ac->req, + ac->basedn, + ac->req->op.search.scope, +- ac->req->op.search.tree, ++ ac->tree, + ac->req->op.search.attrs, + ac->req->controls, + ac, extended_final_callback, +@@ -515,11 +516,14 @@ static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *privat + */ + static int extended_dn_fix_filter(struct ldb_module *module, + struct ldb_request *req, +- uint32_t default_dsdb_flags) ++ uint32_t default_dsdb_flags, ++ struct ldb_parse_tree **down_tree) + { + struct extended_dn_filter_ctx *filter_ctx; + int ret; + ++ *down_tree = NULL; ++ + filter_ctx = talloc_zero(req, struct extended_dn_filter_ctx); + if (filter_ctx == NULL) { + return ldb_module_oom(module); +@@ -550,12 +554,12 @@ static int extended_dn_fix_filter(struct ldb_module *module, + filter_ctx->test_only = false; + filter_ctx->matched = false; + +- req->op.search.tree = ldb_parse_tree_copy_shallow(req, req->op.search.tree); +- if (req->op.search.tree == NULL) { ++ *down_tree = ldb_parse_tree_copy_shallow(req, req->op.search.tree); ++ if (*down_tree == NULL) { + return ldb_oom(ldb_module_get_ctx(module)); + } + +- ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx); ++ ret = ldb_parse_tree_walk(*down_tree, extended_dn_filter_callback, filter_ctx); + if (ret != LDB_SUCCESS) { + talloc_free(filter_ctx); + return ret; +@@ -572,7 +576,8 @@ static int extended_dn_fix_filter(struct ldb_module *module, + static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn) + { + struct extended_search_context *ac; +- struct ldb_request *down_req; ++ struct ldb_request *down_req = NULL; ++ struct ldb_parse_tree *down_tree = NULL; + int ret; + struct ldb_dn *base_dn = NULL; + enum ldb_scope base_dn_scope = LDB_SCOPE_BASE; +@@ -595,7 +600,7 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req + } + + if (req->operation == LDB_SEARCH) { +- ret = extended_dn_fix_filter(module, req, dsdb_flags); ++ ret = extended_dn_fix_filter(module, req, dsdb_flags, &down_tree); + if (ret != LDB_SUCCESS) { + return ret; + } +@@ -603,7 +608,25 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req + + if (!ldb_dn_has_extended(dn)) { + /* Move along there isn't anything to see here */ +- return ldb_next_request(module, req); ++ if (down_tree == NULL) { ++ down_req = req; ++ } else { ++ ret = ldb_build_search_req_ex(&down_req, ++ ldb_module_get_ctx(module), req, ++ req->op.search.base, ++ req->op.search.scope, ++ down_tree, ++ req->op.search.attrs, ++ req->controls, ++ req, dsdb_next_callback, ++ req); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ LDB_REQ_SET_LOCATION(down_req); ++ } ++ ++ return ldb_next_request(module, down_req); + } else { + /* It looks like we need to map the DN */ + const struct ldb_val *sid_val, *guid_val, *wkguid_val; +@@ -690,6 +713,7 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req + + ac->module = module; + ac->req = req; ++ ac->tree = (down_tree != NULL) ? down_tree : req->op.search.tree; + ac->dn = dn; + ac->basedn = NULL; /* Filled in if the search finds the DN by SID/GUID etc */ + ac->wellknown_object = wellknown_object; +-- +2.25.1 \ No newline at end of file diff --git a/backport-0017-CVE-2023-4154.patch b/backport-0017-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..cb533d1a09f60dc7b27c48a6d7ab82eda274252b --- /dev/null +++ b/backport-0017-CVE-2023-4154.patch @@ -0,0 +1,53 @@ +From e0cec7f7908ecbdd6a2d9785352279416cae1ece Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 7 Aug 2023 11:56:56 +1200 +Subject: [PATCH 22/30] CVE-2023-4154 dsdb/tests: Check that secret attributes + are not visible with DirSync ever. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Andrew Bartlett + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 22/30] CVE-2023-4154 dsdb/tests: Check that secret attributes + are not visible with DirSync ever. +--- + selftest/knownfail.d/dirsync | 1 + + source4/dsdb/tests/python/dirsync.py | 12 ++++++++++++ + 2 files changed, 13 insertions(+) + create mode 100644 selftest/knownfail.d/dirsync + +diff --git a/selftest/knownfail.d/dirsync b/selftest/knownfail.d/dirsync +new file mode 100644 +index 00000000000..9367f92e109 +--- /dev/null ++++ b/selftest/knownfail.d/dirsync +@@ -0,0 +1 @@ ++^samba4.ldap.dirsync.python\(.*\).__main__.SimpleDirsyncTests.test_dirsync_unicodePwd +\ No newline at end of file +diff --git a/source4/dsdb/tests/python/dirsync.py b/source4/dsdb/tests/python/dirsync.py +index e06b85bc749..2cacaf01251 100755 +--- a/source4/dsdb/tests/python/dirsync.py ++++ b/source4/dsdb/tests/python/dirsync.py +@@ -742,6 +742,18 @@ class SimpleDirsyncTests(DirsyncBaseTests): + self.assertEqual(guid2, guid) + self.assertEqual(str(res[0].dn), "") + ++ def test_dirsync_unicodePwd(self): ++ res = self.ldb_admin.search(self.base_dn, ++ attrs=["unicodePwd", "supplementalCredentials", "samAccountName"], ++ expression="(samAccountName=krbtgt)", ++ controls=["dirsync:1:0:0"]) ++ ++ self.assertTrue(len(res) == 1) ++ # This form ensures this is a case insensitive comparison ++ self.assertTrue("samAccountName" in res[0]) ++ self.assertTrue(res[0].get("samAccountName")) ++ self.assertTrue(res[0].get("unicodePwd") is None) ++ self.assertTrue(res[0].get("supplementalCredentials") is None) + + if not getattr(opts, "listtests", False): + lp = sambaopts.get_loadparm() +-- +2.34.1 diff --git a/backport-0018-CVE-2023-0614.patch b/backport-0018-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..d2f85e5515ee38423f6e2371a3f5c9393a19db45 --- /dev/null +++ b/backport-0018-CVE-2023-0614.patch @@ -0,0 +1,58 @@ +From 13e0b2190c802dc876b465a201b8dc9f35f9720c Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Tue, 7 Feb 2023 09:48:37 +1300 +Subject: [PATCH 16/34] CVE-2023-0614 s4:dsdb:tests: Fix search in + confidential attributes test + +The object returned by schema_format_value() is a bytes object. +Therefore the search expression would resemble: + +(lastKnownParent=) + +which, due to the extra characters, would fail to match anything. + +Fix it to be: + +(lastKnownParent=) + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/tests/python/confidential_attr.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/source4/dsdb/tests/python/confidential_attr.py b/source4/dsdb/tests/python/confidential_attr.py +index d5c7785485a..1c9c456917a 100755 +--- a/source4/dsdb/tests/python/confidential_attr.py ++++ b/source4/dsdb/tests/python/confidential_attr.py +@@ -924,12 +924,12 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + self.assert_negative_searches(has_rights_to="all", + samdb=self.ldb_admin) + +- def get_guid(self, dn): ++ def get_guid_string(self, dn): + """Returns an object's GUID (in string format)""" + res = self.ldb_admin.search(base=dn, attrs=["objectGUID"], + scope=SCOPE_BASE) + guid = res[0]['objectGUID'][0] +- return self.ldb_admin.schema_format_value("objectGUID", guid) ++ return self.ldb_admin.schema_format_value("objectGUID", guid).decode('utf-8') + + def make_attr_preserve_on_delete(self): + """Marks the attribute under test as being preserve on delete""" +@@ -978,7 +978,7 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + # deleted objects, but only from this particular test run. We can do + # this by matching lastKnownParent against this test case's OU, which + # will match any deleted child objects. +- ou_guid = self.get_guid(self.ou) ++ ou_guid = self.get_guid_string(self.ou) + deleted_filter = "(lastKnownParent=)".format(ou_guid) + + # the extra-filter will get combined via AND with the search expression +-- +2.25.1 \ No newline at end of file diff --git a/backport-0018-CVE-2023-4154.patch b/backport-0018-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..163deefa6975525ca0262d29a1284b63d13748e6 --- /dev/null +++ b/backport-0018-CVE-2023-4154.patch @@ -0,0 +1,43 @@ +From d30349ac4cfa27c5950c54b7c083cb2c53300a0f Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Tue, 8 Aug 2023 11:18:46 +1200 +Subject: [PATCH 23/30] CVE-2023-4154 dsdb/tests: Speed up DirSync test by only + checking positive matches once + +When we (expect to) get back a result, do not waste time against a potentially +slow server confirming we also get back results for all the other attribute +combinations. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Andrew Bartlett + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 23/30] CVE-2023-4154 dsdb/tests: Speed up DirSync test by only + checking positive matches once +--- + source4/dsdb/tests/python/confidential_attr.py | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/source4/dsdb/tests/python/confidential_attr.py b/source4/dsdb/tests/python/confidential_attr.py +index ee7f554a008..678a5a82948 100755 +--- a/source4/dsdb/tests/python/confidential_attr.py ++++ b/source4/dsdb/tests/python/confidential_attr.py +@@ -742,7 +742,13 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + # want to weed out results from any previous test runs + search = "(&{0}{1})".format(expr, self.extra_filter) + +- for attr in self.attr_filters: ++ # If we expect to return multiple results, only check the first ++ if expected_num > 0: ++ attr_filters = [self.attr_filters[0]] ++ else: ++ attr_filters = self.attr_filters ++ ++ for attr in attr_filters: + res = samdb.search(base_dn, expression=search, scope=SCOPE_SUBTREE, + attrs=attr, controls=self.dirsync) + self.assertEqual(len(res), expected_num, +-- +2.34.1 diff --git a/backport-0019-CVE-2023-0614.patch b/backport-0019-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..ec217de92f18c8553d6c0b0cad7a91fb2ff42158 --- /dev/null +++ b/backport-0019-CVE-2023-0614.patch @@ -0,0 +1,49 @@ +From e167524e306241ba14f925f412e3f89828ed8c61 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Thu, 25 Aug 2022 20:15:33 +1200 +Subject: [PATCH 17/34] schema_samba4.ldif: Allocate previously added OIDs + +DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID was added +to source4/dsdb/samdb/samdb.h in commit +c2ab1f4696fa3f52918a126d0b37993a07f68bcb. + +DSDB_EXTENDED_SCHEMA_LOAD was added in commit +1fd4cdfafaa6a41c824d1b3d76635bf3e446de0f. + +Signed-off-by: Joseph Sutton +Reviewed-by: Douglas Bagnall +Reviewed-by: Stefan Metzmacher +(cherry picked from commit 672ec6135f9ae3d7b5439523a4f456c19fb03a88) + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +[abartlet@samba.org This required as context for the above bug] + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/setup/schema_samba4.ldif | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif +index a31b67750d4..54f48bde20e 100644 +--- a/source4/setup/schema_samba4.ldif ++++ b/source4/setup/schema_samba4.ldif +@@ -231,6 +231,7 @@ + #Allocated: DSDB_CONTROL_INVALID_NOT_IMPLEMENTED 1.3.6.1.4.1.7165.4.3.32 + #Allocated: DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID 1.3.6.1.4.1.7165.4.3.33 + #Allocated: DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID 1.3.6.1.4.1.7165.4.3.34 ++#Allocated: DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID 1.3.6.1.4.1.7165.4.3.35 + + + # Extended 1.3.6.1.4.1.7165.4.4.x +@@ -243,6 +244,7 @@ + #Allocated: DSDB_EXTENDED_SEC_DESC_PROPAGATION_OID 1.3.6.1.4.1.7165.4.4.7 + #Allocated: DSDB_EXTENDED_CREATE_OWN_RID_SET 1.3.6.1.4.1.7165.4.4.8 + #Allocated: DSDB_EXTENDED_ALLOCATE_RID 1.3.6.1.4.1.7165.4.4.9 ++#Allocated: DSDB_EXTENDED_SCHEMA_LOAD 1.3.6.1.4.1.7165.4.4.10 + + + ############ +-- +2.25.1 \ No newline at end of file diff --git a/backport-0019-CVE-2023-4154.patch b/backport-0019-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..3ce299448700d4dc327343a48139685d76f77ebb --- /dev/null +++ b/backport-0019-CVE-2023-4154.patch @@ -0,0 +1,101 @@ +From b586f8cc9c797b3dd89d32d12921e2820dbcf1ce Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Tue, 8 Aug 2023 14:30:19 +1200 +Subject: [PATCH 24/30] CVE-2023-4154 dsdb/tests: Add test for + SEARCH_FLAG_RODC_ATTRIBUTE behaviour + +SEARCH_FLAG_RODC_ATTRIBUTE should be like SEARCH_FLAG_CONFIDENTIAL, +but for DirSync and DRS replication. Accounts with +GUID_DRS_GET_CHANGES rights should not be able to read this +attribute. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Andrew Bartlett + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 24/30] CVE-2023-4154 dsdb/tests: Add test for + SEARCH_FLAG_RODC_ATTRIBUTE behaviour +--- + .../dsdb/tests/python/confidential_attr.py | 45 ++++++++++++++++--- + 1 file changed, 40 insertions(+), 5 deletions(-) + +diff --git a/source4/dsdb/tests/python/confidential_attr.py b/source4/dsdb/tests/python/confidential_attr.py +index 678a5a82948..edbc9593204 100755 +--- a/source4/dsdb/tests/python/confidential_attr.py ++++ b/source4/dsdb/tests/python/confidential_attr.py +@@ -30,13 +30,15 @@ import time + from samba.tests.subunitrun import SubunitOptions, TestProgram + import samba.getopt as options + from ldb import SCOPE_BASE, SCOPE_SUBTREE +-from samba.dsdb import SEARCH_FLAG_CONFIDENTIAL, SEARCH_FLAG_PRESERVEONDELETE ++from samba.dsdb import SEARCH_FLAG_CONFIDENTIAL, SEARCH_FLAG_RODC_ATTRIBUTE, SEARCH_FLAG_PRESERVEONDELETE + from ldb import Message, MessageElement, Dn + from ldb import FLAG_MOD_REPLACE, FLAG_MOD_ADD + from samba.auth import system_session + from samba import gensec, sd_utils + from samba.samdb import SamDB + from samba.credentials import Credentials, DONT_USE_KERBEROS ++from samba.dcerpc import security ++ + import samba.tests + import samba.dsdb + +@@ -137,11 +139,11 @@ class ConfidentialAttrCommon(samba.tests.TestCase): + # sanity-check the flag is not already set (this'll cause problems if + # previous test run didn't clean up properly) + search_flags = int(self.get_attr_search_flags(self.attr_dn)) +- if search_flags & SEARCH_FLAG_CONFIDENTIAL: +- self.set_attr_search_flags(self.attr_dn, str(search_flags &~ SEARCH_FLAG_CONFIDENTIAL)) ++ if search_flags & SEARCH_FLAG_CONFIDENTIAL|SEARCH_FLAG_RODC_ATTRIBUTE: ++ self.set_attr_search_flags(self.attr_dn, str(search_flags &~ (SEARCH_FLAG_CONFIDENTIAL|SEARCH_FLAG_RODC_ATTRIBUTE))) + search_flags = int(self.get_attr_search_flags(self.attr_dn)) +- self.assertEqual(0, search_flags & SEARCH_FLAG_CONFIDENTIAL, +- f"{self.conf_attr} searchFlags did not reset to omit SEARCH_FLAG_CONFIDENTIAL ({search_flags})") ++ self.assertEqual(0, search_flags & (SEARCH_FLAG_CONFIDENTIAL|SEARCH_FLAG_RODC_ATTRIBUTE), ++ f"{self.conf_attr} searchFlags did not reset to omit SEARCH_FLAG_CONFIDENTIAL and SEARCH_FLAG_RODC_ATTRIBUTE ({search_flags})") + + def add_attr(self, dn, attr, value): + m = Message() +@@ -1098,5 +1100,38 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + user_matching, user_non_matching = time_searches(self.ldb_user) + assertRangesOverlap(user_matching, user_non_matching) + ++# Check that using the dirsync controls doesn't reveal confidential ++# "RODC filtered attribute" values to users with only ++# GUID_DRS_GET_CHANGES. The tests is so similar to the Confidential ++# attribute test we base it on that. ++class RodcFilteredAttrDirsync(ConfidentialAttrTestDirsync): ++ ++ def setUp(self): ++ super().setUp() ++ self.dirsync = ["dirsync:1:0:1000"] ++ ++ user_sid = self.sd_utils.get_object_sid(self.get_user_dn(self.user)) ++ mod = "(OA;;CR;%s;;%s)" % (security.GUID_DRS_GET_CHANGES, ++ str(user_sid)) ++ self.sd_utils.dacl_add_ace(self.base_dn, mod) ++ ++ self.ldb_user = self.get_ldb_connection(self.user, self.user_pass) ++ ++ self.addCleanup(self.sd_utils.dacl_delete_aces, self.base_dn, mod) ++ ++ def make_attr_confidential(self): ++ """Marks the attribute under test as being confidential AND RODC ++ filtered (which should mean it is not visible with only ++ GUID_DRS_GET_CHANGES) ++ """ ++ ++ # work out the original 'searchFlags' value before we overwrite it ++ old_value = self.get_attr_search_flags(self.attr_dn) ++ ++ self.set_attr_search_flags(self.attr_dn, str(SEARCH_FLAG_RODC_ATTRIBUTE|SEARCH_FLAG_CONFIDENTIAL)) ++ ++ # reset the value after the test completes ++ self.addCleanup(self.set_attr_search_flags, self.attr_dn, old_value) ++ + + TestProgram(module=__name__, opts=subunitopts) +-- +2.34.1 diff --git a/backport-0020-CVE-2023-0614.patch b/backport-0020-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..3547310591521d7c6bdf0faedc002466866ade57 --- /dev/null +++ b/backport-0020-CVE-2023-0614.patch @@ -0,0 +1,34 @@ +From 829157cf07ec887a7164600a53bdc688aa4717be Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Tue, 7 Feb 2023 09:25:48 +1300 +Subject: [PATCH 18/34] CVE-2023-0614 schema_samba4.ldif: Allocate previously + added OID + +DSDB_CONTROL_CALCULATED_DEFAULT_SD_OID was added in commit +08187833fee57a8dba6c67546dfca516cd1f9d7a. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/setup/schema_samba4.ldif | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif +index 54f48bde20e..79800bfd6df 100644 +--- a/source4/setup/schema_samba4.ldif ++++ b/source4/setup/schema_samba4.ldif +@@ -232,6 +232,7 @@ + #Allocated: DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID 1.3.6.1.4.1.7165.4.3.33 + #Allocated: DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID 1.3.6.1.4.1.7165.4.3.34 + #Allocated: DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID 1.3.6.1.4.1.7165.4.3.35 ++#Allocated: DSDB_CONTROL_CALCULATED_DEFAULT_SD_OID 1.3.6.1.4.1.7165.4.3.36 + + + # Extended 1.3.6.1.4.1.7165.4.4.x +-- +2.25.1 \ No newline at end of file diff --git a/backport-0020-CVE-2023-4154.patch b/backport-0020-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..5390e9c9266d258e82c9e38427c462a27d8f47d3 --- /dev/null +++ b/backport-0020-CVE-2023-4154.patch @@ -0,0 +1,634 @@ +From 4c897f5b8542ad29b51ffc9eb219fcb9eaf7754b Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Tue, 22 Aug 2023 15:08:17 +1200 +Subject: [PATCH 25/30] CVE-2023-4154 dsdb/tests: Extend attribute read DirSync + tests + +The aim here is to document the expected (even if not implemented) +SEARCH_FLAG_RODC_ATTRIBUTE vs SEARCH_FLAG_CONFIDENTIAL, behaviour, so +that any change once CVE-2023-4154 is fixed can be noted. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Andrew Bartlett + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 25/30] CVE-2023-4154 dsdb/tests: Extend attribute read DirSync + tests +--- + selftest/knownfail.d/dirsync | 15 +- + source4/dsdb/tests/python/dirsync.py | 456 +++++++++++++++++++++++---- + 2 files changed, 414 insertions(+), 57 deletions(-) + +diff --git a/selftest/knownfail.d/dirsync b/selftest/knownfail.d/dirsync +index 9367f92e109..db098549a08 100644 +--- a/selftest/knownfail.d/dirsync ++++ b/selftest/knownfail.d/dirsync +@@ -1 +1,14 @@ +-^samba4.ldap.dirsync.python\(.*\).__main__.SimpleDirsyncTests.test_dirsync_unicodePwd +\ No newline at end of file ++^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_OBJECT_SECURITY_insist_on_empty_element\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_unicodePwd_OBJ_SEC_insist_on_empty_element\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_unicodePwd_with_GET_CHANGES\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_unicodePwd_with_GET_CHANGES_OBJ_SEC_insist_on_empty_element\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_unicodePwd_with_GET_CHANGES_insist_on_empty_element\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_with_GET_CHANGES_OBJECT_SECURITY_insist_on_empty_element\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialFilteredDirsyncTests.test_dirsync_OBJECT_SECURITY_insist_on_empty_element\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialFilteredDirsyncTests.test_dirsync_OBJECT_SECURITY_with_GET_CHANGES_insist_on_empty_element\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialFilteredDirsyncTests.test_dirsync_with_GET_CHANGES\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialFilteredDirsyncTests.test_dirsync_with_GET_CHANGES_attr\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialFilteredDirsyncTests.test_dirsync_with_GET_CHANGES_insist_on_empty_element\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.FilteredDirsyncTests.test_dirsync_with_GET_CHANGES\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.FilteredDirsyncTests.test_dirsync_with_GET_CHANGES_attr\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.FilteredDirsyncTests.test_dirsync_with_GET_CHANGES_insist_on_empty_element\(.*\) +diff --git a/source4/dsdb/tests/python/dirsync.py b/source4/dsdb/tests/python/dirsync.py +index 2cacaf01251..a0691f0afe0 100755 +--- a/source4/dsdb/tests/python/dirsync.py ++++ b/source4/dsdb/tests/python/dirsync.py +@@ -3,6 +3,7 @@ + # Unit tests for dirsync control + # Copyright (C) Matthieu Patou 2011 + # Copyright (C) Jelmer Vernooij 2014 ++# Copyright (C) Catalyst.Net Ltd + # + # This program is free software; you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by +@@ -30,7 +31,8 @@ import base64 + import ldb + from ldb import LdbError, SCOPE_BASE + from ldb import Message, MessageElement, Dn +-from ldb import FLAG_MOD_ADD, FLAG_MOD_DELETE ++from ldb import FLAG_MOD_ADD, FLAG_MOD_DELETE, FLAG_MOD_REPLACE ++from samba.dsdb import SEARCH_FLAG_CONFIDENTIAL, SEARCH_FLAG_RODC_ATTRIBUTE + from samba.dcerpc import security, misc, drsblobs + from samba.ndr import ndr_unpack, ndr_pack + +@@ -60,7 +62,6 @@ if len(args) < 1: + host = args.pop() + if "://" not in host: + ldaphost = "ldap://%s" % host +- ldapshost = "ldaps://%s" % host + else: + ldaphost = host + start = host.rindex("://") +@@ -77,8 +78,8 @@ creds = credopts.get_credentials(lp) + class DirsyncBaseTests(samba.tests.TestCase): + + def setUp(self): +- super(DirsyncBaseTests, self).setUp() +- self.ldb_admin = SamDB(ldapshost, credentials=creds, session_info=system_session(lp), lp=lp) ++ super().setUp() ++ self.ldb_admin = SamDB(ldaphost, credentials=creds, session_info=system_session(lp), lp=lp) + self.base_dn = self.ldb_admin.domain_dn() + self.domain_sid = security.dom_sid(self.ldb_admin.get_domain_sid()) + self.user_pass = samba.generate_random_password(12, 16) +@@ -87,63 +88,60 @@ class DirsyncBaseTests(samba.tests.TestCase): + # used for anonymous login + print("baseDN: %s" % self.base_dn) + +- def get_user_dn(self, name): +- return "CN=%s,CN=Users,%s" % (name, self.base_dn) ++ userou = "OU=dirsync-test" ++ self.ou = f"{userou},{self.base_dn}" ++ samba.tests.delete_force(self.ldb_admin, self.ou, controls=['tree_delete:1']) ++ self.ldb_admin.create_ou(self.ou) ++ self.addCleanup(samba.tests.delete_force, self.ldb_admin, self.ou, controls=['tree_delete:1']) + +- def get_ldb_connection(self, target_username, target_password): +- creds_tmp = Credentials() +- creds_tmp.set_username(target_username) +- creds_tmp.set_password(target_password) +- creds_tmp.set_domain(creds.get_domain()) +- creds_tmp.set_realm(creds.get_realm()) +- creds_tmp.set_workstation(creds.get_workstation()) +- creds_tmp.set_gensec_features(creds_tmp.get_gensec_features() +- | gensec.FEATURE_SEAL) +- creds_tmp.set_kerberos_state(DONT_USE_KERBEROS) # kinit is too expensive to use in a tight loop +- ldb_target = SamDB(url=ldaphost, credentials=creds_tmp, lp=lp) +- return ldb_target +- +- +-# tests on ldap add operations +-class SimpleDirsyncTests(DirsyncBaseTests): +- +- def setUp(self): +- super(SimpleDirsyncTests, self).setUp() + # Regular user + self.dirsync_user = "test_dirsync_user" + self.simple_user = "test_simple_user" + self.admin_user = "test_admin_user" +- self.ouname = None ++ self.dirsync_pass = self.user_pass ++ self.simple_pass = self.user_pass ++ self.admin_pass = self.user_pass + +- self.ldb_admin.newuser(self.dirsync_user, self.user_pass) +- self.ldb_admin.newuser(self.simple_user, self.user_pass) +- self.ldb_admin.newuser(self.admin_user, self.user_pass) ++ self.ldb_admin.newuser(self.dirsync_user, self.dirsync_pass, userou=userou) ++ self.ldb_admin.newuser(self.simple_user, self.simple_pass, userou=userou) ++ self.ldb_admin.newuser(self.admin_user, self.admin_pass, userou=userou) + self.desc_sddl = self.sd_utils.get_sd_as_sddl(self.base_dn) + + user_sid = self.sd_utils.get_object_sid(self.get_user_dn(self.dirsync_user)) + mod = "(OA;;CR;%s;;%s)" % (security.GUID_DRS_GET_CHANGES, + str(user_sid)) + self.sd_utils.dacl_add_ace(self.base_dn, mod) ++ self.addCleanup(self.sd_utils.dacl_delete_aces, self.base_dn, mod) + + # add admins to the Domain Admins group + self.ldb_admin.add_remove_group_members("Domain Admins", [self.admin_user], + add_members_operation=True) + +- def tearDown(self): +- super(SimpleDirsyncTests, self).tearDown() +- delete_force(self.ldb_admin, self.get_user_dn(self.dirsync_user)) +- delete_force(self.ldb_admin, self.get_user_dn(self.simple_user)) +- delete_force(self.ldb_admin, self.get_user_dn(self.admin_user)) +- if self.ouname: +- delete_force(self.ldb_admin, self.ouname) +- self.sd_utils.modify_sd_on_dn(self.base_dn, self.desc_sddl) ++ def get_user_dn(self, name): ++ return ldb.Dn(self.ldb_admin, "CN={0},{1}".format(name, self.ou)) ++ ++ def get_ldb_connection(self, target_username, target_password): ++ creds_tmp = Credentials() ++ creds_tmp.set_username(target_username) ++ creds_tmp.set_password(target_password) ++ creds_tmp.set_domain(creds.get_domain()) ++ creds_tmp.set_realm(creds.get_realm()) ++ creds_tmp.set_workstation(creds.get_workstation()) ++ creds_tmp.set_gensec_features(creds_tmp.get_gensec_features() ++ | gensec.FEATURE_SEAL) ++ creds_tmp.set_kerberos_state(DONT_USE_KERBEROS) # kinit is too expensive to use in a tight loop ++ ldb_target = SamDB(url=ldaphost, credentials=creds_tmp, lp=lp) ++ return ldb_target ++ ++# tests on ldap add operations ++class SimpleDirsyncTests(DirsyncBaseTests): + + # def test_dirsync_errors(self): + + def test_dirsync_supported(self): + """Test the basic of the dirsync is supported""" + self.ldb_dirsync = self.get_ldb_connection(self.dirsync_user, self.user_pass) +- self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) ++ self.ldb_simple = self.get_ldb_connection(self.simple_user, self.simple_pass) + res = self.ldb_admin.search(self.base_dn, expression="samaccountname=*", controls=["dirsync:1:0:1"]) + res = self.ldb_dirsync.search(self.base_dn, expression="samaccountname=*", controls=["dirsync:1:0:1"]) + try: +@@ -169,8 +167,8 @@ class SimpleDirsyncTests(DirsyncBaseTests): + + def test_dirsync_errors(self): + """Test if dirsync returns the correct LDAP errors in case of pb""" +- self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) +- self.ldb_dirsync = self.get_ldb_connection(self.dirsync_user, self.user_pass) ++ self.ldb_simple = self.get_ldb_connection(self.simple_user, self.simple_pass) ++ self.ldb_dirsync = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) + try: + self.ldb_simple.search(self.base_dn, + expression="samaccountname=*", +@@ -292,11 +290,11 @@ class SimpleDirsyncTests(DirsyncBaseTests): + attrs=["parentGUID"], + controls=["dirsync:1:0:1"]) + self.assertEqual(len(res.msgs), 0) +- ouname = "OU=testou,%s" % self.base_dn ++ ouname = "OU=testou,%s" % self.ou + self.ouname = ouname + self.ldb_admin.create_ou(ouname) + delta = Message() +- delta.dn = Dn(self.ldb_admin, str(ouname)) ++ delta.dn = Dn(self.ldb_admin, ouname) + delta["cn"] = MessageElement("test ou", + FLAG_MOD_ADD, + "cn") +@@ -457,7 +455,7 @@ class SimpleDirsyncTests(DirsyncBaseTests): + def test_dirsync_linkedattributes_OBJECT_SECURITY(self): + """Check that dirsync returned deleted objects too""" + # Let's search for members +- self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) ++ self.ldb_simple = self.get_ldb_connection(self.simple_user, self.simple_pass) + res = self.ldb_simple.search(self.base_dn, + expression="(name=Administrators)", + controls=["dirsync:1:1:1"]) +@@ -582,7 +580,7 @@ class SimpleDirsyncTests(DirsyncBaseTests): + controls=controls) + + def test_dirsync_linkedattributes_range(self): +- self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) ++ self.ldb_simple = self.get_ldb_connection(self.simple_user, self.simple_pass) + res = self.ldb_admin.search(self.base_dn, + attrs=["member;range=1-1"], + expression="(name=Administrators)", +@@ -594,7 +592,7 @@ class SimpleDirsyncTests(DirsyncBaseTests): + self.assertTrue(len(res[0].get("member")) > 0) + + def test_dirsync_linkedattributes_range_user(self): +- self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) ++ self.ldb_simple = self.get_ldb_connection(self.simple_user, self.simple_pass) + try: + res = self.ldb_simple.search(self.base_dn, + attrs=["member;range=1-1"], +@@ -608,7 +606,7 @@ class SimpleDirsyncTests(DirsyncBaseTests): + + def test_dirsync_linkedattributes(self): + flag_incr_linked = 2147483648 +- self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) ++ self.ldb_simple = self.get_ldb_connection(self.simple_user, self.simple_pass) + res = self.ldb_admin.search(self.base_dn, + attrs=["member"], + expression="(name=Administrators)", +@@ -676,7 +674,7 @@ class SimpleDirsyncTests(DirsyncBaseTests): + def test_dirsync_extended_dn(self): + """Check that dirsync works together with the extended_dn control""" + # Let's search for members +- self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) ++ self.ldb_simple = self.get_ldb_connection(self.simple_user, self.simple_pass) + res = self.ldb_simple.search(self.base_dn, + expression="(name=Administrators)", + controls=["dirsync:1:1:1"]) +@@ -707,7 +705,7 @@ class SimpleDirsyncTests(DirsyncBaseTests): + def test_dirsync_deleted_items_OBJECT_SECURITY(self): + """Check that dirsync returned deleted objects too""" + # Let's create an OU +- self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) ++ self.ldb_simple = self.get_ldb_connection(self.simple_user, self.simple_pass) + ouname = "OU=testou3,%s" % self.base_dn + self.ouname = ouname + self.ldb_admin.create_ou(ouname) +@@ -742,18 +740,364 @@ class SimpleDirsyncTests(DirsyncBaseTests): + self.assertEqual(guid2, guid) + self.assertEqual(str(res[0].dn), "") + +- def test_dirsync_unicodePwd(self): ++class SpecialDirsyncTests(DirsyncBaseTests): ++ ++ def setUp(self): ++ super().setUp() ++ ++ self.schema_dn = self.ldb_admin.get_schema_basedn() ++ ++ # the tests work by setting the 'Confidential' or 'RODC Filtered' bit in the searchFlags ++ # for an existing schema attribute. This only works against Windows if ++ # the systemFlags does not have FLAG_SCHEMA_BASE_OBJECT set for the ++ # schema attribute being modified. There are only a few attributes that ++ # meet this criteria (most of which only apply to 'user' objects) ++ self.conf_attr = "homePostalAddress" ++ attr_cn = "CN=Address-Home" ++ # schemaIdGuid for homePostalAddress (used for ACE tests) ++ self.attr_dn = f"{attr_cn},{self.schema_dn}" ++ ++ userou = "OU=conf-attr-test" ++ self.ou = "{0},{1}".format(userou, self.base_dn) ++ samba.tests.delete_force(self.ldb_admin, self.ou, controls=['tree_delete:1']) ++ self.ldb_admin.create_ou(self.ou) ++ self.addCleanup(samba.tests.delete_force, self.ldb_admin, self.ou, controls=['tree_delete:1']) ++ ++ # add a test object with this attribute set ++ self.conf_value = "abcdef" ++ self.conf_user = "conf-user" ++ self.ldb_admin.newuser(self.conf_user, self.user_pass, userou=userou) ++ self.conf_dn = self.get_user_dn(self.conf_user) ++ self.add_attr(self.conf_dn, self.conf_attr, self.conf_value) ++ ++ # sanity-check the flag is not already set (this'll cause problems if ++ # previous test run didn't clean up properly) ++ ++ search_flags = int(self.get_attr_search_flags(self.attr_dn)) ++ if search_flags & SEARCH_FLAG_CONFIDENTIAL|SEARCH_FLAG_RODC_ATTRIBUTE: ++ self.set_attr_search_flags(self.attr_dn, str(search_flags &~ (SEARCH_FLAG_CONFIDENTIAL|SEARCH_FLAG_RODC_ATTRIBUTE))) ++ search_flags = int(self.get_attr_search_flags(self.attr_dn)) ++ self.assertEqual(0, search_flags & (SEARCH_FLAG_CONFIDENTIAL|SEARCH_FLAG_RODC_ATTRIBUTE), ++ f"{self.conf_attr} searchFlags did not reset to omit SEARCH_FLAG_CONFIDENTIAL and SEARCH_FLAG_RODC_ATTRIBUTE ({search_flags})") ++ ++ # work out the original 'searchFlags' value before we overwrite it ++ old_value = self.get_attr_search_flags(self.attr_dn) ++ ++ self.set_attr_search_flags(self.attr_dn, str(self.flag_under_test)) ++ ++ # reset the value after the test completes ++ self.addCleanup(self.set_attr_search_flags, self.attr_dn, old_value) ++ ++ def add_attr(self, dn, attr, value): ++ m = Message() ++ m.dn = dn ++ m[attr] = MessageElement(value, FLAG_MOD_ADD, attr) ++ self.ldb_admin.modify(m) ++ ++ def set_attr_search_flags(self, attr_dn, flags): ++ """Modifies the searchFlags for an object in the schema""" ++ m = Message() ++ m.dn = Dn(self.ldb_admin, attr_dn) ++ m['searchFlags'] = MessageElement(flags, FLAG_MOD_REPLACE, ++ 'searchFlags') ++ self.ldb_admin.modify(m) ++ ++ # note we have to update the schema for this change to take effect (on ++ # Windows, at least) ++ self.ldb_admin.set_schema_update_now() ++ ++ def get_attr_search_flags(self, attr_dn): ++ res = self.ldb_admin.search(attr_dn, scope=SCOPE_BASE, ++ attrs=['searchFlags']) ++ return res[0]['searchFlags'][0] ++ ++ def find_under_current_ou(self, res): ++ for msg in res: ++ if msg.dn == self.conf_dn: ++ return msg ++ self.fail(f"Failed to find object {self.conf_dn} in {len(res)} results") ++ ++ ++class ConfidentialDirsyncTests(SpecialDirsyncTests): ++ ++ def setUp(self): ++ self.flag_under_test = SEARCH_FLAG_CONFIDENTIAL ++ super().setUp() ++ ++ def test_unicodePwd_normal(self): + res = self.ldb_admin.search(self.base_dn, + attrs=["unicodePwd", "supplementalCredentials", "samAccountName"], +- expression="(samAccountName=krbtgt)", +- controls=["dirsync:1:0:0"]) ++ expression=f"(samAccountName={self.conf_user})") ++ ++ msg = res[0] ++ ++ self.assertTrue("samAccountName" in msg) ++ # This form ensures this is a case insensitive comparison ++ self.assertTrue(msg.get("samAccountName")) ++ self.assertTrue(msg.get("unicodePwd") is None) ++ self.assertTrue(msg.get("supplementalCredentials") is None) ++ ++ def _test_dirsync_unicodePwd(self, ldb_conn, control=None, insist_on_empty_element=False): ++ res = ldb_conn.search(self.base_dn, ++ attrs=["unicodePwd", "supplementalCredentials", "samAccountName"], ++ expression=f"(samAccountName={self.conf_user})", ++ controls=[control]) ++ ++ msg = self.find_under_current_ou(res) + +- self.assertTrue(len(res) == 1) ++ self.assertTrue("samAccountName" in msg) + # This form ensures this is a case insensitive comparison +- self.assertTrue("samAccountName" in res[0]) +- self.assertTrue(res[0].get("samAccountName")) +- self.assertTrue(res[0].get("unicodePwd") is None) +- self.assertTrue(res[0].get("supplementalCredentials") is None) ++ self.assertTrue(msg.get("samAccountName")) ++ if insist_on_empty_element: ++ self.assertTrue(msg.get("unicodePwd") is not None) ++ self.assertEqual(len(msg.get("unicodePwd")), 0) ++ self.assertTrue(msg.get("supplementalCredentials") is not None) ++ self.assertEqual(len(msg.get("supplementalCredentials")), 0) ++ else: ++ self.assertTrue(msg.get("unicodePwd") is None ++ or len(msg.get("unicodePwd")) == 0) ++ self.assertTrue(msg.get("supplementalCredentials") is None ++ or len(msg.get("supplementalCredentials")) == 0) ++ ++ def test_dirsync_unicodePwd_OBJ_SEC(self): ++ ldb_conn = self.get_ldb_connection(self.simple_user, self.simple_pass) ++ self._test_dirsync_unicodePwd(ldb_conn, control="dirsync:1:1:0") ++ ++ def test_dirsync_unicodePwd_OBJ_SEC_insist_on_empty_element(self): ++ ldb_conn = self.get_ldb_connection(self.simple_user, self.simple_pass) ++ self._test_dirsync_unicodePwd(ldb_conn, control="dirsync:1:1:0", insist_on_empty_element=True) ++ ++ def test_dirsync_unicodePwd_with_GET_CHANGES_OBJ_SEC(self): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ self._test_dirsync_unicodePwd(ldb_conn, control="dirsync:1:1:0") ++ ++ def test_dirsync_unicodePwd_with_GET_CHANGES_OBJ_SEC_insist_on_empty_element(self): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ self._test_dirsync_unicodePwd(ldb_conn, control="dirsync:1:1:0", insist_on_empty_element=True) ++ ++ def test_dirsync_unicodePwd_with_GET_CHANGES(self): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ self._test_dirsync_unicodePwd(ldb_conn, control="dirsync:1:0:0") ++ ++ def test_dirsync_unicodePwd_with_GET_CHANGES_insist_on_empty_element(self): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ self._test_dirsync_unicodePwd(ldb_conn, control="dirsync:1:0:0", insist_on_empty_element=True) ++ ++ def test_normal(self): ++ ldb_conn = self.get_ldb_connection(self.simple_user, self.simple_pass) ++ res = ldb_conn.search(self.base_dn, ++ attrs=[self.conf_attr, "samAccountName"], ++ expression=f"(samAccountName={self.conf_user})") ++ ++ msg = res[0] ++ self.assertTrue("samAccountName" in msg) ++ # This form ensures this is a case insensitive comparison ++ self.assertTrue(msg.get("samAccountName")) ++ self.assertTrue(msg.get(self.conf_attr) is None) ++ ++ def _test_dirsync_OBJECT_SECURITY(self, ldb_conn, insist_on_empty_element=False): ++ res = ldb_conn.search(self.base_dn, ++ attrs=[self.conf_attr, "samAccountName"], ++ expression=f"(samAccountName={self.conf_user})", ++ controls=["dirsync:1:1:0"]) ++ ++ msg = self.find_under_current_ou(res) ++ self.assertTrue("samAccountName" in msg) ++ # This form ensures this is a case insensitive comparison ++ self.assertTrue(msg.get("samAccountName")) ++ if insist_on_empty_element: ++ self.assertTrue(msg.get(self.conf_attr) is not None) ++ self.assertEqual(len(msg.get(self.conf_attr)), 0) ++ else: ++ self.assertTrue(msg.get(self.conf_attr) is None ++ or len(msg.get(self.conf_attr)) == 0) ++ ++ def test_dirsync_OBJECT_SECURITY(self): ++ ldb_conn = self.get_ldb_connection(self.simple_user, self.simple_pass) ++ self._test_dirsync_OBJECT_SECURITY(ldb_conn) ++ ++ def test_dirsync_OBJECT_SECURITY_insist_on_empty_element(self): ++ ldb_conn = self.get_ldb_connection(self.simple_user, self.simple_pass) ++ self._test_dirsync_OBJECT_SECURITY(ldb_conn, insist_on_empty_element=True) ++ ++ def test_dirsync_with_GET_CHANGES(self): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ res = ldb_conn.search(self.base_dn, ++ attrs=[self.conf_attr, "samAccountName"], ++ expression=f"(samAccountName={self.conf_user})", ++ controls=["dirsync:1:0:0"]) ++ ++ msg = self.find_under_current_ou(res) ++ # This form ensures this is a case insensitive comparison ++ self.assertTrue(msg.get("samAccountName")) ++ self.assertTrue(msg.get(self.conf_attr)) ++ self.assertEqual(len(msg.get(self.conf_attr)), 1) ++ ++ def test_dirsync_with_GET_CHANGES_OBJECT_SECURITY(self): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ self._test_dirsync_OBJECT_SECURITY(ldb_conn) ++ ++ def test_dirsync_with_GET_CHANGES_OBJECT_SECURITY_insist_on_empty_element(self): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ self._test_dirsync_OBJECT_SECURITY(ldb_conn, insist_on_empty_element=True) ++ ++class FilteredDirsyncTests(SpecialDirsyncTests): ++ ++ def setUp(self): ++ self.flag_under_test = SEARCH_FLAG_RODC_ATTRIBUTE ++ super().setUp() ++ ++ def test_attr(self): ++ ldb_conn = self.get_ldb_connection(self.simple_user, self.simple_pass) ++ res = ldb_conn.search(self.base_dn, ++ attrs=[self.conf_attr, "samAccountName"], ++ expression=f"(samAccountName={self.conf_user})") ++ ++ msg = res[0] ++ self.assertTrue("samAccountName" in msg) ++ # This form ensures this is a case insensitive comparison ++ self.assertTrue(msg.get("samAccountName")) ++ self.assertTrue(msg.get(self.conf_attr)) ++ self.assertEqual(len(msg.get(self.conf_attr)), 1) ++ ++ def _test_dirsync_OBJECT_SECURITY(self, ldb_conn): ++ res = ldb_conn.search(self.base_dn, ++ attrs=[self.conf_attr, "samAccountName"], ++ expression=f"(samAccountName={self.conf_user})", ++ controls=["dirsync:1:1:0"]) ++ ++ msg = self.find_under_current_ou(res) ++ self.assertTrue("samAccountName" in msg) ++ # This form ensures this is a case insensitive comparison ++ self.assertTrue(msg.get("samAccountName")) ++ self.assertTrue(msg.get(self.conf_attr)) ++ self.assertEqual(len(msg.get(self.conf_attr)), 1) ++ ++ def test_dirsync_OBJECT_SECURITY(self): ++ ldb_conn = self.get_ldb_connection(self.simple_user, self.simple_pass) ++ self._test_dirsync_OBJECT_SECURITY(ldb_conn) ++ ++ def test_dirsync_OBJECT_SECURITY_with_GET_CHANGES(self): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ self._test_dirsync_OBJECT_SECURITY(ldb_conn) ++ ++ def _test_dirsync_with_GET_CHANGES(self, insist_on_empty_element=False): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ res = ldb_conn.search(self.base_dn, ++ expression=f"(samAccountName={self.conf_user})", ++ controls=["dirsync:1:0:0"]) ++ ++ msg = self.find_under_current_ou(res) ++ # This form ensures this is a case insensitive comparison ++ self.assertTrue(msg.get("samAccountName")) ++ if insist_on_empty_element: ++ self.assertTrue(msg.get(self.conf_attr) is not None) ++ self.assertEqual(len(msg.get(self.conf_attr)), 0) ++ else: ++ self.assertTrue(msg.get(self.conf_attr) is None ++ or len(msg.get(self.conf_attr)) == 0) ++ ++ def test_dirsync_with_GET_CHANGES(self): ++ self._test_dirsync_with_GET_CHANGES() ++ ++ def test_dirsync_with_GET_CHANGES_insist_on_empty_element(self): ++ self._test_dirsync_with_GET_CHANGES(insist_on_empty_element=True) ++ ++ def test_dirsync_with_GET_CHANGES_attr(self): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ try: ++ res = ldb_conn.search(self.base_dn, ++ attrs=[self.conf_attr, "samAccountName"], ++ expression=f"(samAccountName={self.conf_user})", ++ controls=["dirsync:1:0:0"]) ++ self.fail("ldb.search() should have failed with LDAP_INSUFFICIENT_ACCESS_RIGHTS") ++ except ldb.LdbError as e: ++ (errno, errstr) = e.args ++ self.assertEqual(errno, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) ++ ++class ConfidentialFilteredDirsyncTests(SpecialDirsyncTests): ++ ++ def setUp(self): ++ self.flag_under_test = SEARCH_FLAG_RODC_ATTRIBUTE|SEARCH_FLAG_CONFIDENTIAL ++ super().setUp() ++ ++ def test_attr(self): ++ ldb_conn = self.get_ldb_connection(self.simple_user, self.simple_pass) ++ res = ldb_conn.search(self.base_dn, ++ attrs=["unicodePwd", "supplementalCredentials", "samAccountName"], ++ expression=f"(samAccountName={self.conf_user})") ++ ++ msg = res[0] ++ self.assertTrue(msg.get("samAccountName")) ++ self.assertTrue(msg.get(self.conf_attr) is None) ++ ++ def _test_dirsync_OBJECT_SECURITY(self, ldb_conn, insist_on_empty_element=False): ++ res = ldb_conn.search(self.base_dn, ++ attrs=[self.conf_attr, "samAccountName"], ++ expression=f"(samAccountName={self.conf_user})", ++ controls=["dirsync:1:1:0"]) ++ ++ msg = self.find_under_current_ou(res) ++ self.assertTrue("samAccountName" in msg) ++ # This form ensures this is a case insensitive comparison ++ self.assertTrue(msg.get("samAccountName")) ++ if insist_on_empty_element: ++ self.assertTrue(msg.get(self.conf_attr) is not None) ++ self.assertEqual(len(msg.get(self.conf_attr)), 0) ++ else: ++ self.assertTrue(msg.get(self.conf_attr) is None ++ or len(msg.get(self.conf_attr)) == 0) ++ ++ def test_dirsync_OBJECT_SECURITY(self): ++ ldb_conn = self.get_ldb_connection(self.simple_user, self.simple_pass) ++ self._test_dirsync_OBJECT_SECURITY(ldb_conn) ++ ++ def test_dirsync_OBJECT_SECURITY_insist_on_empty_element(self): ++ ldb_conn = self.get_ldb_connection(self.simple_user, self.simple_pass) ++ self._test_dirsync_OBJECT_SECURITY(ldb_conn, insist_on_empty_element=True) ++ ++ def test_dirsync_OBJECT_SECURITY_with_GET_CHANGES(self): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ self._test_dirsync_OBJECT_SECURITY(ldb_conn) ++ ++ def test_dirsync_OBJECT_SECURITY_with_GET_CHANGES_insist_on_empty_element(self): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ self._test_dirsync_OBJECT_SECURITY(ldb_conn, insist_on_empty_element=True) ++ ++ def _test_dirsync_with_GET_CHANGES(self, insist_on_empty_element=False): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ res = ldb_conn.search(self.base_dn, ++ expression=f"(samAccountName={self.conf_user})", ++ controls=["dirsync:1:0:0"]) ++ ++ msg = self.find_under_current_ou(res) ++ # This form ensures this is a case insensitive comparison ++ self.assertTrue(msg.get("samAccountName")) ++ if insist_on_empty_element: ++ self.assertTrue(msg.get(self.conf_attr) is not None) ++ self.assertEqual(len(msg.get(self.conf_attr)), 0) ++ else: ++ self.assertTrue(msg.get(self.conf_attr) is None ++ or len(msg.get(self.conf_attr)) == 0) ++ ++ def test_dirsync_with_GET_CHANGES(self): ++ self._test_dirsync_with_GET_CHANGES() ++ ++ def test_dirsync_with_GET_CHANGES_insist_on_empty_element(self): ++ self._test_dirsync_with_GET_CHANGES(insist_on_empty_element=True) ++ ++ def test_dirsync_with_GET_CHANGES_attr(self): ++ ldb_conn = self.get_ldb_connection(self.dirsync_user, self.dirsync_pass) ++ try: ++ res = ldb_conn.search(self.base_dn, ++ attrs=[self.conf_attr, "samAccountName"], ++ expression=f"(samAccountName={self.conf_user})", ++ controls=["dirsync:1:0:0"]) ++ self.fail("ldb.search() should have failed with LDAP_INSUFFICIENT_ACCESS_RIGHTS") ++ except ldb.LdbError as e: ++ (errno, errstr) = e.args ++ self.assertEqual(errno, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) ++ + + if not getattr(opts, "listtests", False): + lp = sambaopts.get_loadparm() +-- +2.34.1 diff --git a/backport-0021-CVE-2023-0614.patch b/backport-0021-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..0db2c42962932994c3f56d73fb7ec77228fbb749 --- /dev/null +++ b/backport-0021-CVE-2023-0614.patch @@ -0,0 +1,205 @@ +From 009026fae8eea85789bd912cbf397423480485da Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 27 Jan 2023 08:32:41 +1300 +Subject: [PATCH 19/34] CVE-2023-0614 tests/krb5: Add test for confidential + attributes timing differences + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + selftest/knownfail.d/confidential-attr-timing | 1 + + .../dsdb/tests/python/confidential_attr.py | 162 ++++++++++++++++++ + 2 files changed, 163 insertions(+) + create mode 100644 selftest/knownfail.d/confidential-attr-timing + +diff --git a/selftest/knownfail.d/confidential-attr-timing b/selftest/knownfail.d/confidential-attr-timing +new file mode 100644 +index 00000000000..e213cdb16d3 +--- /dev/null ++++ b/selftest/knownfail.d/confidential-attr-timing +@@ -0,0 +1 @@ ++^samba4.ldap.confidential_attr.python\(ad_dc_slowtests\).__main__.ConfidentialAttrTestDirsync.test_timing_attack\(ad_dc_slowtests\) +diff --git a/source4/dsdb/tests/python/confidential_attr.py b/source4/dsdb/tests/python/confidential_attr.py +index 1c9c456917a..031c9690ba6 100755 +--- a/source4/dsdb/tests/python/confidential_attr.py ++++ b/source4/dsdb/tests/python/confidential_attr.py +@@ -25,6 +25,9 @@ sys.path.insert(0, "bin/python") + + import samba + import os ++import random ++import statistics ++import time + from samba.tests.subunitrun import SubunitOptions, TestProgram + import samba.getopt as options + from ldb import SCOPE_BASE, SCOPE_SUBTREE +@@ -1022,4 +1025,163 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + self.assert_conf_attr_searches(has_rights_to=0) + self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) + ++ def test_timing_attack(self): ++ # Create the machine account. ++ mach_name = f'conf_timing_{random.randint(0, 0xffff)}' ++ mach_dn = Dn(self.ldb_admin, f'CN={mach_name},{self.ou}') ++ details = { ++ 'dn': mach_dn, ++ 'objectclass': 'computer', ++ 'sAMAccountName': f'{mach_name}$', ++ } ++ self.ldb_admin.add(details) ++ ++ # Get the machine account's GUID. ++ res = self.ldb_admin.search(mach_dn, ++ attrs=['objectGUID'], ++ scope=SCOPE_BASE) ++ mach_guid = res[0].get('objectGUID', idx=0) ++ ++ # Now we can create an msFVE-RecoveryInformation object that is a child ++ # of the machine account object. ++ recovery_dn = Dn(self.ldb_admin, str(mach_dn)) ++ recovery_dn.add_child('CN=recovery_info') ++ ++ secret_pw = 'Secret007' ++ not_secret_pw = 'Secret008' ++ ++ secret_pw_utf8 = secret_pw.encode('utf-8') ++ ++ # The crucial attribute, msFVE-RecoveryPassword, is a confidential ++ # attribute. ++ conf_attr = 'msFVE-RecoveryPassword' ++ ++ m = Message(recovery_dn) ++ m['objectClass'] = 'msFVE-RecoveryInformation' ++ m['msFVE-RecoveryGuid'] = mach_guid ++ m[conf_attr] = secret_pw ++ self.ldb_admin.add(m) ++ ++ attrs = [conf_attr] ++ ++ # Search for the confidential attribute as administrator, ensuring it ++ # is visible. ++ res = self.ldb_admin.search(recovery_dn, ++ attrs=attrs, ++ scope=SCOPE_BASE) ++ self.assertEqual(1, len(res)) ++ pw = res[0].get(conf_attr, idx=0) ++ self.assertEqual(secret_pw_utf8, pw) ++ ++ # Repeat the search with an expression matching on the confidential ++ # attribute. This should also work. ++ res = self.ldb_admin.search( ++ recovery_dn, ++ attrs=attrs, ++ expression=f'({conf_attr}={secret_pw})', ++ scope=SCOPE_BASE) ++ self.assertEqual(1, len(res)) ++ pw = res[0].get(conf_attr, idx=0) ++ self.assertEqual(secret_pw_utf8, pw) ++ ++ # Search for the attribute as an unprivileged user. It should not be ++ # visible. ++ user_res = self.ldb_user.search(recovery_dn, ++ attrs=attrs, ++ scope=SCOPE_BASE) ++ pw = user_res[0].get(conf_attr, idx=0) ++ # The attribute should be None. ++ self.assertIsNone(pw) ++ ++ # We use LDAP_MATCHING_RULE_TRANSITIVE_EVAL to create a search ++ # expression that takes a long time to execute, by setting off another ++ # search each time it is evaluated. It makes no difference that the ++ # object on which we're searching has no 'member' attribute. ++ dummy_dn = 'cn=user,cn=users,dc=samba,dc=example,dc=com' ++ slow_subexpr = f'(member:1.2.840.113556.1.4.1941:={dummy_dn})' ++ slow_expr = f'(|{slow_subexpr * 100})' ++ ++ # The full search expression. It comprises a match on the confidential ++ # attribute joined by an AND to our slow search expression, The AND ++ # operator is short-circuiting, so if our first subexpression fails to ++ # match, we'll bail out of the search early. Otherwise, we'll evaluate ++ # the slow part; as its subexpressions are joined by ORs, and will all ++ # fail to match, every one of them will need to be evaluated. By ++ # measuring how long the search takes, we'll be able to infer whether ++ # the confidential attribute matched or not. ++ ++ # This is bad if we are not an administrator, and are able to use this ++ # to determine the values of confidential attributes. Therefore we need ++ # to ensure we can't observe any difference in timing. ++ correct_expr = f'(&({conf_attr}={secret_pw}){slow_expr})' ++ wrong_expr = f'(&({conf_attr}={not_secret_pw}){slow_expr})' ++ ++ def standard_uncertainty_bounds(times): ++ mean = statistics.mean(times) ++ stdev = statistics.stdev(times, mean) ++ ++ return (mean - stdev, mean + stdev) ++ ++ # Perform a number of searches with both correct and incorrect ++ # expressions, and return the uncertainty bounds for each. ++ def time_searches(samdb): ++ warmup_samples = 3 ++ samples = 10 ++ matching_times = [] ++ non_matching_times = [] ++ ++ for _ in range(warmup_samples): ++ samdb.search(recovery_dn, ++ attrs=attrs, ++ expression=correct_expr, ++ scope=SCOPE_BASE) ++ ++ for _ in range(samples): ++ # Measure the time taken for a search, for both a matching and ++ # a non-matching search expression. ++ ++ prev = time.time() ++ samdb.search(recovery_dn, ++ attrs=attrs, ++ expression=correct_expr, ++ scope=SCOPE_BASE) ++ now = time.time() ++ matching_times.append(now - prev) ++ ++ prev = time.time() ++ samdb.search(recovery_dn, ++ attrs=attrs, ++ expression=wrong_expr, ++ scope=SCOPE_BASE) ++ now = time.time() ++ non_matching_times.append(now - prev) ++ ++ matching = standard_uncertainty_bounds(matching_times) ++ non_matching = standard_uncertainty_bounds(non_matching_times) ++ return matching, non_matching ++ ++ def assertRangesDistinct(a, b): ++ a0, a1 = a ++ b0, b1 = b ++ self.assertLess(min(a1, b1), max(a0, b0)) ++ ++ def assertRangesOverlap(a, b): ++ a0, a1 = a ++ b0, b1 = b ++ self.assertGreaterEqual(min(a1, b1), max(a0, b0)) ++ ++ # For an administrator, the uncertainty bounds for matching and ++ # non-matching searches should be distinct. This shows that the two ++ # cases are distinguishable, and therefore that confidential attributes ++ # are visible. ++ admin_matching, admin_non_matching = time_searches(self.ldb_admin) ++ assertRangesDistinct(admin_matching, admin_non_matching) ++ ++ # The user cannot view the confidential attribute, so the uncertainty ++ # bounds for matching and non-matching searches must overlap. The two ++ # cases must be indistinguishable. ++ user_matching, user_non_matching = time_searches(self.ldb_user) ++ assertRangesOverlap(user_matching, user_non_matching) ++ ++ + TestProgram(module=__name__, opts=subunitopts) +-- +2.25.1 \ No newline at end of file diff --git a/backport-0021-CVE-2023-4154.patch b/backport-0021-CVE-2023-4154.patch new file mode 100644 index 0000000000000000000000000000000000000000..cba4472e5f00ef610c469c028e6aa2b44f7784c5 --- /dev/null +++ b/backport-0021-CVE-2023-4154.patch @@ -0,0 +1,109 @@ +From 8f87277b4e926035d825e81c4f8381d917e9d229 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Tue, 8 Aug 2023 17:58:27 +1200 +Subject: [PATCH 26/30] CVE-2023-4154: Unimplement the original DirSync + behaviour without LDAP_DIRSYNC_OBJECT_SECURITY + +This makes LDAP_DIRSYNC_OBJECT_SECURITY the only behaviour provided by +Samba. + +Having a second access control system withing the LDAP stack is unsafe +and this layer is incomplete. + +The current system gives all accounts that have been given the +GUID_DRS_GET_CHANGES extended right SYSTEM access. Currently in Samba +this equates to full access to passwords as well as "RODC Filtered +attributes" (often used with confidential attributes). + +Rather than attempting to correctly filter for secrets (passwords) and +these filtered attributes, as well as preventing search expressions for +both, we leave this complexity to the acl_read module which has this +facility already well tested. + +The implication is that callers will only see and filter by attribute +in DirSync that they could without DirSync. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15424 + +Signed-off-by: Andrew Bartlett + +Conflict: NA +Reference: https://download.samba.org/pub/samba/patches/security/samba-4.17.12-security-2023-10-10.patch +[PATCH 26/30] CVE-2023-4154: Unimplement the original DirSync + behaviour without LDAP_DIRSYNC_OBJECT_SECURITY +--- + selftest/knownfail.d/dirsync | 3 +-- + source4/dsdb/samdb/ldb_modules/dirsync.c | 22 +++++++++++----------- + 2 files changed, 12 insertions(+), 13 deletions(-) + +diff --git a/selftest/knownfail.d/dirsync b/selftest/knownfail.d/dirsync +index db098549a08..fcf4d469d6e 100644 +--- a/selftest/knownfail.d/dirsync ++++ b/selftest/knownfail.d/dirsync +@@ -1,12 +1,11 @@ + ^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_OBJECT_SECURITY_insist_on_empty_element\(.*\) + ^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_unicodePwd_OBJ_SEC_insist_on_empty_element\(.*\) +-^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_unicodePwd_with_GET_CHANGES\(.*\) + ^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_unicodePwd_with_GET_CHANGES_OBJ_SEC_insist_on_empty_element\(.*\) + ^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_unicodePwd_with_GET_CHANGES_insist_on_empty_element\(.*\) + ^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_with_GET_CHANGES_OBJECT_SECURITY_insist_on_empty_element\(.*\) ++^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialDirsyncTests.test_dirsync_with_GET_CHANGES\(.*\) + ^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialFilteredDirsyncTests.test_dirsync_OBJECT_SECURITY_insist_on_empty_element\(.*\) + ^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialFilteredDirsyncTests.test_dirsync_OBJECT_SECURITY_with_GET_CHANGES_insist_on_empty_element\(.*\) +-^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialFilteredDirsyncTests.test_dirsync_with_GET_CHANGES\(.*\) + ^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialFilteredDirsyncTests.test_dirsync_with_GET_CHANGES_attr\(.*\) + ^samba4.ldap.dirsync.python\(.*\).__main__.ConfidentialFilteredDirsyncTests.test_dirsync_with_GET_CHANGES_insist_on_empty_element\(.*\) + ^samba4.ldap.dirsync.python\(.*\).__main__.FilteredDirsyncTests.test_dirsync_with_GET_CHANGES\(.*\) +diff --git a/source4/dsdb/samdb/ldb_modules/dirsync.c b/source4/dsdb/samdb/ldb_modules/dirsync.c +index b3c463741c8..fbb75790095 100644 +--- a/source4/dsdb/samdb/ldb_modules/dirsync.c ++++ b/source4/dsdb/samdb/ldb_modules/dirsync.c +@@ -56,7 +56,6 @@ struct dirsync_context { + bool linkIncrVal; + bool localonly; + bool partial; +- bool assystem; + int functional_level; + const struct GUID *our_invocation_id; + const struct dsdb_schema *schema; +@@ -872,10 +871,6 @@ static int dirsync_search_callback(struct ldb_request *req, struct ldb_reply *ar + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_SHOW_EXTENDED_DN; + +- if (dsc->assystem) { +- flags = flags | DSDB_FLAG_AS_SYSTEM; +- } +- + ret = dsdb_module_search_tree(dsc->module, dsc, &res, + dn, LDB_SCOPE_BASE, + req->op.search.tree, +@@ -1102,16 +1097,21 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req + return LDB_ERR_OPERATIONS_ERROR; + } + objectclass = dsdb_get_structural_oc_from_msg(schema, acl_res->msgs[0]); ++ ++ /* ++ * While we never use the answer to this for access ++ * control (after CVE-2023-4154), we return a ++ * different error message depending on if the user ++ * was granted GUID_DRS_GET_CHANGES to provide a closer ++ * emulation and keep some tests passing. ++ * ++ * (Samba's ACL logic is not well suited to redacting ++ * only the secret and RODC filtered attributes). ++ */ + 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; +- } +- dsc->assystem = true; +- ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL); +- + if (ret != LDB_SUCCESS) { + return ret; + } +-- +2.34.1 diff --git a/backport-0022-CVE-2023-0614.patch b/backport-0022-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..228cd21ced3301e37239fcc8cdadbdb4ccc484e6 --- /dev/null +++ b/backport-0022-CVE-2023-0614.patch @@ -0,0 +1,66 @@ +From b23fb132e63a6d3d791469614593c43906686ac9 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 3 Mar 2023 17:31:54 +1300 +Subject: [PATCH 20/34] CVE-2023-0614 ldb: Add ldb_parse_tree_get_attr() + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb/common/ldb_parse.c | 25 +++++++++++++++++++++++++ + lib/ldb/include/ldb_module.h | 3 +++ + 2 files changed, 28 insertions(+) + +diff --git a/lib/ldb/common/ldb_parse.c b/lib/ldb/common/ldb_parse.c +index f0045ad2093..2d102ff750e 100644 +--- a/lib/ldb/common/ldb_parse.c ++++ b/lib/ldb/common/ldb_parse.c +@@ -997,3 +997,28 @@ struct ldb_parse_tree *ldb_parse_tree_copy_shallow(TALLOC_CTX *mem_ctx, + + return nt; + } ++ ++/* Get the attribute (if any) associated with the top node of a parse tree. */ ++const char *ldb_parse_tree_get_attr(const struct ldb_parse_tree *tree) ++{ ++ switch (tree->operation) { ++ case LDB_OP_AND: ++ case LDB_OP_OR: ++ case LDB_OP_NOT: ++ return NULL; ++ case LDB_OP_EQUALITY: ++ return tree->u.equality.attr; ++ case LDB_OP_SUBSTRING: ++ return tree->u.substring.attr; ++ case LDB_OP_GREATER: ++ case LDB_OP_LESS: ++ case LDB_OP_APPROX: ++ return tree->u.comparison.attr; ++ case LDB_OP_PRESENT: ++ return tree->u.present.attr; ++ case LDB_OP_EXTENDED: ++ return tree->u.extended.attr; ++ } ++ ++ return NULL; ++} +diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h +index 4ae381ba5be..bd369ed9512 100644 +--- a/lib/ldb/include/ldb_module.h ++++ b/lib/ldb/include/ldb_module.h +@@ -490,6 +490,9 @@ int ldb_init_module(const char *version); + */ + bool ldb_dn_replace_components(struct ldb_dn *dn, struct ldb_dn *new_dn); + ++/* Get the attribute (if any) associated with the top node of a parse tree. */ ++const char *ldb_parse_tree_get_attr(const struct ldb_parse_tree *tree); ++ + /* + walk a parse tree, calling the provided callback on each node + */ +-- +2.25.1 \ No newline at end of file diff --git a/backport-0023-CVE-2023-0614.patch b/backport-0023-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..2be9e01114e592858bf8f768f2a738448529856d --- /dev/null +++ b/backport-0023-CVE-2023-0614.patch @@ -0,0 +1,102 @@ +From 3127ba92bf91fa6f666552ac31cb06ffdc6d7e63 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Mon, 27 Feb 2023 13:40:33 +1300 +Subject: [PATCH 21/34] CVE-2023-0614 s4-acl: Split out logic to remove access + checking attributes + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/samdb/ldb_modules/acl_read.c | 58 ++++++++++++++--------- + 1 file changed, 35 insertions(+), 23 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c +index 8814a816797..3980c44345e 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl_read.c ++++ b/source4/dsdb/samdb/ldb_modules/acl_read.c +@@ -545,6 +545,39 @@ static int check_search_ops_access(struct aclread_context *ac, + return ret; + } + ++/* ++ * Whether this attribute was added to perform access checks and must be ++ * removed. ++ */ ++static bool should_remove_attr(const char *attr, const struct aclread_context *ac) ++{ ++ if (ac->added_nTSecurityDescriptor && ++ ldb_attr_cmp("nTSecurityDescriptor", attr) == 0) ++ { ++ return true; ++ } ++ ++ if (ac->added_objectSid && ++ ldb_attr_cmp("objectSid", attr) == 0) ++ { ++ return true; ++ } ++ ++ if (ac->added_instanceType && ++ ldb_attr_cmp("instanceType", attr) == 0) ++ { ++ return true; ++ } ++ ++ if (ac->added_objectClass && ++ ldb_attr_cmp("objectClass", attr) == 0) ++ { ++ return true; ++ } ++ ++ return false; ++} ++ + static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + { + struct ldb_context *ldb; +@@ -619,7 +652,6 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + /* for every element in the message check RP */ + for (i=0; i < msg->num_elements; i++) { + const struct dsdb_attribute *attr; +- bool is_sd, is_objectsid, is_instancetype, is_objectclass; + uint32_t access_mask; + attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, + msg->elements[i].name); +@@ -631,28 +663,8 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + ret = LDB_ERR_OPERATIONS_ERROR; + goto fail; + } +- is_sd = ldb_attr_cmp("nTSecurityDescriptor", +- msg->elements[i].name) == 0; +- is_objectsid = ldb_attr_cmp("objectSid", +- msg->elements[i].name) == 0; +- is_instancetype = ldb_attr_cmp("instanceType", +- msg->elements[i].name) == 0; +- is_objectclass = ldb_attr_cmp("objectClass", +- msg->elements[i].name) == 0; +- /* these attributes were added to perform access checks and must be removed */ +- if (is_objectsid && ac->added_objectSid) { +- ldb_msg_element_mark_inaccessible(&msg->elements[i]); +- continue; +- } +- if (is_instancetype && ac->added_instanceType) { +- ldb_msg_element_mark_inaccessible(&msg->elements[i]); +- continue; +- } +- if (is_objectclass && ac->added_objectClass) { +- ldb_msg_element_mark_inaccessible(&msg->elements[i]); +- continue; +- } +- if (is_sd && ac->added_nTSecurityDescriptor) { ++ /* Remove attributes added to perform access checks. */ ++ if (should_remove_attr(msg->elements[i].name, ac)) { + ldb_msg_element_mark_inaccessible(&msg->elements[i]); + continue; + } +-- +2.25.1 \ No newline at end of file diff --git a/backport-0024-CVE-2023-0614.patch b/backport-0024-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..247eb143727c26ee5907d8ffa31344075fbe4af1 --- /dev/null +++ b/backport-0024-CVE-2023-0614.patch @@ -0,0 +1,52 @@ +From 652fecd7d037992b89ed1a4eb17f9f467c2aadf7 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Mon, 27 Feb 2023 12:19:08 +1300 +Subject: [PATCH 22/34] CVE-2023-0614 s4-dsdb: Add samdb_result_dom_sid_buf() + +This function parses a SID from an ldb_message, similar to +samdb_result_dom_sid(), but does it without allocating anything. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/common/util.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c +index a30ae662c1e..b556f06cb63 100644 +--- a/source4/dsdb/common/util.c ++++ b/source4/dsdb/common/util.c +@@ -365,6 +365,26 @@ struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_messa + return sid; + } + ++/* ++ pull a dom_sid structure from a objectSid in a result set. ++*/ ++int samdb_result_dom_sid_buf(const struct ldb_message *msg, ++ const char *attr, ++ struct dom_sid *sid) ++{ ++ ssize_t ret; ++ const struct ldb_val *v = NULL; ++ v = ldb_msg_find_ldb_val(msg, attr); ++ if (v == NULL) { ++ return LDB_ERR_NO_SUCH_ATTRIBUTE; ++ } ++ ret = sid_parse(v->data, v->length, sid); ++ if (ret == -1) { ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ return LDB_SUCCESS; ++} ++ + /* + pull a guid structure from a objectGUID in a result set. + */ +-- +2.25.1 \ No newline at end of file diff --git a/backport-0025-CVE-2023-0614.patch b/backport-0025-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..78069a2eb93b169c1c05681aa7f0c74317723080 --- /dev/null +++ b/backport-0025-CVE-2023-0614.patch @@ -0,0 +1,218 @@ +From 3ebfe8666c02ab2de823457c68a922d0b0437cec Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Mon, 27 Feb 2023 13:55:36 +1300 +Subject: [PATCH 23/34] CVE-2023-0614 s4-acl: Split out function to set up + access checking variables + +These variables are often used together, and it is useful to have the +setup code in one place. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org adapted to the use of + acl_check_access_on_attribute as + acl_check_access_on_attribute_implicit_owner is + only in Samba 4.18 and newer] + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/samdb/ldb_modules/acl_read.c | 113 +++++++++++++++------- + 1 file changed, 80 insertions(+), 33 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c +index 3980c44345e..6659c71c965 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl_read.c ++++ b/source4/dsdb/samdb/ldb_modules/acl_read.c +@@ -70,6 +70,13 @@ struct aclread_private { + struct ldb_val sd_cached_blob; + }; + ++struct access_check_context { ++ struct security_descriptor *sd; ++ struct dom_sid sid_buf; ++ const struct dom_sid *sid; ++ const struct dsdb_class *objectclass; ++}; ++ + /* + * the object has a parent, so we have to check for visibility + * +@@ -254,7 +261,7 @@ static int aclread_check_object_visible(struct aclread_context *ac, + */ + + static int aclread_get_sd_from_ldb_message(struct aclread_context *ac, +- struct ldb_message *acl_res, ++ const struct ldb_message *acl_res, + struct security_descriptor **sd) + { + struct ldb_message_element *sd_element; +@@ -358,7 +365,7 @@ static uint32_t get_attr_access_mask(const struct dsdb_attribute *attr, + struct parse_tree_aclread_ctx { + struct aclread_context *ac; + TALLOC_CTX *mem_ctx; +- struct dom_sid *sid; ++ const struct dom_sid *sid; + struct ldb_dn *dn; + struct security_descriptor *sd; + const struct dsdb_class *objectclass; +@@ -372,7 +379,7 @@ static int check_attr_access_rights(TALLOC_CTX *mem_ctx, const char *attr_name, + struct aclread_context *ac, + struct security_descriptor *sd, + const struct dsdb_class *objectclass, +- struct dom_sid *sid, struct ldb_dn *dn) ++ const struct dom_sid *sid, struct ldb_dn *dn) + { + int ret; + const struct dsdb_attribute *attr = NULL; +@@ -448,6 +455,69 @@ static const char * parse_tree_get_attr(struct ldb_parse_tree *tree) + return attr; + } + ++static int setup_access_check_context(struct aclread_context *ac, ++ const struct ldb_message *msg, ++ struct access_check_context *ctx) ++{ ++ int ret; ++ ++ /* ++ * Fetch the schema so we can check which attributes are ++ * considered confidential. ++ */ ++ if (ac->schema == NULL) { ++ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); ++ ++ /* Cache the schema for later use. */ ++ ac->schema = dsdb_get_schema(ldb, ac); ++ ++ if (ac->schema == NULL) { ++ return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, ++ "aclread_callback: Error obtaining schema."); ++ } ++ } ++ ++ /* Fetch the object's security descriptor. */ ++ ret = aclread_get_sd_from_ldb_message(ac, msg, &ctx->sd); ++ if (ret != LDB_SUCCESS) { ++ ldb_debug_set(ldb_module_get_ctx(ac->module), LDB_DEBUG_FATAL, ++ "acl_read: cannot get descriptor of %s: %s\n", ++ ldb_dn_get_linearized(msg->dn), ldb_strerror(ret)); ++ return LDB_ERR_OPERATIONS_ERROR; ++ } else if (ctx->sd == NULL) { ++ ldb_debug_set(ldb_module_get_ctx(ac->module), LDB_DEBUG_FATAL, ++ "acl_read: cannot get descriptor of %s (attribute not found)\n", ++ ldb_dn_get_linearized(msg->dn)); ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ /* ++ * Get the most specific structural object class for the ACL check ++ */ ++ ctx->objectclass = dsdb_get_structural_oc_from_msg(ac->schema, msg); ++ if (ctx->objectclass == NULL) { ++ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module), ++ "acl_read: Failed to find a structural class for %s", ++ ldb_dn_get_linearized(msg->dn)); ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ ++ /* Fetch the object's SID. */ ++ ret = samdb_result_dom_sid_buf(msg, "objectSid", &ctx->sid_buf); ++ if (ret == LDB_SUCCESS) { ++ ctx->sid = &ctx->sid_buf; ++ } else if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { ++ /* This is expected. */ ++ ctx->sid = NULL; ++ } else { ++ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module), ++ "acl_read: Failed to parse objectSid as dom_sid for %s", ++ ldb_dn_get_linearized(msg->dn)); ++ return ret; ++ } ++ ++ return LDB_SUCCESS; ++} ++ + /* + * Checks a single attribute in the search parse-tree to make sure the user has + * sufficient rights to view it. +@@ -522,7 +592,7 @@ static int check_search_ops_access(struct aclread_context *ac, + TALLOC_CTX *mem_ctx, + struct security_descriptor *sd, + const struct dsdb_class *objectclass, +- struct dom_sid *sid, struct ldb_dn *dn, ++ const struct dom_sid *sid, struct ldb_dn *dn, + bool *suppress_result) + { + int ret; +@@ -585,10 +655,8 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + struct ldb_message *msg; + int ret; + unsigned int i; +- struct security_descriptor *sd = NULL; +- struct dom_sid *sid = NULL; ++ struct access_check_context acl_ctx; + TALLOC_CTX *tmp_ctx; +- const struct dsdb_class *objectclass; + bool suppress_result = false; + + ac = talloc_get_type_abort(req->context, struct aclread_context); +@@ -604,32 +672,11 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + switch (ares->type) { + case LDB_REPLY_ENTRY: + msg = ares->message; +- ret = aclread_get_sd_from_ldb_message(ac, msg, &sd); ++ ret = setup_access_check_context(ac, msg, &acl_ctx); + if (ret != LDB_SUCCESS) { +- ldb_debug_set(ldb, LDB_DEBUG_FATAL, +- "acl_read: cannot get descriptor of %s: %s\n", +- ldb_dn_get_linearized(msg->dn), ldb_strerror(ret)); +- ret = LDB_ERR_OPERATIONS_ERROR; +- goto fail; +- } else if (sd == NULL) { +- ldb_debug_set(ldb, LDB_DEBUG_FATAL, +- "acl_read: cannot get descriptor of %s (attribute not found)\n", +- ldb_dn_get_linearized(msg->dn)); +- ret = LDB_ERR_OPERATIONS_ERROR; +- goto fail; +- } +- /* +- * Get the most specific structural object class for the ACL check +- */ +- objectclass = dsdb_get_structural_oc_from_msg(ac->schema, msg); +- if (objectclass == NULL) { +- ldb_asprintf_errstring(ldb, "acl_read: Failed to find a structural class for %s", +- ldb_dn_get_linearized(msg->dn)); +- ret = LDB_ERR_OPERATIONS_ERROR; +- goto fail; ++ return ret; + } + +- sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid"); + if (!ldb_dn_is_null(msg->dn)) { + /* + * this is a real object, so we have +@@ -678,8 +725,8 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + + ret = acl_check_access_on_attribute(ac->module, + tmp_ctx, +- sd, +- sid, ++ acl_ctx.sd, ++ acl_ctx.sid, + access_mask, + attr, + objectclass); +@@ -733,7 +780,7 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + * check access rights for the search attributes, as well as the + * attribute values actually being returned + */ +- ret = check_search_ops_access(ac, tmp_ctx, sd, objectclass, sid, ++ ret = check_search_ops_access(ac, tmp_ctx, acl_ctx.sd, acl_ctx.objectclass, acl_ctx.sid, + msg->dn, &suppress_result); + if (ret != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, +-- +2.25.1 \ No newline at end of file diff --git a/backport-0026-CVE-2023-0614.patch b/backport-0026-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..1fa10f617b9e58c0f533cf3518b202ac4bbec116 --- /dev/null +++ b/backport-0026-CVE-2023-0614.patch @@ -0,0 +1,1711 @@ +From f87af853e2db99269acea572dcc109bc6f797aa9 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 3 Mar 2023 17:34:29 +1300 +Subject: [PATCH 24/34] CVE-2023-0614 ldb: Prevent disclosure of confidential + attributes + +Add a hook, acl_redact_msg_for_filter(), in the aclread module, that +marks inaccessible any message elements used by an LDAP search filter +that the user has no right to access. Make the various ldb_match_*() +functions check whether message elements are accessible, and refuse to +match any that are not. Remaining message elements, not mentioned in the +search filter, are checked in aclread_callback(), and any inaccessible +elements are removed at this point. + +Certain attributes, namely objectClass, distinguishedName, name, and +objectGUID, are always present, and hence the presence of said +attributes is always allowed to be checked in a search filter. This +corresponds with the behaviour of Windows. + +Further, we unconditionally allow the attributes isDeleted and +isRecycled in a check for presence or equality. Windows is not known to +make this special exception, but it seems mostly harmless, and should +mitigate the performance impact on searches made by the show_deleted +module. + +As a result of all these changes, our behaviour regarding confidential +attributes happens to match Windows more closely. For the test in +confidential_attr.py, we can now model our attribute handling with +DC_MODE_RETURN_ALL, which corresponds to the behaviour exhibited by +Windows. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Pair-Programmed-With: Andrew Bartlett + +Signed-off-by: Joseph Sutton +Signed-off-by: Andrew Bartlett +Reviewed-by: Andrew Bartlett + +[abartlet@samba.org adapted due to Samba 4.17 and lower +not having the patches for CVE-2020-25720] + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb-samba/ldb_matching_rules.c | 15 + + lib/ldb/common/ldb_match.c | 37 + + lib/ldb/include/ldb_module.h | 11 + + lib/ldb/include/ldb_private.h | 5 + + lib/ldb/ldb_key_value/ldb_kv_index.c | 8 + + lib/ldb/ldb_key_value/ldb_kv_search.c | 15 + + selftest/knownfail.d/confidential-attr-timing | 1 - + source4/dsdb/samdb/ldb_modules/acl.c | 183 +--- + source4/dsdb/samdb/ldb_modules/acl_read.c | 837 ++++++++++++------ + source4/dsdb/samdb/samdb.h | 2 + + .../dsdb/tests/python/confidential_attr.py | 12 +- + source4/setup/schema_samba4.ldif | 1 + + 12 files changed, 672 insertions(+), 455 deletions(-) + delete mode 100644 selftest/knownfail.d/confidential-attr-timing + +diff --git a/lib/ldb-samba/ldb_matching_rules.c b/lib/ldb-samba/ldb_matching_rules.c +index 827f3920ae8..0c4c31e49f9 100644 +--- a/lib/ldb-samba/ldb_matching_rules.c ++++ b/lib/ldb-samba/ldb_matching_rules.c +@@ -87,6 +87,11 @@ static int ldb_eval_transitive_filter_helper(TALLOC_CTX *mem_ctx, + return LDB_SUCCESS; + } + ++ if (ldb_msg_element_is_inaccessible(el)) { ++ *matched = false; ++ return LDB_SUCCESS; ++ } ++ + /* + * If the value to match is present in the attribute values of the + * current entry being visited, set matched to true and return OK +@@ -370,6 +375,11 @@ static int dsdb_match_for_dns_to_tombstone_time(struct ldb_context *ldb, + return LDB_SUCCESS; + } + ++ if (ldb_msg_element_is_inaccessible(el)) { ++ *matched = false; ++ return LDB_SUCCESS; ++ } ++ + session_info = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), + struct auth_session_info); + if (session_info == NULL) { +@@ -489,6 +499,11 @@ static int dsdb_match_for_expunge(struct ldb_context *ldb, + return LDB_SUCCESS; + } + ++ if (ldb_msg_element_is_inaccessible(el)) { ++ *matched = false; ++ return LDB_SUCCESS; ++ } ++ + session_info + = talloc_get_type(ldb_get_opaque(ldb, DSDB_SESSION_INFO), + struct auth_session_info); +diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c +index 2f4d41f3441..17314f1b9ca 100644 +--- a/lib/ldb/common/ldb_match.c ++++ b/lib/ldb/common/ldb_match.c +@@ -98,6 +98,11 @@ static int ldb_match_present(struct ldb_context *ldb, + return LDB_SUCCESS; + } + ++ if (ldb_msg_element_is_inaccessible(el)) { ++ *matched = false; ++ return LDB_SUCCESS; ++ } ++ + a = ldb_schema_attribute_by_name(ldb, el->name); + if (!a) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; +@@ -139,6 +144,11 @@ static int ldb_match_comparison(struct ldb_context *ldb, + return LDB_SUCCESS; + } + ++ if (ldb_msg_element_is_inaccessible(el)) { ++ *matched = false; ++ return LDB_SUCCESS; ++ } ++ + a = ldb_schema_attribute_by_name(ldb, el->name); + if (!a) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; +@@ -209,6 +219,11 @@ static int ldb_match_equality(struct ldb_context *ldb, + return LDB_SUCCESS; + } + ++ if (ldb_msg_element_is_inaccessible(el)) { ++ *matched = false; ++ return LDB_SUCCESS; ++ } ++ + a = ldb_schema_attribute_by_name(ldb, el->name); + if (a == NULL) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; +@@ -370,6 +385,11 @@ static int ldb_match_substring(struct ldb_context *ldb, + return LDB_SUCCESS; + } + ++ if (ldb_msg_element_is_inaccessible(el)) { ++ *matched = false; ++ return LDB_SUCCESS; ++ } ++ + for (i = 0; i < el->num_values; i++) { + int ret; + ret = ldb_wildcard_compare(ldb, tree, el->values[i], matched); +@@ -443,6 +463,11 @@ static int ldb_match_bitmask(struct ldb_context *ldb, + return LDB_SUCCESS; + } + ++ if (ldb_msg_element_is_inaccessible(el)) { ++ *matched = false; ++ return LDB_SUCCESS; ++ } ++ + for (i=0;inum_values;i++) { + int ret; + struct ldb_val *v = &el->values[i]; +@@ -741,3 +766,15 @@ int ldb_register_extended_match_rule(struct ldb_context *ldb, + return LDB_SUCCESS; + } + ++int ldb_register_redact_callback(struct ldb_context *ldb, ++ ldb_redact_fn redact_fn, ++ struct ldb_module *module) ++{ ++ if (ldb->redact.callback != NULL) { ++ return LDB_ERR_ENTRY_ALREADY_EXISTS; ++ } ++ ++ ldb->redact.callback = redact_fn; ++ ldb->redact.module = module; ++ return LDB_SUCCESS; ++} +diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h +index bd369ed9512..0f14b1ad346 100644 +--- a/lib/ldb/include/ldb_module.h ++++ b/lib/ldb/include/ldb_module.h +@@ -102,6 +102,12 @@ struct ldb_module; + */ + #define LDB_FLAG_INTERNAL_SHARED_VALUES 0x200 + ++/* ++ * this attribute has been access checked. We know the user has the right to ++ * view it. Used internally in Samba aclread module. ++ */ ++#define LDB_FLAG_INTERNAL_ACCESS_CHECKED 0x400 ++ + /* an extended match rule that always fails to match */ + #define SAMBA_LDAP_MATCH_ALWAYS_FALSE "1.3.6.1.4.1.7165.4.5.1" + +@@ -520,6 +526,11 @@ void ldb_msg_element_mark_inaccessible(struct ldb_message_element *el); + bool ldb_msg_element_is_inaccessible(const struct ldb_message_element *el); + void ldb_msg_remove_inaccessible(struct ldb_message *msg); + ++typedef int (*ldb_redact_fn)(struct ldb_module *, struct ldb_request *, struct ldb_message *); ++int ldb_register_redact_callback(struct ldb_context *ldb, ++ ldb_redact_fn redact_fn, ++ struct ldb_module *module); ++ + /* + * these pack/unpack functions are exposed in the library for use by + * ldb tools like ldbdump and for use in tests, +diff --git a/lib/ldb/include/ldb_private.h b/lib/ldb/include/ldb_private.h +index ca43817d07a..b0a42f6421c 100644 +--- a/lib/ldb/include/ldb_private.h ++++ b/lib/ldb/include/ldb_private.h +@@ -119,6 +119,11 @@ struct ldb_context { + struct ldb_extended_match_entry *prev, *next; + } *extended_match_rules; + ++ struct { ++ struct ldb_module *module; ++ ldb_redact_fn callback; ++ } redact; ++ + /* custom utf8 functions */ + struct ldb_utf8_fns utf8_fns; + +diff --git a/lib/ldb/ldb_key_value/ldb_kv_index.c b/lib/ldb/ldb_key_value/ldb_kv_index.c +index 203266ea8c9..163052fecf7 100644 +--- a/lib/ldb/ldb_key_value/ldb_kv_index.c ++++ b/lib/ldb/ldb_key_value/ldb_kv_index.c +@@ -2428,6 +2428,14 @@ static int ldb_kv_index_filter(struct ldb_kv_private *ldb_kv, + return LDB_ERR_OPERATIONS_ERROR; + } + ++ if (ldb->redact.callback != NULL) { ++ ret = ldb->redact.callback(ldb->redact.module, ac->req, msg); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(msg); ++ return ret; ++ } ++ } ++ + /* + * We trust the index for LDB_SCOPE_ONELEVEL + * unless the index key has been truncated. +diff --git a/lib/ldb/ldb_key_value/ldb_kv_search.c b/lib/ldb/ldb_key_value/ldb_kv_search.c +index f3333510eab..d187ba223e1 100644 +--- a/lib/ldb/ldb_key_value/ldb_kv_search.c ++++ b/lib/ldb/ldb_key_value/ldb_kv_search.c +@@ -395,6 +395,14 @@ static int search_func(_UNUSED_ struct ldb_kv_private *ldb_kv, + } + } + ++ if (ldb->redact.callback != NULL) { ++ ret = ldb->redact.callback(ldb->redact.module, ac->req, msg); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(msg); ++ return ret; ++ } ++ } ++ + /* see if it matches the given expression */ + ret = ldb_match_msg_error(ldb, msg, + ac->tree, ac->base, ac->scope, &matched); +@@ -530,6 +538,13 @@ static int ldb_kv_search_and_return_base(struct ldb_kv_private *ldb_kv, + return ret; + } + ++ if (ldb->redact.callback != NULL) { ++ ret = ldb->redact.callback(ldb->redact.module, ctx->req, msg); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(msg); ++ return ret; ++ } ++ } + + /* + * We use this, not ldb_match_msg_error() as we know +diff --git a/selftest/knownfail.d/confidential-attr-timing b/selftest/knownfail.d/confidential-attr-timing +deleted file mode 100644 +index e213cdb16d3..00000000000 +--- a/selftest/knownfail.d/confidential-attr-timing ++++ /dev/null +@@ -1 +0,0 @@ +-^samba4.ldap.confidential_attr.python\(ad_dc_slowtests\).__main__.ConfidentialAttrTestDirsync.test_timing_attack\(ad_dc_slowtests\) +diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c +index 4098ae2d671..5c57dd25faa 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl.c ++++ b/source4/dsdb/samdb/ldb_modules/acl.c +@@ -46,11 +46,6 @@ + #undef strcasecmp + #undef strncasecmp + +-struct extended_access_check_attribute { +- const char *oa_name; +- const uint32_t requires_rights; +-}; +- + struct acl_private { + bool acl_search; + const char **password_attrs; +@@ -58,7 +53,6 @@ struct acl_private { + uint64_t cached_schema_metadata_usn; + uint64_t cached_schema_loaded_usn; + const char **confidential_attrs; +- bool userPassword_support; + }; + + struct acl_context { +@@ -66,15 +60,12 @@ struct acl_context { + struct ldb_request *req; + bool am_system; + bool am_administrator; +- bool modify_search; + bool constructed_attrs; + bool allowedAttributes; + bool allowedAttributesEffective; + bool allowedChildClasses; + bool allowedChildClassesEffective; + bool sDRightsEffective; +- bool userPassword; +- const char * const *attrs; + struct dsdb_schema *schema; + }; + +@@ -83,25 +74,9 @@ static int acl_module_init(struct ldb_module *module) + struct ldb_context *ldb; + struct acl_private *data; + int ret; +- unsigned int i, n, j; +- TALLOC_CTX *mem_ctx; +- static const char * const attrs[] = { "passwordAttribute", NULL }; +- static const char * const secret_attrs[] = { +- DSDB_SECRET_ATTRIBUTES +- }; +- struct ldb_result *res; +- struct ldb_message *msg; +- struct ldb_message_element *password_attributes; + + ldb = ldb_module_get_ctx(module); + +- ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID); +- if (ret != LDB_SUCCESS) { +- ldb_debug(ldb, LDB_DEBUG_ERROR, +- "acl_module_init: Unable to register control with rootdse!\n"); +- return ldb_operr(ldb); +- } +- + data = talloc_zero(module, struct acl_private); + if (data == NULL) { + return ldb_oom(ldb); +@@ -111,91 +86,14 @@ static int acl_module_init(struct ldb_module *module) + NULL, "acl", "search", true); + ldb_module_set_private(module, data); + +- mem_ctx = talloc_new(module); +- if (!mem_ctx) { +- return ldb_oom(ldb); +- } +- +- ret = dsdb_module_search_dn(module, mem_ctx, &res, +- ldb_dn_new(mem_ctx, ldb, "@KLUDGEACL"), +- attrs, +- DSDB_FLAG_NEXT_MODULE | +- DSDB_FLAG_AS_SYSTEM, +- NULL); +- if (ret != LDB_SUCCESS) { +- goto done; +- } +- if (res->count == 0) { +- goto done; +- } +- +- if (res->count > 1) { +- talloc_free(mem_ctx); +- return LDB_ERR_CONSTRAINT_VIOLATION; +- } +- +- msg = res->msgs[0]; +- +- password_attributes = ldb_msg_find_element(msg, "passwordAttribute"); +- if (!password_attributes) { +- goto done; +- } +- data->password_attrs = talloc_array(data, const char *, +- password_attributes->num_values + +- ARRAY_SIZE(secret_attrs) + 1); +- if (!data->password_attrs) { +- talloc_free(mem_ctx); +- return ldb_oom(ldb); +- } +- +- n = 0; +- for (i=0; i < password_attributes->num_values; i++) { +- data->password_attrs[n] = (const char *)password_attributes->values[i].data; +- talloc_steal(data->password_attrs, password_attributes->values[i].data); +- n++; +- } +- +- for (i=0; i < ARRAY_SIZE(secret_attrs); i++) { +- bool found = false; +- +- for (j=0; j < n; j++) { +- if (strcasecmp(data->password_attrs[j], secret_attrs[i]) == 0) { +- found = true; +- break; +- } +- } +- +- if (found) { +- continue; +- } +- +- data->password_attrs[n] = talloc_strdup(data->password_attrs, +- secret_attrs[i]); +- if (data->password_attrs[n] == NULL) { +- talloc_free(mem_ctx); +- return ldb_oom(ldb); +- } +- n++; +- } +- data->password_attrs[n] = NULL; +- +-done: +- talloc_free(mem_ctx); +- ret = ldb_next_init(module); +- ++ ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID); + if (ret != LDB_SUCCESS) { +- return ret; ++ ldb_debug(ldb, LDB_DEBUG_ERROR, ++ "acl_module_init: Unable to register control with rootdse!\n"); ++ return ldb_operr(ldb); + } + +- /* +- * Check this after the modules have be initialised so we +- * can actually read the backend DB. +- */ +- data->userPassword_support +- = dsdb_user_password_support(module, +- module, +- NULL); +- return ret; ++ return ldb_next_init(module); + } + + static int acl_allowedAttributes(struct ldb_module *module, +@@ -2522,29 +2420,11 @@ static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares) + ares->controls); + } + +- if (data->password_attrs != NULL) { +- for (i = 0; data->password_attrs[i]; i++) { +- if ((!ac->userPassword) && +- (ldb_attr_cmp(data->password_attrs[i], +- "userPassword") == 0)) +- { +- continue; +- } +- +- ldb_msg_remove_attr(ares->message, data->password_attrs[i]); +- } +- } +- + if (ac->am_administrator) { + return ldb_module_send_entry(ac->req, ares->message, + ares->controls); + } + +- ret = acl_search_update_confidential_attrs(ac, data); +- if (ret != LDB_SUCCESS) { +- return ret; +- } +- + if (data->confidential_attrs != NULL) { + for (i = 0; data->confidential_attrs[i]; i++) { + ldb_msg_remove_attr(ares->message, +@@ -2569,11 +2449,12 @@ static int acl_search(struct ldb_module *module, struct ldb_request *req) + { + struct ldb_context *ldb; + struct acl_context *ac; +- struct ldb_parse_tree *down_tree; ++ struct ldb_parse_tree *down_tree = req->op.search.tree; + struct ldb_request *down_req; + struct acl_private *data; + int ret; + unsigned int i; ++ bool modify_search = true; + + if (ldb_dn_is_special(req->op.search.base)) { + return ldb_next_request(module, req); +@@ -2592,13 +2473,11 @@ static int acl_search(struct ldb_module *module, struct ldb_request *req) + ac->am_system = dsdb_module_am_system(module); + ac->am_administrator = dsdb_module_am_administrator(module); + ac->constructed_attrs = false; +- ac->modify_search = true; + ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes"); + ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective"); + ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses"); + ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective"); + ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective"); +- ac->userPassword = true; + ac->schema = dsdb_get_schema(ldb, ac); + + ac->constructed_attrs |= ac->allowedAttributes; +@@ -2608,13 +2487,13 @@ static int acl_search(struct ldb_module *module, struct ldb_request *req) + ac->constructed_attrs |= ac->sDRightsEffective; + + if (data == NULL) { +- ac->modify_search = false; ++ modify_search = false; + } + if (ac->am_system) { +- ac->modify_search = false; ++ modify_search = false; + } + +- if (!ac->constructed_attrs && !ac->modify_search) { ++ if (!ac->constructed_attrs && !modify_search) { + talloc_free(ac); + return ldb_next_request(module, req); + } +@@ -2624,38 +2503,24 @@ static int acl_search(struct ldb_module *module, struct ldb_request *req) + return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, + "acl_private data is missing"); + } +- ac->userPassword = data->userPassword_support; +- +- ret = acl_search_update_confidential_attrs(ac, data); +- if (ret != LDB_SUCCESS) { +- return ret; +- } + +- down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree); +- if (down_tree == NULL) { +- return ldb_oom(ldb); +- } ++ if (!ac->am_system && !ac->am_administrator) { ++ ret = acl_search_update_confidential_attrs(ac, data); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } + +- if (!ac->am_system && data->password_attrs) { +- for (i = 0; data->password_attrs[i]; i++) { +- if ((!ac->userPassword) && +- (ldb_attr_cmp(data->password_attrs[i], +- "userPassword") == 0)) +- { +- continue; ++ if (data->confidential_attrs != NULL) { ++ down_tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree); ++ if (down_tree == NULL) { ++ return ldb_oom(ldb); + } + +- ldb_parse_tree_attr_replace(down_tree, +- data->password_attrs[i], +- "kludgeACLredactedattribute"); +- } +- } +- +- if (!ac->am_system && !ac->am_administrator && data->confidential_attrs) { +- for (i = 0; data->confidential_attrs[i]; i++) { +- ldb_parse_tree_attr_replace(down_tree, +- data->confidential_attrs[i], +- "kludgeACLredactedattribute"); ++ for (i = 0; data->confidential_attrs[i]; i++) { ++ ldb_parse_tree_attr_replace(down_tree, ++ data->confidential_attrs[i], ++ "kludgeACLredactedattribute"); ++ } + } + } + +diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c +index 6659c71c965..8ca8607b925 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl_read.c ++++ b/source4/dsdb/samdb/ldb_modules/acl_read.c +@@ -37,20 +37,25 @@ + #include "librpc/gen_ndr/ndr_security.h" + #include "param/param.h" + #include "dsdb/samdb/ldb_modules/util.h" ++#include "lib/util/binsearch.h" + + #undef strcasecmp + ++struct ldb_attr_vec { ++ const char** attrs; ++ size_t len; ++ size_t capacity; ++}; ++ + struct aclread_context { + struct ldb_module *module; + struct ldb_request *req; +- const char * const *attrs; + const struct dsdb_schema *schema; + uint32_t sd_flags; + bool added_nTSecurityDescriptor; + bool added_instanceType; + bool added_objectSid; + bool added_objectClass; +- bool indirsync; + + bool do_list_object_initialized; + bool do_list_object; +@@ -60,6 +65,11 @@ struct aclread_context { + /* cache on the last parent we checked in this search */ + struct ldb_dn *last_parent_dn; + int last_parent_check_ret; ++ ++ bool am_administrator; ++ ++ bool got_tree_attrs; ++ struct ldb_attr_vec tree_attrs; + }; + + struct aclread_private { +@@ -68,6 +78,7 @@ struct aclread_private { + /* cache of the last SD we read during any search */ + struct security_descriptor *sd_cached; + struct ldb_val sd_cached_blob; ++ const char **password_attrs; + }; + + struct access_check_context { +@@ -77,6 +88,183 @@ struct access_check_context { + const struct dsdb_class *objectclass; + }; + ++static void acl_element_mark_access_checked(struct ldb_message_element *el) ++{ ++ el->flags |= LDB_FLAG_INTERNAL_ACCESS_CHECKED; ++} ++ ++static bool acl_element_is_access_checked(const struct ldb_message_element *el) ++{ ++ return (el->flags & LDB_FLAG_INTERNAL_ACCESS_CHECKED) != 0; ++} ++ ++static bool attr_in_vec(const struct ldb_attr_vec *vec, const char *attr) ++{ ++ const char **found = NULL; ++ ++ if (vec == NULL) { ++ return false; ++ } ++ ++ BINARY_ARRAY_SEARCH_V(vec->attrs, ++ vec->len, ++ attr, ++ ldb_attr_cmp, ++ found); ++ return found != NULL; ++} ++ ++static int acl_attr_cmp_fn(const char *a, const char **b) ++{ ++ return ldb_attr_cmp(a, *b); ++} ++ ++static int attr_vec_add_unique(TALLOC_CTX *mem_ctx, ++ struct ldb_attr_vec *vec, ++ const char *attr) ++{ ++ const char **exact = NULL; ++ const char **next = NULL; ++ size_t next_idx = 0; ++ ++ BINARY_ARRAY_SEARCH_GTE(vec->attrs, ++ vec->len, ++ attr, ++ acl_attr_cmp_fn, ++ exact, ++ next); ++ if (exact != NULL) { ++ return LDB_SUCCESS; ++ } ++ ++ if (vec->len == SIZE_MAX) { ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ ++ if (next != NULL) { ++ next_idx = next - vec->attrs; ++ } ++ ++ if (vec->len >= vec->capacity) { ++ const char **attrs = NULL; ++ ++ if (vec->capacity == 0) { ++ vec->capacity = 4; ++ } else { ++ if (vec->capacity > SIZE_MAX / 2) { ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ vec->capacity *= 2; ++ } ++ ++ attrs = talloc_realloc(mem_ctx, vec->attrs, const char *, vec->capacity); ++ if (attrs == NULL) { ++ return LDB_ERR_OPERATIONS_ERROR; ++ } ++ ++ vec->attrs = attrs; ++ } ++ SMB_ASSERT(vec->len < vec->capacity); ++ ++ if (next == NULL) { ++ vec->attrs[vec->len++] = attr; ++ } else { ++ size_t count = (vec->len - next_idx) * sizeof (vec->attrs[0]); ++ memmove(&vec->attrs[next_idx + 1], ++ &vec->attrs[next_idx], ++ count); ++ ++ vec->attrs[next_idx] = attr; ++ ++vec->len; ++ } ++ ++ return LDB_SUCCESS; ++} ++ ++static bool ldb_attr_always_present(const char *attr) ++{ ++ static const char * const attrs_always_present[] = { ++ "objectClass", ++ "distinguishedName", ++ "name", ++ "objectGUID", ++ NULL ++ }; ++ ++ return ldb_attr_in_list(attrs_always_present, attr); ++} ++ ++static bool ldb_attr_always_visible(const char *attr) ++{ ++ static const char * const attrs_always_visible[] = { ++ "isDeleted", ++ "isRecycled", ++ NULL ++ }; ++ ++ return ldb_attr_in_list(attrs_always_visible, attr); ++} ++ ++/* Collect a list of attributes required to match a given parse tree. */ ++static int ldb_parse_tree_collect_acl_attrs(struct ldb_module *module, ++ TALLOC_CTX *mem_ctx, ++ struct ldb_attr_vec *attrs, ++ const struct ldb_parse_tree *tree) ++{ ++ const char *attr = NULL; ++ unsigned int i; ++ int ret; ++ ++ if (tree == NULL) { ++ return 0; ++ } ++ ++ switch (tree->operation) { ++ case LDB_OP_OR: ++ case LDB_OP_AND: /* attributes stored in list of subtrees */ ++ for (i = 0; i < tree->u.list.num_elements; i++) { ++ ret = ldb_parse_tree_collect_acl_attrs(module, mem_ctx, ++ attrs, tree->u.list.elements[i]); ++ if (ret) { ++ return ret; ++ } ++ } ++ return 0; ++ ++ case LDB_OP_NOT: /* attributes stored in single subtree */ ++ return ldb_parse_tree_collect_acl_attrs(module, mem_ctx, attrs, tree->u.isnot.child); ++ ++ case LDB_OP_PRESENT: ++ /* ++ * If the search filter is checking for an attribute's presence, ++ * and the attribute is always present, we can skip access ++ * rights checks. Every object has these attributes, and so ++ * there's no security reason to hide their presence. ++ * Note: the acl.py tests (e.g. test_search1()) rely on this ++ * exception. I.e. even if we lack Read Property (RP) rights ++ * for a child object, it should still appear as a visible ++ * object in 'objectClass=*' searches, so long as we have List ++ * Contents (LC) rights for the object. ++ */ ++ if (ldb_attr_always_present(tree->u.present.attr)) { ++ /* No need to check this attribute. */ ++ return 0; ++ } ++ ++ FALL_THROUGH; ++ case LDB_OP_EQUALITY: ++ if (ldb_attr_always_visible(tree->u.present.attr)) { ++ /* No need to check this attribute. */ ++ return 0; ++ } ++ ++ FALL_THROUGH; ++ default: /* single attribute in tree */ ++ attr = ldb_parse_tree_get_attr(tree); ++ return attr_vec_add_unique(mem_ctx, attrs, attr); ++ } ++} ++ + /* + * the object has a parent, so we have to check for visibility + * +@@ -308,16 +496,11 @@ static int aclread_get_sd_from_ldb_message(struct aclread_context *ac, + } + + talloc_unlink(private_data, private_data->sd_cached_blob.data); +- if (ac->added_nTSecurityDescriptor) { +- private_data->sd_cached_blob = sd_element->values[0]; +- talloc_steal(private_data, sd_element->values[0].data); +- } else { +- private_data->sd_cached_blob = ldb_val_dup(private_data, +- &sd_element->values[0]); +- if (private_data->sd_cached_blob.data == NULL) { +- TALLOC_FREE(*sd); +- return ldb_operr(ldb); +- } ++ private_data->sd_cached_blob = ldb_val_dup(private_data, ++ &sd_element->values[0]); ++ if (private_data->sd_cached_blob.data == NULL) { ++ TALLOC_FREE(*sd); ++ return ldb_operr(ldb); + } + + talloc_unlink(private_data, private_data->sd_cached); +@@ -326,6 +509,27 @@ static int aclread_get_sd_from_ldb_message(struct aclread_context *ac, + return LDB_SUCCESS; + } + ++/* Check whether the attribute is a password attribute. */ ++static bool attr_is_secret(const char *attr, const struct aclread_private *private_data) ++{ ++ unsigned i; ++ ++ if (private_data->password_attrs == NULL) { ++ return false; ++ } ++ ++ for (i = 0; private_data->password_attrs[i] != NULL; ++i) { ++ const char *password_attr = private_data->password_attrs[i]; ++ if (ldb_attr_cmp(attr, password_attr) != 0) { ++ continue; ++ } ++ ++ return true; ++ } ++ ++ return false; ++} ++ + /* + * Returns the access mask required to read a given attribute + */ +@@ -361,61 +565,59 @@ static uint32_t get_attr_access_mask(const struct dsdb_attribute *attr, + return access_mask; + } + +-/* helper struct for traversing the attributes in the search-tree */ +-struct parse_tree_aclread_ctx { +- struct aclread_context *ac; +- TALLOC_CTX *mem_ctx; +- const struct dom_sid *sid; +- struct ldb_dn *dn; +- struct security_descriptor *sd; +- const struct dsdb_class *objectclass; +- bool suppress_result; +-}; +- + /* +- * Checks that the user has sufficient access rights to view an attribute ++ * Checks that the user has sufficient access rights to view an attribute, else ++ * marks it as inaccessible. + */ +-static int check_attr_access_rights(TALLOC_CTX *mem_ctx, const char *attr_name, +- struct aclread_context *ac, +- struct security_descriptor *sd, +- const struct dsdb_class *objectclass, +- const struct dom_sid *sid, struct ldb_dn *dn) ++static int acl_redact_attr(TALLOC_CTX *mem_ctx, ++ struct ldb_message_element *el, ++ struct aclread_context *ac, ++ const struct aclread_private *private_data, ++ const struct ldb_message *msg, ++ const struct dsdb_schema *schema, ++ const struct security_descriptor *sd, ++ const struct dom_sid *sid, ++ const struct dsdb_class *objectclass) + { + int ret; + const struct dsdb_attribute *attr = NULL; + uint32_t access_mask; + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + +- attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, attr_name); ++ if (attr_is_secret(el->name, private_data)) { ++ ldb_msg_element_mark_inaccessible(el); ++ return LDB_SUCCESS; ++ } ++ ++ /* Look up the attribute in the schema. */ ++ attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name); + if (!attr) { + ldb_debug_set(ldb, +- LDB_DEBUG_TRACE, +- "acl_read: %s cannot find attr[%s] in schema," +- "ignoring\n", +- ldb_dn_get_linearized(dn), attr_name); +- return LDB_SUCCESS; ++ LDB_DEBUG_FATAL, ++ "acl_read: %s cannot find attr[%s] in schema\n", ++ ldb_dn_get_linearized(msg->dn), el->name); ++ return LDB_ERR_OPERATIONS_ERROR; + } + + access_mask = get_attr_access_mask(attr, ac->sd_flags); +- +- /* the access-mask should be non-zero. Skip attribute otherwise */ + if (access_mask == 0) { + DBG_ERR("Could not determine access mask for attribute %s\n", +- attr_name); ++ el->name); ++ ldb_msg_element_mark_inaccessible(el); + return LDB_SUCCESS; + } + ++ /* We must check whether the user has rights to view the attribute. */ ++ + ret = acl_check_access_on_attribute(ac->module, mem_ctx, sd, sid, + access_mask, attr, objectclass); + + if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { +- return ret; +- } +- +- if (ret != LDB_SUCCESS) { ++ ldb_msg_element_mark_inaccessible(el); ++ } else if (ret != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "acl_read: %s check attr[%s] gives %s - %s\n", +- ldb_dn_get_linearized(dn), attr_name, ++ ldb_dn_get_linearized(msg->dn), el->name, + ldb_strerror(ret), ldb_errstring(ldb)); + return ret; + } +@@ -423,38 +625,6 @@ static int check_attr_access_rights(TALLOC_CTX *mem_ctx, const char *attr_name, + return LDB_SUCCESS; + } + +-/* +- * Returns the attribute name for this particular level of a search operation +- * parse-tree. +- */ +-static const char * parse_tree_get_attr(struct ldb_parse_tree *tree) +-{ +- const char *attr = NULL; +- +- switch (tree->operation) { +- case LDB_OP_EQUALITY: +- case LDB_OP_GREATER: +- case LDB_OP_LESS: +- case LDB_OP_APPROX: +- attr = tree->u.equality.attr; +- break; +- case LDB_OP_SUBSTRING: +- attr = tree->u.substring.attr; +- break; +- case LDB_OP_PRESENT: +- attr = tree->u.present.attr; +- break; +- case LDB_OP_EXTENDED: +- attr = tree->u.extended.attr; +- break; +- +- /* we'll check LDB_OP_AND/_OR/_NOT children later on in the walk */ +- default: +- break; +- } +- return attr; +-} +- + static int setup_access_check_context(struct aclread_context *ac, + const struct ldb_message *msg, + struct access_check_context *ctx) +@@ -518,103 +688,6 @@ static int setup_access_check_context(struct aclread_context *ac, + return LDB_SUCCESS; + } + +-/* +- * Checks a single attribute in the search parse-tree to make sure the user has +- * sufficient rights to view it. +- */ +-static int parse_tree_check_attr_access(struct ldb_parse_tree *tree, +- void *private_context) +-{ +- struct parse_tree_aclread_ctx *ctx = NULL; +- const char *attr_name = NULL; +- int ret; +- static const char * const attrs_always_present[] = { +- "objectClass", +- "distinguishedName", +- "name", +- "objectGUID", +- NULL +- }; +- +- ctx = (struct parse_tree_aclread_ctx *)private_context; +- +- /* +- * we can skip any further checking if we already know that this object +- * shouldn't be visible in this user's search +- */ +- if (ctx->suppress_result) { +- return LDB_SUCCESS; +- } +- +- /* skip this level of the search-tree if it has no attribute to check */ +- attr_name = parse_tree_get_attr(tree); +- if (attr_name == NULL) { +- return LDB_SUCCESS; +- } +- +- /* +- * If the search filter is checking for an attribute's presence, and the +- * attribute is always present, we can skip access rights checks. Every +- * object has these attributes, and so there's no security reason to +- * hide their presence. +- * Note: the acl.py tests (e.g. test_search1()) rely on this exception. +- * I.e. even if we lack Read Property (RP) rights for a child object, it +- * should still appear as a visible object in 'objectClass=*' searches, +- * so long as we have List Contents (LC) rights for the object. +- */ +- if (tree->operation == LDB_OP_PRESENT && +- is_attr_in_list(attrs_always_present, attr_name)) { +- return LDB_SUCCESS; +- } +- +- ret = check_attr_access_rights(ctx->mem_ctx, attr_name, ctx->ac, +- ctx->sd, ctx->objectclass, ctx->sid, +- ctx->dn); +- +- /* +- * if the user does not have the rights to view this attribute, then we +- * should not return the object as a search result, i.e. act as if the +- * object doesn't exist (for this particular user, at least) +- */ +- if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { +- ctx->suppress_result = true; +- return LDB_SUCCESS; +- } +- +- return ret; +-} +- +-/* +- * Traverse the search-tree to check that the user has sufficient access rights +- * to view all the attributes. +- */ +-static int check_search_ops_access(struct aclread_context *ac, +- TALLOC_CTX *mem_ctx, +- struct security_descriptor *sd, +- const struct dsdb_class *objectclass, +- const struct dom_sid *sid, struct ldb_dn *dn, +- bool *suppress_result) +-{ +- int ret; +- struct parse_tree_aclread_ctx ctx = { 0 }; +- struct ldb_parse_tree *tree = ac->req->op.search.tree; +- +- ctx.ac = ac; +- ctx.mem_ctx = mem_ctx; +- ctx.suppress_result = false; +- ctx.sid = sid; +- ctx.dn = dn; +- ctx.sd = sd; +- ctx.objectclass = objectclass; +- +- /* walk the search tree, checking each attribute as we go */ +- ret = ldb_parse_tree_walk(tree, parse_tree_check_attr_access, &ctx); +- +- /* return whether this search result should be hidden to this user */ +- *suppress_result = ctx.suppress_result; +- return ret; +-} +- + /* + * Whether this attribute was added to perform access checks and must be + * removed. +@@ -650,17 +723,14 @@ static bool should_remove_attr(const char *attr, const struct aclread_context *a + + static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + { +- struct ldb_context *ldb; + struct aclread_context *ac; ++ struct aclread_private *private_data = NULL; + struct ldb_message *msg; + int ret; + unsigned int i; + struct access_check_context acl_ctx; +- TALLOC_CTX *tmp_ctx; +- bool suppress_result = false; + + ac = talloc_get_type_abort(req->context, struct aclread_context); +- ldb = ldb_module_get_ctx(ac->module); + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR ); + } +@@ -668,14 +738,9 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } +- tmp_ctx = talloc_new(ac); + switch (ares->type) { + case LDB_REPLY_ENTRY: + msg = ares->message; +- ret = setup_access_check_context(ac, msg, &acl_ctx); +- if (ret != LDB_SUCCESS) { +- return ret; +- } + + if (!ldb_dn_is_null(msg->dn)) { + /* +@@ -684,132 +749,88 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + */ + ret = aclread_check_object_visible(ac, msg, req); + if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { +- talloc_free(tmp_ctx); + return LDB_SUCCESS; + } else if (ret != LDB_SUCCESS) { ++ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "acl_read: %s check parent %s - %s\n", + ldb_dn_get_linearized(msg->dn), + ldb_strerror(ret), + ldb_errstring(ldb)); +- goto fail; ++ return ldb_module_done(ac->req, NULL, NULL, ret); + } + } + + /* for every element in the message check RP */ +- for (i=0; i < msg->num_elements; i++) { +- const struct dsdb_attribute *attr; +- uint32_t access_mask; +- attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, +- msg->elements[i].name); +- if (!attr) { +- ldb_debug_set(ldb, LDB_DEBUG_FATAL, +- "acl_read: %s cannot find attr[%s] in of schema\n", +- ldb_dn_get_linearized(msg->dn), +- msg->elements[i].name); +- ret = LDB_ERR_OPERATIONS_ERROR; +- goto fail; +- } ++ for (i = 0; i < msg->num_elements; ++i) { ++ struct ldb_message_element *el = &msg->elements[i]; ++ + /* Remove attributes added to perform access checks. */ +- if (should_remove_attr(msg->elements[i].name, ac)) { +- ldb_msg_element_mark_inaccessible(&msg->elements[i]); ++ if (should_remove_attr(el->name, ac)) { ++ ldb_msg_element_mark_inaccessible(el); + continue; + } + +- access_mask = get_attr_access_mask(attr, ac->sd_flags); +- +- if (access_mask == 0) { +- ldb_msg_element_mark_inaccessible(&msg->elements[i]); ++ if (acl_element_is_access_checked(el)) { ++ /* We will have already checked this attribute. */ + continue; + } + +- ret = acl_check_access_on_attribute(ac->module, +- tmp_ctx, +- acl_ctx.sd, +- acl_ctx.sid, +- access_mask, +- attr, +- objectclass); +- + /* +- * Dirsync control needs the replpropertymetadata attribute +- * so return it as it will be removed by the control +- * in anycase. ++ * We need to fetch the security descriptor to check ++ * this attribute. + */ +- if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { +- bool in_search_filter; +- +- /* check if attr is part of the search filter */ +- in_search_filter = dsdb_attr_in_parse_tree(ac->req->op.search.tree, +- msg->elements[i].name); +- +- if (in_search_filter) { +- +- /* +- * We are doing dirysnc answers +- * and the object shouldn't be returned (normally) +- * but we will return it without replPropertyMetaData +- * so that the dirysync module will do what is needed +- * (remove the object if it is not deleted, or return +- * just the objectGUID if it's deleted). +- */ +- if (ac->indirsync) { +- ldb_msg_remove_attr(msg, "replPropertyMetaData"); +- break; +- } else { +- +- /* do not return this entry */ +- talloc_free(tmp_ctx); +- return LDB_SUCCESS; +- } +- } else { +- ldb_msg_element_mark_inaccessible(&msg->elements[i]); +- } +- } else if (ret != LDB_SUCCESS) { +- ldb_debug_set(ldb, LDB_DEBUG_FATAL, +- "acl_read: %s check attr[%s] gives %s - %s\n", +- ldb_dn_get_linearized(msg->dn), +- msg->elements[i].name, +- ldb_strerror(ret), +- ldb_errstring(ldb)); +- goto fail; +- } ++ break; + } + +- /* +- * check access rights for the search attributes, as well as the +- * attribute values actually being returned +- */ +- ret = check_search_ops_access(ac, tmp_ctx, acl_ctx.sd, acl_ctx.objectclass, acl_ctx.sid, +- msg->dn, &suppress_result); ++ if (i == msg->num_elements) { ++ /* All elements have been checked. */ ++ goto reply_entry_done; ++ } ++ ++ ret = setup_access_check_context(ac, msg, &acl_ctx); + if (ret != LDB_SUCCESS) { +- ldb_debug_set(ldb, LDB_DEBUG_FATAL, +- "acl_read: %s check search ops %s - %s\n", +- ldb_dn_get_linearized(msg->dn), +- ldb_strerror(ret), ldb_errstring(ldb)); +- goto fail; ++ return ret; + } + +- if (suppress_result) { ++ private_data = talloc_get_type_abort(ldb_module_get_private(ac->module), ++ struct aclread_private); ++ ++ for (/* begin where we left off */; i < msg->num_elements; ++i) { ++ struct ldb_message_element *el = &msg->elements[i]; ++ ++ /* Remove attributes added to perform access checks. */ ++ if (should_remove_attr(el->name, ac)) { ++ ldb_msg_element_mark_inaccessible(el); ++ continue; ++ } ++ ++ if (acl_element_is_access_checked(el)) { ++ /* We will have already checked this attribute. */ ++ continue; ++ } + + /* +- * As per the above logic, we strip replPropertyMetaData +- * out of the msg so that the dirysync module will do +- * what is needed (return just the objectGUID if it's, +- * deleted, or remove the object if it is not). ++ * We need to check whether the attribute is secret, ++ * confidential, or access-controlled. + */ +- if (ac->indirsync) { +- ldb_msg_remove_attr(msg, "replPropertyMetaData"); +- } else { +- talloc_free(tmp_ctx); +- return LDB_SUCCESS; ++ ret = acl_redact_attr(ac, ++ el, ++ ac, ++ private_data, ++ msg, ++ ac->schema, ++ acl_ctx.sd, ++ acl_ctx.sid, ++ acl_ctx.objectclass); ++ if (ret != LDB_SUCCESS) { ++ return ldb_module_done(ac->req, NULL, NULL, ret); + } + } + ++ reply_entry_done: + ldb_msg_remove_inaccessible(msg); + +- talloc_free(tmp_ctx); +- + ac->num_entries++; + return ldb_module_send_entry(ac->req, msg, ares->controls); + case LDB_REPLY_REFERRAL: +@@ -830,9 +851,6 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares) + + } + return LDB_SUCCESS; +-fail: +- talloc_free(tmp_ctx); +- return ldb_module_done(ac->req, NULL, NULL, ret); + } + + +@@ -843,7 +861,6 @@ static int aclread_search(struct ldb_module *module, struct ldb_request *req) + struct aclread_context *ac; + struct ldb_request *down_req; + struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); +- uint32_t flags = ldb_req_get_custom_flags(req); + struct ldb_result *res; + struct aclread_private *p; + bool need_sd = false; +@@ -878,15 +895,6 @@ static int aclread_search(struct ldb_module *module, struct ldb_request *req) + } + ac->module = module; + ac->req = req; +- ac->schema = dsdb_get_schema(ldb, req); +- if (flags & DSDB_ACL_CHECKS_DIRSYNC_FLAG) { +- ac->indirsync = true; +- } else { +- ac->indirsync = false; +- } +- if (!ac->schema) { +- return ldb_operr(ldb); +- } + + attrs = req->op.search.attrs; + if (attrs == NULL) { +@@ -943,7 +951,7 @@ static int aclread_search(struct ldb_module *module, struct ldb_request *req) + ac->added_nTSecurityDescriptor = true; + } + +- ac->attrs = req->op.search.attrs; ++ ac->am_administrator = dsdb_module_am_administrator(module); + + /* check accessibility of base */ + if (!ldb_dn_is_null(req->op.search.base)) { +@@ -987,19 +995,270 @@ static int aclread_search(struct ldb_module *module, struct ldb_request *req) + return LDB_ERR_OPERATIONS_ERROR; + } + ++ /* ++ * We provide 'ac' as the control value, which is then used by the ++ * callback to avoid double-work. ++ */ ++ ret = ldb_request_add_control(down_req, DSDB_CONTROL_ACL_READ_OID, false, ac); ++ if (ret != LDB_SUCCESS) { ++ return ldb_error(ldb, ret, ++ "acl_read: Error adding acl_read control."); ++ } ++ + return ldb_next_request(module, down_req); + } + ++/* ++ * Here we mark inaccessible attributes known to be looked for in the ++ * filter. This only redacts attributes found in the search expression. If any ++ * extended attribute match rules examine different attributes without their own ++ * access control checks, a security bypass is possible. ++ */ ++static int acl_redact_msg_for_filter(struct ldb_module *module, struct ldb_request *req, struct ldb_message *msg) ++{ ++ struct ldb_context *ldb = ldb_module_get_ctx(module); ++ const struct aclread_private *private_data = NULL; ++ struct ldb_control *control = NULL; ++ struct aclread_context *ac = NULL; ++ struct access_check_context acl_ctx; ++ int ret; ++ unsigned i; ++ ++ /* ++ * The private data contains a list of attributes which are to be ++ * considered secret. ++ */ ++ private_data = talloc_get_type(ldb_module_get_private(module), struct aclread_private); ++ if (private_data == NULL) { ++ return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, ++ "aclread_private data is missing"); ++ } ++ if (!private_data->enabled) { ++ return LDB_SUCCESS; ++ } ++ ++ control = ldb_request_get_control(req, DSDB_CONTROL_ACL_READ_OID); ++ if (control == NULL) { ++ /* ++ * We've bypassed the acl_read module for this request, and ++ * should skip redaction in this case. ++ */ ++ return LDB_SUCCESS; ++ } ++ ++ ac = talloc_get_type_abort(control->data, struct aclread_context); ++ ++ if (!ac->got_tree_attrs) { ++ ret = ldb_parse_tree_collect_acl_attrs(module, ac, &ac->tree_attrs, req->op.search.tree); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ ac->got_tree_attrs = true; ++ } ++ ++ for (i = 0; i < msg->num_elements; ++i) { ++ struct ldb_message_element *el = &msg->elements[i]; ++ ++ /* Is the attribute mentioned in the search expression? */ ++ if (attr_in_vec(&ac->tree_attrs, el->name)) { ++ /* ++ * We need to fetch the security descriptor to check ++ * this element. ++ */ ++ break; ++ } ++ ++ /* ++ * This attribute is not in the search filter, so we can leave ++ * handling it till aclread_callback(), by which time we know ++ * this object is a match. This saves work checking ACLs if the ++ * search is unindexed and most objects don't match the filter. ++ */ ++ } ++ ++ if (i == msg->num_elements) { ++ /* All elements have been checked. */ ++ return LDB_SUCCESS; ++ } ++ ++ ret = setup_access_check_context(ac, msg, &acl_ctx); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ ++ /* For every element in the message and the parse tree, check RP. */ ++ ++ for (/* begin where we left off */; i < msg->num_elements; ++i) { ++ struct ldb_message_element *el = &msg->elements[i]; ++ ++ /* Is the attribute mentioned in the search expression? */ ++ if (!attr_in_vec(&ac->tree_attrs, el->name)) { ++ /* ++ * If not, leave it for later and check the next ++ * attribute. ++ */ ++ continue; ++ } ++ ++ /* ++ * We need to check whether the attribute is secret, ++ * confidential, or access-controlled. ++ */ ++ ret = acl_redact_attr(ac, ++ el, ++ ac, ++ private_data, ++ msg, ++ ac->schema, ++ acl_ctx.sd, ++ acl_ctx.sid, ++ acl_ctx.objectclass); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ ++ acl_element_mark_access_checked(el); ++ } ++ ++ return LDB_SUCCESS; ++} ++ + static int aclread_init(struct ldb_module *module) + { + struct ldb_context *ldb = ldb_module_get_ctx(module); ++ unsigned int i, n, j; ++ TALLOC_CTX *mem_ctx = NULL; ++ int ret; ++ bool userPassword_support; ++ static const char * const attrs[] = { "passwordAttribute", NULL }; ++ static const char * const secret_attrs[] = { ++ DSDB_SECRET_ATTRIBUTES ++ }; ++ struct ldb_result *res; ++ struct ldb_message *msg; ++ struct ldb_message_element *password_attributes; + struct aclread_private *p = talloc_zero(module, struct aclread_private); + if (p == NULL) { + return ldb_module_oom(module); + } + p->enabled = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"), NULL, "acl", "search", true); ++ ++ ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID); ++ if (ret != LDB_SUCCESS) { ++ ldb_debug(ldb, LDB_DEBUG_ERROR, ++ "acl_module_init: Unable to register sd_flags control with rootdse!\n"); ++ return ldb_operr(ldb); ++ } ++ + ldb_module_set_private(module, p); +- return ldb_next_init(module); ++ ++ mem_ctx = talloc_new(module); ++ if (!mem_ctx) { ++ return ldb_oom(ldb); ++ } ++ ++ ret = dsdb_module_search_dn(module, mem_ctx, &res, ++ ldb_dn_new(mem_ctx, ldb, "@KLUDGEACL"), ++ attrs, ++ DSDB_FLAG_NEXT_MODULE | ++ DSDB_FLAG_AS_SYSTEM, ++ NULL); ++ if (ret != LDB_SUCCESS) { ++ goto done; ++ } ++ if (res->count == 0) { ++ goto done; ++ } ++ ++ if (res->count > 1) { ++ talloc_free(mem_ctx); ++ return LDB_ERR_CONSTRAINT_VIOLATION; ++ } ++ ++ msg = res->msgs[0]; ++ ++ password_attributes = ldb_msg_find_element(msg, "passwordAttribute"); ++ if (!password_attributes) { ++ goto done; ++ } ++ p->password_attrs = talloc_array(p, const char *, ++ password_attributes->num_values + ++ ARRAY_SIZE(secret_attrs) + 1); ++ if (!p->password_attrs) { ++ talloc_free(mem_ctx); ++ return ldb_oom(ldb); ++ } ++ ++ n = 0; ++ for (i=0; i < password_attributes->num_values; i++) { ++ p->password_attrs[n] = (const char *)password_attributes->values[i].data; ++ talloc_steal(p->password_attrs, password_attributes->values[i].data); ++ n++; ++ } ++ ++ for (i=0; i < ARRAY_SIZE(secret_attrs); i++) { ++ bool found = false; ++ ++ for (j=0; j < n; j++) { ++ if (strcasecmp(p->password_attrs[j], secret_attrs[i]) == 0) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (found) { ++ continue; ++ } ++ ++ p->password_attrs[n] = talloc_strdup(p->password_attrs, ++ secret_attrs[i]); ++ if (p->password_attrs[n] == NULL) { ++ talloc_free(mem_ctx); ++ return ldb_oom(ldb); ++ } ++ n++; ++ } ++ p->password_attrs[n] = NULL; ++ ++ ret = ldb_register_redact_callback(ldb, acl_redact_msg_for_filter, module); ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ ++done: ++ talloc_free(mem_ctx); ++ ret = ldb_next_init(module); ++ ++ if (ret != LDB_SUCCESS) { ++ return ret; ++ } ++ ++ if (p->password_attrs != NULL) { ++ /* ++ * Check this after the modules have be initialised so we can ++ * actually read the backend DB. ++ */ ++ userPassword_support = dsdb_user_password_support(module, ++ module, ++ NULL); ++ if (!userPassword_support) { ++ /* ++ * Remove the userPassword attribute, as it is not ++ * considered secret. ++ */ ++ for (i = 0; p->password_attrs[i] != NULL; ++i) { ++ if (ldb_attr_cmp(p->password_attrs[i], "userPassword") == 0) { ++ break; ++ } ++ } ++ ++ /* Shift following elements backwards by one. */ ++ for (; p->password_attrs[i] != NULL; ++i) { ++ p->password_attrs[i] = p->password_attrs[i + 1]; ++ } ++ } ++ } ++ return ret; + } + + static const struct ldb_module_ops ldb_aclread_module_ops = { +diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h +index 3db7704307f..f22b4d99972 100644 +--- a/source4/dsdb/samdb/samdb.h ++++ b/source4/dsdb/samdb/samdb.h +@@ -232,6 +232,8 @@ struct dsdb_control_transaction_identifier { + */ + #define DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID "1.3.6.1.4.1.7165.4.3.35" + ++#define DSDB_CONTROL_ACL_READ_OID "1.3.6.1.4.1.7165.4.3.37" ++ + #define DSDB_EXTENDED_REPLICATED_OBJECTS_OID "1.3.6.1.4.1.7165.4.4.1" + struct dsdb_extended_replicated_object { + struct ldb_message *msg; +diff --git a/source4/dsdb/tests/python/confidential_attr.py b/source4/dsdb/tests/python/confidential_attr.py +index 031c9690ba6..6889d5a5560 100755 +--- a/source4/dsdb/tests/python/confidential_attr.py ++++ b/source4/dsdb/tests/python/confidential_attr.py +@@ -490,7 +490,7 @@ class ConfidentialAttrTest(ConfidentialAttrCommon): + self.make_attr_confidential() + + self.assert_conf_attr_searches(has_rights_to=0) +- dc_mode = self.guess_dc_mode() ++ dc_mode = DC_MODE_RETURN_ALL + self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) + self.assert_attr_visible(expect_attr=False) + +@@ -503,7 +503,7 @@ class ConfidentialAttrTest(ConfidentialAttrCommon): + self.make_attr_confidential() + + self.assert_conf_attr_searches(has_rights_to=0) +- dc_mode = self.guess_dc_mode() ++ dc_mode = DC_MODE_RETURN_ALL + self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) + self.assert_attr_visible(expect_attr=False) + +@@ -566,7 +566,7 @@ class ConfidentialAttrTest(ConfidentialAttrCommon): + self.make_attr_confidential() + + self.assert_conf_attr_searches(has_rights_to=0) +- dc_mode = self.guess_dc_mode() ++ dc_mode = DC_MODE_RETURN_ALL + self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) + self.assert_attr_visible(expect_attr=False) + +@@ -741,7 +741,7 @@ class ConfidentialAttrTestDenyAcl(ConfidentialAttrCommon): + + # the user shouldn't be able to see the attribute anymore + self.assert_conf_attr_searches(has_rights_to="deny-one") +- dc_mode = self.guess_dc_mode() ++ dc_mode = DC_MODE_RETURN_ALL + self.assert_negative_searches(has_rights_to="deny-one", + dc_mode=dc_mode) + self.assert_attr_visible(expect_attr=False) +@@ -917,7 +917,7 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + + self.assert_conf_attr_searches(has_rights_to=0) + self.assert_attr_visible(expect_attr=False) +- dc_mode = self.guess_dc_mode() ++ dc_mode = DC_MODE_RETURN_ALL + self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) + + # as a final sanity-check, make sure the admin can still see the attr +@@ -1012,7 +1012,7 @@ class ConfidentialAttrTestDirsync(ConfidentialAttrCommon): + # check we can't see the objects now, even with using dirsync controls + self.assert_conf_attr_searches(has_rights_to=0) + self.assert_attr_visible(expect_attr=False) +- dc_mode = self.guess_dc_mode() ++ dc_mode = DC_MODE_RETURN_ALL + self.assert_negative_searches(has_rights_to=0, dc_mode=dc_mode) + + # now delete the users (except for the user whose LDB connection +diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif +index 79800bfd6df..27c7e9dbb47 100644 +--- a/source4/setup/schema_samba4.ldif ++++ b/source4/setup/schema_samba4.ldif +@@ -233,6 +233,7 @@ + #Allocated: DSDB_CONTROL_TRANSACTION_IDENTIFIER_OID 1.3.6.1.4.1.7165.4.3.34 + #Allocated: DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID 1.3.6.1.4.1.7165.4.3.35 + #Allocated: DSDB_CONTROL_CALCULATED_DEFAULT_SD_OID 1.3.6.1.4.1.7165.4.3.36 ++#Allocated: DSDB_CONTROL_ACL_READ_OID 1.3.6.1.4.1.7165.4.3.37 + + + # Extended 1.3.6.1.4.1.7165.4.4.x +-- +2.25.1 \ No newline at end of file diff --git a/backport-0027-CVE-2023-0614.patch b/backport-0027-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..dffacf7c4110f3eeb4340527b123787b4ad151b6 --- /dev/null +++ b/backport-0027-CVE-2023-0614.patch @@ -0,0 +1,54 @@ +From 976b0c37d82daf1269664a1fce8dfcca5770456b Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Mon, 27 Feb 2023 13:31:44 +1300 +Subject: [PATCH 25/34] CVE-2023-0614 s4-acl: Avoid calling + dsdb_module_am_system() if we can help it + +If the AS_SYSTEM control is present, we know we have system privileges, +and have no need to call dsdb_module_am_system(). + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/samdb/ldb_modules/acl_read.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c +index 8ca8607b925..6dcc3c9b36e 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl_read.c ++++ b/source4/dsdb/samdb/ldb_modules/acl_read.c +@@ -860,7 +860,7 @@ static int aclread_search(struct ldb_module *module, struct ldb_request *req) + int ret; + struct aclread_context *ac; + struct ldb_request *down_req; +- struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); ++ bool am_system; + struct ldb_result *res; + struct aclread_private *p; + bool need_sd = false; +@@ -877,11 +877,16 @@ static int aclread_search(struct ldb_module *module, struct ldb_request *req) + ldb = ldb_module_get_ctx(module); + p = talloc_get_type(ldb_module_get_private(module), struct aclread_private); + ++ am_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID) != NULL; ++ if (!am_system) { ++ am_system = dsdb_module_am_system(module); ++ } ++ + /* skip access checks if we are system or system control is supplied + * or this is not LDAP server request */ + if (!p || !p->enabled || +- dsdb_module_am_system(module) +- || as_system || !is_untrusted) { ++ am_system || ++ !is_untrusted) { + return ldb_next_request(module, req); + } + /* no checks on special dn */ +-- +2.25.1 \ No newline at end of file diff --git a/backport-0028-CVE-2023-0614.patch b/backport-0028-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..4ced8ae00513820ef96768b1442b79643ae9a45b --- /dev/null +++ b/backport-0028-CVE-2023-0614.patch @@ -0,0 +1,131 @@ +From 8cf6c358e27a3926397e0d5fbb562e76926589d9 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Thu, 16 Feb 2023 12:35:34 +1300 +Subject: [PATCH 26/34] CVE-2023-0614 ldb: Use binary search to check whether + attribute is secret + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/samdb/ldb_modules/acl_read.c | 56 ++++++++++++++--------- + 1 file changed, 35 insertions(+), 21 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/acl_read.c b/source4/dsdb/samdb/ldb_modules/acl_read.c +index 6dcc3c9b36e..21f72fbe720 100644 +--- a/source4/dsdb/samdb/ldb_modules/acl_read.c ++++ b/source4/dsdb/samdb/ldb_modules/acl_read.c +@@ -79,6 +79,7 @@ struct aclread_private { + struct security_descriptor *sd_cached; + struct ldb_val sd_cached_blob; + const char **password_attrs; ++ size_t num_password_attrs; + }; + + struct access_check_context { +@@ -512,22 +513,18 @@ static int aclread_get_sd_from_ldb_message(struct aclread_context *ac, + /* Check whether the attribute is a password attribute. */ + static bool attr_is_secret(const char *attr, const struct aclread_private *private_data) + { +- unsigned i; ++ const char **found = NULL; + + if (private_data->password_attrs == NULL) { + return false; + } + +- for (i = 0; private_data->password_attrs[i] != NULL; ++i) { +- const char *password_attr = private_data->password_attrs[i]; +- if (ldb_attr_cmp(attr, password_attr) != 0) { +- continue; +- } +- +- return true; +- } +- +- return false; ++ BINARY_ARRAY_SEARCH_V(private_data->password_attrs, ++ private_data->num_password_attrs, ++ attr, ++ ldb_attr_cmp, ++ found); ++ return found != NULL; + } + + /* +@@ -1128,6 +1125,14 @@ static int acl_redact_msg_for_filter(struct ldb_module *module, struct ldb_reque + return LDB_SUCCESS; + } + ++static int ldb_attr_cmp_fn(const void *_a, const void *_b) ++{ ++ const char * const *a = _a; ++ const char * const *b = _b; ++ ++ return ldb_attr_cmp(*a, *b); ++} ++ + static int aclread_init(struct ldb_module *module) + { + struct ldb_context *ldb = ldb_module_get_ctx(module); +@@ -1188,7 +1193,7 @@ static int aclread_init(struct ldb_module *module) + } + p->password_attrs = talloc_array(p, const char *, + password_attributes->num_values + +- ARRAY_SIZE(secret_attrs) + 1); ++ ARRAY_SIZE(secret_attrs)); + if (!p->password_attrs) { + talloc_free(mem_ctx); + return ldb_oom(ldb); +@@ -1223,7 +1228,10 @@ static int aclread_init(struct ldb_module *module) + } + n++; + } +- p->password_attrs[n] = NULL; ++ p->num_password_attrs = n; ++ ++ /* Sort the password attributes so we can use binary search. */ ++ TYPESAFE_QSORT(p->password_attrs, p->num_password_attrs, ldb_attr_cmp_fn); + + ret = ldb_register_redact_callback(ldb, acl_redact_msg_for_filter, module); + if (ret != LDB_SUCCESS) { +@@ -1247,19 +1255,25 @@ done: + module, + NULL); + if (!userPassword_support) { ++ const char **found = NULL; ++ + /* + * Remove the userPassword attribute, as it is not + * considered secret. + */ +- for (i = 0; p->password_attrs[i] != NULL; ++i) { +- if (ldb_attr_cmp(p->password_attrs[i], "userPassword") == 0) { +- break; ++ BINARY_ARRAY_SEARCH_V(p->password_attrs, ++ p->num_password_attrs, ++ "userPassword", ++ ldb_attr_cmp, ++ found); ++ if (found != NULL) { ++ size_t found_idx = found - p->password_attrs; ++ ++ /* Shift following elements backwards by one. */ ++ for (i = found_idx; i < p->num_password_attrs - 1; ++i) { ++ p->password_attrs[i] = p->password_attrs[i + 1]; + } +- } +- +- /* Shift following elements backwards by one. */ +- for (; p->password_attrs[i] != NULL; ++i) { +- p->password_attrs[i] = p->password_attrs[i + 1]; ++ --p->num_password_attrs; + } + } + } +-- +2.25.1 \ No newline at end of file diff --git a/backport-0029-CVE-2023-0614.patch b/backport-0029-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..bdd885b4904822bc2c8d884ecc4a64041b8b50b2 --- /dev/null +++ b/backport-0029-CVE-2023-0614.patch @@ -0,0 +1,147 @@ +From 94efa3fc3053a623a7a5c3a4a6428356bc334152 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Tue, 14 Feb 2023 13:17:24 +1300 +Subject: [PATCH 27/34] CVE-2023-0614 ldb: Centralise checking for inaccessible + matches + +This makes it less likely that we forget to handle a case. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb-samba/ldb_matching_rules.c | 5 --- + lib/ldb/common/ldb_match.c | 56 +++++++++++++++++------------- + 2 files changed, 31 insertions(+), 30 deletions(-) + +diff --git a/lib/ldb-samba/ldb_matching_rules.c b/lib/ldb-samba/ldb_matching_rules.c +index 0c4c31e49f9..b86594c1823 100644 +--- a/lib/ldb-samba/ldb_matching_rules.c ++++ b/lib/ldb-samba/ldb_matching_rules.c +@@ -87,11 +87,6 @@ static int ldb_eval_transitive_filter_helper(TALLOC_CTX *mem_ctx, + return LDB_SUCCESS; + } + +- if (ldb_msg_element_is_inaccessible(el)) { +- *matched = false; +- return LDB_SUCCESS; +- } +- + /* + * If the value to match is present in the attribute values of the + * current entry being visited, set matched to true and return OK +diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c +index 17314f1b9ca..645cb695ef1 100644 +--- a/lib/ldb/common/ldb_match.c ++++ b/lib/ldb/common/ldb_match.c +@@ -98,11 +98,6 @@ static int ldb_match_present(struct ldb_context *ldb, + return LDB_SUCCESS; + } + +- if (ldb_msg_element_is_inaccessible(el)) { +- *matched = false; +- return LDB_SUCCESS; +- } +- + a = ldb_schema_attribute_by_name(ldb, el->name); + if (!a) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; +@@ -144,11 +139,6 @@ static int ldb_match_comparison(struct ldb_context *ldb, + return LDB_SUCCESS; + } + +- if (ldb_msg_element_is_inaccessible(el)) { +- *matched = false; +- return LDB_SUCCESS; +- } +- + a = ldb_schema_attribute_by_name(ldb, el->name); + if (!a) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; +@@ -219,11 +209,6 @@ static int ldb_match_equality(struct ldb_context *ldb, + return LDB_SUCCESS; + } + +- if (ldb_msg_element_is_inaccessible(el)) { +- *matched = false; +- return LDB_SUCCESS; +- } +- + a = ldb_schema_attribute_by_name(ldb, el->name); + if (a == NULL) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; +@@ -385,11 +370,6 @@ static int ldb_match_substring(struct ldb_context *ldb, + return LDB_SUCCESS; + } + +- if (ldb_msg_element_is_inaccessible(el)) { +- *matched = false; +- return LDB_SUCCESS; +- } +- + for (i = 0; i < el->num_values; i++) { + int ret; + ret = ldb_wildcard_compare(ldb, tree, el->values[i], matched); +@@ -463,11 +443,6 @@ static int ldb_match_bitmask(struct ldb_context *ldb, + return LDB_SUCCESS; + } + +- if (ldb_msg_element_is_inaccessible(el)) { +- *matched = false; +- return LDB_SUCCESS; +- } +- + for (i=0;inum_values;i++) { + int ret; + struct ldb_val *v = &el->values[i]; +@@ -556,6 +531,26 @@ static int ldb_match_extended(struct ldb_context *ldb, + &tree->u.extended.value, matched); + } + ++static bool ldb_must_suppress_match(const struct ldb_message *msg, ++ const struct ldb_parse_tree *tree) ++{ ++ const char *attr = NULL; ++ struct ldb_message_element *el = NULL; ++ ++ attr = ldb_parse_tree_get_attr(tree); ++ if (attr == NULL) { ++ return false; ++ } ++ ++ /* find the message element */ ++ el = ldb_msg_find_element(msg, attr); ++ if (el == NULL) { ++ return false; ++ } ++ ++ return ldb_msg_element_is_inaccessible(el); ++} ++ + /* + Check if a particular message will match the given filter + +@@ -580,6 +575,17 @@ int ldb_match_message(struct ldb_context *ldb, + return LDB_SUCCESS; + } + ++ /* ++ * Suppress matches on confidential attributes (handled ++ * manually in extended matches as these can do custom things ++ * like read other parts of the DB or other attributes). ++ */ ++ if (tree->operation != LDB_OP_EXTENDED) { ++ if (ldb_must_suppress_match(msg, tree)) { ++ return LDB_SUCCESS; ++ } ++ } ++ + switch (tree->operation) { + case LDB_OP_AND: + for (i=0;iu.list.num_elements;i++) { +-- +2.25.1 \ No newline at end of file diff --git a/backport-0030-CVE-2023-0614.patch b/backport-0030-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..8534930bf509805dbd504083b6d0aa5e72261a30 --- /dev/null +++ b/backport-0030-CVE-2023-0614.patch @@ -0,0 +1,155 @@ +From a0c888bd0ed2ec5b4d84f9df241bebd5d428818c Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 3 Mar 2023 17:35:55 +1300 +Subject: [PATCH 28/34] CVE-2023-0614 ldb: Filter on search base before + redacting message + +Redaction may be expensive if we end up needing to fetch a security +descriptor to verify rights to an attribute. Checking the search scope +is probably cheaper, so do that first. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb/common/ldb_match.c | 8 +++--- + lib/ldb/include/ldb_private.h | 8 ++++++ + lib/ldb/ldb_key_value/ldb_kv_index.c | 40 +++++++++++++++------------ + lib/ldb/ldb_key_value/ldb_kv_search.c | 14 ++++++++-- + 4 files changed, 47 insertions(+), 23 deletions(-) + +diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c +index 645cb695ef1..8e27ecbe723 100644 +--- a/lib/ldb/common/ldb_match.c ++++ b/lib/ldb/common/ldb_match.c +@@ -38,10 +38,10 @@ + /* + check if the scope matches in a search result + */ +-static int ldb_match_scope(struct ldb_context *ldb, +- struct ldb_dn *base, +- struct ldb_dn *dn, +- enum ldb_scope scope) ++int ldb_match_scope(struct ldb_context *ldb, ++ struct ldb_dn *base, ++ struct ldb_dn *dn, ++ enum ldb_scope scope) + { + int ret = 0; + +diff --git a/lib/ldb/include/ldb_private.h b/lib/ldb/include/ldb_private.h +index b0a42f6421c..5e29de34f79 100644 +--- a/lib/ldb/include/ldb_private.h ++++ b/lib/ldb/include/ldb_private.h +@@ -322,6 +322,14 @@ int ldb_match_message(struct ldb_context *ldb, + const struct ldb_parse_tree *tree, + enum ldb_scope scope, bool *matched); + ++/* ++ check if the scope matches in a search result ++*/ ++int ldb_match_scope(struct ldb_context *ldb, ++ struct ldb_dn *base, ++ struct ldb_dn *dn, ++ enum ldb_scope scope); ++ + /* Reallocate elements to drop any excess capacity. */ + void ldb_msg_shrink_to_fit(struct ldb_message *msg); + +diff --git a/lib/ldb/ldb_key_value/ldb_kv_index.c b/lib/ldb/ldb_key_value/ldb_kv_index.c +index 163052fecf7..aac0913f431 100644 +--- a/lib/ldb/ldb_key_value/ldb_kv_index.c ++++ b/lib/ldb/ldb_key_value/ldb_kv_index.c +@@ -2428,31 +2428,37 @@ static int ldb_kv_index_filter(struct ldb_kv_private *ldb_kv, + return LDB_ERR_OPERATIONS_ERROR; + } + +- if (ldb->redact.callback != NULL) { +- ret = ldb->redact.callback(ldb->redact.module, ac->req, msg); +- if (ret != LDB_SUCCESS) { +- talloc_free(msg); +- return ret; +- } +- } +- + /* + * We trust the index for LDB_SCOPE_ONELEVEL + * unless the index key has been truncated. + * + * LDB_SCOPE_BASE is not passed in by our only caller. + */ +- if (ac->scope == LDB_SCOPE_ONELEVEL && +- ldb_kv->cache->one_level_indexes && +- scope_one_truncation == KEY_NOT_TRUNCATED) { +- ret = ldb_match_message(ldb, msg, ac->tree, +- ac->scope, &matched); +- } else { +- ret = ldb_match_msg_error(ldb, msg, +- ac->tree, ac->base, +- ac->scope, &matched); ++ if (ac->scope != LDB_SCOPE_ONELEVEL || ++ !ldb_kv->cache->one_level_indexes || ++ scope_one_truncation != KEY_NOT_TRUNCATED) ++ { ++ /* ++ * The redaction callback may be expensive to call if it ++ * fetches a security descriptor. Check the DN early and ++ * bail out if it doesn't match the base. ++ */ ++ if (!ldb_match_scope(ldb, ac->base, msg->dn, ac->scope)) { ++ talloc_free(msg); ++ continue; ++ } ++ } ++ ++ if (ldb->redact.callback != NULL) { ++ ret = ldb->redact.callback(ldb->redact.module, ac->req, msg); ++ if (ret != LDB_SUCCESS) { ++ talloc_free(msg); ++ return ret; ++ } + } + ++ ret = ldb_match_message(ldb, msg, ac->tree, ++ ac->scope, &matched); + if (ret != LDB_SUCCESS) { + talloc_free(keys); + talloc_free(msg); +diff --git a/lib/ldb/ldb_key_value/ldb_kv_search.c b/lib/ldb/ldb_key_value/ldb_kv_search.c +index d187ba223e1..27f68caef01 100644 +--- a/lib/ldb/ldb_key_value/ldb_kv_search.c ++++ b/lib/ldb/ldb_key_value/ldb_kv_search.c +@@ -395,6 +395,16 @@ static int search_func(_UNUSED_ struct ldb_kv_private *ldb_kv, + } + } + ++ /* ++ * The redaction callback may be expensive to call if it fetches a ++ * security descriptor. Check the DN early and bail out if it doesn't ++ * match the base. ++ */ ++ if (!ldb_match_scope(ldb, ac->base, msg->dn, ac->scope)) { ++ talloc_free(msg); ++ return 0; ++ } ++ + if (ldb->redact.callback != NULL) { + ret = ldb->redact.callback(ldb->redact.module, ac->req, msg); + if (ret != LDB_SUCCESS) { +@@ -404,8 +414,8 @@ static int search_func(_UNUSED_ struct ldb_kv_private *ldb_kv, + } + + /* see if it matches the given expression */ +- ret = ldb_match_msg_error(ldb, msg, +- ac->tree, ac->base, ac->scope, &matched); ++ ret = ldb_match_message(ldb, msg, ++ ac->tree, ac->scope, &matched); + if (ret != LDB_SUCCESS) { + talloc_free(msg); + ac->error = LDB_ERR_OPERATIONS_ERROR; +-- +2.25.1 \ No newline at end of file diff --git a/backport-0031-CVE-2023-0614.patch b/backport-0031-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..6d808bc278ec0a939631795ee3648421da9216e3 --- /dev/null +++ b/backport-0031-CVE-2023-0614.patch @@ -0,0 +1,108 @@ +From 62d100b64a25c740187f687dd058a543d43984ec Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Fri, 24 Feb 2023 10:03:25 +1300 +Subject: [PATCH 29/34] CVE-2023-0614 s4-dsdb: Treat confidential attributes as + unindexed + +In the unlikely case that someone adds a confidential indexed attribute +to the schema, LDAP search expressions on that attribute could disclose +information via timing differences. Let's not use the index for searches +on confidential attributes. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/samdb/ldb_modules/extended_dn_in.c | 10 +++++++++- + source4/dsdb/schema/schema_description.c | 7 +++++++ + source4/dsdb/schema/schema_init.c | 11 +++++++++-- + source4/dsdb/schema/schema_set.c | 9 ++++++++- + 4 files changed, 33 insertions(+), 4 deletions(-) + +diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c +index 1dc1e1f2d42..248bb66f039 100644 +--- a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c ++++ b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c +@@ -423,7 +423,15 @@ static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *privat + guid_val = ldb_dn_get_extended_component(dn, "GUID"); + sid_val = ldb_dn_get_extended_component(dn, "SID"); + +- if (!guid_val && !sid_val && (attribute->searchFlags & SEARCH_FLAG_ATTINDEX)) { ++ /* ++ * Is the attribute indexed? By treating confidential attributes ++ * as unindexed, we force searches to go through the unindexed ++ * search path, avoiding observable timing differences. ++ */ ++ if (!guid_val && !sid_val && ++ (attribute->searchFlags & SEARCH_FLAG_ATTINDEX) && ++ !(attribute->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) ++ { + /* if it is indexed, then fixing the string DN will do + no good here, as we will not find the attribute in + the index. So for now fall through to a standard DN +diff --git a/source4/dsdb/schema/schema_description.c b/source4/dsdb/schema/schema_description.c +index 243a02a15f3..5fc70154bf8 100644 +--- a/source4/dsdb/schema/schema_description.c ++++ b/source4/dsdb/schema/schema_description.c +@@ -160,6 +160,13 @@ char *schema_attribute_to_extendedInfo(TALLOC_CTX *mem_ctx, const struct dsdb_at + attribute->rangeUpper, + GUID_hexstring(tmp_ctx, &attribute->schemaIDGUID), + GUID_hexstring(tmp_ctx, &attribute->attributeSecurityGUID), ++ /* ++ * We actually ignore the indexed ++ * flag for confidential ++ * attributes, but we'll include ++ * it for the purposes of ++ * description. ++ */ + (attribute->searchFlags & SEARCH_FLAG_ATTINDEX), + attribute->systemOnly); + talloc_free(tmp_ctx); +diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c +index a3b00497b6b..c8197b86306 100644 +--- a/source4/dsdb/schema/schema_init.c ++++ b/source4/dsdb/schema/schema_init.c +@@ -514,8 +514,15 @@ static int dsdb_schema_setup_ldb_schema_attribute(struct ldb_context *ldb, + if (attr->isSingleValued) { + a->flags |= LDB_ATTR_FLAG_SINGLE_VALUE; + } +- +- if (attr->searchFlags & SEARCH_FLAG_ATTINDEX) { ++ ++ /* ++ * Is the attribute indexed? By treating confidential attributes as ++ * unindexed, we force searches to go through the unindexed search path, ++ * avoiding observable timing differences. ++ */ ++ if (attr->searchFlags & SEARCH_FLAG_ATTINDEX && ++ !(attr->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) ++ { + a->flags |= LDB_ATTR_FLAG_INDEXED; + } + +diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c +index 45faa0912ec..03cf2405595 100644 +--- a/source4/dsdb/schema/schema_set.c ++++ b/source4/dsdb/schema/schema_set.c +@@ -221,7 +221,14 @@ int dsdb_schema_set_indices_and_attributes(struct ldb_context *ldb, + break; + } + +- if (attr->searchFlags & SEARCH_FLAG_ATTINDEX) { ++ /* ++ * Is the attribute indexed? By treating confidential attributes ++ * as unindexed, we force searches to go through the unindexed ++ * search path, avoiding observable timing differences. ++ */ ++ if (attr->searchFlags & SEARCH_FLAG_ATTINDEX && ++ !(attr->searchFlags & SEARCH_FLAG_CONFIDENTIAL)) ++ { + /* + * When preparing to downgrade Samba, we need to write + * out an LDB without the new key word ORDERED_INTEGER. +-- +2.25.1 \ No newline at end of file diff --git a/backport-0032-CVE-2023-0614.patch b/backport-0032-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..c37f48e21a09cfb1228b44196fbf0f46b0cd3f59 --- /dev/null +++ b/backport-0032-CVE-2023-0614.patch @@ -0,0 +1,49 @@ +From d857b406e44254b37aa91d0c8d226e417ce123ce Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Thu, 2 Mar 2023 16:31:17 +1300 +Subject: [PATCH 30/34] CVE-2023-0614 dsdb: Add DSDB_MARK_REQ_UNTRUSTED + +This will allow our dsdb helper search functions to mark the new +request as untrusted, forcing read ACL evaluation (per current behaviour). + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + source4/dsdb/common/util.c | 4 ++++ + source4/dsdb/common/util.h | 1 + + 2 files changed, 5 insertions(+) + +diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c +index b556f06cb63..39b29cd2a0c 100644 +--- a/source4/dsdb/common/util.c ++++ b/source4/dsdb/common/util.c +@@ -4878,6 +4878,10 @@ int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags) + } + } + ++ if (dsdb_flags & DSDB_MARK_REQ_UNTRUSTED) { ++ ldb_req_mark_untrusted(req); ++ } ++ + return LDB_SUCCESS; + } + +diff --git a/source4/dsdb/common/util.h b/source4/dsdb/common/util.h +index e1854644d53..5bb96d60b3c 100644 +--- a/source4/dsdb/common/util.h ++++ b/source4/dsdb/common/util.h +@@ -43,6 +43,7 @@ + #define DSDB_MODIFY_PARTIAL_REPLICA 0x04000 + #define DSDB_PASSWORD_BYPASS_LAST_SET 0x08000 + #define DSDB_REPLMD_VANISH_LINKS 0x10000 ++#define DSDB_MARK_REQ_UNTRUSTED 0x20000 + + bool is_attr_in_list(const char * const * attrs, const char *attr); + +-- +2.25.1 \ No newline at end of file diff --git a/backport-0033-CVE-2023-0614.patch b/backport-0033-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..409473fbb98c8455e97a76933c151a4ef3b1197f --- /dev/null +++ b/backport-0033-CVE-2023-0614.patch @@ -0,0 +1,43 @@ +From 0151a2a4c4cea64b0d931aa0e227b187abf28280 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Fri, 3 Mar 2023 16:49:00 +1300 +Subject: [PATCH 31/34] CVE-2023-0614 dsdb: Add pre-cleanup and + self.addCleanup() of OU created in match_rules tests + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb-samba/tests/match_rules.py | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/lib/ldb-samba/tests/match_rules.py b/lib/ldb-samba/tests/match_rules.py +index abf485c9eab..2af1dd6a070 100755 +--- a/lib/ldb-samba/tests/match_rules.py ++++ b/lib/ldb-samba/tests/match_rules.py +@@ -31,11 +31,19 @@ class MatchRulesTests(samba.tests.TestCase): + self.ou_groups = "OU=groups,%s" % self.ou + self.ou_computers = "OU=computers,%s" % self.ou + ++ try: ++ self.ldb.delete(self.ou, ["tree_delete:1"]) ++ except LdbError as e: ++ pass ++ + # Add a organizational unit to create objects + self.ldb.add({ + "dn": self.ou, + "objectclass": "organizationalUnit"}) + ++ self.addCleanup(self.ldb.delete, self.ou, controls=['tree_delete:0']) ++ ++ + # Add the following OU hierarchy and set otherWellKnownObjects, + # which has BinaryDN syntax: + # +-- +2.25.1 \ No newline at end of file diff --git a/backport-0034-CVE-2023-0614.patch b/backport-0034-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..0665c5d5d67a81565748669bbe557cdb581ab0a8 --- /dev/null +++ b/backport-0034-CVE-2023-0614.patch @@ -0,0 +1,319 @@ +From 91ecb27e706ac4500fb0d5242cf412173f8a5e7a Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Thu, 2 Mar 2023 16:51:25 +1300 +Subject: [PATCH 32/34] CVE-2023-0614 lib/ldb-samba: Add test for + SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL / LDAP_MATCHING_RULE_IN_CHAIN with and + ACL hidden attributes + +The chain for transitive evaluation does consider ACLs, avoiding the disclosure of +confidential information. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb-samba/tests/match_rules.py | 127 ++++++++++++---------- + lib/ldb-samba/tests/match_rules_remote.py | 104 ++++++++++++++++++ + source4/selftest/tests.py | 1 + + 3 files changed, 175 insertions(+), 57 deletions(-) + create mode 100755 lib/ldb-samba/tests/match_rules_remote.py + +diff --git a/lib/ldb-samba/tests/match_rules.py b/lib/ldb-samba/tests/match_rules.py +index 2af1dd6a070..2fe6c3e2264 100755 +--- a/lib/ldb-samba/tests/match_rules.py ++++ b/lib/ldb-samba/tests/match_rules.py +@@ -20,13 +20,18 @@ from ldb import SCOPE_BASE, SCOPE_SUBTREE, SCOPE_ONELEVEL + # Windows appear to preserve casing of the RDN and uppercase the other keys. + + +-class MatchRulesTests(samba.tests.TestCase): ++class MatchRulesTestsBase(samba.tests.TestCase): + def setUp(self): +- super(MatchRulesTests, self).setUp() +- self.lp = lp +- self.ldb = SamDB(host, credentials=creds, session_info=system_session(lp), lp=lp) ++ super().setUp() ++ self.lp = self.sambaopts.get_loadparm() ++ self.creds = self.credopts.get_credentials(self.lp) ++ ++ self.ldb = SamDB(self.host, credentials=self.creds, ++ session_info=system_session(self.lp), ++ lp=self.lp) + self.base_dn = self.ldb.domain_dn() +- self.ou = "OU=matchrulestest,%s" % self.base_dn ++ self.ou_rdn = "OU=matchrulestest" ++ self.ou = self.ou_rdn + "," + self.base_dn + self.ou_users = "OU=users,%s" % self.ou + self.ou_groups = "OU=groups,%s" % self.ou + self.ou_computers = "OU=computers,%s" % self.ou +@@ -212,6 +217,39 @@ class MatchRulesTests(samba.tests.TestCase): + FLAG_MOD_ADD, "member") + self.ldb.modify(m) + ++ # Add a couple of ms-Exch-Configuration-Container to test forward-link ++ # attributes without backward link (addressBookRoots2) ++ # e1 ++ # |--> e2 ++ # | |--> c1 ++ self.ldb.add({ ++ "dn": "cn=e1,%s" % self.ou, ++ "objectclass": "msExchConfigurationContainer"}) ++ self.ldb.add({ ++ "dn": "cn=e2,%s" % self.ou, ++ "objectclass": "msExchConfigurationContainer"}) ++ ++ m = Message() ++ m.dn = Dn(self.ldb, "cn=e2,%s" % self.ou) ++ m["e1"] = MessageElement("cn=c1,%s" % self.ou_computers, ++ FLAG_MOD_ADD, "addressBookRoots2") ++ self.ldb.modify(m) ++ ++ m = Message() ++ m.dn = Dn(self.ldb, "cn=e1,%s" % self.ou) ++ m["e1"] = MessageElement("cn=e2,%s" % self.ou, ++ FLAG_MOD_ADD, "addressBookRoots2") ++ self.ldb.modify(m) ++ ++ ++ ++class MatchRulesTests(MatchRulesTestsBase): ++ def setUp(self): ++ self.sambaopts = sambaopts ++ self.credopts = credopts ++ self.host = host ++ super().setUp() ++ + # The msDS-RevealedUsers is owned by system and cannot be modified + # directly. Set the schemaUpgradeInProgress flag as workaround + # and create this hierarchy: +@@ -251,33 +289,6 @@ class MatchRulesTests(samba.tests.TestCase): + m["e1"] = MessageElement("0", FLAG_MOD_REPLACE, "schemaUpgradeInProgress") + self.ldb.modify(m) + +- # Add a couple of ms-Exch-Configuration-Container to test forward-link +- # attributes without backward link (addressBookRoots2) +- # e1 +- # |--> e2 +- # | |--> c1 +- self.ldb.add({ +- "dn": "cn=e1,%s" % self.ou, +- "objectclass": "msExchConfigurationContainer"}) +- self.ldb.add({ +- "dn": "cn=e2,%s" % self.ou, +- "objectclass": "msExchConfigurationContainer"}) +- +- m = Message() +- m.dn = Dn(self.ldb, "cn=e2,%s" % self.ou) +- m["e1"] = MessageElement("cn=c1,%s" % self.ou_computers, +- FLAG_MOD_ADD, "addressBookRoots2") +- self.ldb.modify(m) +- +- m = Message() +- m.dn = Dn(self.ldb, "cn=e1,%s" % self.ou) +- m["e1"] = MessageElement("cn=e2,%s" % self.ou, +- FLAG_MOD_ADD, "addressBookRoots2") +- self.ldb.modify(m) +- +- def tearDown(self): +- super(MatchRulesTests, self).tearDown() +- self.ldb.delete(self.ou, controls=['tree_delete:0']) + + def test_u1_member_of_g4(self): + # Search without transitive match must return 0 results +@@ -953,8 +964,12 @@ class MatchRulesTests(samba.tests.TestCase): + class MatchRuleConditionTests(samba.tests.TestCase): + def setUp(self): + super(MatchRuleConditionTests, self).setUp() +- self.lp = lp +- self.ldb = SamDB(host, credentials=creds, session_info=system_session(lp), lp=lp) ++ self.lp = sambaopts.get_loadparm() ++ self.creds = credopts.get_credentials(self.lp) ++ ++ self.ldb = SamDB(host, credentials=self.creds, ++ session_info=system_session(self.lp), ++ lp=self.lp) + self.base_dn = self.ldb.domain_dn() + self.ou = "OU=matchruleconditiontests,%s" % self.base_dn + self.ou_users = "OU=users,%s" % self.ou +@@ -1753,32 +1768,30 @@ class MatchRuleConditionTests(samba.tests.TestCase): + self.ou_groups, self.ou_computers)) + self.assertEqual(len(res1), 0) + ++if __name__ == "__main__": + +-parser = optparse.OptionParser("match_rules.py [options] ") +-sambaopts = options.SambaOptions(parser) +-parser.add_option_group(sambaopts) +-parser.add_option_group(options.VersionOptions(parser)) +- +-# use command line creds if available +-credopts = options.CredentialsOptions(parser) +-parser.add_option_group(credopts) +-opts, args = parser.parse_args() +-subunitopts = SubunitOptions(parser) +-parser.add_option_group(subunitopts) ++ parser = optparse.OptionParser("match_rules.py [options] ") ++ sambaopts = options.SambaOptions(parser) ++ parser.add_option_group(sambaopts) ++ parser.add_option_group(options.VersionOptions(parser)) + +-if len(args) < 1: +- parser.print_usage() +- sys.exit(1) ++ # use command line creds if available ++ credopts = options.CredentialsOptions(parser) ++ parser.add_option_group(credopts) ++ opts, args = parser.parse_args() ++ subunitopts = SubunitOptions(parser) ++ parser.add_option_group(subunitopts) + +-host = args[0] ++ if len(args) < 1: ++ parser.print_usage() ++ sys.exit(1) + +-lp = sambaopts.get_loadparm() +-creds = credopts.get_credentials(lp) ++ host = args[0] + +-if "://" not in host: +- if os.path.isfile(host): +- host = "tdb://%s" % host +- else: +- host = "ldap://%s" % host ++ if "://" not in host: ++ if os.path.isfile(host): ++ host = "tdb://%s" % host ++ else: ++ host = "ldap://%s" % host + +-TestProgram(module=__name__, opts=subunitopts) ++ TestProgram(module=__name__, opts=subunitopts) +diff --git a/lib/ldb-samba/tests/match_rules_remote.py b/lib/ldb-samba/tests/match_rules_remote.py +new file mode 100755 +index 00000000000..122231f2a60 +--- /dev/null ++++ b/lib/ldb-samba/tests/match_rules_remote.py +@@ -0,0 +1,104 @@ ++#!/usr/bin/env python3 ++ ++import optparse ++import sys ++import os ++import samba ++import samba.getopt as options ++ ++from samba.tests.subunitrun import SubunitOptions, TestProgram ++ ++from samba.samdb import SamDB ++from samba.auth import system_session ++from samba import sd_utils ++from samba.ndr import ndr_unpack ++from ldb import Message, MessageElement, Dn, LdbError ++from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE ++from ldb import SCOPE_BASE, SCOPE_SUBTREE, SCOPE_ONELEVEL ++ ++from match_rules import MatchRulesTestsBase ++ ++ ++class MatchRulesTestsUser(MatchRulesTestsBase): ++ def setUp(self): ++ self.sambaopts = sambaopts ++ self.credopts = credopts ++ self.host = host ++ super().setUp() ++ self.sd_utils = sd_utils.SDUtils(self.ldb) ++ ++ self.user_pass = "samba123@" ++ self.match_test_user = "matchtestuser" ++ self.ldb.newuser(self.match_test_user, ++ self.user_pass, ++ userou=self.ou_rdn) ++ user_creds = self.insta_creds(template=self.creds, ++ username=self.match_test_user, ++ userpass=self.user_pass) ++ self.user_ldb = SamDB(host, credentials=user_creds, lp=self.lp) ++ token_res = self.user_ldb.search(scope=SCOPE_BASE, ++ base="", ++ attrs=["tokenGroups"]) ++ self.user_sid = ndr_unpack(samba.dcerpc.security.dom_sid, ++ token_res[0]["tokenGroups"][0]) ++ ++ self.member_attr_guid = "bf9679c0-0de6-11d0-a285-00aa003049e2" ++ ++ def test_with_denied_link(self): ++ ++ # add an ACE that denies the user Read Property (RP) access to ++ # the member attr (which is similar to making the attribute ++ # confidential) ++ ace = "(OD;;RP;{0};;{1})".format(self.member_attr_guid, ++ self.user_sid) ++ g2_dn = Dn(self.ldb, "CN=g2,%s" % self.ou_groups) ++ ++ # add the ACE that denies access to the attr under test ++ self.sd_utils.dacl_add_ace(g2_dn, ace) ++ ++ # Search without transitive match must return 0 results ++ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups, ++ scope=SCOPE_BASE, ++ expression="member=cn=u1,%s" % self.ou_users) ++ self.assertEqual(len(res1), 0) ++ ++ # Search with transitive match must return 1 results ++ res1 = self.ldb.search("cn=g4,%s" % self.ou_groups, ++ scope=SCOPE_BASE, ++ expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users) ++ self.assertEqual(len(res1), 1) ++ self.assertEqual(str(res1[0].dn).lower(), ("CN=g4,%s" % self.ou_groups).lower()) ++ ++ # Search as a user match must return 0 results as the intermediate link can't be seen ++ res1 = self.user_ldb.search("cn=g4,%s" % self.ou_groups, ++ scope=SCOPE_BASE, ++ expression="member:1.2.840.113556.1.4.1941:=cn=u1,%s" % self.ou_users) ++ self.assertEqual(len(res1), 0) ++ ++ ++ ++parser = optparse.OptionParser("match_rules_remote.py [options] ") ++sambaopts = options.SambaOptions(parser) ++parser.add_option_group(sambaopts) ++parser.add_option_group(options.VersionOptions(parser)) ++ ++# use command line creds if available ++credopts = options.CredentialsOptions(parser) ++parser.add_option_group(credopts) ++opts, args = parser.parse_args() ++subunitopts = SubunitOptions(parser) ++parser.add_option_group(subunitopts) ++ ++if len(args) < 1: ++ parser.print_usage() ++ sys.exit(1) ++ ++host = args[0] ++ ++if "://" not in host: ++ if os.path.isfile(host): ++ host = "tdb://%s" % host ++ else: ++ host = "ldap://%s" % host ++ ++TestProgram(module=__name__, opts=subunitopts) +diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py +index c6bf668aa9c..a09945f40da 100755 +--- a/source4/selftest/tests.py ++++ b/source4/selftest/tests.py +@@ -1322,6 +1322,7 @@ for env in ['ad_dc_default:local', 'schema_dc:local']: + plantestsuite_loadlist("samba4.urgent_replication.python(ad_dc_ntvfs)", "ad_dc_ntvfs:local", [python, os.path.join(DSDB_PYTEST_DIR, "urgent_replication.py"), '$PREFIX_ABS/ad_dc_ntvfs/private/sam.ldb', '$LOADLIST', '$LISTOPT']) + plantestsuite_loadlist("samba4.ldap.dirsync.python(ad_dc_ntvfs)", "ad_dc_ntvfs", [python, os.path.join(DSDB_PYTEST_DIR, "dirsync.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) + plantestsuite_loadlist("samba4.ldap.match_rules.python", "ad_dc_ntvfs", [python, os.path.join(srcdir(), "lib/ldb-samba/tests/match_rules.py"), '$PREFIX_ABS/ad_dc_ntvfs/private/sam.ldb', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) ++plantestsuite_loadlist("samba4.ldap.match_rules.python", "ad_dc_ntvfs", [python, os.path.join(srcdir(), "lib/ldb-samba/tests/match_rules_remote.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) + plantestsuite("samba4.ldap.index.python", "none", [python, os.path.join(srcdir(), "lib/ldb-samba/tests/index.py")]) + plantestsuite_loadlist("samba4.ldap.notification.python(ad_dc_ntvfs)", "ad_dc_ntvfs", [python, os.path.join(DSDB_PYTEST_DIR, "notification.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) + plantestsuite_loadlist("samba4.ldap.sites.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "sites.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) +-- +2.25.1 \ No newline at end of file diff --git a/backport-0035-CVE-2023-0614.patch b/backport-0035-CVE-2023-0614.patch new file mode 100644 index 0000000000000000000000000000000000000000..1622cbd1fc1a57c3739ca4da86d65ac1067f6b90 --- /dev/null +++ b/backport-0035-CVE-2023-0614.patch @@ -0,0 +1,39 @@ +From bb092fc576868e30edf78136894472f95c4b039d Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Thu, 2 Mar 2023 17:24:15 +1300 +Subject: [PATCH 33/34] CVE-2023-0614 lib/ldb-samba Ensure ACLs are evaluated + on SAMBA_LDAP_MATCH_RULE_TRANSITIVE_EVAL / LDAP_MATCHING_RULE_IN_CHAIN + +Setting the LDB_HANDLE_FLAG_UNTRUSTED tells the acl_read module to operate on this request. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17821 +--- + lib/ldb-samba/ldb_matching_rules.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/lib/ldb-samba/ldb_matching_rules.c b/lib/ldb-samba/ldb_matching_rules.c +index b86594c1823..59d1385f4e3 100644 +--- a/lib/ldb-samba/ldb_matching_rules.c ++++ b/lib/ldb-samba/ldb_matching_rules.c +@@ -67,7 +67,12 @@ static int ldb_eval_transitive_filter_helper(TALLOC_CTX *mem_ctx, + * Note also that we don't have the original request + * here, so we can not apply controls or timeouts here. + */ +- ret = dsdb_search_dn(ldb, tmp_ctx, &res, to_visit->dn, attrs, 0); ++ ret = dsdb_search_dn(ldb, ++ tmp_ctx, ++ &res, ++ to_visit->dn, ++ attrs, ++ DSDB_MARK_REQ_UNTRUSTED); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; +-- +2.25.1 \ No newline at end of file diff --git a/backport-CVE-2023-0922.patch b/backport-CVE-2023-0922.patch new file mode 100644 index 0000000000000000000000000000000000000000..9133496ebbfb585214e54e55763cd9a879654838 --- /dev/null +++ b/backport-CVE-2023-0922.patch @@ -0,0 +1,108 @@ +From faa7babcd8db9ef14398848d0c398578d1a79d85 Mon Sep 17 00:00:00 2001 +From: Rob van der Linde +Date: Mon, 27 Feb 2023 14:06:23 +1300 +Subject: [PATCH] CVE-2023-0922 set default ldap client sasl wrapping to seal + +This avoids sending new or reset passwords in the clear +(integrity protected only) from samba-tool in particular. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15315 + +Signed-off-by: Rob van der Linde +Signed-off-by: Andrew Bartlett +Reviewed-by: Joseph Sutton + +Conflict: NA +Reference: https://attachments.samba.org/attachment.cgi?id=17831 +--- + .../ldap/clientldapsaslwrapping.xml | 27 +++++++++---------- + lib/param/loadparm.c | 2 +- + python/samba/tests/auth_log.py | 2 +- + source3/param/loadparm.c | 2 +- + 4 files changed, 16 insertions(+), 17 deletions(-) + +diff --git a/docs-xml/smbdotconf/ldap/clientldapsaslwrapping.xml b/docs-xml/smbdotconf/ldap/clientldapsaslwrapping.xml +index 3152f0682dd..21bd2090057 100644 +--- a/docs-xml/smbdotconf/ldap/clientldapsaslwrapping.xml ++++ b/docs-xml/smbdotconf/ldap/clientldapsaslwrapping.xml +@@ -18,25 +18,24 @@ + + + +- This option is needed in the case of Domain Controllers enforcing +- the usage of signed LDAP connections (e.g. Windows 2000 SP3 or higher). +- LDAP sign and seal can be controlled with the registry key +- "HKLM\System\CurrentControlSet\Services\ +- NTDS\Parameters\LDAPServerIntegrity" +- on the Windows server side. +- ++ This option is needed firstly to secure the privacy of ++ administrative connections from samba-tool, ++ including in particular new or reset passwords for users. For ++ this reason the default is seal. + +- +- Depending on the used KRB5 library (MIT and older Heimdal versions) +- it is possible that the message "integrity only" is not supported. +- In this case, sign is just an alias for +- seal. ++ Additionally, winbindd and the ++ net tool can use LDAP to communicate with ++ Domain Controllers, so this option also controls the level of ++ privacy for those connections. All supported AD DC versions ++ will enforce the usage of at least signed LDAP connections by ++ default, so a value of at least sign is ++ required in practice. + + + +- The default value is sign. That implies synchronizing the time ++ The default value is seal. That implies synchronizing the time + with the KDC in the case of using Kerberos. + + +-sign ++seal + +diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c +index 6ab7fa89db7..16cb0d47f31 100644 +--- a/lib/param/loadparm.c ++++ b/lib/param/loadparm.c +@@ -2990,7 +2990,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) + + lpcfg_do_global_parameter(lp_ctx, "ldap debug threshold", "10"); + +- lpcfg_do_global_parameter(lp_ctx, "client ldap sasl wrapping", "sign"); ++ lpcfg_do_global_parameter(lp_ctx, "client ldap sasl wrapping", "seal"); + + lpcfg_do_global_parameter(lp_ctx, "mdns name", "netbios"); + +diff --git a/python/samba/tests/auth_log.py b/python/samba/tests/auth_log.py +index d166b93d90a..8f9f487f82a 100644 +--- a/python/samba/tests/auth_log.py ++++ b/python/samba/tests/auth_log.py +@@ -470,7 +470,7 @@ class AuthLogTests(samba.tests.auth_log_base.AuthLogTestBase): + def isLastExpectedMessage(msg): + return (msg["type"] == "Authorization" and + msg["Authorization"]["serviceDescription"] == "LDAP" and +- msg["Authorization"]["transportProtection"] == "SIGN" and ++ msg["Authorization"]["transportProtection"] == "SEAL" and + msg["Authorization"]["authType"] == "krb5") + + self.samdb = SamDB(url="ldap://%s" % os.environ["SERVER"], +diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c +index 05a5ae20abe..12718ced9e7 100644 +--- a/source3/param/loadparm.c ++++ b/source3/param/loadparm.c +@@ -756,7 +756,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) + Globals.ldap_debug_level = 0; + Globals.ldap_debug_threshold = 10; + +- Globals.client_ldap_sasl_wrapping = ADS_AUTH_SASL_SIGN; ++ Globals.client_ldap_sasl_wrapping = ADS_AUTH_SASL_SEAL; + + Globals.ldap_server_require_strong_auth = + LDAP_SERVER_REQUIRE_STRONG_AUTH_YES; +-- +2.25.1 + diff --git a/gpgkey-52FBC0B86D954B0843324CDC6F33915B6568B7EA.gpg b/gpgkey-52FBC0B86D954B0843324CDC6F33915B6568B7EA.gpg deleted file mode 100644 index a61ebc450995a418da1144e95cbfb66bc1edcd0b..0000000000000000000000000000000000000000 Binary files a/gpgkey-52FBC0B86D954B0843324CDC6F33915B6568B7EA.gpg and /dev/null differ diff --git a/remove-sensitive-info.patch b/remove-sensitive-info.patch new file mode 100644 index 0000000000000000000000000000000000000000..05b3a55a28846add67348da8dd34922418c9eb98 --- /dev/null +++ b/remove-sensitive-info.patch @@ -0,0 +1,144 @@ +From 54e951d6795bad1f0451ea2e03403e791df3856a Mon Sep 17 00:00:00 2001 +From: zhouyihang +Date: Fri, 25 Dec 2020 00:11:23 +0800 +Subject: [PATCH] remove sensitive info + +Conflict: NA +Reference: NA + +--- + source3/lib/netapi/examples/share/share_enum.c | 1 - + source3/lib/netapi/examples/share/share_getinfo.c | 1 - + source3/lib/netapi/examples/user/user_getinfo.c | 3 --- + source3/rpcclient/cmd_lsarpc.c | 3 --- + source3/rpcclient/cmd_srvsvc.c | 2 -- + source3/utils/net_rpc.c | 1 - + source4/scripting/bin/samba3dump | 2 -- + source4/torture/shell.c | 1 - + 8 files changed, 14 deletions(-) + +diff --git a/source3/lib/netapi/examples/share/share_enum.c b/source3/lib/netapi/examples/share/share_enum.c +index b1f4043..ee69d60 100644 +--- a/source3/lib/netapi/examples/share/share_enum.c ++++ b/source3/lib/netapi/examples/share/share_enum.c +@@ -118,7 +118,6 @@ int main(int argc, const char **argv) + printf("#%d max users: %d\n", i, i2->shi2_max_uses); + printf("#%d current users: %d\n", i, i2->shi2_current_uses); + printf("#%d path: %s\n", i, i2->shi2_path); +- printf("#%d password: %s\n", i, i2->shi2_passwd); + i2++; + break; + default: +diff --git a/source3/lib/netapi/examples/share/share_getinfo.c b/source3/lib/netapi/examples/share/share_getinfo.c +index 479da5c..3ef7825 100644 +--- a/source3/lib/netapi/examples/share/share_getinfo.c ++++ b/source3/lib/netapi/examples/share/share_getinfo.c +@@ -128,7 +128,6 @@ int main(int argc, const char **argv) + printf("max users: %d\n", i2->shi2_max_uses); + printf("current users: %d\n", i2->shi2_current_uses); + printf("path: %s\n", i2->shi2_path); +- printf("password: %s\n", i2->shi2_passwd); + break; + case 501: + printf("netname: %s\n", i501->shi501_netname); +diff --git a/source3/lib/netapi/examples/user/user_getinfo.c b/source3/lib/netapi/examples/user/user_getinfo.c +index 9e95260..154aa7d 100644 +--- a/source3/lib/netapi/examples/user/user_getinfo.c ++++ b/source3/lib/netapi/examples/user/user_getinfo.c +@@ -104,7 +104,6 @@ int main(int argc, const char **argv) + case 1: + u1 = (struct USER_INFO_1 *)buffer; + printf("name: %s\n", u1->usri1_name); +- printf("password: %s\n", u1->usri1_password); + printf("password_age: %d\n", u1->usri1_password_age); + printf("priv: %d\n", u1->usri1_priv); + printf("homedir: %s\n", u1->usri1_home_dir); +@@ -115,7 +114,6 @@ int main(int argc, const char **argv) + case 2: + u2 = (struct USER_INFO_2 *)buffer; + printf("name: %s\n", u2->usri2_name); +- printf("password: %s\n", u2->usri2_password); + printf("password_age: %d\n", u2->usri2_password_age); + printf("priv: %d\n", u2->usri2_priv); + printf("homedir: %s\n", u2->usri2_home_dir); +@@ -187,7 +185,6 @@ int main(int argc, const char **argv) + case 4: + u4 = (struct USER_INFO_4 *)buffer; + printf("name: %s\n", u4->usri4_name); +- printf("password: %s\n", u4->usri4_password); + printf("password_age: %d\n", u4->usri4_password_age); + printf("priv: %d\n", u4->usri4_priv); + printf("homedir: %s\n", u4->usri4_home_dir); +diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c +index abb4543..81baece 100644 +--- a/source3/rpcclient/cmd_lsarpc.c ++++ b/source3/rpcclient/cmd_lsarpc.c +@@ -1289,9 +1289,6 @@ static void display_trust_dom_info_4(struct lsa_TrustDomainInfoPassword *p, + pwd = sess_decrypt_string(talloc_tos(), &data, &session_key); + pwd_old = sess_decrypt_string(talloc_tos(), &data_old, &session_key); + +- d_printf("Password:\t%s\n", pwd); +- d_printf("Old Password:\t%s\n", pwd_old); +- + talloc_free(pwd); + talloc_free(pwd_old); + } +diff --git a/source3/rpcclient/cmd_srvsvc.c b/source3/rpcclient/cmd_srvsvc.c +index 9c00060..b107741 100644 +--- a/source3/rpcclient/cmd_srvsvc.c ++++ b/source3/rpcclient/cmd_srvsvc.c +@@ -233,7 +233,6 @@ static void display_share_info_2(struct srvsvc_NetShareInfo2 *r) + printf("netname: %s\n", r->name); + printf("\tremark:\t%s\n", r->comment); + printf("\tpath:\t%s\n", r->path); +- printf("\tpassword:\t%s\n", r->password); + } + + static void display_share_info_502(struct srvsvc_NetShareInfo502 *r) +@@ -241,7 +240,6 @@ static void display_share_info_502(struct srvsvc_NetShareInfo502 *r) + printf("netname: %s\n", r->name); + printf("\tremark:\t%s\n", r->comment); + printf("\tpath:\t%s\n", r->path); +- printf("\tpassword:\t%s\n", r->password); + + printf("\ttype:\t0x%x\n", r->type); + printf("\tperms:\t%d\n", r->permissions); +diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c +index a56190f..28a1808 100644 +--- a/source3/utils/net_rpc.c ++++ b/source3/utils/net_rpc.c +@@ -5582,7 +5582,6 @@ static NTSTATUS rpc_sh_share_info(struct net_context *c, + d_printf(_("Name: %s\n"), info.info2->name); + d_printf(_("Comment: %s\n"), info.info2->comment); + d_printf(_("Path: %s\n"), info.info2->path); +- d_printf(_("Password: %s\n"), info.info2->password); + + done: + return werror_to_ntstatus(result); +diff --git a/source4/scripting/bin/samba3dump b/source4/scripting/bin/samba3dump +index 1a5d74f..4b311c2 100755 +--- a/source4/scripting/bin/samba3dump ++++ b/source4/scripting/bin/samba3dump +@@ -70,8 +70,6 @@ def print_samba3_secrets(secrets): + print("IPC Credentials:") + if secrets.get_auth_user(): + print(" User: %s\n" % secrets.get_auth_user()) +- if secrets.get_auth_password(): +- print(" Password: %s\n" % secrets.get_auth_password()) + if secrets.get_auth_domain(): + print(" Domain: %s\n" % secrets.get_auth_domain()) + +diff --git a/source4/torture/shell.c b/source4/torture/shell.c +index 195149a..f63694a 100644 +--- a/source4/torture/shell.c ++++ b/source4/torture/shell.c +@@ -240,7 +240,6 @@ static void shell_auth(const struct shell_command * command, + printf("User Principal: %s\n", principal ? principal : ""); + printf("Domain: %s\n", domain ? domain : ""); + printf("Realm: %s\n", realm ? realm : ""); +- printf("Password: %s\n", password ? password : ""); + } else if (argc == 2) { + bool result; + +-- +2.23.0 \ No newline at end of file diff --git a/samba-4.12.5.tar.asc b/samba-4.12.5.tar.asc deleted file mode 100644 index ec3af40b57d7d04d20f750a850f404787dcf4703..0000000000000000000000000000000000000000 --- a/samba-4.12.5.tar.asc +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iHMEABECADMWIQRS+8C4bZVLCEMyTNxvM5FbZWi36gUCXv3BXhUcc2FtYmEtYnVn -c0BzYW1iYS5vcmcACgkQbzORW2Vot+quPwCcDfpwxTo7ZDrFD768SgWqRmKI/+QA -oJqPMNOtzBJYbxVbKY+OyCqwQ2Zl -=2OtH ------END PGP SIGNATURE----- diff --git a/samba-4.17.5.tar.asc b/samba-4.17.5.tar.asc new file mode 100644 index 0000000000000000000000000000000000000000..6d0b732092ebf4680c154a2535e31267163f36ab --- /dev/null +++ b/samba-4.17.5.tar.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCgAdFiEEgfXigyvSVFoYl7cTqplEL7aAtiAFAmPSvJEACgkQqplEL7aA +tiDXbA//bPY+2A4y8zPJLibWjRtmv76xTgj1EJMZoC5d7+5PXQfuVhVULGYrxriF +MIF4CtTnMDk20mihnQb03csGpZGvqfBKbZg6jYolqeTmwRDgKXf9dxLxYYBGswPN +JXiF/ZvDQzEorrsz24o7i9Pe44IXpdf7+3RjIXhKjCa2vFQibTndGRhYb0UYiR9S +DELp6V/rmV9/BrYWVhHVnuzROzNWsrXIyu1GPNRWdX6ptJmjq6f8wZUP0NODYsBP +e0+BpXwob795tDSAMBnbnp7ZsHRYgB2/iWDTe19MF5LjHCcPwRWmzfZjiWQuz11D +kg7RUmlTkpU0mrToM+Uyg3Lhc8sayojDTHkIuIPBTuirdKuyP5Zov1wCaPuvf8Ew +LCQlQsC2AVeko8xY7P5ieXrmsfncoKR23S0MaKM6oNXooMJcNFnemMvCsOGGeGCi +HJa1whPdI5Cj3zLB5X35UNMmauS7qWyyj3lS2horg8L/iIQ3R3q+0Xkd5VmX1BXz +EhVDvOnb1F7E9HFlxhZRJFufpnHrGZX6ZYe6BqP8oU092UUU5JMeIqe20wG/dAtX +B91QhITdPDnM4KrSbch9i+BKW1xD8srRXu4yqMTZp6X6dPh6lnzVn6vj4uKNCMwz +2qLa3Rl+cRON1uTeFJXSTHg/diHjKriu3+bCqm0RlHAFLMtvudk= +=gZl3 +-----END PGP SIGNATURE----- diff --git a/samba-4.12.5.tar.gz b/samba-4.17.5.tar.gz similarity index 50% rename from samba-4.12.5.tar.gz rename to samba-4.17.5.tar.gz index 252e7feb03a8f3bc3f8be1afcea5c2bc275781a0..100c6f0cc19c874eaa5b90e01b1162d0f61b9099 100644 Binary files a/samba-4.12.5.tar.gz and b/samba-4.17.5.tar.gz differ diff --git a/samba-pubkey_AA99442FB680B620.gpg b/samba-pubkey_AA99442FB680B620.gpg new file mode 100644 index 0000000000000000000000000000000000000000..c901409c92a9ccaa3f29dca796283d35ba462c4c Binary files /dev/null and b/samba-pubkey_AA99442FB680B620.gpg differ diff --git a/samba.spec b/samba.spec index d62db47c639b909ccbf923c09d119d94a792b729..8dc13f32238cc2292f7583612a138697a4b1cfef 100644 --- a/samba.spec +++ b/samba.spec @@ -1,12 +1,12 @@ %bcond_with testsuite %bcond_without clustering +%{?python3_sitearch: %global python3_sitearch %{python3_sitearch}} -%define samba_requires_eq() %(LC_ALL="C" echo '%*' | xargs -r rpm -q --qf 'Requires: %%{name} = %%{epoch}:%%{version -}\\n' | sed -e 's/ (none):/ /' -e 's/ 0:/ /' | grep -v "is not") -%define talloc_version 2.3.1 -%define tdb_version 1.4.3 -%define tevent_version 0.10.2 -%define ldb_version 2.1.4 +%define samba_requires_eq() %(LC_ALL="C" echo '%*' | xargs -r rpm -q --qf 'Requires: %%{name} = %%{epoch}:%%{version}\\n' | sed -e 's/ (none):/ /' -e 's/ 0:/ /' | grep -v "is not") +%global talloc_version 2.3.4 +%global tdb_version 1.4.7 +%global tevent_version 0.13.0 +%global ldb_version 2.6.1-2 %undefine _strict_symbol_defs_build @@ -32,7 +32,7 @@ %global with_dc 1 %endif -%global required_mit_krb5 1.18 +%global required_mit_krb5 1.19 %global with_clustering_support 0 @@ -45,11 +45,11 @@ %global with_vfs_io_uring 0 %global _systemd_extra "Environment=KRB5CCNAME=FILE:/run/samba/krb5cc_samba" -%define samba_depver %{version}-%{release} +%global samba_depver %{version}-%{release} Name: samba -Version: 4.12.5 -Release: 6 +Version: 4.17.5 +Release: 11 Summary: A suite for Linux to interoperate with Windows License: GPLv3+ and LGPLv3+ @@ -57,31 +57,127 @@ URL: https://www.samba.org Source0: https://download.samba.org/pub/samba/stable/%{name}-%{version}.tar.gz Source1: https://download.samba.org/pub/samba/stable/%{name}-%{version}.tar.asc -Source2: gpgkey-52FBC0B86D954B0843324CDC6F33915B6568B7EA.gpg +Source2: samba-pubkey_AA99442FB680B620.gpg Source3: samba.logrotate Source4: smb.conf.vendor Source5: smb.conf.example Source6: pam_winbind.conf Source7: samba.pamd +Source8: usershares.conf.vendor Source201: README.downgrade -Patch0: CVE-2020-1472.patch -Patch1: 0001-CVE-2020-14383.patch -Patch2: 0002-CVE-2020-14383.patch -Patch3: CVE-2020-14318.patch -Patch4: CVE-2020-14323.patch -Patch5: CVE-2021-20277.patch -Patch6: CVE-2020-27840.patch -Patch7: CVE-2021-20254.patch - -BuildRequires: avahi-devel bison cups-devel dbus-devel docbook-style-xsl e2fsprogs-devel flex gawk gnupg2 gnutls-devel >= 3.4.7 gpgme-devel +Patch0001: backport-0001-CVE-2023-0614.patch +Patch0002: backport-0002-CVE-2023-0614.patch +Patch0003: backport-0003-CVE-2023-0614.patch +Patch0004: backport-0004-CVE-2023-0614.patch +Patch0005: backport-0005-CVE-2023-0614.patch +Patch0006: backport-0006-CVE-2023-0614.patch +Patch0007: backport-0007-CVE-2023-0614.patch +Patch0008: backport-0008-CVE-2023-0614.patch +Patch0009: backport-0009-CVE-2023-0614.patch +Patch0010: backport-0010-CVE-2023-0614.patch +Patch0011: backport-0011-CVE-2023-0614.patch +Patch0012: backport-0012-CVE-2023-0614.patch +Patch0013: backport-0013-CVE-2023-0614.patch +Patch0014: backport-0014-CVE-2023-0614.patch +Patch0015: backport-0015-CVE-2023-0614.patch +Patch0016: backport-0016-CVE-2023-0614.patch +Patch0017: backport-0017-CVE-2023-0614.patch +Patch0018: backport-0018-CVE-2023-0614.patch +Patch0019: backport-0019-CVE-2023-0614.patch +Patch0020: backport-0020-CVE-2023-0614.patch +Patch0021: backport-0021-CVE-2023-0614.patch +Patch0022: backport-0022-CVE-2023-0614.patch +Patch0023: backport-0023-CVE-2023-0614.patch +Patch0024: backport-0024-CVE-2023-0614.patch +Patch0025: backport-0025-CVE-2023-0614.patch +Patch0026: backport-0026-CVE-2023-0614.patch +Patch0027: backport-0027-CVE-2023-0614.patch +Patch0028: backport-0028-CVE-2023-0614.patch +Patch0029: backport-0029-CVE-2023-0614.patch +Patch0030: backport-0030-CVE-2023-0614.patch +Patch0031: backport-0031-CVE-2023-0614.patch +Patch0032: backport-0032-CVE-2023-0614.patch +Patch0033: backport-0033-CVE-2023-0614.patch +Patch0034: backport-0034-CVE-2023-0614.patch +Patch0035: backport-0035-CVE-2023-0614.patch +Patch0036: backport-0001-CVE-2023-0225.patch +Patch0037: backport-0002-CVE-2023-0225.patch +Patch0038: backport-0003-CVE-2023-0225.patch +Patch0039: backport-0004-CVE-2023-0225.patch +Patch0040: backport-CVE-2023-0922.patch +Patch0041: backport-0001-CVE-2022-2127.patch +Patch0042: backport-0002-CVE-2022-2127.patch +Patch0043: backport-0001-CVE-2023-34966.patch +Patch0044: backport-0002-CVE-2023-34966.patch +Patch0045: backport-0001-CVE-2023-34967.patch +Patch0046: backport-0002-CVE-2023-34967.patch +Patch0047: backport-0001-CVE-2023-34968.patch +Patch0048: backport-0002-CVE-2023-34968.patch +Patch0049: backport-0003-CVE-2023-34968.patch +Patch0050: backport-0004-CVE-2023-34968.patch +Patch0051: backport-0005-CVE-2023-34968.patch +Patch0052: backport-0006-CVE-2023-34968.patch +Patch0053: backport-0007-CVE-2023-34968.patch +Patch0054: backport-0008-CVE-2023-34968.patch +Patch0055: backport-0009-CVE-2023-34968.patch +Patch0056: backport-0010-CVE-2023-34968.patch +Patch0057: backport-0011-CVE-2023-34968.patch +Patch0058: backport-0001-CVE-2023-3347.patch +Patch0059: backport-0002-CVE-2023-3347.patch +Patch0060: backport-0003-CVE-2023-3347.patch +Patch0061: backport-0004-CVE-2023-3347.patch +Patch0062: backport-0005-CVE-2023-3347.patch +Patch0063: backport-0001-CVE-2023-3961.patch +Patch0064: backport-0002-CVE-2023-3961.patch +Patch0065: backport-0003-CVE-2023-3961.patch +Patch0066: backport-0001-CVE-2023-4091.patch +Patch0067: backport-0002-CVE-2023-4091.patch +Patch0068: backport-0001-CVE-2023-4154.patch +Patch0069: backport-0002-CVE-2023-4154.patch +Patch0070: backport-0003-CVE-2023-4154.patch +Patch0071: backport-0004-CVE-2023-4154.patch +Patch0072: backport-0005-CVE-2023-4154.patch +Patch0073: backport-0006-CVE-2023-4154.patch +Patch0074: backport-0007-CVE-2023-4154.patch +Patch0075: backport-0008-CVE-2023-4154.patch +Patch0076: backport-0009-CVE-2023-4154.patch +Patch0077: backport-0010-CVE-2023-4154.patch +Patch0078: backport-0011-CVE-2023-4154.patch +Patch0079: backport-0012-CVE-2023-4154.patch +Patch0080: backport-0013-CVE-2023-4154.patch +Patch0081: backport-0014-CVE-2023-4154.patch +Patch0082: backport-0015-CVE-2023-4154.patch +Patch0083: backport-0016-CVE-2023-4154.patch +Patch0084: backport-0017-CVE-2023-4154.patch +Patch0085: backport-0018-CVE-2023-4154.patch +Patch0086: backport-0019-CVE-2023-4154.patch +Patch0087: backport-0020-CVE-2023-4154.patch +Patch0088: backport-0021-CVE-2023-4154.patch +Patch0089: backport-0001-CVE-2023-42669.patch +Patch0090: backport-0002-CVE-2023-42669.patch +Patch0091: backport-0001-CVE-2023-42670.patch +Patch0092: backport-0002-CVE-2023-42670.patch +Patch0093: backport-0001-CVE-2018-14628.patch +Patch0094: backport-0002-CVE-2018-14628.patch +Patch0095: backport-0003-CVE-2018-14628.patch +Patch0096: backport-0004-CVE-2018-14628.patch +Patch0097: backport-0005-CVE-2018-14628.patch +Patch0098: backport-0006-CVE-2018-14628.patch +Patch0099: remove-sensitive-info.patch + + +BuildRequires: avahi-devel bison dbus-devel docbook-style-xsl e2fsprogs-devel flex 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 libicu-devel libcmocka-devel libnsl2-devel libtirpc-devel libuuid-devel libxslt lmdb ncurses-devel openldap-devel +BuildRequires: libcap-devel libicu-devel libcmocka-devel libtirpc-devel libuuid-devel libxslt lmdb ncurses-devel openldap-devel BuildRequires: pam-devel perl-interpreter perl-generators perl(Archive::Tar) perl(Test::More) popt-devel python3-devel python3-setuptools quota-devel -BuildRequires: readline-devel rpcgen rpcsvc-proto-devel sed libtasn1-devel libtasn1-tools xfsprogs-devel xz zlib-devel >= 1.2.3 -BuildRequires: gcc +BuildRequires: readline-devel rpcgen rpcsvc-proto-devel sed libtasn1-devel libtasn1-tools xfsprogs-devel xz zlib-devel >= 1.2.3 python3-dns +BuildRequires: gcc make BuildRequires: chrpath +%if %{?openEuler:1}0 +BuildRequires: cups-devel +%endif %if %{with_winexe} BuildRequires: mingw32-gcc @@ -91,7 +187,7 @@ BuildRequires: mingw64-gcc BuildRequires: pkgconfig(libsystemd) %if %{with_vfs_glusterfs} -BuildRequires: glusterfs-api-devel >= 3.4.0.16 glusterfs-devel >= 3.4.0.16 +BuildRequires: glusterfs-api-devel >= 3.4.0.16 glusterfs-devel >= 3.4.0.16 libgfapi0 %endif %if %{with_vfs_cephfs} @@ -99,7 +195,7 @@ BuildRequires: libcephfs-devel %endif %if %{with_dc} -BuildRequires: python3-iso8601 bind krb5-server >= %{required_mit_krb5} +BuildRequires: python3-iso8601 bind krb5-server >= %{required_mit_krb5} python3-pyasn1 >= 0.4.8 %endif BuildRequires: perl(ExtUtils::MakeMaker) perl(FindBin) perl(Parse::Yapp) libtalloc-devel >= %{talloc_version} python3-talloc-devel >= %{talloc_version} @@ -109,7 +205,7 @@ BuildRequires: libtdb-devel >= %{tdb_version} python3-tdb >= %{tdb_version} BuildRequires: libldb-devel >= %{ldb_version} python3-ldb-devel >= %{ldb_version} %if %{with testsuite} || %{with_dc} -BuildRequires: ldb-tools tdb-tools python3-gpg python3-markdown +BuildRequires: ldb-tools tdb-tools python3-gpg python3-markdown python3-cryptography %endif %if %{with_vfs_io_uring} @@ -122,7 +218,7 @@ BuildRequires: krb5-server >= %{required_mit_krb5} bind Requires: systemd shadow-utils pam %{name}-common = %{samba_depver} Requires: %{name}-common = %{samba_depver} %{name}-common-tools = %{samba_depver} -Requires: %{name}-client = %{samba_depver} +Requires: %{name}-client-libs = %{samba_depver} %if %with_libwbclient Requires: libwbclient = %{samba_depver} %endif @@ -152,7 +248,8 @@ Librariesfor%{name}. %package client Summary: Client package for %{name} Requires: %{name}-common = %{samba_depver} -Requires: chkconfig krb5-libs >= %{required_mit_krb5} +Requires: %{name}-client-libs = %{samba_depver} +Requires: chkconfig %if %with_libsmbclient Requires: libsmbclient = %{samba_depver} %endif @@ -160,13 +257,24 @@ Requires: libsmbclient = %{samba_depver} Requires: libwbclient = %{samba_depver} %endif -Provides: samba4-client = %{samba_depver} %{name}-client-libs -Obsoletes: samba4-client < %{samba_depver} %{name}-client-libs +Provides: samba4-client = %{samba_depver} +Obsoletes: samba4-client < %{samba_depver} Obsoletes: python2-samba %description client This package includes some files about SMB/CIFS clients to complement the SMB/CIFS clients. +%package client-libs +Summary: Samba client libraries +Requires: %{name}-common = %{samba_depver} +%if %with_libwbclient +Requires: libwbclient = %{samba_depver} +%endif +Requires: krb5-libs >= %{required_mit_krb5} + +%description client-libs +The samba-client-libs package contains internal libraries needed by the SMB/CIFS clients. + %package common Summary: Common package for %{name} client and server Requires: systemd @@ -178,22 +286,31 @@ Obsoletes: samba-dc-libs < %{samba_depver} Obsoletes: samba-dc-bind-dlz < %{samba_depver} %endif -Requires: %{name}-client = %{samba_depver} +Requires: libldb >= %{ldb_version} +Requires: %{name}-client-libs = %{samba_depver} %if %with_libwbclient Requires: libwbclient = %{samba_depver} %endif -Provides: samba4-common = %{samba_depver} %{name}-common-libs -Obsoletes: samba4-common < %{samba_depver} %{name}-common-libs +Provides: samba4-common = %{samba_depver} %{name}-common-libs = %{samba_depver} +Obsoletes: samba4-common < %{samba_depver} %{name}-common-libs < %{samba_depver} %description common This package contains some common basic files needed by %{name} client and server. +# ctdb-tests package has been dropped if we do not build the testsuite +%if %with_clustering_support +%if %{without testsuite} +Obsoletes: ctdb-tests < %{samba_depver} +# endif without testsuite +%endif +# endif with clustering support +%endif %package common-tools Summary: Tools package for %{name} -Requires: %{name}-common = %{samba_depver} %{name}-client = %{samba_depver} +Requires: %{name}-common = %{samba_depver} %{name}-client-libs = %{samba_depver} Requires: %{name}-libs = %{samba_depver} %if %with_libwbclient Requires: libwbclient = %{samba_depver} @@ -208,12 +325,14 @@ Summary: Domain Controller package for %{name} Requires: %{name} = %{samba_depver} %{name}-winbind = %{samba_depver} Requires: %{name}-common = %{samba_depver} tdb-tools Requires: %{name}-libs = %{samba_depver} +Requires: %{name}-dc-provision = %{samba_depver} +Requires: %{name}-dc-libs = %{samba_depver} Requires: lmdb ldb-tools %samba_requires_eq libldb -Provides: samba4-dc = %{samba_depver} %{name}-dc-libs samba4-dc-libs = %{samba_depver} -Obsoletes: samba4-dc < %{samba_depver} %{name}-dc-libs samba4-dc-libs < %{samba_depver} +Provides: samba4-dc = %{samba_depver} +Obsoletes: samba4-dc < %{samba_depver} %description dc The samba-dc package provides AD Domain Controller functionality, including some @@ -226,6 +345,18 @@ Summary: Samba AD files to provision a DC %description dc-provision The samba-dc-provision package provides files to setup a domain controller +%package dc-libs +Summary: Samba AD Domain Controller Libraries +Requires: %{name}-client-libs = %{samba_depver} +Requires: %{name}-common = %{samba_depver} +Requires: %{name}-libs = %{samba_depver} + +Provides: samba4-dc-libs = %{samba_depver} +Obsoletes: samba4-dc-libs < %{samba_depver} + +%description dc-libs +The %{name}-dc-libs package contains the libraries needed by the DC to +link against the SMB, RPC and other protocols. %package dc-bind-dlz Summary: Bind DLZ module for Samba AD @@ -238,6 +369,9 @@ Samba AD. %package devel Summary: Developer tools for Samba libraries Requires: %{name}-libs = %{samba_depver} %{name}-client-libs = %{samba_depver} +%if %{with dc} +Requires: %{name}-dc-libs = %{samba_depver} +%endif Provides: samba4-devel = %{samba_depver} Obsoletes: samba4-devel < %{samba_depver} @@ -263,7 +397,7 @@ This is the samba VFS module for Ceph distributed storage system integration. Summary: Samba VFS module for GlusterFS Requires: glusterfs-api >= 3.4.0.16 glusterfs >= 3.4.0.16 Requires: %{name} = %{samba_depver} %{name}-libs = %{samba_depver} -Requires: %{name}-common = %{samba_depver} %{name}-client = %{samba_depver} +Requires: %{name}-common = %{samba_depver} %{name}-client-libs = %{samba_depver} %if %with_libwbclient Requires: libwbclient = %{samba_depver} @@ -278,7 +412,8 @@ Samba VFS module for GlusterFS integration. %package krb5-printing Summary: The samba CUPS backend package for printing with Kerberos -Requires: %{name}-client = %{samba_depver} +Requires: %{name}-client = %{samba_depver} +Requires: %{name}-client-libs = %{samba_depver} %description krb5-printing This package will allow cups to access the Kerberos credentials cache @@ -288,7 +423,7 @@ of the user issuing the print job. %if %with_libsmbclient %package -n libsmbclient Summary: The SMB client library -Requires: %{name}-common = %{samba_depver} %{name}-client = %{samba_depver} +Requires: %{name}-common = %{samba_depver} %{name}-client-libs = %{samba_depver} %if %with_libwbclient Requires: libwbclient = %{samba_depver} %endif @@ -309,7 +444,7 @@ This package provides developer tools for the wbclient library. %if %with_libwbclient %package -n libwbclient Summary: The winbind client library for %{name} -Requires: %{name}-client = %{samba_depver} +Requires: %{name}-client-libs = %{samba_depver} %description -n libwbclient This package contains the winbind client library from the Samba. @@ -328,7 +463,7 @@ This package provides developer tools for the wbclient library. ### PYTHON3 %package -n python3-%{name} Summary: Python3 library package for %{name} -Requires: %{name} = %{samba_depver} %{name}-client = %{samba_depver} %{name}-common = %{samba_depver} +Requires: %{name}-client-libs = %{samba_depver} %{name}-common = %{samba_depver} Requires: python3-talloc python3-tevent python3-tdb python3-ldb python3-dns Requires: %{name}-libs = %{samba_depver} Obsoletes: python2-samba @@ -339,6 +474,9 @@ Requires: libsmbclient = %{samba_depver} %if %with_libwbclient Requires: libwbclient = %{samba_depver} %endif +%if %{with dc} +Requires: %{name}-dc-libs = %{samba_depver} +%endif %description -n python3-%{name} This package contains the Python 3 libraries needed by programs @@ -348,7 +486,7 @@ that use SMB, RPC and other Samba provided protocols in Python 3 programs. Summary: Test package for python3 binding for %{name} Requires: python3-%{name} = %{samba_depver} -Requires: %{name}-client = %{samba_depver} +Requires: %{name}-client-libs = %{samba_depver} Requires: %{name}-libs = %{samba_depver} %description -n python3-samba-test @@ -359,6 +497,7 @@ If you want to run full set of Samba tests, you need to install this package. %package -n python3-samba-dc Summary: The Samba Python libraries for Samba AD Requires: python3-%{name} = %{samba_depver} +Requires: %{name}-dc-libs = %{samba_depver} %description -n python3-samba-dc This contains the Python libraries needed by programs @@ -381,9 +520,9 @@ and Wireshark to parse IDL and similar protocols. %package test Summary: Testing tools and libraries for Samba servers and clients Requires: %{name} = %{samba_depver} %{name}-common = %{samba_depver} %{name}-winbind = %{samba_depver} -Requires: %{name}-client = %{samba_depver} %{name}-libs = %{samba_depver} +Requires: %{name}-client-libs = %{samba_depver} %{name}-libs = %{samba_depver} %if %with_dc -Requires: %{name}-dc = %{samba_depver} +Requires: %{name}-dc-libs = %{samba_depver} %endif %if %with_libsmbclient Requires: libsmbclient = %{samba_depver} @@ -395,18 +534,27 @@ Requires: libwbclient = %{samba_depver} Requires: python3-%{name} = %{samba_depver} Requires: perl(Archive::Tar) -Provides: samba4-test = %{samba_depver} %{name}-test-libs %{name}-test-devel = %{samba_depver} -Obsoletes: samba4-test < %{samba_depver} %{name}-test-libs %{name}-test-devel < %{samba_depver} +Provides: samba4-test = %{samba_depver} %{name}-test-libs = %{samba_depver} %{name}-test-devel = %{samba_depver} +Obsoletes: samba4-test < %{samba_depver} %{name}-test-libs < %{samba_depver} %{name}-test-devel < %{samba_depver} %description test %{name}-test provides testing tools for both the server and client packages of Samba. +%package usershares +Summary: Provides support for non-root user shares +Requires: %{name} = %{samba_depver} +Requires: %{name}-common-tools = %{samba_depver} + +%description usershares +Installing this package will provide a configuration file, group and +directories to support non-root user shares. You can configure them +as a user using the `net usershare` command. %package winbind Summary: The winbind package for %{name} Requires: %{name}-common = %{samba_depver} %{name}-common-tools = %{samba_depver} -Requires: %{name}-client = %{samba_depver} %{name}-winbind-modules = %{samba_depver} +Requires: %{name}-client-libs = %{samba_depver} %{name}-winbind-modules = %{samba_depver} Requires: libwbclient = %{samba_depver} %{name}-libs = %{samba_depver} Provides: samba4-winbind = %{samba_depver} Obsoletes: samba4-winbind < %{samba_depver} @@ -421,7 +569,7 @@ Windows user and group accounts on Linux. %package winbind-clients Summary: The winbind client package for %{name} -Requires: %{name}-common = %{samba_depver} %{name}-client = %{samba_depver} +Requires: %{name}-common = %{samba_depver} %{name}-client-libs = %{samba_depver} Requires: %{name}-libs = %{samba_depver} %{name}-winbind = %{samba_depver} %if %with_libwbclient Requires: libwbclient = %{samba_depver} @@ -440,7 +588,7 @@ Requires: libwbclient = %{samba_depver} %{name}-winbind = %{samba_depver} %else Requires: %{name}-libs = %{samba_depver} %endif -Requires: samba-client = %{samba_depver} +Requires: samba-client-libs = %{samba_depver} Provides: samba4-winbind-krb5-locator = %{samba_depver} Obsoletes: samba4-winbind-krb5-locator < %{samba_depver} @@ -451,7 +599,7 @@ the local kerberos library to use the same KDC as samba and winbind use %package winbind-modules Summary: The winbind modules for %{name} -Requires: %{name}-client = %{samba_depver} %{name}-libs = %{samba_depver} pam +Requires: %{name}-client-libs = %{samba_depver} %{name}-libs = %{samba_depver} pam %if %with_libwbclient Requires: libwbclient = %{samba_depver} %endif @@ -473,7 +621,8 @@ Winexe is a Remote Windows®-command executor %if %with_clustering_support %package -n ctdb Summary: A Clustered Database package based on Samba's Trivial Database (TDB) -Requires: %{name}-common = %{samba_depver} %{name}-client = %{samba_depver} coreutils psmisc +Requires: %{name}-winbind-clients = %{samba_depver} +Requires: %{name}-common = %{samba_depver} %{name}-client-libs = %{samba_depver} coreutils psmisc Requires: sed tdb-tools gawk procps-ng net-tools ethtool iproute iptables util-linux systemd-units %description -n ctdb @@ -482,11 +631,12 @@ projects to store temporary data. If an application is already using TDB for temporary data it is very easy to convert that application to be cluster aware and use CTDB instead. +%if %{with testsuite} ### CTDB-TEST %package -n ctdb-tests Summary: The test package fors CTDB clustered database Requires: %{name}-common = %{samba_depver} -Requires: %{name}-client = %{samba_depver} +Requires: %{name}-client-libs = %{samba_depver} Requires: ctdb = %{samba_depver} Recommends: nc @@ -495,6 +645,9 @@ Obsoletes: ctdb-devel < %{samba_depver} %description -n ctdb-tests This package contains the test suite for CTDB clustered database. +#endif with testsuite +%endif +#endif with clustering %endif %package help @@ -507,6 +660,9 @@ This package contains some man help files for %{name}. zcat %{SOURCE0} | gpgv2 --quiet --keyring %{SOURCE2} %{SOURCE1} - %autosetup -n %{name}-%{version} -p1 +rm -rf third_party/{aesni-intel,heimdal} +rm -f lib/crypto/{aes,rijndael}*.c + %build %global _talloc_lib ,talloc,pytalloc,pytalloc-util %global _tevent_lib ,tevent,pytevent @@ -518,7 +674,7 @@ zcat %{SOURCE0} | gpgv2 --quiet --keyring %{SOURCE2} %{SOURCE1} - %global _tdb_lib ,!tdb,!pytdb %global _ldb_lib ,!ldb,!pyldb,!pyldb-util -%global _samba_libraries !zlib,!popt%{_talloc_lib}%{_tevent_lib}%{_tdb_lib}%{_ldb_lib} +%global _samba_libraries !popt%{_talloc_lib}%{_tevent_lib}%{_tdb_lib}%{_ldb_lib} %global _samba_idmap_modules idmap_ad,idmap_rid,idmap_ldap,idmap_hash,idmap_tdb2 %global _samba_pdb_modules pdb_tdbsam,pdb_ldap,pdb_smbpasswd,pdb_wbc_sam,pdb_samba4 @@ -543,10 +699,22 @@ zcat %{SOURCE0} | gpgv2 --quiet --keyring %{SOURCE2} %{SOURCE1} - export python_LDFLAGS="$(echo %{__global_ldflags} | sed -e 's/-Wl,-z,defs//g')" export LDFLAGS="%{__global_ldflags} -fuse-ld=gold" - +%ifarch riscv64 sw_64 +export LDFLAGS="%{__global_ldflags}" +%endif +%ifarch loongarch64 +export LDFLAGS="%{__global_ldflags} -fuse-ld=bfd" +%endif %configure \ --enable-fhs \ +%if %{?openEuler:1}0 + --enable-cups \ + --enable-iprint \ +%else + --disable-cups \ + --disable-iprint \ +%endif --with-piddir=/run \ --with-sockets-dir=/run/samba \ --with-modulesdir=%{_libdir}/samba \ @@ -587,6 +755,9 @@ export LDFLAGS="%{__global_ldflags} -fuse-ld=gold" --systemd-smb-extra=%{_systemd_extra} \ --systemd-nmb-extra=%{_systemd_extra} \ --systemd-winbind-extra=%{_systemd_extra} \ +%if %with_clustering_support + --systemd-ctdb-extra=%{_systemd_extra} \ +%endif --systemd-samba-extra=%{_systemd_extra} %make_build @@ -609,9 +780,9 @@ install -d -m 0755 %{buildroot}/var/lib/samba/lock install -d -m 0755 %{buildroot}/var/lib/samba/private install -d -m 0755 %{buildroot}/var/lib/samba/scripts install -d -m 0755 %{buildroot}/var/lib/samba/sysvol +install -d -m 0755 %{buildroot}/var/lib/samba/usershares install -d -m 0755 %{buildroot}/var/lib/samba/winbindd_privileged install -d -m 0755 %{buildroot}/var/log/samba/old -install -d -m 0755 %{buildroot}/var/spool/samba install -d -m 0755 %{buildroot}/run/samba install -d -m 0755 %{buildroot}/run/winbindd install -d -m 0755 %{buildroot}/%{_libdir}/samba @@ -628,15 +799,20 @@ then exit -1 fi - +%if %{?openEuler:1}0 touch %{buildroot}%{_libexecdir}/samba/cups_backend_smb +%endif # Install other stuff install -d -m 0755 %{buildroot}%{_sysconfdir}/logrotate.d install -m 0644 %{SOURCE3} %{buildroot}%{_sysconfdir}/logrotate.d/samba install -m 0644 %{SOURCE4} %{buildroot}%{_sysconfdir}/samba/smb.conf +%if %{!?openEuler:1}0 +sed -i -e '/printing = cups/d' -e '/printcap name = cups/d' -e '/load printers = yes/d' -e '/cups options = raw/d' %{buildroot}%{_sysconfdir}/samba/smb.conf +%endif install -m 0644 %{SOURCE5} %{buildroot}%{_sysconfdir}/samba/smb.conf.example +install -m 0644 %{SOURCE8} %{buildroot}%{_sysconfdir}/samba/usershares.conf install -d -m 0755 %{buildroot}%{_sysconfdir}/security install -m 0644 %{SOURCE6} %{buildroot}%{_sysconfdir}/security/pam_winbind.conf @@ -672,10 +848,6 @@ install -m 0644 ctdb/config/ctdb.conf %{buildroot}%{_sysconfdir}/ctdb/ctdb.conf install -m 0644 %{SOURCE201} packaging/README.downgrade -%if %with_clustering_support -install -m 0644 ctdb/config/ctdb.service %{buildroot}%{_unitdir} -%endif - # NetworkManager online/offline script install -d -m 0755 %{buildroot}%{_prefix}/lib/NetworkManager/dispatcher.d/ install -m 0755 packaging/NetworkManager/30-winbind-systemd \ @@ -701,12 +873,15 @@ chrpath -d %{buildroot}%{_libdir}/%{name}/gensec/*.so* chrpath -d %{buildroot}%{_libdir}/%{name}/bind9/*.so* chrpath -d %{buildroot}%{_libdir}/security/*.so* chrpath -d %{buildroot}%{_libdir}/krb5/plugins/kdb/samba.so +chrpath -d %{buildroot}%{_libdir}/%{name}/krb5/async_dns_krb5_locator.so chrpath -d %{buildroot}%{python3_sitearch}/%{name}/*.so* chrpath -d %{buildroot}%{python3_sitearch}/%{name}/samba3/*.so* chrpath -d %{buildroot}%{python3_sitearch}/%{name}/dcerpc/*.so* find %{buildroot}%{_libexecdir}/ctdb -type f ! -name ctdb_lvs ! -name ctdb_natgw| xargs chrpath -d +%if %{?openEuler:1}0 chrpath -d %{buildroot}%{_libexecdir}/%{name}/smbspool_krb5_wrapper +%endif chrpath -d %{buildroot}%{_bindir}/rpcclient chrpath -d %{buildroot}%{_bindir}/smbclient chrpath -d %{buildroot}%{_bindir}/regshell @@ -738,11 +913,11 @@ chrpath -d %{buildroot}%{_bindir}/masktest chrpath -d %{buildroot}%{_bindir}/ndrdump chrpath -d %{buildroot}%{_bindir}/locktest chrpath -d %{buildroot}%{_bindir}/gentest -chrpath -d %{buildroot}%{_bindir}/mdfind chrpath -d %{buildroot}%{_bindir}/wbinfo chrpath -d %{buildroot}%{_bindir}/ntlm_auth chrpath -d %{buildroot}%{_bindir}/ltdbtool chrpath -d %{buildroot}%{_bindir}/ctdb +chrpath -d %{buildroot}%{_bindir}/mdsearch chrpath -d %{buildroot}%{_sbindir}/eventlogadm chrpath -d %{buildroot}%{_sbindir}/smbd @@ -751,17 +926,24 @@ chrpath -d %{buildroot}%{_sbindir}/winbindd chrpath -d %{buildroot}%{_sbindir}/samba chrpath -d %{buildroot}%{_sbindir}/ctdbd +chrpath -d %{buildroot}%{_libexecdir}/%{name}/samba-bgqd +chrpath -d %{buildroot}%{_libexecdir}/%{name}/samba-dcerpcd +chrpath -d %{buildroot}%{_libexecdir}/%{name}/rpcd_classic +chrpath -d %{buildroot}%{_libexecdir}/%{name}/rpcd_epmapper +chrpath -d %{buildroot}%{_libexecdir}/%{name}/rpcd_fsrvp +chrpath -d %{buildroot}%{_libexecdir}/%{name}/rpcd_lsad +chrpath -d %{buildroot}%{_libexecdir}/%{name}/rpcd_mdssvc +chrpath -d %{buildroot}%{_libexecdir}/%{name}/rpcd_spoolss +chrpath -d %{buildroot}%{_libexecdir}/%{name}/rpcd_winreg + mkdir -p %{buildroot}/etc/ld.so.conf.d echo "%{_libdir}/%{name}" > %{buildroot}/etc/ld.so.conf.d/%{name}-%{_arch}.conf %if ! %with_dc for i in \ %{_libdir}/samba/libdfs-server-ad-samba4.so \ - %{_libdir}/samba/libdnsserver-common-samba4.so \ %{_libdir}/samba/libdsdb-garbage-collect-tombstones-samba4.so \ %{_libdir}/samba/libscavenge-dns-records-samba4.so \ - %{_libdir}/samba/ldb/ildap.so \ - %{_libdir}/samba/ldb/ldbsamba_extensions.so \ %{_unitdir}/samba.service \ %{python3_sitearch}/samba/dcerpc/dnsserver.*.so \ %{python3_sitearch}/samba/dnsserver.py \ @@ -886,19 +1068,25 @@ fi %post client /sbin/ldconfig +%if %{?openEuler:1}0 %{_sbindir}/update-alternatives --install %{_libexecdir}/samba/cups_backend_smb \ cups_backend_smb \ %{_bindir}/smbspool 10 +%endif %postun client /sbin/ldconfig +%if %{?openEuler:1}0 if [ $1 -eq 0 ] ; then %{_sbindir}/update-alternatives --remove cups_backend_smb %{_bindir}/smbspool fi +%endif + +%ldconfig_scriptlets client-libs %if %{with_dc} %ldconfig_scriptlets -n python3-samba-dc -%ldconfig_scriptlets dc-provision +%ldconfig_scriptlets dc-libs %ldconfig_scriptlets dc-bind-dlz %post dc @@ -916,15 +1104,19 @@ fi %endif %post krb5-printing +%if %{?openEuler:1}0 %{_sbindir}/update-alternatives --install %{_libexecdir}/samba/cups_backend_smb \ cups_backend_smb \ %{_libexecdir}/samba/smbspool_krb5_wrapper 50 +%endif /sbin/ldconfig %postun krb5-printing +%if %{?openEuler:1}0 if [ $1 -eq 0 ] ; then %{_sbindir}/update-alternatives --remove cups_backend_smb %{_libexecdir}/samba/smbspool_krb5_wrapper fi +%endif /sbin/ldconfig %ldconfig_scriptlets libs @@ -986,6 +1178,9 @@ fi %ldconfig_scriptlets test +%pre usershares +getent group usershares >/dev/null || groupadd -r usershares || : + %pre winbind /usr/sbin/groupadd -g 88 wbpriv >/dev/null 2>&1 || : @@ -1104,15 +1299,25 @@ fi %{_libdir}/samba/vfs/time_audit.so %{_libdir}/samba/vfs/unityed_media.so %{_libdir}/samba/vfs/virusfilter.so +%{_libdir}/samba/vfs/widelinks.so %{_libdir}/samba/vfs/worm.so %{_libdir}/samba/vfs/xattr_tdb.so +%dir %{_libexecdir}/samba +%{_libexecdir}/samba/samba-bgqd +%{_libexecdir}/samba/samba-dcerpcd +%{_libexecdir}/samba/rpcd_classic +%{_libexecdir}/samba/rpcd_epmapper +%{_libexecdir}/samba/rpcd_fsrvp +%{_libexecdir}/samba/rpcd_lsad +%{_libexecdir}/samba/rpcd_mdssvc +%{_libexecdir}/samba/rpcd_spoolss +%{_libexecdir}/samba/rpcd_winreg %dir %{_datadir}/samba %dir %{_datadir}/samba/mdssvc %{_datadir}/samba/mdssvc/elasticsearch_mappings.json %{_unitdir}/nmb.service %{_unitdir}/smb.service -%attr(1777,root,root) %dir /var/spool/samba %dir %{_sysconfdir}/openldap/schema %config %{_sysconfdir}/openldap/schema/samba.schema %config(noreplace) %{_sysconfdir}/pam.d/samba @@ -1125,12 +1330,15 @@ fi %{_libdir}/libdcerpc-server-core.so.* %{_libdir}/samba/libLIBWBCLIENT-OLD-samba4.so -%{_libdir}/samba/libauth4-samba4.so %{_libdir}/samba/libauth-unix-token-samba4.so %{_libdir}/samba/libdcerpc-samba4.so +%{_libdir}/samba/libdnsserver-common-samba4.so %{_libdir}/samba/libshares-samba4.so %{_libdir}/samba/libsmbpasswdparser-samba4.so %{_libdir}/samba/libxattr-tdb-samba4.so +%{_libdir}/samba/libREG-FULL-samba4.so +%{_libdir}/samba/libRPC-SERVER-LOOP-samba4.so +%{_libdir}/samba/libRPC-WORKER-samba4.so %config(noreplace) /etc/ld.so.conf.d/* %files client @@ -1138,9 +1346,8 @@ fi %{_bindir}/cifsdd %{_bindir}/dbwrap_tool %{_bindir}/dumpmscat -%{_bindir}/findsmb %{_bindir}/mvxattr -%{_bindir}/mdfind +%{_bindir}/mdsearch %{_bindir}/nmblookup %{_bindir}/oLschema2ldif %{_bindir}/regdiff @@ -1158,10 +1365,13 @@ fi %{_bindir}/smbspool %{_bindir}/smbtar %{_bindir}/smbtree +%if %{?openEuler:1}0 %dir %{_libexecdir}/samba %ghost %{_libexecdir}/samba/cups_backend_smb +%endif +%config(noreplace) /etc/ld.so.conf.d/* - +%files client-libs %{_libdir}/libdcerpc-binding.so.* %{_libdir}/libndr.so.* %{_libdir}/libndr-krb5pac.so.* @@ -1198,10 +1408,10 @@ fi %{_libdir}/samba/libclidns-samba4.so %{_libdir}/samba/libcluster-samba4.so %{_libdir}/samba/libcmdline-contexts-samba4.so -%{_libdir}/samba/libcmdline-credentials-samba4.so %{_libdir}/samba/libcommon-auth-samba4.so %{_libdir}/samba/libctdb-event-client-samba4.so %{_libdir}/samba/libdbwrap-samba4.so +%{_libdir}/samba/libdcerpc-pkt-auth-samba4.so %{_libdir}/samba/libdcerpc-samba-samba4.so %{_libdir}/samba/libevents-samba4.so %{_libdir}/samba/libflag-mapping-samba4.so @@ -1246,7 +1456,6 @@ fi %{_libdir}/samba/libsmb-transport-samba4.so %{_libdir}/samba/libsmbclient-raw-samba4.so %{_libdir}/samba/libsmbd-base-samba4.so -%{_libdir}/samba/libsmbd-conn-samba4.so %{_libdir}/samba/libsmbd-shim-samba4.so %{_libdir}/samba/libsmbldaphelper-samba4.so %{_libdir}/samba/libsys-rw-samba4.so @@ -1257,7 +1466,6 @@ fi %{_libdir}/samba/libtime-basic-samba4.so %{_libdir}/samba/libtorture-samba4.so %{_libdir}/samba/libtrusts-util-samba4.so -%{_libdir}/samba/libutil-cmdline-samba4.so %{_libdir}/samba/libutil-reg-samba4.so %{_libdir}/samba/libutil-setid-samba4.so %{_libdir}/samba/libutil-tdb-samba4.so @@ -1265,7 +1473,6 @@ fi %if ! %with_libwbclient %{_libdir}/samba/libwbclient.so.* -%{_libdir}/samba/libwinbind-client-samba4.so #endif ! with_libwbclient %endif @@ -1291,8 +1498,7 @@ fi %config(noreplace) %{_sysconfdir}/samba/lmhosts %config(noreplace) %{_sysconfdir}/sysconfig/samba -%{_libdir}/samba/libpopt-samba3-cmdline-samba4.so -%{_libdir}/samba/libpopt-samba3-samba4.so +%{_libdir}/samba/libcmdline-samba4.so %dir %{_libdir}/samba/ldb @@ -1306,6 +1512,7 @@ fi %{_bindir}/net %{_bindir}/pdbedit %{_bindir}/profiles +%{_bindir}/samba-tool %{_bindir}/smbcontrol %{_bindir}/smbpasswd %{_bindir}/testparm @@ -1314,7 +1521,6 @@ fi %if %{with_dc} %files dc %{_unitdir}/samba.service -%{_bindir}/samba-tool %{_sbindir}/samba %{_sbindir}/samba_dnsupdate %{_sbindir}/samba_downgrade_db @@ -1326,7 +1532,6 @@ fi %{_libdir}/krb5/plugins/kdb/samba.so %{_libdir}/samba/auth/samba4.so -%{_libdir}/samba/libpac-samba4.so %dir %{_libdir}/samba/gensec %{_libdir}/samba/gensec/krb5.so %{_libdir}/samba/ldb/acl.so @@ -1383,8 +1588,14 @@ fi %files dc-provision %license source4/setup/ad-schema/licence.txt %{_datadir}/samba/setup +#endif with_dc +%endif +%files dc-libs +%{_libdir}/samba/libauth4-samba4.so +%if %{with dc} %{_libdir}/samba/libdb-glue-samba4.so +%{_libdir}/samba/libpac-samba4.so %{_libdir}/samba/libprocess-model-samba4.so %{_libdir}/samba/libservice-samba4.so %dir %{_libdir}/samba/process_model @@ -1405,7 +1616,6 @@ fi %{_libdir}/samba/service/winbindd.so %{_libdir}/samba/service/wrepl.so %{_libdir}/libdcerpc-server.so.* -%{_libdir}/samba/libdnsserver-common-samba4.so %{_libdir}/samba/libdsdb-module-samba4.so %{_libdir}/samba/libdsdb-garbage-collect-tombstones-samba4.so %{_libdir}/samba/libscavenge-dns-records-samba4.so @@ -1414,11 +1624,12 @@ fi %files dc-bind-dlz %attr(770,root,named) %dir /var/lib/samba/bind-dns %dir %{_libdir}/samba/bind9 -%{_libdir}/samba/bind9/dlz_bind9.so -%{_libdir}/samba/bind9/dlz_bind9_9.so %{_libdir}/samba/bind9/dlz_bind9_10.so %{_libdir}/samba/bind9/dlz_bind9_11.so %{_libdir}/samba/bind9/dlz_bind9_12.so +%{_libdir}/samba/bind9/dlz_bind9_14.so +%{_libdir}/samba/bind9/dlz_bind9_16.so +%{_libdir}/samba/bind9/dlz_bind9_18.so %config(noreplace) /etc/ld.so.conf.d/* #endif with_dc %endif @@ -1490,7 +1701,6 @@ fi %dir %{_includedir}/samba-4.0/util %{_includedir}/samba-4.0/util/attr.h %{_includedir}/samba-4.0/util/blocking.h -%{_includedir}/samba-4.0/util/byteorder.h %{_includedir}/samba-4.0/util/data_blob.h %{_includedir}/samba-4.0/util/debug.h %{_includedir}/samba-4.0/util/discard.h @@ -1499,7 +1709,6 @@ fi %{_includedir}/samba-4.0/util/idtree.h %{_includedir}/samba-4.0/util/idtree_random.h %{_includedir}/samba-4.0/util/signal.h -%{_includedir}/samba-4.0/util/string_wrappers.h %{_includedir}/samba-4.0/util/substitute.h %{_includedir}/samba-4.0/util/tevent_ntstatus.h %{_includedir}/samba-4.0/util/tevent_unix.h @@ -1565,7 +1774,9 @@ fi %endif %files krb5-printing +%if %{?openEuler:1}0 %attr(0700,root,root) %{_libexecdir}/samba/smbspool_krb5_wrapper +%endif %config(noreplace) /etc/ld.so.conf.d/* %if %with_libsmbclient @@ -1583,7 +1794,6 @@ fi %if %with_libwbclient %files -n libwbclient %{_libdir}/samba/wbclient/libwbclient.so.* -%{_libdir}/samba/libwinbind-client-samba4.so %config(noreplace) /etc/ld.so.conf.d/* %files -n libwbclient-devel @@ -1625,6 +1835,7 @@ fi %attr(644,root,root) %{perl_vendorlib}/Parse/Pidl/Samba4/Template.pm %dir %{perl_vendorlib}/Parse/Pidl/Samba4/NDR %attr(644,root,root) %{perl_vendorlib}/Parse/Pidl/Samba4/NDR/Server.pm +%attr(644,root,root) %{perl_vendorlib}/Parse/Pidl/Samba4/NDR/ServerCompat.pm %attr(644,root,root) %{perl_vendorlib}/Parse/Pidl/Samba4/NDR/Client.pm %attr(644,root,root) %{perl_vendorlib}/Parse/Pidl/Samba4/NDR/Parser.pm %attr(644,root,root) %{perl_vendorlib}/Parse/Pidl/Samba4/TDR.pm @@ -1639,14 +1850,11 @@ fi %{python3_sitearch}/samba/__pycache__/auth_util.*.pyc %{python3_sitearch}/samba/__pycache__/colour.*.pyc %{python3_sitearch}/samba/__pycache__/common.*.pyc -%{python3_sitearch}/samba/__pycache__/compat.*.pyc %{python3_sitearch}/samba/__pycache__/dbchecker.*.pyc %{python3_sitearch}/samba/__pycache__/descriptor.*.pyc +%{python3_sitearch}/samba/__pycache__/dnsresolver.*.pyc %{python3_sitearch}/samba/__pycache__/drs_utils.*.pyc %{python3_sitearch}/samba/__pycache__/getopt.*.pyc -%{python3_sitearch}/samba/__pycache__/gpclass.*.pyc -%{python3_sitearch}/samba/__pycache__/gp_ext_loader.*.pyc -%{python3_sitearch}/samba/__pycache__/gp_sec_ext.*.pyc %{python3_sitearch}/samba/__pycache__/graph.*.pyc %{python3_sitearch}/samba/__pycache__/hostconfig.*.pyc %{python3_sitearch}/samba/__pycache__/idmap.*.pyc @@ -1661,6 +1869,7 @@ fi %{python3_sitearch}/samba/__pycache__/sites.*.pyc %{python3_sitearch}/samba/__pycache__/subnets.*.pyc %{python3_sitearch}/samba/__pycache__/tdb_util.*.pyc +%{python3_sitearch}/samba/__pycache__/trust_utils.*.pyc %{python3_sitearch}/samba/__pycache__/upgrade.*.pyc %{python3_sitearch}/samba/__pycache__/upgradehelpers.*.pyc %{python3_sitearch}/samba/__pycache__/xattr.*.pyc @@ -1671,7 +1880,6 @@ fi %{python3_sitearch}/samba/dbchecker.py %{python3_sitearch}/samba/colour.py %{python3_sitearch}/samba/common.py -%{python3_sitearch}/samba/compat.py %{python3_sitearch}/samba/credentials.*.so %{python3_sitearch}/samba/crypto.*.so %dir %{python3_sitearch}/samba/dcerpc @@ -1692,6 +1900,7 @@ fi %{python3_sitearch}/samba/dcerpc/idmap.*.so %{python3_sitearch}/samba/dcerpc/initshutdown.*.so %{python3_sitearch}/samba/dcerpc/irpc.*.so +%{python3_sitearch}/samba/dcerpc/krb5ccache.*.so %{python3_sitearch}/samba/dcerpc/krb5pac.*.so %{python3_sitearch}/samba/dcerpc/lsa.*.so %{python3_sitearch}/samba/dcerpc/messaging.*.so @@ -1718,12 +1927,12 @@ fi %{python3_sitearch}/samba/dcerpc/wkssvc.*.so %{python3_sitearch}/samba/dcerpc/xattr.*.so %{python3_sitearch}/samba/descriptor.py +%{python3_sitearch}/samba/dnsresolver.py %{python3_sitearch}/samba/drs_utils.py +%{python3_sitearch}/samba/dsdb.*.so +%{python3_sitearch}/samba/dsdb_dns.*.so %{python3_sitearch}/samba/gensec.*.so %{python3_sitearch}/samba/getopt.py -%{python3_sitearch}/samba/gpclass.py -%{python3_sitearch}/samba/gp_sec_ext.py -%{python3_sitearch}/samba/gpo.*.so %{python3_sitearch}/samba/graph.py %{python3_sitearch}/samba/hostconfig.py %{python3_sitearch}/samba/idmap.py @@ -1731,6 +1940,7 @@ fi %{python3_sitearch}/samba/messaging.*.so %{python3_sitearch}/samba/ndr.py %{python3_sitearch}/samba/net.*.so +%{python3_sitearch}/samba/net_s3.*.so %{python3_sitearch}/samba/ntstatus.*.so %{python3_sitearch}/samba/posix_eadb.*.so %dir %{python3_sitearch}/samba/emulate @@ -1741,7 +1951,57 @@ fi %{python3_sitearch}/samba/emulate/__init__.py %{python3_sitearch}/samba/emulate/traffic.py %{python3_sitearch}/samba/emulate/traffic_packets.py -%{python3_sitearch}/samba/gp_ext_loader.py +%dir %{python3_sitearch}/samba/gp +%dir %{python3_sitearch}/samba/gp/__pycache__ +%{python3_sitearch}/samba/gp/__pycache__/gpclass.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_centrify_crontab_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_centrify_sudoers_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_cert_auto_enroll_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_chromium_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_ext_loader.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_firefox_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_firewalld_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_gnome_settings_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_msgs_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_scripts_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_sec_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_smb_conf_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/gp_sudoers_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/vgp_access_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/vgp_files_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/vgp_issue_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/vgp_motd_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/vgp_openssh_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/vgp_startup_scripts_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/vgp_sudoers_ext.*.pyc +%{python3_sitearch}/samba/gp/__pycache__/vgp_symlink_ext.*.pyc +%{python3_sitearch}/samba/gp/gpclass.py +%{python3_sitearch}/samba/gp/gp_gnome_settings_ext.py +%{python3_sitearch}/samba/gp/gp_scripts_ext.py +%{python3_sitearch}/samba/gp/gp_sec_ext.py +%{python3_sitearch}/samba/gp/gp_centrify_crontab_ext.py +%{python3_sitearch}/samba/gp/gp_centrify_sudoers_ext.py +%{python3_sitearch}/samba/gp/gp_cert_auto_enroll_ext.py +%{python3_sitearch}/samba/gp/gp_chromium_ext.py +%{python3_sitearch}/samba/gp/gp_ext_loader.py +%{python3_sitearch}/samba/gp/gp_firefox_ext.py +%{python3_sitearch}/samba/gp/gp_firewalld_ext.py +%{python3_sitearch}/samba/gp/gp_msgs_ext.py +%{python3_sitearch}/samba/gp/gp_smb_conf_ext.py +%{python3_sitearch}/samba/gp/gp_sudoers_ext.py +%dir %{python3_sitearch}/samba/gp/util +%dir %{python3_sitearch}/samba/gp/util/__pycache__ +%{python3_sitearch}/samba/gp/util/__pycache__/logging.*.pyc +%{python3_sitearch}/samba/gp/util/logging.py +%{python3_sitearch}/samba/gp/vgp_access_ext.py +%{python3_sitearch}/samba/gp/vgp_files_ext.py +%{python3_sitearch}/samba/gp/vgp_issue_ext.py +%{python3_sitearch}/samba/gp/vgp_motd_ext.py +%{python3_sitearch}/samba/gp/vgp_openssh_ext.py +%{python3_sitearch}/samba/gp/vgp_startup_scripts_ext.py +%{python3_sitearch}/samba/gp/vgp_sudoers_ext.py +%{python3_sitearch}/samba/gp/vgp_symlink_ext.py +%{python3_sitearch}/samba/gpo.*.so %dir %{python3_sitearch}/samba/gp_parse %{python3_sitearch}/samba/gp_parse/__init__.py %dir %{python3_sitearch}/samba/gp_parse/__pycache__ @@ -1830,13 +2090,17 @@ fi %{python3_sitearch}/samba/samba3/__init__.py %dir %{python3_sitearch}/samba/samba3/__pycache__ %{python3_sitearch}/samba/samba3/__pycache__/__init__.*.pyc -%{python3_sitearch}/samba/samba3/libsmb_samba_internal.*.so +%{python3_sitearch}/samba/samba3/__pycache__/libsmb_samba_internal.*.pyc +%{python3_sitearch}/samba/samba3/libsmb_samba_cwrapper.cpython*.so +%{python3_sitearch}/samba/samba3/libsmb_samba_internal.py %{python3_sitearch}/samba/samba3/mdscli.*.so %{python3_sitearch}/samba/samba3/param.*.so %{python3_sitearch}/samba/samba3/passdb.*.so +%{python3_sitearch}/samba/samba3/smbconf.*.so %{python3_sitearch}/samba/samba3/smbd.*.so %{python3_sitearch}/samba/sd_utils.py %{python3_sitearch}/samba/sites.py +%{python3_sitearch}/samba/smbconf.*.so %{python3_sitearch}/samba/subnets.py %dir %{python3_sitearch}/samba/subunit %{python3_sitearch}/samba/subunit/__init__.py @@ -1845,10 +2109,7 @@ fi %{python3_sitearch}/samba/subunit/__pycache__/run.*.pyc %{python3_sitearch}/samba/subunit/run.py %{python3_sitearch}/samba/tdb_util.py -%dir %{python3_sitearch}/samba/third_party -%{python3_sitearch}/samba/third_party/__init__.py -%dir %{python3_sitearch}/samba/third_party/__pycache__ -%{python3_sitearch}/samba/third_party/__pycache__/__init__.*.pyc +%{python3_sitearch}/samba/trust_utils.py %{python3_sitearch}/samba/upgrade.py %{python3_sitearch}/samba/upgradehelpers.py %{python3_sitearch}/samba/werror.*.so @@ -1880,8 +2141,6 @@ fi %{python3_sitearch}/samba/dcerpc/dnsserver.*.so %{python3_sitearch}/samba/dckeytab.*.so -%{python3_sitearch}/samba/dsdb.*.so -%{python3_sitearch}/samba/dsdb_dns.*.so %{python3_sitearch}/samba/domain_update.py %{python3_sitearch}/samba/forest_update.py %{python3_sitearch}/samba/ms_forest_updates_markdown.py @@ -1946,8 +2205,10 @@ fi %{python3_sitearch}/samba/tests/__pycache__/complex_expressions.*.pyc %{python3_sitearch}/samba/tests/__pycache__/core.*.pyc %{python3_sitearch}/samba/tests/__pycache__/credentials.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/cred_opt.*.pyc %{python3_sitearch}/samba/tests/__pycache__/dckeytab.*.pyc %{python3_sitearch}/samba/tests/__pycache__/dns.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/dns_aging.*.pyc %{python3_sitearch}/samba/tests/__pycache__/dns_base.*.pyc %{python3_sitearch}/samba/tests/__pycache__/dns_forwarder.*.pyc %{python3_sitearch}/samba/tests/__pycache__/dns_invalid.*.pyc @@ -1955,6 +2216,8 @@ fi %{python3_sitearch}/samba/tests/__pycache__/dns_tkey.*.pyc %{python3_sitearch}/samba/tests/__pycache__/dns_wildcard.*.pyc %{python3_sitearch}/samba/tests/__pycache__/dsdb.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/dsdb_api.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/dsdb_dns.*.pyc %{python3_sitearch}/samba/tests/__pycache__/dsdb_lock.*.pyc %{python3_sitearch}/samba/tests/__pycache__/dsdb_schema_attributes.*.pyc %{python3_sitearch}/samba/tests/__pycache__/docs.*.pyc @@ -1966,17 +2229,23 @@ fi %{python3_sitearch}/samba/tests/__pycache__/getdcname.*.pyc %{python3_sitearch}/samba/tests/__pycache__/glue.*.pyc %{python3_sitearch}/samba/tests/__pycache__/gpo.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/gpo_member.*.pyc %{python3_sitearch}/samba/tests/__pycache__/graph.*.pyc %{python3_sitearch}/samba/tests/__pycache__/group_audit.*.pyc %{python3_sitearch}/samba/tests/__pycache__/hostconfig.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/imports.*.pyc %{python3_sitearch}/samba/tests/__pycache__/join.*.pyc %{python3_sitearch}/samba/tests/__pycache__/krb5_credentials.*.pyc %{python3_sitearch}/samba/tests/__pycache__/ldap_raw.*.pyc %{python3_sitearch}/samba/tests/__pycache__/ldap_referrals.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/ldap_spn.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/ldap_upn_sam_account.*.pyc %{python3_sitearch}/samba/tests/__pycache__/loadparm.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/logfiles.*.pyc %{python3_sitearch}/samba/tests/__pycache__/libsmb.*.pyc %{python3_sitearch}/samba/tests/__pycache__/lsa_string.*.pyc %{python3_sitearch}/samba/tests/__pycache__/messaging.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/ndr.*.pyc %{python3_sitearch}/samba/tests/__pycache__/netbios.*.pyc %{python3_sitearch}/samba/tests/__pycache__/netcmd.*.pyc %{python3_sitearch}/samba/tests/__pycache__/net_join_no_spnego.*.pyc @@ -1990,6 +2259,7 @@ fi %{python3_sitearch}/samba/tests/__pycache__/ntlm_auth_krb5.*.pyc %{python3_sitearch}/samba/tests/__pycache__/pam_winbind.*.pyc %{python3_sitearch}/samba/tests/__pycache__/pam_winbind_chauthtok.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/pam_winbind_setcred.*.pyc %{python3_sitearch}/samba/tests/__pycache__/pam_winbind_warn_pwd_expire.*.pyc %{python3_sitearch}/samba/tests/__pycache__/param.*.pyc %{python3_sitearch}/samba/tests/__pycache__/password_hash.*.pyc @@ -2012,16 +2282,22 @@ fi %{python3_sitearch}/samba/tests/__pycache__/s3passdb.*.pyc %{python3_sitearch}/samba/tests/__pycache__/s3registry.*.pyc %{python3_sitearch}/samba/tests/__pycache__/s3windb.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/s3_net_join.*.pyc %{python3_sitearch}/samba/tests/__pycache__/samba3sam.*.pyc %{python3_sitearch}/samba/tests/__pycache__/samba_upgradedns_lmdb.*.pyc %{python3_sitearch}/samba/tests/__pycache__/samdb.*.pyc %{python3_sitearch}/samba/tests/__pycache__/samdb_api.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/sddl.*.pyc %{python3_sitearch}/samba/tests/__pycache__/security.*.pyc %{python3_sitearch}/samba/tests/__pycache__/segfault.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/sid_strings.*.pyc %{python3_sitearch}/samba/tests/__pycache__/smb.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/smbconf.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/smb-notify.*.pyc %{python3_sitearch}/samba/tests/__pycache__/smbd_base.*.pyc %{python3_sitearch}/samba/tests/__pycache__/smbd_fuzztest.*.pyc %{python3_sitearch}/samba/tests/__pycache__/source.*.pyc +%{python3_sitearch}/samba/tests/__pycache__/source_chars.*.pyc %{python3_sitearch}/samba/tests/__pycache__/strings.*.pyc %{python3_sitearch}/samba/tests/__pycache__/subunitrun.*.pyc %{python3_sitearch}/samba/tests/__pycache__/tdb_util.*.pyc @@ -2049,10 +2325,15 @@ fi %{python3_sitearch}/samba/tests/blackbox/__pycache__/bug13653.*.pyc %{python3_sitearch}/samba/tests/blackbox/__pycache__/check_output.*.pyc %{python3_sitearch}/samba/tests/blackbox/__pycache__/downgradedatabase.*.pyc -%{python3_sitearch}/samba/tests/blackbox/__pycache__/mdfind.*.pyc +%{python3_sitearch}/samba/tests/blackbox/__pycache__/mdsearch.*.pyc %{python3_sitearch}/samba/tests/blackbox/__pycache__/ndrdump.*.pyc +%{python3_sitearch}/samba/tests/blackbox/__pycache__/netads_dns.*.pyc %{python3_sitearch}/samba/tests/blackbox/__pycache__/netads_json.*.pyc %{python3_sitearch}/samba/tests/blackbox/__pycache__/samba_dnsupdate.*.pyc +%{python3_sitearch}/samba/tests/blackbox/__pycache__/smbcacls.*.pyc +%{python3_sitearch}/samba/tests/blackbox/__pycache__/smbcacls_basic.*.pyc +%{python3_sitearch}/samba/tests/blackbox/__pycache__/smbcacls_dfs_propagate_inherit.*.pyc +%{python3_sitearch}/samba/tests/blackbox/__pycache__/smbcacls_propagate_inhertance.*.pyc %{python3_sitearch}/samba/tests/blackbox/__pycache__/smbcontrol.*.pyc %{python3_sitearch}/samba/tests/blackbox/__pycache__/smbcontrol_process.*.pyc %{python3_sitearch}/samba/tests/blackbox/__pycache__/traffic_learner.*.pyc @@ -2061,10 +2342,15 @@ fi %{python3_sitearch}/samba/tests/blackbox/bug13653.py %{python3_sitearch}/samba/tests/blackbox/check_output.py %{python3_sitearch}/samba/tests/blackbox/downgradedatabase.py -%{python3_sitearch}/samba/tests/blackbox/mdfind.py +%{python3_sitearch}/samba/tests/blackbox/mdsearch.py %{python3_sitearch}/samba/tests/blackbox/ndrdump.py +%{python3_sitearch}/samba/tests/blackbox/netads_dns.py %{python3_sitearch}/samba/tests/blackbox/netads_json.py %{python3_sitearch}/samba/tests/blackbox/samba_dnsupdate.py +%{python3_sitearch}/samba/tests/blackbox/smbcacls.py +%{python3_sitearch}/samba/tests/blackbox/smbcacls_basic.py +%{python3_sitearch}/samba/tests/blackbox/smbcacls_dfs_propagate_inherit.py +%{python3_sitearch}/samba/tests/blackbox/smbcacls_propagate_inhertance.py %{python3_sitearch}/samba/tests/blackbox/smbcontrol.py %{python3_sitearch}/samba/tests/blackbox/smbcontrol_process.py %{python3_sitearch}/samba/tests/blackbox/traffic_learner.py @@ -2074,14 +2360,18 @@ fi %{python3_sitearch}/samba/tests/complex_expressions.py %{python3_sitearch}/samba/tests/core.py %{python3_sitearch}/samba/tests/credentials.py +%{python3_sitearch}/samba/tests/cred_opt.py %dir %{python3_sitearch}/samba/tests/dcerpc %{python3_sitearch}/samba/tests/dcerpc/__init__.py %dir %{python3_sitearch}/samba/tests/dcerpc/__pycache__ %{python3_sitearch}/samba/tests/dcerpc/__pycache__/__init__.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/array.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/bare.*.pyc +%{python3_sitearch}/samba/tests/dcerpc/__pycache__/createtrustrelax.*.pyc +%{python3_sitearch}/samba/tests/dcerpc/__pycache__/binding.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/dnsserver.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/integer.*.pyc +%{python3_sitearch}/samba/tests/dcerpc/__pycache__/lsa.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/mdssvc.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/misc.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/raw_protocol.*.pyc @@ -2090,14 +2380,18 @@ fi %{python3_sitearch}/samba/tests/dcerpc/__pycache__/rpc_talloc.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/rpcecho.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/sam.*.pyc +%{python3_sitearch}/samba/tests/dcerpc/__pycache__/samr_change_password.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/srvsvc.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/string_tests.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/testrpc.*.pyc %{python3_sitearch}/samba/tests/dcerpc/__pycache__/unix.*.pyc %{python3_sitearch}/samba/tests/dcerpc/array.py %{python3_sitearch}/samba/tests/dcerpc/bare.py +%{python3_sitearch}/samba/tests/dcerpc/binding.py +%{python3_sitearch}/samba/tests/dcerpc/createtrustrelax.py %{python3_sitearch}/samba/tests/dcerpc/dnsserver.py %{python3_sitearch}/samba/tests/dcerpc/integer.py +%{python3_sitearch}/samba/tests/dcerpc/lsa.py %{python3_sitearch}/samba/tests/dcerpc/mdssvc.py %{python3_sitearch}/samba/tests/dcerpc/misc.py %{python3_sitearch}/samba/tests/dcerpc/raw_protocol.py @@ -2106,12 +2400,14 @@ fi %{python3_sitearch}/samba/tests/dcerpc/rpc_talloc.py %{python3_sitearch}/samba/tests/dcerpc/rpcecho.py %{python3_sitearch}/samba/tests/dcerpc/sam.py +%{python3_sitearch}/samba/tests/dcerpc/samr_change_password.py %{python3_sitearch}/samba/tests/dcerpc/srvsvc.py %{python3_sitearch}/samba/tests/dcerpc/string_tests.py %{python3_sitearch}/samba/tests/dcerpc/testrpc.py %{python3_sitearch}/samba/tests/dcerpc/unix.py %{python3_sitearch}/samba/tests/dckeytab.py %{python3_sitearch}/samba/tests/dns.py +%{python3_sitearch}/samba/tests/dns_aging.py %{python3_sitearch}/samba/tests/dns_base.py %{python3_sitearch}/samba/tests/dns_forwarder.py %dir %{python3_sitearch}/samba/tests/dns_forwarder_helpers @@ -2122,6 +2418,8 @@ fi %{python3_sitearch}/samba/tests/dns_tkey.py %{python3_sitearch}/samba/tests/dns_wildcard.py %{python3_sitearch}/samba/tests/dsdb.py +%{python3_sitearch}/samba/tests/dsdb_api.py +%{python3_sitearch}/samba/tests/dsdb_dns.py %{python3_sitearch}/samba/tests/dsdb_lock.py %{python3_sitearch}/samba/tests/dsdb_schema_attributes.py %{python3_sitearch}/samba/tests/docs.py @@ -2141,9 +2439,11 @@ fi %{python3_sitearch}/samba/tests/get_opt.py %{python3_sitearch}/samba/tests/glue.py %{python3_sitearch}/samba/tests/gpo.py +%{python3_sitearch}/samba/tests/gpo_member.py %{python3_sitearch}/samba/tests/graph.py %{python3_sitearch}/samba/tests/group_audit.py %{python3_sitearch}/samba/tests/hostconfig.py +%{python3_sitearch}/samba/tests/imports.py %{python3_sitearch}/samba/tests/join.py %dir %{python3_sitearch}/samba/tests/kcc %{python3_sitearch}/samba/tests/kcc/__init__.py @@ -2157,13 +2457,81 @@ fi %{python3_sitearch}/samba/tests/kcc/graph_utils.py %{python3_sitearch}/samba/tests/kcc/kcc_utils.py %{python3_sitearch}/samba/tests/kcc/ldif_import_export.py +%dir %{python3_sitearch}/samba/tests/krb5 +%dir %{python3_sitearch}/samba/tests/krb5/__pycache__ +%{python3_sitearch}/samba/tests/krb5/__pycache__/alias_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/as_canonicalization_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/as_req_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/compatability_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/etype_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/fast_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/kcrypto.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/kdc_base_test.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/kdc_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/kdc_tgs_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/kpasswd_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/lockout_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/ms_kile_client_principal_lookup_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/nt_hash_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/pac_align_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/protected_users_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/raw_testcase.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/rfc4120_constants.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/rfc4120_pyasn1.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/rodc_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/salt_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/simple_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/spn_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/s4u_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/test_ccache.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/test_idmap_nss.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/test_ldap.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/test_min_domain_uid.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/test_rpc.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/test_smb.*.pyc +%{python3_sitearch}/samba/tests/krb5/__pycache__/xrealm_tests.*.pyc +%{python3_sitearch}/samba/tests/krb5/alias_tests.py +%{python3_sitearch}/samba/tests/krb5/as_canonicalization_tests.py +%{python3_sitearch}/samba/tests/krb5/as_req_tests.py +%{python3_sitearch}/samba/tests/krb5/compatability_tests.py +%{python3_sitearch}/samba/tests/krb5/etype_tests.py +%{python3_sitearch}/samba/tests/krb5/fast_tests.py +%{python3_sitearch}/samba/tests/krb5/kcrypto.py +%{python3_sitearch}/samba/tests/krb5/kdc_base_test.py +%{python3_sitearch}/samba/tests/krb5/kdc_tests.py +%{python3_sitearch}/samba/tests/krb5/kdc_tgs_tests.py +%{python3_sitearch}/samba/tests/krb5/kpasswd_tests.py +%{python3_sitearch}/samba/tests/krb5/lockout_tests.py +%{python3_sitearch}/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py +%{python3_sitearch}/samba/tests/krb5/nt_hash_tests.py +%{python3_sitearch}/samba/tests/krb5/pac_align_tests.py +%{python3_sitearch}/samba/tests/krb5/protected_users_tests.py +%{python3_sitearch}/samba/tests/krb5/raw_testcase.py +%{python3_sitearch}/samba/tests/krb5/rfc4120_constants.py +%{python3_sitearch}/samba/tests/krb5/rfc4120_pyasn1.py +%{python3_sitearch}/samba/tests/krb5/rodc_tests.py +%{python3_sitearch}/samba/tests/krb5/salt_tests.py +%{python3_sitearch}/samba/tests/krb5/simple_tests.py +%{python3_sitearch}/samba/tests/krb5/spn_tests.py +%{python3_sitearch}/samba/tests/krb5/test_ccache.py +%{python3_sitearch}/samba/tests/krb5/test_idmap_nss.py +%{python3_sitearch}/samba/tests/krb5/test_ldap.py +%{python3_sitearch}/samba/tests/krb5/test_min_domain_uid.py +%{python3_sitearch}/samba/tests/krb5/test_rpc.py +%{python3_sitearch}/samba/tests/krb5/test_smb.py +%{python3_sitearch}/samba/tests/krb5/s4u_tests.py +%{python3_sitearch}/samba/tests/krb5/xrealm_tests.py %{python3_sitearch}/samba/tests/krb5_credentials.py %{python3_sitearch}/samba/tests/ldap_raw.py %{python3_sitearch}/samba/tests/ldap_referrals.py +%{python3_sitearch}/samba/tests/ldap_spn.py +%{python3_sitearch}/samba/tests/ldap_upn_sam_account.py %{python3_sitearch}/samba/tests/libsmb.py %{python3_sitearch}/samba/tests/loadparm.py +%{python3_sitearch}/samba/tests/logfiles.py %{python3_sitearch}/samba/tests/lsa_string.py %{python3_sitearch}/samba/tests/messaging.py +%{python3_sitearch}/samba/tests/ndr.py %{python3_sitearch}/samba/tests/netbios.py %{python3_sitearch}/samba/tests/netcmd.py %{python3_sitearch}/samba/tests/net_join_no_spnego.py @@ -2177,6 +2545,7 @@ fi %{python3_sitearch}/samba/tests/ntlm_auth_krb5.py %{python3_sitearch}/samba/tests/pam_winbind.py %{python3_sitearch}/samba/tests/pam_winbind_chauthtok.py +%{python3_sitearch}/samba/tests/pam_winbind_setcred.py %{python3_sitearch}/samba/tests/pam_winbind_warn_pwd_expire.py %{python3_sitearch}/samba/tests/param.py %{python3_sitearch}/samba/tests/password_hash.py @@ -2199,6 +2568,7 @@ fi %{python3_sitearch}/samba/tests/s3passdb.py %{python3_sitearch}/samba/tests/s3registry.py %{python3_sitearch}/samba/tests/s3windb.py +%{python3_sitearch}/samba/tests/s3_net_join.py %{python3_sitearch}/samba/tests/samba3sam.py %{python3_sitearch}/samba/tests/samba_upgradedns_lmdb.py %dir %{python3_sitearch}/samba/tests/samba_tool @@ -2215,10 +2585,12 @@ fi %{python3_sitearch}/samba/tests/samba_tool/__pycache__/forest.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/fsmo.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/gpo.*.pyc +%{python3_sitearch}/samba/tests/samba_tool/__pycache__/gpo_exts.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/group.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/help.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/join.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/join_lmdb_size.*.pyc +%{python3_sitearch}/samba/tests/samba_tool/__pycache__/join_member.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/ntacl.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/ou.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/passwordsettings.*.pyc @@ -2226,6 +2598,7 @@ fi %{python3_sitearch}/samba/tests/samba_tool/__pycache__/promote_dc_lmdb_size.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/provision_lmdb_size.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/provision_password_check.*.pyc +%{python3_sitearch}/samba/tests/samba_tool/__pycache__/provision_userPassword_crypt.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/rodc.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/schema.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/sites.*.pyc @@ -2233,6 +2606,9 @@ fi %{python3_sitearch}/samba/tests/samba_tool/__pycache__/user.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_check_password_script.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_virtualCryptSHA.*.pyc +%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_virtualCryptSHA_base.*.pyc +%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_virtualCryptSHA_gpg.*.pyc +%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_virtualCryptSHA_userPassword.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_wdigest.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/visualize.*.pyc %{python3_sitearch}/samba/tests/samba_tool/__pycache__/visualize_drs.*.pyc @@ -2246,10 +2622,12 @@ fi %{python3_sitearch}/samba/tests/samba_tool/forest.py %{python3_sitearch}/samba/tests/samba_tool/fsmo.py %{python3_sitearch}/samba/tests/samba_tool/gpo.py +%{python3_sitearch}/samba/tests/samba_tool/gpo_exts.py %{python3_sitearch}/samba/tests/samba_tool/group.py %{python3_sitearch}/samba/tests/samba_tool/help.py %{python3_sitearch}/samba/tests/samba_tool/join.py %{python3_sitearch}/samba/tests/samba_tool/join_lmdb_size.py +%{python3_sitearch}/samba/tests/samba_tool/join_member.py %{python3_sitearch}/samba/tests/samba_tool/ntacl.py %{python3_sitearch}/samba/tests/samba_tool/ou.py %{python3_sitearch}/samba/tests/samba_tool/passwordsettings.py @@ -2257,6 +2635,7 @@ fi %{python3_sitearch}/samba/tests/samba_tool/promote_dc_lmdb_size.py %{python3_sitearch}/samba/tests/samba_tool/provision_lmdb_size.py %{python3_sitearch}/samba/tests/samba_tool/provision_password_check.py +%{python3_sitearch}/samba/tests/samba_tool/provision_userPassword_crypt.py %{python3_sitearch}/samba/tests/samba_tool/rodc.py %{python3_sitearch}/samba/tests/samba_tool/schema.py %{python3_sitearch}/samba/tests/samba_tool/sites.py @@ -2264,17 +2643,25 @@ fi %{python3_sitearch}/samba/tests/samba_tool/user.py %{python3_sitearch}/samba/tests/samba_tool/user_check_password_script.py %{python3_sitearch}/samba/tests/samba_tool/user_virtualCryptSHA.py +%{python3_sitearch}/samba/tests/samba_tool/user_virtualCryptSHA_base.py +%{python3_sitearch}/samba/tests/samba_tool/user_virtualCryptSHA_gpg.py +%{python3_sitearch}/samba/tests/samba_tool/user_virtualCryptSHA_userPassword.py %{python3_sitearch}/samba/tests/samba_tool/user_wdigest.py %{python3_sitearch}/samba/tests/samba_tool/visualize.py %{python3_sitearch}/samba/tests/samba_tool/visualize_drs.py %{python3_sitearch}/samba/tests/samdb.py %{python3_sitearch}/samba/tests/samdb_api.py +%{python3_sitearch}/samba/tests/sddl.py %{python3_sitearch}/samba/tests/security.py %{python3_sitearch}/samba/tests/segfault.py +%{python3_sitearch}/samba/tests/sid_strings.py %{python3_sitearch}/samba/tests/smb.py +%{python3_sitearch}/samba/tests/smbconf.py +%{python3_sitearch}/samba/tests/smb-notify.py %{python3_sitearch}/samba/tests/smbd_base.py %{python3_sitearch}/samba/tests/smbd_fuzztest.py %{python3_sitearch}/samba/tests/source.py +%{python3_sitearch}/samba/tests/source_chars.py %{python3_sitearch}/samba/tests/strings.py %{python3_sitearch}/samba/tests/subunitrun.py %{python3_sitearch}/samba/tests/tdb_util.py @@ -2305,6 +2692,10 @@ fi %{_libdir}/samba/libdsdb-module-samba4.so %endif +%files usershares +%config(noreplace) %{_sysconfdir}/samba/usershares.conf +%attr(1770,root,usershares) %dir /var/lib/samba/usershares + ### WINBIND %files winbind %config(noreplace) /etc/ld.so.conf.d/* @@ -2325,7 +2716,9 @@ fi %files winbind-krb5-locator %ghost %{_libdir}/krb5/plugins/libkrb5/winbind_krb5_locator.so +%dir %{_libdir}/samba/krb5 %{_libdir}/samba/krb5/winbind_krb5_locator.so +%{_libdir}/samba/krb5/async_dns_krb5_locator.so %config(noreplace) /etc/ld.so.conf.d/* %files winbind-modules @@ -2369,13 +2762,11 @@ fi %config(noreplace) %{_sysconfdir}/ctdb/nfs-checks.d/50.rquotad.check %{_sbindir}/ctdbd -%{_sbindir}/ctdbd_wrapper %{_bindir}/ctdb -%{_bindir}/ctdb_local_daemons -%{_bindir}/ping_pong -%{_bindir}/ltdbtool %{_bindir}/ctdb_diagnostics +%{_bindir}/ltdbtool %{_bindir}/onnode +%{_bindir}/ping_pong %dir %{_libexecdir}/ctdb %{_libexecdir}/ctdb/ctdb-config @@ -2390,6 +2781,7 @@ fi %{_libexecdir}/ctdb/ctdb_recovery_helper %{_libexecdir}/ctdb/ctdb_takeover_helper %{_libexecdir}/ctdb/smnotify +%{_libexecdir}/ctdb/tdb_mutex_check %dir %{_localstatedir}/lib/ctdb/ %dir %{_localstatedir}/lib/ctdb/persistent @@ -2415,6 +2807,7 @@ fi %{_datadir}/ctdb/events/legacy/31.clamd.script %{_datadir}/ctdb/events/legacy/40.vsftpd.script %{_datadir}/ctdb/events/legacy/41.httpd.script +%{_datadir}/ctdb/events/legacy/48.netbios.script %{_datadir}/ctdb/events/legacy/49.winbind.script %{_datadir}/ctdb/events/legacy/50.samba.script %{_datadir}/ctdb/events/legacy/60.nfs.script @@ -2422,8 +2815,10 @@ fi %{_datadir}/ctdb/events/legacy/91.lvs.script %config(noreplace) /etc/ld.so.conf.d/* +%if %{with testsuite} %files -n ctdb-tests %doc ctdb/tests/README +%{_bindir}/ctdb_local_daemons %{_bindir}/ctdb_run_tests %{_bindir}/ctdb_run_cluster_tests @@ -2515,6 +2910,7 @@ fi %{_datadir}/ctdb/tests/INTEGRATION/database/basics.004.wipe.sh %{_datadir}/ctdb/tests/INTEGRATION/database/basics.010.backup_restore.sh %{_datadir}/ctdb/tests/INTEGRATION/database/fetch.001.ring.sh +%{_datadir}/ctdb/tests/INTEGRATION/database/fetch.002.ring-hotkeys.sh %{_datadir}/ctdb/tests/INTEGRATION/database/readonly.001.basic.sh %{_datadir}/ctdb/tests/INTEGRATION/database/recovery.001.volatile.sh %{_datadir}/ctdb/tests/INTEGRATION/database/recovery.002.large.sh @@ -2559,7 +2955,6 @@ fi %{_datadir}/ctdb/tests/INTEGRATION/simple/basics.005.process_exists.sh %{_datadir}/ctdb/tests/INTEGRATION/simple/basics.010.statistics.sh %{_datadir}/ctdb/tests/INTEGRATION/simple/basics.011.statistics_reset.sh -%{_datadir}/ctdb/tests/INTEGRATION/simple/cluster.001.isnotrecmaster.sh %{_datadir}/ctdb/tests/INTEGRATION/simple/cluster.002.recmaster_yield.sh %{_datadir}/ctdb/tests/INTEGRATION/simple/cluster.010.getrelock.sh %{_datadir}/ctdb/tests/INTEGRATION/simple/cluster.012.reclock_command.sh @@ -2627,6 +3022,8 @@ fi %{_datadir}/ctdb/tests/UNIT/cunit/sock_io_test_001.sh %{_datadir}/ctdb/tests/UNIT/cunit/srvid_test_001.sh %{_datadir}/ctdb/tests/UNIT/cunit/system_socket_test_001.sh +%{_datadir}/ctdb/tests/UNIT/cunit/system_socket_test_002.sh +%{_datadir}/ctdb/tests/UNIT/cunit/system_socket_test_003.sh %dir %{_datadir}/ctdb/tests/UNIT/eventd %dir %{_datadir}/ctdb/tests/UNIT/eventd/etc-ctdb %{_datadir}/ctdb/tests/UNIT/eventd/etc-ctdb/ctdb.conf @@ -2810,6 +3207,8 @@ fi %{_datadir}/ctdb/tests/UNIT/eventscripts/41.httpd.monitor.002.sh %{_datadir}/ctdb/tests/UNIT/eventscripts/41.httpd.shutdown.002.sh %{_datadir}/ctdb/tests/UNIT/eventscripts/41.httpd.startup.002.sh +%{_datadir}/ctdb/tests/UNIT/eventscripts/48.netbios.shutdown.011.sh +%{_datadir}/ctdb/tests/UNIT/eventscripts/48.netbios.startup.011.sh %{_datadir}/ctdb/tests/UNIT/eventscripts/49.winbind.monitor.101.sh %{_datadir}/ctdb/tests/UNIT/eventscripts/49.winbind.monitor.102.sh %{_datadir}/ctdb/tests/UNIT/eventscripts/49.winbind.shutdown.002.sh @@ -2899,6 +3298,7 @@ fi %{_datadir}/ctdb/tests/UNIT/eventscripts/scripts/31.clamd.sh %{_datadir}/ctdb/tests/UNIT/eventscripts/scripts/40.vsftpd.sh %{_datadir}/ctdb/tests/UNIT/eventscripts/scripts/41.httpd.sh +%{_datadir}/ctdb/tests/UNIT/eventscripts/scripts/48.netbios.sh %{_datadir}/ctdb/tests/UNIT/eventscripts/scripts/49.winbind.sh %{_datadir}/ctdb/tests/UNIT/eventscripts/scripts/50.samba.sh %{_datadir}/ctdb/tests/UNIT/eventscripts/scripts/60.nfs.sh @@ -2930,6 +3330,7 @@ fi %{_datadir}/ctdb/tests/UNIT/eventscripts/stubs/kill %{_datadir}/ctdb/tests/UNIT/eventscripts/stubs/killall %{_datadir}/ctdb/tests/UNIT/eventscripts/stubs/multipath +%{_datadir}/ctdb/tests/UNIT/eventscripts/stubs/nfsconf %{_datadir}/ctdb/tests/UNIT/eventscripts/stubs/net %{_datadir}/ctdb/tests/UNIT/eventscripts/stubs/pidof %{_datadir}/ctdb/tests/UNIT/eventscripts/stubs/pkill @@ -3090,6 +3491,7 @@ fi %{_datadir}/ctdb/tests/UNIT/tool/ctdb.getdbstatus.001.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.getdbstatus.002.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.getpid.001.sh +%{_datadir}/ctdb/tests/UNIT/tool/ctdb.getpid.010.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.getreclock.001.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.getreclock.002.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.getvar.001.sh @@ -3116,6 +3518,7 @@ fi %{_datadir}/ctdb/tests/UNIT/tool/ctdb.lvs.006.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.lvs.007.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.lvs.008.sh +%{_datadir}/ctdb/tests/UNIT/tool/ctdb.lvs.010.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.natgw.001.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.natgw.002.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.natgw.003.sh @@ -3124,6 +3527,7 @@ fi %{_datadir}/ctdb/tests/UNIT/tool/ctdb.natgw.006.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.natgw.007.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.natgw.008.sh +%{_datadir}/ctdb/tests/UNIT/tool/ctdb.natgw.010.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.nodestatus.001.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.nodestatus.002.sh %{_datadir}/ctdb/tests/UNIT/tool/ctdb.nodestatus.003.sh @@ -3194,12 +3598,17 @@ fi %dir %{_datadir}/ctdb/tests/UNIT/tool/scripts %{_datadir}/ctdb/tests/UNIT/tool/scripts/local.sh %config(noreplace) /etc/ld.so.conf.d/* - +#endif with_testsuite +%endif #endif with_clustering_support %endif %files help %{_mandir}/man* +%dir %{_datadir}/samba/admx +%{_datadir}/samba/admx/samba.admx +%dir %{_datadir}/samba/admx/en-US +%{_datadir}/samba/admx/en-US/samba.adml %if %{with_winexe} ### WINEXE @@ -3208,6 +3617,186 @@ fi %endif %changelog +* Fri Jan 19 2024 xinghe - 4.17.5-11 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:speeds up the creation of source rpm + +* Tue Jan 16 2024 xinghe - 4.17.5-10 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:remove sensitive info + +* Thu Dec 28 2023 xinghe - 4.17.5-9 +- Type:cves +- ID:CVE-2018-14628 +- SUG:NA +- DESC:fix CVE-2018-14628 + +* Thu Oct 12 2023 xinghe - 4.17.5-8 +- Type:cves +- ID:CVE-2023-3961 CVE-2023-4091 CVE-2023-4154 CVE-2023-42669 CVE-2023-42670 +- SUG:NA +- DESC:fix CVE-2023-3961 CVE-2023-4091 CVE-2023-4154 CVE-2023-42669 CVE-2023-42670 + +* Fri Aug 11 2023 panchenbo - 4.17.5-7 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:add loongarch64 and sw_64 support + +* Thu Jul 20 2023 xinghe - 4.17.5-6 +- Type:cves +- ID:CVE-2022-2127 CVE-2023-3347 CVE-2023-34966 CVE-2023-34967 CVE-2023-34968 +- SUG:NA +- DESC:fix CVE-2022-2127 CVE-2023-3347 CVE-2023-34966 CVE-2023-34967 CVE-2023-34968 + +* Wed Jun 21 2023 yanglu - 4.17.5-5 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:add Obsoletes '< version' and Provides '= version' in spec + +* Tue Apr 11 2023 yanglu - 4.17.5-4 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:split samba-client-libs and samba-dc-libs + +* Thu Apr 06 2023 xinghe - 4.17.5-3 +- Type:cves +- ID:CVE-2023-0225 CVE-2023-0614 CVE-2023-0922 +- SUG:NA +- DESC:fix CVE-2023-0225 CVE-2023-0614 CVE-2023-0922 + +* Mon Feb 27 2023 gaihuiying - 4.17.5-2 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:delete useless file + +* Fri Feb 24 2023 gaihuiying - 4.17.5-1 +- Type:requirement +- ID:NA +- SUG:NA +- DESC:update samba to 4.17.5-1 + +* Wed Feb 08 2023 laokz - 4.17.2-6 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:isolate unsupported gold for riscv64 + +* Thu Dec 29 2022 xinghe - 4.17.2-5 +- Type:cves +- ID:CVE-2022-38023 CVE-2022-37966 CVE-2022-37967 +- SUG:NA +- DESC:fix CVE-2022-38023 CVE-2022-37966 CVE-2022-37967 + +* Sat Dec 17 2022 xinghe - 4.17.2-4 +- Type:cves +- ID:CVE-2022-44640 +- SUG:NA +- DESC:fix CVE-2022-44640 + +* Thu Dec 08 2022 xinghe - 4.17.2-3 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:remove runpath of samba's binary files + +* Mon Nov 21 2022 zhouyihang - 4.17.2-2 +- Type:cves +- ID:CVE-2022-42898 +- SUG:NA +- DESC:fix CVE-2022-42898 + +* Tue Nov 08 2022 xinghe - 4.17.2-1 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: update to 4.17.2 + +* Wed Oct 26 2022 xinghe - 4.15.3-12 +- Type:cves +- ID:CVE-2022-3437 +- SUG:NA +- DESC:fix CVE-2022-3437 + +* Thu Sep 29 2022 xinghe - 4.15.3-11 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:clear the compilation alarms + +* Wed Aug 31 2022 zhouyihang - 4.15.3-10 +- Type:cves +- ID:CVE-2022-1615 +- SUG:NA +- DESC:fix CVE-2022-1615 + +* Fri Aug 26 2022 zhouyihang - 4.15.3-9 +- Type:cves +- ID:CVE-2022-32743 +- SUG:NA +- DESC:fix CVE-2022-32743 + +* Fri Aug 12 2022 xinghe - 4.15.3-8 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:add ldb require version + +* Tue Aug 02 2022 xinghe - 4.15.3-7 +- Type:cves +- ID:CVE-2022-32746 CVE-2022-2031 CVE-2022-32744 CVE-2022-32742 CVE-2022-32745 +- SUG:NA +- DESC:fix CVE-2022-32746 CVE-2022-2031 CVE-2022-32744 CVE-2022-32742 CVE-2022-32745 + +* Wed Jul 20 2022 gaihuiying - 4.15.3-6 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:add macros to control if need cups in configure file + +* Thu Jul 14 2022 gaihuiying - 4.15.3-5 +- Type:cves +- ID:CVE-2021-44141 +- SUG:NA +- DESC:fix CVE-2021-44141 + +* Fri Mar 11 2022 xingwei - 4.15.3-4 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:remove runpath of samba's binary files + +* Tue Feb 15 2022 gaihuiying - 4.15.3-3 +- Type:cves +- ID:CVE-2022-0336 CVE-2021-44142 +- SUG:NA +- DESC:backport to fix CVE-2022-0336 CVE-2021-44142 + +* Mon Jan 17 2022 gaihuiying - 4.15.3-2 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:add "openEuler" macro to control if cups is needed + +* Fri Dec 24 2021 yanglu - 4.15.3-1 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:update samba to 4.15.3 + +* Mon Oct 25 2021 gaihuiying - 4.12.5-7 +- Type:cves +- ID:CVE-2021-3671 +- SUG:NA +- DESC:fix CVE-2021-3671 + * Fri Sep 10 2021 gaihuiying - 4.12.5-6 - Type:bugfix - ID:NA @@ -3299,7 +3888,7 @@ fi - Type: enhancement - ID: NA - SUG: NA -- DESC:modify spec file +- DESC:modify spec file * Mon Sep 23 2019 huzhiyu - 4.9.1-3 - Package init diff --git a/smb.conf.example b/smb.conf.example index e672ce9e1e6a62f44dc61c5d70c29edd722cece8..4e6b5d4c7cb1be7fe3316594112c750fb0cb8b87 100644 --- a/smb.conf.example +++ b/smb.conf.example @@ -281,7 +281,7 @@ [printers] comment = All Printers - path = /var/spool/samba + path = /var/tmp browseable = no guest ok = no writable = no diff --git a/smb.conf.vendor b/smb.conf.vendor index fe3f80646f12d1e01fe128a0b576211d0529c72d..127382e930e9ccef75df36dd476a6a77b8636c44 100644 --- a/smb.conf.vendor +++ b/smb.conf.vendor @@ -14,6 +14,7 @@ load printers = yes cups options = raw + include = /etc/samba/usershares.conf [homes] comment = Home Directories valid users = %S, %D%w%S diff --git a/usershares.conf.vendor b/usershares.conf.vendor new file mode 100644 index 0000000000000000000000000000000000000000..38a7885c810da0d1e0efadd42e3c301dacb3a800 --- /dev/null +++ b/usershares.conf.vendor @@ -0,0 +1,3 @@ +[global] + usershare max shares = 100 + usershare allow guests = yes