diff --git a/0001-CVE-2019-10218.patch b/0001-CVE-2019-10218.patch new file mode 100644 index 0000000..965e9e1 --- /dev/null +++ b/0001-CVE-2019-10218.patch @@ -0,0 +1,133 @@ +From fc6022b9b19473076c4236fdf4ac474f44ca73e2 Mon Sep 17 00:00:00 2001 +From: Jeremy Allison +Date: Mon, 5 Aug 2019 13:39:53 -0700 +Subject: [PATCH 1/7] CVE-2019-10218 - s3: libsmb: Protect SMB1 client code + from evil server returned names. + +Disconnect with NT_STATUS_INVALID_NETWORK_RESPONSE if so. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14071 + +Signed-off-by: Jeremy Allison +--- + source3/libsmb/clilist.c | 75 ++++++++++++++++++++++++++++++++++++++++ + source3/libsmb/proto.h | 3 ++ + 2 files changed, 78 insertions(+) + +diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c +index 5cb1fce4338..4f518339e2b 100644 +--- a/source3/libsmb/clilist.c ++++ b/source3/libsmb/clilist.c +@@ -24,6 +24,66 @@ + #include "trans2.h" + #include "../libcli/smb/smbXcli_base.h" + ++/**************************************************************************** ++ Check if a returned directory name is safe. ++****************************************************************************/ ++ ++static NTSTATUS is_bad_name(bool windows_names, const char *name) ++{ ++ const char *bad_name_p = NULL; ++ ++ bad_name_p = strchr(name, '/'); ++ if (bad_name_p != NULL) { ++ /* ++ * Windows and POSIX names can't have '/'. ++ * Server is attacking us. ++ */ ++ return NT_STATUS_INVALID_NETWORK_RESPONSE; ++ } ++ if (windows_names) { ++ bad_name_p = strchr(name, '\\'); ++ if (bad_name_p != NULL) { ++ /* ++ * Windows names can't have '\\'. ++ * Server is attacking us. ++ */ ++ return NT_STATUS_INVALID_NETWORK_RESPONSE; ++ } ++ } ++ return NT_STATUS_OK; ++} ++ ++/**************************************************************************** ++ Check if a returned directory name is safe. Disconnect if server is ++ sending bad names. ++****************************************************************************/ ++ ++NTSTATUS is_bad_finfo_name(const struct cli_state *cli, ++ const struct file_info *finfo) ++{ ++ NTSTATUS status = NT_STATUS_OK; ++ bool windows_names = true; ++ ++ if (cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) { ++ windows_names = false; ++ } ++ if (finfo->name != NULL) { ++ status = is_bad_name(windows_names, finfo->name); ++ if (!NT_STATUS_IS_OK(status)) { ++ DBG_ERR("bad finfo->name\n"); ++ return status; ++ } ++ } ++ if (finfo->short_name != NULL) { ++ status = is_bad_name(windows_names, finfo->short_name); ++ if (!NT_STATUS_IS_OK(status)) { ++ DBG_ERR("bad finfo->short_name\n"); ++ return status; ++ } ++ } ++ return NT_STATUS_OK; ++} ++ + /**************************************************************************** + Calculate a safe next_entry_offset. + ****************************************************************************/ +@@ -492,6 +552,13 @@ static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + TALLOC_FREE(finfo); + return NT_STATUS_NO_MEMORY; + } ++ ++ status = is_bad_finfo_name(state->cli, finfo); ++ if (!NT_STATUS_IS_OK(status)) { ++ smbXcli_conn_disconnect(state->cli->conn, status); ++ TALLOC_FREE(finfo); ++ return status; ++ } + } + *pfinfo = finfo; + return NT_STATUS_OK; +@@ -727,6 +794,14 @@ static void cli_list_trans_done(struct tevent_req *subreq) + ff_eos = true; + break; + } ++ ++ status = is_bad_finfo_name(state->cli, finfo); ++ if (!NT_STATUS_IS_OK(status)) { ++ smbXcli_conn_disconnect(state->cli->conn, status); ++ tevent_req_nterror(req, status); ++ return; ++ } ++ + if (!state->first && (state->mask[0] != '\0') && + strcsequal(finfo->name, state->mask)) { + DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has " +diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h +index 2bd61b1d2c2..e708e911b97 100644 +--- a/source3/libsmb/proto.h ++++ b/source3/libsmb/proto.h +@@ -722,6 +722,9 @@ NTSTATUS cli_posix_whoami(struct cli_state *cli, + + /* The following definitions come from libsmb/clilist.c */ + ++NTSTATUS is_bad_finfo_name(const struct cli_state *cli, ++ const struct file_info *finfo); ++ + NTSTATUS cli_list_old(struct cli_state *cli,const char *Mask,uint16_t attribute, + NTSTATUS (*fn)(const char *, struct file_info *, + const char *, void *), void *state); +-- +2.17.1 + diff --git a/0001-CVE-2019-14833.patch b/0001-CVE-2019-14833.patch new file mode 100644 index 0000000..aa5910c --- /dev/null +++ b/0001-CVE-2019-14833.patch @@ -0,0 +1,39 @@ +From e6de467a763b93152eef27726957a32879268fb7 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Thu, 19 Sep 2019 11:50:01 +1200 +Subject: [PATCH 3/7] CVE-2019-14833: Use utf8 characters in the unacceptable + password + +This shows that the "check password script" handling has a bug. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=12438 +Signed-off-by: Andrew Bartlett +--- + selftest/knownfail.d/unacceptable-passwords | 1 + + selftest/target/Samba4.pm | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + create mode 100644 selftest/knownfail.d/unacceptable-passwords + +diff --git a/selftest/knownfail.d/unacceptable-passwords b/selftest/knownfail.d/unacceptable-passwords +new file mode 100644 +index 00000000000..75fa2fc32b8 +--- /dev/null ++++ b/selftest/knownfail.d/unacceptable-passwords +@@ -0,0 +1 @@ ++^samba.tests.samba_tool.user_check_password_script.samba.tests.samba_tool.user_check_password_script.UserCheckPwdTestCase.test_checkpassword_unacceptable\(chgdcpass:local\) +\ No newline at end of file +diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm +index b565d466477..d7c22ce4e23 100755 +--- a/selftest/target/Samba4.pm ++++ b/selftest/target/Samba4.pm +@@ -1986,7 +1986,7 @@ sub provision_chgdcpass($$) + my $extra_provision_options = undef; + # This environment disallows the use of this password + # (and also removes the default AD complexity checks) +- my $unacceptable_password = "widk3Dsle32jxdBdskldsk55klASKQ"; ++ my $unacceptable_password = "Pa脽脽word-widk3Dsle32jxdBdskldsk55klASKQ"; + push (@{$extra_provision_options}, "--dns-backend=BIND9_DLZ"); + my $ret = $self->provision($prefix, + "domain controller", +-- +2.17.1 diff --git a/0001-CVE-2019-14847.patch b/0001-CVE-2019-14847.patch new file mode 100644 index 0000000..ede833e --- /dev/null +++ b/0001-CVE-2019-14847.patch @@ -0,0 +1,33 @@ +From ea39bdd6293041af668f1bfdfea39a725733bad3 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Fri, 3 May 2019 17:27:51 +1200 +Subject: [PATCH 5/7] CVE-2019-14847 dsdb/modules/dirsync: ensure attrs exist + (CID 1107212) + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14040 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Gary Lockyer +(cherry picked from commit 23f72c4d712f8d1fec3d67a66d477709d5b0abe2) +--- + source4/dsdb/samdb/ldb_modules/dirsync.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/source4/dsdb/samdb/ldb_modules/dirsync.c b/source4/dsdb/samdb/ldb_modules/dirsync.c +index b5510eccd24..62a66fef8d4 100644 +--- a/source4/dsdb/samdb/ldb_modules/dirsync.c ++++ b/source4/dsdb/samdb/ldb_modules/dirsync.c +@@ -343,6 +343,10 @@ skip: + + attr = dsdb_attribute_by_lDAPDisplayName(dsc->schema, + el->name); ++ if (attr == NULL) { ++ continue; ++ } ++ + keep = false; + + if (attr->linkID & 1) { +-- +2.17.1 + diff --git a/0001-CVE-2019-3824.patch b/0001-CVE-2019-3824.patch new file mode 100644 index 0000000..8ef27ff --- /dev/null +++ b/0001-CVE-2019-3824.patch @@ -0,0 +1,92 @@ +From 3674b0891afb016c83763520b87e9f190dcfe884 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Fri, 18 Jan 2019 16:37:24 +0100 +Subject: [PATCH] CVE-2019-3824 ldb: Out of bound read in ldb_wildcard_compare + +There is valgrind error in few tests tests/test-generic.sh + 91 echo "Test wildcard match" + 92 $VALGRIND ldbadd $LDBDIR/tests/test-wildcard.ldif || exit 1 + 93 $VALGRIND ldbsearch '(cn=test*multi)' || exit 1 + 95 $VALGRIND ldbsearch '(cn=*test_multi)' || exit 1 + 97 $VALGRIND ldbsearch '(cn=test*multi*test*multi)' || exit 1 + +e.g. + ==3098== Memcheck, a memory error detector + ==3098== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. + ==3098== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info + ==3098== Command: ./bin/ldbsearch (cn=test*multi) + ==3098== + ==3098== Invalid read of size 1 + ==3098== at 0x483CEE7: memchr (vg_replace_strmem.c:890) + ==3098== by 0x49A9073: memmem (in /usr/lib64/libc-2.28.9000.so) + ==3098== by 0x485DFE9: ldb_wildcard_compare (ldb_match.c:313) + ==3098== by 0x485DFE9: ldb_match_substring (ldb_match.c:360) + ==3098== by 0x485DFE9: ldb_match_message (ldb_match.c:572) + ==3098== by 0x558F8FA: search_func (ldb_kv_search.c:549) + ==3098== by 0x48C78CA: ??? (in /usr/lib64/libtdb.so.1.3.17) + ==3098== by 0x48C7A60: tdb_traverse_read (in /usr/lib64/libtdb.so.1.3.17) + ==3098== by 0x557B7C4: ltdb_traverse_fn (ldb_tdb.c:274) + ==3098== by 0x558FBFA: ldb_kv_search_full (ldb_kv_search.c:594) + ==3098== by 0x558FBFA: ldb_kv_search (ldb_kv_search.c:854) + ==3098== by 0x558E497: ldb_kv_callback (ldb_kv.c:1713) + ==3098== by 0x48FCD58: tevent_common_invoke_timer_handler (in /usr/lib64/libtevent.so.0.9.38) + ==3098== by 0x48FCEFD: tevent_common_loop_timer_delay (in /usr/lib64/libtevent.so.0.9.38) + ==3098== by 0x48FE14A: ??? (in /usr/lib64/libtevent.so.0.9.38) + ==3098== Address 0x4b4ab81 is 0 bytes after a block of size 129 alloc'd + ==3098== at 0x483880B: malloc (vg_replace_malloc.c:309) + ==3098== by 0x491048B: talloc_strndup (in /usr/lib64/libtalloc.so.2.1.15) + ==3098== by 0x48593CA: ldb_casefold_default (ldb_utf8.c:59) + ==3098== by 0x485F68D: ldb_handler_fold (attrib_handlers.c:64) + ==3098== by 0x485DB88: ldb_wildcard_compare (ldb_match.c:257) + ==3098== by 0x485DB88: ldb_match_substring (ldb_match.c:360) + ==3098== by 0x485DB88: ldb_match_message (ldb_match.c:572) + ==3098== by 0x558F8FA: search_func (ldb_kv_search.c:549) + ==3098== by 0x48C78CA: ??? (in /usr/lib64/libtdb.so.1.3.17) + ==3098== by 0x48C7A60: tdb_traverse_read (in /usr/lib64/libtdb.so.1.3.17) + ==3098== by 0x557B7C4: ltdb_traverse_fn (ldb_tdb.c:274) + ==3098== by 0x558FBFA: ldb_kv_search_full (ldb_kv_search.c:594) + ==3098== by 0x558FBFA: ldb_kv_search (ldb_kv_search.c:854) + ==3098== by 0x558E497: ldb_kv_callback (ldb_kv.c:1713) + ==3098== by 0x48FCD58: tevent_common_invoke_timer_handler (in /usr/lib64/libtevent.so.0.9.38) + ==3098== + # record 1 + dn: cn=test_multi_test_multi_test_multi,o=University of Michigan,c=TEST + cn: test_multi_test_multi_test_multi + description: test multi wildcards matching + objectclass: person + sn: multi_test + name: test_multi_test_multi_test_multi + distinguishedName: cn=test_multi_test_multi_test_multi,o=University of Michiga + n,c=TEST + + # returned 1 records + # 1 entries + # 0 referrals + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13773 + +Signed-off-by: Lukas Slebodnik +Reviewed-by: Andrew Bartlett +Reviewed-by: Gary Lockyer +--- + lib/ldb/common/ldb_match.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c +index 25fe3f9c21b..8eeedfb12e0 100644 +--- a/lib/ldb/common/ldb_match.c ++++ b/lib/ldb/common/ldb_match.c +@@ -308,9 +308,10 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, + if (p == NULL) goto mismatch; + if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) { + uint8_t *g; ++ uint8_t *end = val.data + val.length; + do { /* greedy */ + g = memmem(p + cnk.length, +- val.length - (p - val.data), ++ end - (p + cnk.length), + (const uint8_t *)cnk.data, + cnk.length); + if (g) p = g; +-- +2.24.0 diff --git a/0002-CVE-2019-10218.patch b/0002-CVE-2019-10218.patch new file mode 100644 index 0000000..d610db7 --- /dev/null +++ b/0002-CVE-2019-10218.patch @@ -0,0 +1,36 @@ +From 167f78aa97af6502cb2027dc9dad40399b0a9c4f Mon Sep 17 00:00:00 2001 +From: Jeremy Allison +Date: Tue, 6 Aug 2019 12:08:09 -0700 +Subject: [PATCH 2/7] CVE-2019-10218 - s3: libsmb: Protect SMB2 client code + from evil server returned names. + +Disconnect with NT_STATUS_INVALID_NETWORK_RESPONSE if so. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14071 + +Signed-off-by: Jeremy Allison +--- + source3/libsmb/cli_smb2_fnum.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c +index 1cfa50ffbac..3cdf68dc24b 100644 +--- a/source3/libsmb/cli_smb2_fnum.c ++++ b/source3/libsmb/cli_smb2_fnum.c +@@ -1017,6 +1017,13 @@ NTSTATUS cli_smb2_list(struct cli_state *cli, + goto fail; + } + ++ /* Protect against server attack. */ ++ status = is_bad_finfo_name(cli, finfo); ++ if (!NT_STATUS_IS_OK(status)) { ++ smbXcli_conn_disconnect(cli->conn, status); ++ goto fail; ++ } ++ + if (dir_check_ftype((uint32_t)finfo->mode, + (uint32_t)attribute)) { + /* +-- +2.17.1 + diff --git a/0002-CVE-2019-14833.patch b/0002-CVE-2019-14833.patch new file mode 100644 index 0000000..3bb1997 --- /dev/null +++ b/0002-CVE-2019-14833.patch @@ -0,0 +1,105 @@ +From 70078d4ddf3b842eeadee058dadeef82ec4edf0b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20Baumbach?= +Date: Tue, 6 Aug 2019 16:32:32 +0200 +Subject: [PATCH 4/7] CVE-2019-14833 dsdb: send full password to check password + script +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +utf8_len represents the number of characters (not bytes) of the +password. If the password includes multi-byte characters it is required +to write the total number of bytes to the check password script. +Otherwise the last bytes of the password string would be ignored. + +Therefore we rename utf8_len to be clear what it does and does +not represent. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=12438 + +Signed-off-by: Bj枚rn Baumbach +Signed-off-by: Andrew Bartlett +--- + selftest/knownfail.d/unacceptable-passwords | 1 - + source4/dsdb/common/util.c | 33 +++++++++++++++++---- + 2 files changed, 27 insertions(+), 7 deletions(-) + delete mode 100644 selftest/knownfail.d/unacceptable-passwords + +diff --git a/selftest/knownfail.d/unacceptable-passwords b/selftest/knownfail.d/unacceptable-passwords +deleted file mode 100644 +index 75fa2fc32b8..00000000000 +--- a/selftest/knownfail.d/unacceptable-passwords ++++ /dev/null +@@ -1 +0,0 @@ +-^samba.tests.samba_tool.user_check_password_script.samba.tests.samba_tool.user_check_password_script.UserCheckPwdTestCase.test_checkpassword_unacceptable\(chgdcpass:local\) +\ No newline at end of file +diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c +index 18f700370a3..c7893bff43b 100644 +--- a/source4/dsdb/common/util.c ++++ b/source4/dsdb/common/util.c +@@ -2088,21 +2088,36 @@ enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx, + const uint32_t pwdProperties, + const uint32_t minPwdLength) + { +- const char *utf8_pw = (const char *)utf8_blob->data; +- size_t utf8_len = strlen_m(utf8_pw); + char *password_script = NULL; ++ const char *utf8_pw = (const char *)utf8_blob->data; ++ ++ /* ++ * This looks strange because it is. ++ * ++ * The check for the number of characters in the password ++ * should clearly not be against the byte length, or else a ++ * single UTF8 character would count for more than one. ++ * ++ * We have chosen to use the number of 16-bit units that the ++ * password encodes to as the measure of length. This is not ++ * the same as the number of codepoints, if a password ++ * contains a character beyond the Basic Multilingual Plane ++ * (above 65535) it will count for more than one "character". ++ */ ++ ++ size_t password_characters_roughly = strlen_m(utf8_pw); + + /* checks if the "minPwdLength" property is satisfied */ +- if (minPwdLength > utf8_len) { ++ if (minPwdLength > password_characters_roughly) { + return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT; + } + +- /* checks the password complexity */ ++ /* We might not be asked to check the password complexity */ + if (!(pwdProperties & DOMAIN_PASSWORD_COMPLEX)) { + return SAMR_VALIDATION_STATUS_SUCCESS; + } + +- if (utf8_len == 0) { ++ if (password_characters_roughly == 0) { + return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH; + } + +@@ -2110,6 +2125,7 @@ enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx, + if (password_script != NULL && *password_script != '\0') { + int check_ret = 0; + int error = 0; ++ ssize_t nwritten = 0; + struct tevent_context *event_ctx = NULL; + struct tevent_req *req = NULL; + struct samba_runcmd_state *run_cmd = NULL; +@@ -2134,7 +2150,12 @@ enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx, + tevent_timeval_current_ofs(10, 0), + 100, 100, cmd, NULL); + run_cmd = tevent_req_data(req, struct samba_runcmd_state); +- if (write(run_cmd->fd_stdin, utf8_pw, utf8_len) != utf8_len) { ++ nwritten = write(run_cmd->fd_stdin, ++ utf8_blob->data, ++ utf8_blob->length); ++ if (nwritten != utf8_blob->length) { ++ close(run_cmd->fd_stdin); ++ run_cmd->fd_stdin = -1; + TALLOC_FREE(password_script); + TALLOC_FREE(event_ctx); + return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR; +-- +2.17.1 diff --git a/0002-CVE-2019-14847.patch b/0002-CVE-2019-14847.patch new file mode 100644 index 0000000..9de3f1d --- /dev/null +++ b/0002-CVE-2019-14847.patch @@ -0,0 +1,72 @@ +From bdb3e3f669bd991da819040e726e003e4e2b841d Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Tue, 15 Oct 2019 16:28:46 +1300 +Subject: [PATCH 6/7] CVE-2019-14847 dsdb: Demonstrate the correct interaction + of ranged_results style attributes and dirsync + +Incremental results are provided by a flag on the dirsync control, not +by changing the attribute name. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14040 + +Signed-off-by: Andrew Bartlett +--- + selftest/knownfail.d/dirsync | 1 + + source4/dsdb/tests/python/dirsync.py | 26 ++++++++++++++++++++++++++ + 2 files changed, 27 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..bc49fe0d9bb +--- /dev/null ++++ b/selftest/knownfail.d/dirsync +@@ -0,0 +1 @@ ++^samba4.ldap.dirsync.python\(ad_dc_ntvfs\).__main__.ExtendedDirsyncTests.test_dirsync_linkedattributes_range\( +\ No newline at end of file +diff --git a/source4/dsdb/tests/python/dirsync.py b/source4/dsdb/tests/python/dirsync.py +index 136f4d3bba6..b6f7022a50b 100755 +--- a/source4/dsdb/tests/python/dirsync.py ++++ b/source4/dsdb/tests/python/dirsync.py +@@ -28,6 +28,7 @@ from samba.tests.subunitrun import TestProgram, SubunitOptions + import samba.getopt as options + 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 +@@ -590,6 +591,31 @@ class SimpleDirsyncTests(DirsyncBaseTests): + + 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, ++ attrs=["member;range=1-1"], ++ expression="(name=Administrators)", ++ controls=["dirsync:1:0:0"]) ++ ++ self.assertTrue(len(res) > 0) ++ self.assertTrue(res[0].get("member;range=1-1") is None) ++ self.assertTrue(res[0].get("member") is not None) ++ 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) ++ try: ++ res = self.ldb_simple.search(self.base_dn, ++ attrs=["member;range=1-1"], ++ expression="(name=Administrators)", ++ controls=["dirsync:1:0:0"]) ++ except LdbError as e: ++ (num, _) = e.args ++ self.assertEquals(num, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) ++ else: ++ self.fail() ++ + def test_dirsync_linkedattributes(self): + flag_incr_linked = 2147483648 + self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) +-- +2.17.1 diff --git a/0002-CVE-2019-3824.patch b/0002-CVE-2019-3824.patch new file mode 100644 index 0000000..49f7c27 --- /dev/null +++ b/0002-CVE-2019-3824.patch @@ -0,0 +1,56 @@ +From 745b99fc6b75db33cdb0a58df1a3f2a5063bc76e Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 4 Feb 2019 11:22:34 +1300 +Subject: [PATCH] CVE-2019-3824 ldb: Extra comments to clarify no pointer wrap + in wildcard processing + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13773 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Gary Lockyer +--- + lib/ldb/common/ldb_match.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c +index 8eeedfb12e0..1920b661f75 100644 +--- a/lib/ldb/common/ldb_match.c ++++ b/lib/ldb/common/ldb_match.c +@@ -306,12 +306,33 @@ 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) goto mismatch; ++ ++ /* ++ * At this point we know cnk.length <= val.length as ++ * otherwise there could be no match ++ */ ++ + if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) { + uint8_t *g; + uint8_t *end = val.data + val.length; + do { /* greedy */ +- g = memmem(p + cnk.length, +- end - (p + cnk.length), ++ ++ /* ++ * haystack is a valid pointer in val ++ * because the memmem() can only ++ * succeed if the needle (cnk.length) ++ * is <= haystacklen ++ * ++ * p will be a pointer at least ++ * cnk.length from the end of haystack ++ */ ++ uint8_t *haystack ++ = p + cnk.length; ++ size_t haystacklen ++ = end - (haystack); ++ ++ g = memmem(haystack, ++ haystacklen, + (const uint8_t *)cnk.data, + cnk.length); + if (g) p = g; +-- +2.24.0 diff --git a/0003-CVE-2019-14847.patch b/0003-CVE-2019-14847.patch new file mode 100644 index 0000000..d763d5b --- /dev/null +++ b/0003-CVE-2019-14847.patch @@ -0,0 +1,112 @@ +From 77b10b360f4ffb7ac90bc5fce0a80306515c1aca Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Tue, 15 Oct 2019 15:44:34 +1300 +Subject: [PATCH 7/7] CVE-2019-14847 dsdb: Correct behaviour of ranged_results + when combined with dirsync + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14040 + +Signed-off-by: Andrew Bartlett +--- + selftest/knownfail.d/dirsync | 1 - + source4/dsdb/samdb/ldb_modules/dirsync.c | 11 ++++---- + .../dsdb/samdb/ldb_modules/ranged_results.c | 25 ++++++++++++++++--- + 3 files changed, 28 insertions(+), 9 deletions(-) + delete mode 100644 selftest/knownfail.d/dirsync + +diff --git a/selftest/knownfail.d/dirsync b/selftest/knownfail.d/dirsync +deleted file mode 100644 +index bc49fe0d9bb..00000000000 +--- a/selftest/knownfail.d/dirsync ++++ /dev/null +@@ -1 +0,0 @@ +-^samba4.ldap.dirsync.python\(ad_dc_ntvfs\).__main__.ExtendedDirsyncTests.test_dirsync_linkedattributes_range\( +\ No newline at end of file +diff --git a/source4/dsdb/samdb/ldb_modules/dirsync.c b/source4/dsdb/samdb/ldb_modules/dirsync.c +index 62a66fef8d4..4ac5faad403 100644 +--- a/source4/dsdb/samdb/ldb_modules/dirsync.c ++++ b/source4/dsdb/samdb/ldb_modules/dirsync.c +@@ -998,7 +998,7 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req + } + + /* +- * check if there's an extended dn control ++ * check if there's a dirsync control + */ + control = ldb_request_get_control(req, LDB_CONTROL_DIRSYNC_OID); + if (control == NULL) { +@@ -1327,11 +1327,12 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req + + } + /* +- * Remove our control from the list of controls ++ * Mark dirsync control as uncritical (done) ++ * ++ * We need this so ranged_results knows how to behave with ++ * dirsync + */ +- if (!ldb_save_controls(control, req, NULL)) { +- return ldb_operr(ldb); +- } ++ control->critical = false; + dsc->schema = dsdb_get_schema(ldb, dsc); + /* + * At the begining we make the hypothesis that we will return a complete +diff --git a/source4/dsdb/samdb/ldb_modules/ranged_results.c b/source4/dsdb/samdb/ldb_modules/ranged_results.c +index 13bf3a2d0a9..98438799997 100644 +--- a/source4/dsdb/samdb/ldb_modules/ranged_results.c ++++ b/source4/dsdb/samdb/ldb_modules/ranged_results.c +@@ -35,14 +35,14 @@ + struct rr_context { + struct ldb_module *module; + struct ldb_request *req; ++ bool dirsync_in_use; + }; + + static struct rr_context *rr_init_context(struct ldb_module *module, + struct ldb_request *req) + { +- struct rr_context *ac; +- +- ac = talloc_zero(req, struct rr_context); ++ struct ldb_control *dirsync_control = NULL; ++ struct rr_context *ac = talloc_zero(req, struct rr_context); + if (ac == NULL) { + ldb_set_errstring(ldb_module_get_ctx(module), "Out of Memory"); + return NULL; +@@ -51,6 +51,16 @@ static struct rr_context *rr_init_context(struct ldb_module *module, + ac->module = module; + ac->req = req; + ++ /* ++ * check if there's a dirsync control (as there is an ++ * interaction between these modules) ++ */ ++ dirsync_control = ldb_request_get_control(req, ++ LDB_CONTROL_DIRSYNC_OID); ++ if (dirsync_control != NULL) { ++ ac->dirsync_in_use = true; ++ } ++ + return ac; + } + +@@ -82,6 +92,15 @@ static int rr_search_callback(struct ldb_request *req, struct ldb_reply *ares) + ares->response, ares->error); + } + ++ if (ac->dirsync_in_use) { ++ /* ++ * We return full attribute values when mixed with ++ * dirsync ++ */ ++ return ldb_module_send_entry(ac->req, ++ ares->message, ++ ares->controls); ++ } + /* LDB_REPLY_ENTRY */ + + temp_ctx = talloc_new(ac->req); +-- +2.17.1 + diff --git a/0003-CVE-2019-3824.patch b/0003-CVE-2019-3824.patch new file mode 100644 index 0000000..2f3dbb5 --- /dev/null +++ b/0003-CVE-2019-3824.patch @@ -0,0 +1,35 @@ +From 9427806f7298d71bd7edfbdda7506ec63f15dda1 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 4 Feb 2019 11:22:50 +1300 +Subject: [PATCH] CVE-2019-3824 ldb: Improve code style and layout in wildcard + processing + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13773 + +Signed-off-by: Andrew Bartlett +Reviewed-by: Gary Lockyer +--- + lib/ldb/common/ldb_match.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c +index 1920b661f75..ab0a89888f0 100644 +--- a/lib/ldb/common/ldb_match.c ++++ b/lib/ldb/common/ldb_match.c +@@ -333,9 +333,11 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, + + g = memmem(haystack, + haystacklen, +- (const uint8_t *)cnk.data, +- cnk.length); +- if (g) p = g; ++ (const uint8_t *)cnk.data, ++ cnk.length); ++ if (g) { ++ p = g; ++ } + } while(g); + } + val.length = val.length - (p - (uint8_t *)(val.data)) - cnk.length; +-- +2.24.0 diff --git a/0004-CVE-2019-3824.patch b/0004-CVE-2019-3824.patch new file mode 100644 index 0000000..85c1cfd --- /dev/null +++ b/0004-CVE-2019-3824.patch @@ -0,0 +1,32 @@ +From 8d34d172092f71baad0d777567e49aebfa07313d Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Tue, 19 Feb 2019 10:25:24 +1300 +Subject: [PATCH] CVE-2019-3824 ldb: ldb_parse_tree use talloc_zero + +Initialise the created ldb_parse_tree with talloc_zero, this ensures +that it is correctly initialised if inadvertently passed to a function +expecting a different operation type. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13773 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett +--- + lib/ldb/common/ldb_parse.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/ldb/common/ldb_parse.c b/lib/ldb/common/ldb_parse.c +index 5fa5a74afa9..db420091311 100644 +--- a/lib/ldb/common/ldb_parse.c ++++ b/lib/ldb/common/ldb_parse.c +@@ -389,7 +389,7 @@ static struct ldb_parse_tree *ldb_parse_simple(TALLOC_CTX *mem_ctx, const char * + struct ldb_parse_tree *ret; + enum ldb_parse_op filtertype; + +- ret = talloc(mem_ctx, struct ldb_parse_tree); ++ ret = talloc_zero(mem_ctx, struct ldb_parse_tree); + if (!ret) { + errno = ENOMEM; + return NULL; +-- +2.24.0 diff --git a/0005-CVE-2019-3824.patch b/0005-CVE-2019-3824.patch new file mode 100644 index 0000000..bb41724 --- /dev/null +++ b/0005-CVE-2019-3824.patch @@ -0,0 +1,38 @@ +From 34383981a0c40860f71a4451ff8fd752e1b67666 Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Tue, 19 Feb 2019 10:26:25 +1300 +Subject: [PATCH] CVE-2019-3824 ldb: wildcard_match check tree operation + +Check the operation type of the passed parse tree, and return +LDB_INAPPROPRIATE_MATCH if the operation is not LDB_OP_SUBSTRING. + +A query of "attribute=*" gets parsed as LDB_OP_PRESENT, checking the +operation and failing ldb_wildcard_match should help prevent confusion +writing tests. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13773 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett +--- + lib/ldb/common/ldb_match.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c +index ab0a89888f0..59f48b52b70 100644 +--- a/lib/ldb/common/ldb_match.c ++++ b/lib/ldb/common/ldb_match.c +@@ -244,6 +244,11 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, + uint8_t *save_p = NULL; + unsigned int c = 0; + ++ if (tree->operation != LDB_OP_SUBSTRING) { ++ *matched = false; ++ return LDB_ERR_INAPPROPRIATE_MATCHING; ++ } ++ + a = ldb_schema_attribute_by_name(ldb, tree->u.substring.attr); + if (!a) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; +-- +2.24.0 diff --git a/0006-CVE-2019-3824.patch b/0006-CVE-2019-3824.patch new file mode 100644 index 0000000..e6d651d --- /dev/null +++ b/0006-CVE-2019-3824.patch @@ -0,0 +1,34 @@ +From 42f0f57eb819ce6b68a8c5b3b53123b83ec917e3 Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Tue, 19 Feb 2019 10:26:56 +1300 +Subject: [PATCH] CVE-2019-3824 ldb: wildcard_match end of data check + +ldb_handler_copy and ldb_val_dup over allocate by one and add a trailing '\0' +to the data, to make them safe to use the C string functions on. + +However testing for the trailing '\0' is not the correct way to test for +the end of a value, the length should be checked instead. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13773 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett +--- + lib/ldb/common/ldb_match.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/ldb/common/ldb_match.c b/lib/ldb/common/ldb_match.c +index 59f48b52b70..829afa77e71 100644 +--- a/lib/ldb/common/ldb_match.c ++++ b/lib/ldb/common/ldb_match.c +@@ -353,7 +353,7 @@ static int ldb_wildcard_compare(struct ldb_context *ldb, + } + + /* last chunk may not have reached end of string */ +- if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto mismatch; ++ if ( (! tree->u.substring.end_with_wildcard) && (val.length != 0) ) goto mismatch; + talloc_free(save_p); + *matched = true; + return LDB_SUCCESS; +-- +2.24.0 diff --git a/0007-CVE-2019-3824.patch b/0007-CVE-2019-3824.patch new file mode 100644 index 0000000..80ac0fe --- /dev/null +++ b/0007-CVE-2019-3824.patch @@ -0,0 +1,270 @@ +From 45b75db50f5c1a7c8c38af59a62fccee5401c845 Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Tue, 19 Feb 2019 10:24:38 +1300 +Subject: [PATCH] CVE-2019-3824 ldb: Add tests for ldb_wildcard_match + +Add cmocka tests for ldb_wildcard_match. + +Running test_wildcard_match under valgrind reproduces + CVE-2019-3824 out of bounds read in wildcard compare (bug 13773) + + valgrind --suppressions=lib/ldb/tests/ldb_match_test.valgrind\ + bin/ldb_match_test + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13773 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett +--- + lib/ldb/tests/ldb_match_test.c | 191 ++++++++++++++++++++++++++ + lib/ldb/tests/ldb_match_test.valgrind | 16 +++ + lib/ldb/wscript | 8 +- + 3 files changed, 214 insertions(+), 1 deletion(-) + create mode 100644 lib/ldb/tests/ldb_match_test.c + create mode 100644 lib/ldb/tests/ldb_match_test.valgrind + +diff --git a/lib/ldb/tests/ldb_match_test.c b/lib/ldb/tests/ldb_match_test.c +new file mode 100644 +index 00000000000..e09f50c86ba +--- /dev/null ++++ b/lib/ldb/tests/ldb_match_test.c +@@ -0,0 +1,191 @@ ++/* ++ * Tests exercising the ldb match operations. ++ * ++ * ++ * Copyright (C) Catalyst.NET Ltd 2017 ++ * ++ * 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 "../common/ldb_match.c" ++ ++#include "../include/ldb.h" ++ ++struct ldbtest_ctx { ++ struct tevent_context *ev; ++ struct ldb_context *ldb; ++}; ++ ++static int ldb_test_canonicalise( ++ struct ldb_context *ldb, ++ void *mem_ctx, ++ const struct ldb_val *in, ++ struct ldb_val *out) ++{ ++ out->length = in->length; ++ out->data = in->data; ++ return 0; ++} ++ ++static int setup(void **state) ++{ ++ struct ldbtest_ctx *test_ctx; ++ struct ldb_schema_syntax *syntax = NULL; ++ int ret; ++ ++ 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); ++ ++ syntax = talloc_zero(test_ctx, struct ldb_schema_syntax); ++ assert_non_null(syntax); ++ syntax->canonicalise_fn = ldb_test_canonicalise; ++ ++ ret = ldb_schema_attribute_add_with_syntax( ++ test_ctx->ldb, "a", LDB_ATTR_FLAG_FIXED, syntax); ++ assert_int_equal(LDB_SUCCESS, ret); ++ ++ *state = test_ctx; ++ return 0; ++} ++ ++static int teardown(void **state) ++{ ++ talloc_free(*state); ++ return 0; ++} ++ ++ ++/* ++ * The wild card pattern "attribute=*" is parsed as an LDB_OP_PRESENT operation ++ * rather than a LDB_OP_???? ++ * ++ * This test serves to document that behaviour, and to confirm that ++ * ldb_wildcard_compare handles this case appropriately. ++ */ ++static void test_wildcard_match_star(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ bool matched = false; ++ int ret; ++ ++ uint8_t value[] = "The value.......end"; ++ struct ldb_val val = { ++ .data = value, ++ .length = (sizeof(value)) ++ }; ++ struct ldb_parse_tree *tree = ldb_parse_tree(ctx, "a=*"); ++ assert_non_null(tree); ++ ++ ret = ldb_wildcard_compare(ctx->ldb, tree, val, &matched); ++ assert_false(matched); ++ assert_int_equal(LDB_ERR_INAPPROPRIATE_MATCHING, ret); ++} ++ ++/* ++ * Test basic wild card matching ++ * ++ */ ++static void test_wildcard_match(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ bool matched = false; ++ ++ uint8_t value[] = "The value.......end"; ++ struct ldb_val val = { ++ .data = value, ++ .length = (sizeof(value)) ++ }; ++ struct ldb_parse_tree *tree = ldb_parse_tree(ctx, "objectClass=*end"); ++ assert_non_null(tree); ++ ++ ldb_wildcard_compare(ctx->ldb, tree, val, &matched); ++ assert_true(matched); ++} ++ ++ ++/* ++ * ldb_handler_copy and ldb_val_dup over allocate by one and add a trailing '\0' ++ * to the data, to make them safe to use the C string functions on. ++ * ++ * However testing for the trailing '\0' is not the correct way to test for ++ * the end of a value, the length should be checked instead. ++ */ ++static void test_wildcard_match_end_condition(void **state) ++{ ++ struct ldbtest_ctx *ctx = *state; ++ bool matched = false; ++ ++ uint8_t value[] = "hellomynameisbobx"; ++ struct ldb_val val = { ++ .data = talloc_memdup(NULL, value, sizeof(value)), ++ .length = (sizeof(value) - 2) ++ }; ++ struct ldb_parse_tree *tree = ldb_parse_tree(ctx, "a=*hello*mynameis*bob"); ++ assert_non_null(tree); ++ ++ ldb_wildcard_compare(ctx->ldb, tree, val, &matched); ++ assert_true(matched); ++} ++ ++/* ++ * Note: to run under valgrind use: ++ * valgrind \ ++ * --suppressions=lib/ldb/tests/ldb_match_test.valgrind \ ++ * bin/ldb_match_test ++ */ ++int main(int argc, const char **argv) ++{ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test_setup_teardown( ++ test_wildcard_match_star, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_wildcard_match, ++ setup, ++ teardown), ++ cmocka_unit_test_setup_teardown( ++ test_wildcard_match_end_condition, ++ setup, ++ teardown), ++ }; ++ ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} +diff --git a/lib/ldb/tests/ldb_match_test.valgrind b/lib/ldb/tests/ldb_match_test.valgrind +new file mode 100644 +index 00000000000..660bd5a6b46 +--- /dev/null ++++ b/lib/ldb/tests/ldb_match_test.valgrind +@@ -0,0 +1,16 @@ ++{ ++ Memory allocated in set-up ++ Memcheck:Leak ++ match-leak-kinds: possible ++ fun:malloc ++ ... ++ fun:setup ++} ++{ ++ Memory allocated by ldb_init ++ Memcheck:Leak ++ match-leak-kinds: possible ++ fun:malloc ++ ... ++ fun:ldb_init ++} +diff --git a/lib/ldb/wscript b/lib/ldb/wscript +index 6e224e7b4b7..5355585f69c 100644 +--- a/lib/ldb/wscript ++++ b/lib/ldb/wscript +@@ -500,6 +500,11 @@ def build(bld): + deps='cmocka ldb', + install=False) + ++ bld.SAMBA_BINARY('ldb_match_test', ++ source='tests/ldb_match_test.c', ++ deps='cmocka ldb', ++ install=False) ++ + if bld.CONFIG_SET('HAVE_LMDB'): + bld.SAMBA_BINARY('ldb_mdb_mod_op_test', + source='tests/ldb_mod_op_test.c', +@@ -567,7 +572,8 @@ def test(ctx): + # we don't want to run ldb_lmdb_size_test (which proves we can + # fit > 4G of data into the DB), it would fill up the disk on + # many of our test instances +- 'ldb_mdb_kv_ops_test'] ++ 'ldb_mdb_kv_ops_test', ++ 'ldb_match_test'] + + for test_exe in test_exes: + cmd = os.path.join(Utils.g_module.blddir, test_exe) diff --git a/CVE-2018-16852-1.patch b/CVE-2018-16852-1.patch new file mode 100644 index 0000000..fc2e900 --- /dev/null +++ b/CVE-2018-16852-1.patch @@ -0,0 +1,398 @@ +From f40e1b3b42ce23b574a4c530545ff8170ddc7330 Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Tue, 6 Nov 2018 12:10:07 +1300 +Subject: [PATCH 04/17] CVE-2018-16852 dcerpc dnsserver: Verification tests + +Tests to verify +Bug 13669 - (CVE-2018-16852) NULL + pointer de-reference in Samba AD DC DNS management + +The presence of the ZONE_MASTER_SERVERS property or the +ZONE_SCAVENGING_SERVERS property in a zone record causes the server to +follow a null pointer and terminate. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13669 + +Reviewed-by: Andrew Bartlett +Signed-off-by: Gary Lockyer +--- + selftest/knownfail.d/bug13669 | 4 + + .../tests/rpc_dns_server_dnsutils_test.c | 304 ++++++++++++++++++ + source4/rpc_server/wscript_build | 17 +- + source4/selftest/tests.py | 2 + + 4 files changed, 325 insertions(+), 2 deletions(-) + create mode 100644 selftest/knownfail.d/bug13669 + create mode 100644 source4/rpc_server/tests/rpc_dns_server_dnsutils_test.c + +diff --git a/selftest/knownfail.d/bug13669 b/selftest/knownfail.d/bug13669 +new file mode 100644 +index 00000000000..74c8c130674 +--- /dev/null ++++ b/selftest/knownfail.d/bug13669 +@@ -0,0 +1,4 @@ ++^samba4.dcerpc.dnsserver.dnsutils.test_dnsserver_init_zoneinfo_master_servers_empty ++^samba4.dcerpc.dnsserver.dnsutils.test_dnsserver_init_zoneinfo_master_servers ++^samba4.dcerpc.dnsserver.dnsutils.test_dnsserver_init_zoneinfo_scavenging_servers_empty ++^samba4.dcerpc.dnsserver.dnsutils.test_dnsserver_init_zoneinfo_scavenging_servers +diff --git a/source4/rpc_server/tests/rpc_dns_server_dnsutils_test.c b/source4/rpc_server/tests/rpc_dns_server_dnsutils_test.c +new file mode 100644 +index 00000000000..89721135658 +--- /dev/null ++++ b/source4/rpc_server/tests/rpc_dns_server_dnsutils_test.c +@@ -0,0 +1,304 @@ ++/* ++ * Unit tests for source4/rpc_server/dnsserver/dnsutils.c ++ * ++ * Copyright (C) Catalyst.NET Ltd 2018 ++ * ++ * 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 "../dnsserver/dnsutils.c" ++ ++ ++/* ++ * Test setting of an empty ZONE_MASTER_SERVERS property ++ */ ++static void test_dnsserver_init_zoneinfo_master_servers_empty(void **state) ++{ ++ struct dnsserver_zone *zone = NULL; ++ struct dnsserver_serverinfo *serverinfo = NULL; ++ struct dnsserver_zoneinfo *zoneinfo = NULL; ++ struct dnsp_DnsProperty *property = NULL; ++ ++ TALLOC_CTX *ctx = talloc_new(NULL); ++ ++ /* ++ * Setup the zone data ++ */ ++ zone = talloc_zero(ctx, struct dnsserver_zone); ++ assert_non_null(zone); ++ zone->name = "test"; ++ ++ /* ++ * Set up an empty ZONE_MASTER_SERVERS property ++ */ ++ property = talloc_zero_array(ctx, struct dnsp_DnsProperty, 1); ++ assert_non_null(property); ++ property->id = DSPROPERTY_ZONE_MASTER_SERVERS; ++ property->data.master_servers.addrCount = 0; ++ property->data.master_servers.addr = NULL; ++ ++ zone->tmp_props = property; ++ zone->num_props = 1; ++ ++ ++ /* ++ * Setup the server info ++ */ ++ serverinfo = talloc_zero(ctx, struct dnsserver_serverinfo); ++ assert_non_null(serverinfo); ++ ++ /* ++ * call dnsserver_init_zoneinfo ++ */ ++ zoneinfo = dnsserver_init_zoneinfo(zone, serverinfo); ++ ++ /* ++ * Check results ++ */ ++ assert_non_null(zoneinfo); ++ assert_non_null(zoneinfo->aipLocalMasters); ++ assert_int_equal(zoneinfo->aipLocalMasters->AddrCount, 0); ++ assert_null(zoneinfo->aipLocalMasters->AddrArray); ++ ++ TALLOC_FREE(ctx); ++} ++ ++/* ++ * Test setting of a non empty ZONE_MASTER_SERVERS property ++ */ ++static void test_dnsserver_init_zoneinfo_master_servers(void **state) ++{ ++ struct dnsserver_zone *zone = NULL; ++ struct dnsserver_serverinfo *serverinfo = NULL; ++ struct dnsserver_zoneinfo *zoneinfo = NULL; ++ struct dnsp_DnsProperty *property = NULL; ++ ++ TALLOC_CTX *ctx = talloc_new(NULL); ++ ++ /* ++ * Setup the zone data ++ */ ++ zone = talloc_zero(ctx, struct dnsserver_zone); ++ assert_non_null(zone); ++ zone->name = "test"; ++ ++ /* ++ * Set up an empty ZONE_MASTER_SERVERS property ++ */ ++ property = talloc_zero_array(ctx, struct dnsp_DnsProperty, 1); ++ assert_non_null(property); ++ property->id = DSPROPERTY_ZONE_MASTER_SERVERS; ++ property->data.master_servers.addrCount = 4; ++ property->data.master_servers.addr = ++ talloc_zero_array(ctx, uint32_t, 4); ++ property->data.master_servers.addr[0] = 1000; ++ property->data.master_servers.addr[1] = 1001; ++ property->data.master_servers.addr[2] = 1002; ++ property->data.master_servers.addr[3] = 1003; ++ ++ zone->tmp_props = property; ++ zone->num_props = 1; ++ ++ ++ /* ++ * Setup the server info ++ */ ++ serverinfo = talloc_zero(ctx, struct dnsserver_serverinfo); ++ assert_non_null(serverinfo); ++ ++ /* ++ * call dnsserver_init_zoneinfo ++ */ ++ zoneinfo = dnsserver_init_zoneinfo(zone, serverinfo); ++ ++ /* ++ * Check results ++ */ ++ assert_non_null(zoneinfo); ++ assert_non_null(zoneinfo->aipLocalMasters); ++ assert_int_equal(zoneinfo->aipLocalMasters->AddrCount, 4); ++ assert_non_null(zoneinfo->aipLocalMasters->AddrArray); ++ assert_int_equal(zoneinfo->aipLocalMasters->AddrArray[0], 1000); ++ assert_int_equal(zoneinfo->aipLocalMasters->AddrArray[1], 1001); ++ assert_int_equal(zoneinfo->aipLocalMasters->AddrArray[2], 1002); ++ assert_int_equal(zoneinfo->aipLocalMasters->AddrArray[3], 1003); ++ ++ /* ++ * Ensure that we're working with a copy of the property data ++ * and not a reference. ++ * The pointers should be different, and we should be able to change ++ * the values in the property without affecting the zoneinfo data ++ */ ++ assert_true(zoneinfo->aipLocalMasters->AddrArray != ++ property->data.master_servers.addr); ++ property->data.master_servers.addr[0] = 0; ++ property->data.master_servers.addr[1] = 1; ++ property->data.master_servers.addr[2] = 2; ++ property->data.master_servers.addr[3] = 3; ++ assert_int_equal(zoneinfo->aipLocalMasters->AddrArray[0], 1000); ++ assert_int_equal(zoneinfo->aipLocalMasters->AddrArray[1], 1001); ++ assert_int_equal(zoneinfo->aipLocalMasters->AddrArray[2], 1002); ++ assert_int_equal(zoneinfo->aipLocalMasters->AddrArray[3], 1003); ++ ++ TALLOC_FREE(ctx); ++} ++ ++/* ++ * Test setting of an empty ZONE_SCAVENGING_SERVERS property ++ */ ++static void test_dnsserver_init_zoneinfo_scavenging_servers_empty(void **state) ++{ ++ struct dnsserver_zone *zone = NULL; ++ struct dnsserver_serverinfo *serverinfo = NULL; ++ struct dnsserver_zoneinfo *zoneinfo = NULL; ++ struct dnsp_DnsProperty *property = NULL; ++ ++ TALLOC_CTX *ctx = talloc_new(NULL); ++ ++ /* ++ * Setup the zone data ++ */ ++ zone = talloc_zero(ctx, struct dnsserver_zone); ++ assert_non_null(zone); ++ zone->name = "test"; ++ ++ property = talloc_zero_array(ctx, struct dnsp_DnsProperty, 1); ++ assert_non_null(property); ++ property->id = DSPROPERTY_ZONE_SCAVENGING_SERVERS; ++ property->data.servers.addrCount = 0; ++ property->data.servers.addr = NULL; ++ ++ zone->tmp_props = property; ++ zone->num_props = 1; ++ ++ ++ serverinfo = talloc_zero(ctx, struct dnsserver_serverinfo); ++ assert_non_null(serverinfo); ++ ++ zoneinfo = dnsserver_init_zoneinfo(zone, serverinfo); ++ ++ assert_non_null(zoneinfo); ++ assert_non_null(zoneinfo->aipScavengeServers); ++ assert_int_equal(zoneinfo->aipScavengeServers->AddrCount, 0); ++ assert_null(zoneinfo->aipScavengeServers->AddrArray); ++ ++ TALLOC_FREE(ctx); ++} ++ ++/* ++ * Test setting of a non empty ZONE_SCAVENGING_SERVERS property ++ */ ++static void test_dnsserver_init_zoneinfo_scavenging_servers(void **state) ++{ ++ struct dnsserver_zone *zone = NULL; ++ struct dnsserver_serverinfo *serverinfo = NULL; ++ struct dnsserver_zoneinfo *zoneinfo = NULL; ++ struct dnsp_DnsProperty *property = NULL; ++ ++ TALLOC_CTX *ctx = talloc_new(NULL); ++ ++ /* ++ * Setup the zone data ++ */ ++ zone = talloc_zero(ctx, struct dnsserver_zone); ++ assert_non_null(zone); ++ zone->name = "test"; ++ ++ property = talloc_zero_array(ctx, struct dnsp_DnsProperty, 1); ++ assert_non_null(property); ++ property->id = DSPROPERTY_ZONE_SCAVENGING_SERVERS; ++ property->data.servers.addrCount = 4; ++ property->data.servers.addr = talloc_zero_array(ctx, uint32_t, 4); ++ property->data.servers.addr[0] = 1000; ++ property->data.servers.addr[1] = 1001; ++ property->data.servers.addr[2] = 1002; ++ property->data.servers.addr[3] = 1003; ++ ++ zone->tmp_props = property; ++ zone->num_props = 1; ++ ++ ++ serverinfo = talloc_zero(ctx, struct dnsserver_serverinfo); ++ assert_non_null(serverinfo); ++ ++ zoneinfo = dnsserver_init_zoneinfo(zone, serverinfo); ++ ++ assert_non_null(zoneinfo); ++ assert_non_null(zoneinfo->aipScavengeServers); ++ assert_int_equal(zoneinfo->aipScavengeServers->AddrCount, 4); ++ assert_non_null(zoneinfo->aipScavengeServers->AddrArray); ++ assert_non_null(zoneinfo->aipScavengeServers->AddrArray); ++ assert_int_equal(zoneinfo->aipScavengeServers->AddrArray[0], 1000); ++ assert_int_equal(zoneinfo->aipScavengeServers->AddrArray[1], 1001); ++ assert_int_equal(zoneinfo->aipScavengeServers->AddrArray[2], 1002); ++ assert_int_equal(zoneinfo->aipScavengeServers->AddrArray[3], 1003); ++ ++ /* ++ * Ensure that we're working with a copy of the property data ++ * and not a reference. ++ * The pointers should be different, and we should be able to change ++ * the values in the property without affecting the zoneinfo data ++ */ ++ assert_true(zoneinfo->aipScavengeServers->AddrArray != ++ property->data.servers.addr); ++ property->data.servers.addr[0] = 0; ++ property->data.servers.addr[1] = 1; ++ property->data.servers.addr[2] = 2; ++ property->data.servers.addr[3] = 3; ++ assert_int_equal(zoneinfo->aipScavengeServers->AddrArray[0], 1000); ++ assert_int_equal(zoneinfo->aipScavengeServers->AddrArray[1], 1001); ++ assert_int_equal(zoneinfo->aipScavengeServers->AddrArray[2], 1002); ++ assert_int_equal(zoneinfo->aipScavengeServers->AddrArray[3], 1003); ++ ++ ++ TALLOC_FREE(ctx); ++} ++int main(int argc, const char **argv) ++{ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test( ++ test_dnsserver_init_zoneinfo_master_servers_empty), ++ cmocka_unit_test( ++ test_dnsserver_init_zoneinfo_master_servers), ++ cmocka_unit_test( ++ test_dnsserver_init_zoneinfo_scavenging_servers_empty), ++ cmocka_unit_test( ++ test_dnsserver_init_zoneinfo_scavenging_servers), ++ }; ++ ++ cmocka_set_message_output(CM_OUTPUT_SUBUNIT); ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} +diff --git a/source4/rpc_server/wscript_build b/source4/rpc_server/wscript_build +index 8e05eb8a0c3..14b68c7ce0f 100644 +--- a/source4/rpc_server/wscript_build ++++ b/source4/rpc_server/wscript_build +@@ -3,7 +3,7 @@ + bld.SAMBA_SUBSYSTEM('DCERPC_SHARE', + source='common/share_info.c', + autoproto='common/share.h', +- deps='ldb', ++ deps='ldb share', + enabled=bld.CONFIG_SET('WITH_NTVFS_FILESERVER'), + ) + +@@ -163,7 +163,7 @@ bld.SAMBA_MODULE('dcerpc_dnsserver', + source='dnsserver/dcerpc_dnsserver.c dnsserver/dnsutils.c dnsserver/dnsdata.c dnsserver/dnsdb.c', + subsystem='dcerpc_server', + init_function='dcerpc_server_dnsserver_init', +- deps='DCERPC_COMMON dnsserver_common' ++ deps='DCERPC_COMMON dnsserver_common netif' + ) + + +@@ -176,3 +176,16 @@ bld.SAMBA_MODULE('service_dcerpc', + deps='dcerpc_server' + ) + ++if bld.CONFIG_GET('ENABLE_SELFTEST'): ++ bld.SAMBA_BINARY( ++ 'test_rpc_dns_server_dnsutils', ++ source='tests/rpc_dns_server_dnsutils_test.c', ++ deps=''' ++ dnsserver_common ++ DCERPC_COMMON ++ cmocka ++ talloc ++ ''', ++ install=False, ++ enabled=bld.AD_DC_BUILD_IS_ENABLED() ++ ) +diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py +index 9dec0adb05c..18b2c1162b0 100755 +--- a/source4/selftest/tests.py ++++ b/source4/selftest/tests.py +@@ -1164,3 +1164,5 @@ plantestsuite("samba4.dsdb.samdb.ldb_modules.audit_util", "none", + [os.path.join(bindir(), "test_audit_util")]) + plantestsuite("samba4.dsdb.samdb.ldb_modules.audit_log", "none", + [os.path.join(bindir(), "test_audit_log")]) ++plantestsuite("samba4.dcerpc.dnsserver.dnsutils", "none", ++ [os.path.join(bindir(), "test_rpc_dns_server_dnsutils")]) +-- +2.17.1 + diff --git a/CVE-2018-16852-2.patch b/CVE-2018-16852-2.patch new file mode 100644 index 0000000..a459a4b --- /dev/null +++ b/CVE-2018-16852-2.patch @@ -0,0 +1,124 @@ +From 05f867db81f118215445f2c49eda4b9c3451d14a Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Tue, 6 Nov 2018 12:16:30 +1300 +Subject: [PATCH 05/17] CVE-2018-16852 dcerpc dnsserver: Ensure properties are + handled correctly + +Fixes for +Bug 13669 - (CVE-2018-16852) NULL + pointer de-reference in Samba AD DC DNS management + +The presence of the ZONE_MASTER_SERVERS property or the +ZONE_SCAVENGING_SERVERS property in a zone record causes the server to +follow a null pointer and terminate. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13669 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett +--- + selftest/knownfail.d/bug13669 | 4 -- + source4/rpc_server/dnsserver/dnsutils.c | 64 +++++++++++++++++++++---- + 2 files changed, 56 insertions(+), 12 deletions(-) + delete mode 100644 selftest/knownfail.d/bug13669 + +diff --git a/selftest/knownfail.d/bug13669 b/selftest/knownfail.d/bug13669 +deleted file mode 100644 +index 74c8c130674..00000000000 +--- a/selftest/knownfail.d/bug13669 ++++ /dev/null +@@ -1,4 +0,0 @@ +-^samba4.dcerpc.dnsserver.dnsutils.test_dnsserver_init_zoneinfo_master_servers_empty +-^samba4.dcerpc.dnsserver.dnsutils.test_dnsserver_init_zoneinfo_master_servers +-^samba4.dcerpc.dnsserver.dnsutils.test_dnsserver_init_zoneinfo_scavenging_servers_empty +-^samba4.dcerpc.dnsserver.dnsutils.test_dnsserver_init_zoneinfo_scavenging_servers +diff --git a/source4/rpc_server/dnsserver/dnsutils.c b/source4/rpc_server/dnsserver/dnsutils.c +index a1c749074af..e4055c99e74 100644 +--- a/source4/rpc_server/dnsserver/dnsutils.c ++++ b/source4/rpc_server/dnsserver/dnsutils.c +@@ -209,6 +209,46 @@ struct dnsserver_serverinfo *dnsserver_init_serverinfo(TALLOC_CTX *mem_ctx, + } + + ++/* ++ * Helper function to copy a dnsp_ip4_array struct to an IP4_ARRAY struct. ++ * The new structure and it's data are allocated on the supplied talloc context ++ */ ++static struct IP4_ARRAY *copy_ip4_array( ++ TALLOC_CTX *ctx, ++ const char *name, ++ struct dnsp_ip4_array array) { ++ ++ struct IP4_ARRAY *ip4_array = NULL; ++ unsigned int i; ++ ++ ip4_array = talloc_zero(ctx, struct IP4_ARRAY); ++ if (ip4_array == NULL) { ++ DBG_ERR("Out of memory copying property [%s]\n", ++ name); ++ return NULL; ++ } ++ ++ ip4_array->AddrCount = array.addrCount; ++ if (ip4_array->AddrCount == 0) { ++ return ip4_array; ++ } ++ ++ ip4_array->AddrArray = talloc_array(ip4_array, uint32_t, ++ ip4_array->AddrCount); ++ if (ip4_array->AddrArray == NULL) { ++ TALLOC_FREE(ip4_array); ++ DBG_ERR("Out of memory copying property [%s] values\n", ++ name); ++ return NULL; ++ } ++ ++ for (i = 0; i < ip4_array->AddrCount; i++) { ++ ip4_array->AddrArray[i] = array.addr[i]; ++ } ++ ++ return ip4_array; ++} ++ + struct dnsserver_zoneinfo *dnsserver_init_zoneinfo(struct dnsserver_zone *zone, + struct dnsserver_serverinfo *serverinfo) + { +@@ -309,20 +349,28 @@ struct dnsserver_zoneinfo *dnsserver_init_zoneinfo(struct dnsserver_zone *zone, + prop->aging_enabled; + break; + case DSPROPERTY_ZONE_SCAVENGING_SERVERS: +- zoneinfo->aipScavengeServers->AddrCount = +- prop->servers.addrCount; +- zoneinfo->aipScavengeServers->AddrArray = +- prop->servers.addr; ++ zoneinfo->aipScavengeServers = ++ copy_ip4_array(zoneinfo, ++ "ZONE_SCAVENGING_SERVERS", ++ prop->servers); ++ if (zoneinfo->aipScavengeServers == NULL) { ++ TALLOC_FREE(zoneinfo); ++ return NULL; ++ } + break; + case DSPROPERTY_ZONE_AGING_ENABLED_TIME: + zoneinfo->dwAvailForScavengeTime = + prop->next_scavenging_cycle_hours; + break; + case DSPROPERTY_ZONE_MASTER_SERVERS: +- zoneinfo->aipLocalMasters->AddrCount = +- prop->master_servers.addrCount; +- zoneinfo->aipLocalMasters->AddrArray = +- prop->master_servers.addr; ++ zoneinfo->aipLocalMasters = ++ copy_ip4_array(zoneinfo, ++ "ZONE_MASTER_SERVERS", ++ prop->master_servers); ++ if (zoneinfo->aipLocalMasters == NULL) { ++ TALLOC_FREE(zoneinfo); ++ return NULL; ++ } + break; + case DSPROPERTY_ZONE_EMPTY: + case DSPROPERTY_ZONE_SECURE_TIME: +-- +2.17.1 diff --git a/CVE-2018-16852-3.patch b/CVE-2018-16852-3.patch new file mode 100644 index 0000000..b5c89af --- /dev/null +++ b/CVE-2018-16852-3.patch @@ -0,0 +1,328 @@ +From c78ca8b9b48a19e71f4d6ddd2e300f282fb0b247 Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Wed, 7 Nov 2018 15:08:04 +1300 +Subject: [PATCH 06/17] CVE-2018-16852 dcerpc dnsserver: refactor common + properties handling + +dnsserver_common.c and dnsutils.c both share similar code to process +zone properties. This patch extracts the common code and moves it to +dnsserver_common.c. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13669 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett +--- + source4/dns_server/dnsserver_common.c | 129 +++++++++++++++++------- + source4/dns_server/dnsserver_common.h | 3 + + source4/rpc_server/dnsserver/dnsutils.c | 107 ++------------------ + 3 files changed, 104 insertions(+), 135 deletions(-) + +diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c +index bbbfe920f4e..cc24a6c1b52 100644 +--- a/source4/dns_server/dnsserver_common.c ++++ b/source4/dns_server/dnsserver_common.c +@@ -742,6 +742,94 @@ bool dns_name_is_static(struct dnsp_DnssrvRpcRecord *records, + return false; + } + ++/* ++ * Helper function to copy a dnsp_ip4_array struct to an IP4_ARRAY struct. ++ * The new structure and it's data are allocated on the supplied talloc context ++ */ ++static struct IP4_ARRAY *copy_ip4_array(TALLOC_CTX *ctx, ++ const char *name, ++ struct dnsp_ip4_array array) ++{ ++ ++ struct IP4_ARRAY *ip4_array = NULL; ++ unsigned int i; ++ ++ ip4_array = talloc_zero(ctx, struct IP4_ARRAY); ++ if (ip4_array == NULL) { ++ DBG_ERR("Out of memory copying property [%s]\n", name); ++ return NULL; ++ } ++ ++ ip4_array->AddrCount = array.addrCount; ++ if (ip4_array->AddrCount == 0) { ++ return ip4_array; ++ } ++ ++ ip4_array->AddrArray = ++ talloc_array(ip4_array, uint32_t, ip4_array->AddrCount); ++ if (ip4_array->AddrArray == NULL) { ++ TALLOC_FREE(ip4_array); ++ DBG_ERR("Out of memory copying property [%s] values\n", name); ++ return NULL; ++ } ++ ++ for (i = 0; i < ip4_array->AddrCount; i++) { ++ ip4_array->AddrArray[i] = array.addr[i]; ++ } ++ ++ return ip4_array; ++} ++ ++bool dns_zoneinfo_load_zone_property(struct dnsserver_zoneinfo *zoneinfo, ++ struct dnsp_DnsProperty *prop) ++{ ++ switch (prop->id) { ++ case DSPROPERTY_ZONE_TYPE: ++ zoneinfo->dwZoneType = prop->data.zone_type; ++ break; ++ case DSPROPERTY_ZONE_ALLOW_UPDATE: ++ zoneinfo->fAllowUpdate = prop->data.allow_update_flag; ++ break; ++ case DSPROPERTY_ZONE_NOREFRESH_INTERVAL: ++ zoneinfo->dwNoRefreshInterval = prop->data.norefresh_hours; ++ break; ++ case DSPROPERTY_ZONE_REFRESH_INTERVAL: ++ zoneinfo->dwRefreshInterval = prop->data.refresh_hours; ++ break; ++ case DSPROPERTY_ZONE_AGING_STATE: ++ zoneinfo->fAging = prop->data.aging_enabled; ++ break; ++ case DSPROPERTY_ZONE_SCAVENGING_SERVERS: ++ zoneinfo->aipScavengeServers = copy_ip4_array( ++ zoneinfo, "ZONE_SCAVENGING_SERVERS", prop->data.servers); ++ if (zoneinfo->aipScavengeServers == NULL) { ++ return false; ++ } ++ break; ++ case DSPROPERTY_ZONE_AGING_ENABLED_TIME: ++ zoneinfo->dwAvailForScavengeTime = ++ prop->data.next_scavenging_cycle_hours; ++ break; ++ case DSPROPERTY_ZONE_MASTER_SERVERS: ++ zoneinfo->aipLocalMasters = copy_ip4_array( ++ zoneinfo, "ZONE_MASTER_SERVERS", prop->data.master_servers); ++ if (zoneinfo->aipLocalMasters == NULL) { ++ return false; ++ } ++ break; ++ case DSPROPERTY_ZONE_EMPTY: ++ case DSPROPERTY_ZONE_SECURE_TIME: ++ case DSPROPERTY_ZONE_DELETED_FROM_HOSTNAME: ++ case DSPROPERTY_ZONE_AUTO_NS_SERVERS: ++ case DSPROPERTY_ZONE_DCPROMO_CONVERT: ++ case DSPROPERTY_ZONE_SCAVENGING_SERVERS_DA: ++ case DSPROPERTY_ZONE_MASTER_SERVERS_DA: ++ case DSPROPERTY_ZONE_NS_SERVERS_DA: ++ case DSPROPERTY_ZONE_NODE_DBFLAGS: ++ break; ++ } ++ return true; ++} + WERROR dns_get_zone_properties(struct ldb_context *samdb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *zone_dn, +@@ -774,6 +862,7 @@ WERROR dns_get_zone_properties(struct ldb_context *samdb, + } + + for (i = 0; i < element->num_values; i++) { ++ bool valid_property; + prop = talloc_zero(mem_ctx, struct dnsp_DnsProperty); + if (prop == NULL) { + return WERR_NOT_ENOUGH_MEMORY; +@@ -787,42 +876,10 @@ WERROR dns_get_zone_properties(struct ldb_context *samdb, + return DNS_ERR(SERVER_FAILURE); + } + +- switch (prop->id) { +- case DSPROPERTY_ZONE_AGING_STATE: +- zoneinfo->fAging = prop->data.aging_enabled; +- break; +- case DSPROPERTY_ZONE_NOREFRESH_INTERVAL: +- zoneinfo->dwNoRefreshInterval = +- prop->data.norefresh_hours; +- break; +- case DSPROPERTY_ZONE_REFRESH_INTERVAL: +- zoneinfo->dwRefreshInterval = prop->data.refresh_hours; +- break; +- case DSPROPERTY_ZONE_ALLOW_UPDATE: +- zoneinfo->fAllowUpdate = prop->data.allow_update_flag; +- break; +- case DSPROPERTY_ZONE_AGING_ENABLED_TIME: +- zoneinfo->dwAvailForScavengeTime = +- prop->data.next_scavenging_cycle_hours; +- break; +- case DSPROPERTY_ZONE_SCAVENGING_SERVERS: +- zoneinfo->aipScavengeServers->AddrCount = +- prop->data.servers.addrCount; +- zoneinfo->aipScavengeServers->AddrArray = +- prop->data.servers.addr; +- break; +- case DSPROPERTY_ZONE_EMPTY: +- case DSPROPERTY_ZONE_TYPE: +- case DSPROPERTY_ZONE_SECURE_TIME: +- case DSPROPERTY_ZONE_DELETED_FROM_HOSTNAME: +- case DSPROPERTY_ZONE_MASTER_SERVERS: +- case DSPROPERTY_ZONE_AUTO_NS_SERVERS: +- case DSPROPERTY_ZONE_DCPROMO_CONVERT: +- case DSPROPERTY_ZONE_SCAVENGING_SERVERS_DA: +- case DSPROPERTY_ZONE_MASTER_SERVERS_DA: +- case DSPROPERTY_ZONE_NS_SERVERS_DA: +- case DSPROPERTY_ZONE_NODE_DBFLAGS: +- break; ++ valid_property = ++ dns_zoneinfo_load_zone_property(zoneinfo, prop); ++ if (!valid_property) { ++ return DNS_ERR(SERVER_FAILURE); + } + } + +diff --git a/source4/dns_server/dnsserver_common.h b/source4/dns_server/dnsserver_common.h +index 380f61b8dbc..60ecde4fa91 100644 +--- a/source4/dns_server/dnsserver_common.h ++++ b/source4/dns_server/dnsserver_common.h +@@ -87,4 +87,7 @@ NTSTATUS dns_common_zones(struct ldb_context *samdb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *base_dn, + struct dns_server_zone **zones_ret); ++ ++bool dns_zoneinfo_load_zone_property(struct dnsserver_zoneinfo *zoneinfo, ++ struct dnsp_DnsProperty *prop); + #endif /* __DNSSERVER_COMMON_H__ */ +diff --git a/source4/rpc_server/dnsserver/dnsutils.c b/source4/rpc_server/dnsserver/dnsutils.c +index e4055c99e74..bb52a1797a9 100644 +--- a/source4/rpc_server/dnsserver/dnsutils.c ++++ b/source4/rpc_server/dnsserver/dnsutils.c +@@ -25,6 +25,7 @@ + #include "dsdb/samdb/samdb.h" + #include "lib/socket/netif.h" + #include "lib/util/util_net.h" ++#include "dnsserver_common.h" + + static struct DNS_ADDR_ARRAY *fill_dns_addr_array(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, +@@ -208,47 +209,6 @@ struct dnsserver_serverinfo *dnsserver_init_serverinfo(TALLOC_CTX *mem_ctx, + return serverinfo; + } + +- +-/* +- * Helper function to copy a dnsp_ip4_array struct to an IP4_ARRAY struct. +- * The new structure and it's data are allocated on the supplied talloc context +- */ +-static struct IP4_ARRAY *copy_ip4_array( +- TALLOC_CTX *ctx, +- const char *name, +- struct dnsp_ip4_array array) { +- +- struct IP4_ARRAY *ip4_array = NULL; +- unsigned int i; +- +- ip4_array = talloc_zero(ctx, struct IP4_ARRAY); +- if (ip4_array == NULL) { +- DBG_ERR("Out of memory copying property [%s]\n", +- name); +- return NULL; +- } +- +- ip4_array->AddrCount = array.addrCount; +- if (ip4_array->AddrCount == 0) { +- return ip4_array; +- } +- +- ip4_array->AddrArray = talloc_array(ip4_array, uint32_t, +- ip4_array->AddrCount); +- if (ip4_array->AddrArray == NULL) { +- TALLOC_FREE(ip4_array); +- DBG_ERR("Out of memory copying property [%s] values\n", +- name); +- return NULL; +- } +- +- for (i = 0; i < ip4_array->AddrCount; i++) { +- ip4_array->AddrArray[i] = array.addr[i]; +- } +- +- return ip4_array; +-} +- + struct dnsserver_zoneinfo *dnsserver_init_zoneinfo(struct dnsserver_zone *zone, + struct dnsserver_serverinfo *serverinfo) + { +@@ -257,8 +217,7 @@ struct dnsserver_zoneinfo *dnsserver_init_zoneinfo(struct dnsserver_zone *zone, + const char *revzone = "in-addr.arpa"; + const char *revzone6 = "ip6.arpa"; + int len1, len2; +- union dnsPropertyData *prop = NULL; +- int i=0; ++ unsigned int i = 0; + + zoneinfo = talloc_zero(zone, struct dnsserver_zoneinfo); + if (zoneinfo == NULL) { +@@ -326,62 +285,12 @@ struct dnsserver_zoneinfo *dnsserver_init_zoneinfo(struct dnsserver_zone *zone, + zoneinfo->dwLastXfrResult = 0; + + for(i=0; inum_props; i++){ +- prop=&(zone->tmp_props[i].data); +- switch (zone->tmp_props[i].id) { +- case DSPROPERTY_ZONE_TYPE: +- zoneinfo->dwZoneType = +- prop->zone_type; +- break; +- case DSPROPERTY_ZONE_ALLOW_UPDATE: +- zoneinfo->fAllowUpdate = +- prop->allow_update_flag; +- break; +- case DSPROPERTY_ZONE_NOREFRESH_INTERVAL: +- zoneinfo->dwNoRefreshInterval = +- prop->norefresh_hours; +- break; +- case DSPROPERTY_ZONE_REFRESH_INTERVAL: +- zoneinfo->dwRefreshInterval = +- prop->refresh_hours; +- break; +- case DSPROPERTY_ZONE_AGING_STATE: +- zoneinfo->fAging = +- prop->aging_enabled; +- break; +- case DSPROPERTY_ZONE_SCAVENGING_SERVERS: +- zoneinfo->aipScavengeServers = +- copy_ip4_array(zoneinfo, +- "ZONE_SCAVENGING_SERVERS", +- prop->servers); +- if (zoneinfo->aipScavengeServers == NULL) { +- TALLOC_FREE(zoneinfo); +- return NULL; +- } +- break; +- case DSPROPERTY_ZONE_AGING_ENABLED_TIME: +- zoneinfo->dwAvailForScavengeTime = +- prop->next_scavenging_cycle_hours; +- break; +- case DSPROPERTY_ZONE_MASTER_SERVERS: +- zoneinfo->aipLocalMasters = +- copy_ip4_array(zoneinfo, +- "ZONE_MASTER_SERVERS", +- prop->master_servers); +- if (zoneinfo->aipLocalMasters == NULL) { +- TALLOC_FREE(zoneinfo); +- return NULL; +- } +- break; +- case DSPROPERTY_ZONE_EMPTY: +- case DSPROPERTY_ZONE_SECURE_TIME: +- case DSPROPERTY_ZONE_DELETED_FROM_HOSTNAME: +- case DSPROPERTY_ZONE_AUTO_NS_SERVERS: +- case DSPROPERTY_ZONE_DCPROMO_CONVERT: +- case DSPROPERTY_ZONE_SCAVENGING_SERVERS_DA: +- case DSPROPERTY_ZONE_MASTER_SERVERS_DA: +- case DSPROPERTY_ZONE_NS_SERVERS_DA: +- case DSPROPERTY_ZONE_NODE_DBFLAGS: +- break; ++ bool valid_property; ++ valid_property = dns_zoneinfo_load_zone_property( ++ zoneinfo, &zone->tmp_props[i]); ++ if (!valid_property) { ++ TALLOC_FREE(zoneinfo); ++ return NULL; + } + } + +-- +2.17.1 + diff --git a/CVE-2018-16857-1.patch b/CVE-2018-16857-1.patch new file mode 100644 index 0000000..8b2ad3a --- /dev/null +++ b/CVE-2018-16857-1.patch @@ -0,0 +1,68 @@ +From 862d4909eccd18942e3de8e8b0dc6e1594ec27f1 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Sun, 2 Sep 2018 17:34:03 +1200 +Subject: [PATCH 09/17] CVE-2018-16857 selftest: Prepare to allow override of + lockout duration in password_lockout tests + +This will make it easier to avoid flapping tests. + +Signed-off-by: Andrew Bartlett +Reviewed-by: Gary Lockyer +(cherry picked from commit a740a6131c967f9640b19a6964fd5d6f85ce853a) + +Backported as a dependency for: +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13683 +--- + source4/dsdb/tests/python/password_lockout.py | 9 ++++----- + source4/dsdb/tests/python/password_lockout_base.py | 11 +++++++++-- + 2 files changed, 13 insertions(+), 7 deletions(-) + +diff --git a/source4/dsdb/tests/python/password_lockout.py b/source4/dsdb/tests/python/password_lockout.py +index ec6cf13fe66..e817e656a2a 100755 +--- a/source4/dsdb/tests/python/password_lockout.py ++++ b/source4/dsdb/tests/python/password_lockout.py +@@ -616,15 +616,14 @@ userPassword: thatsAcomplPASS2XYZ + initial_lastlogon_relation='greater') + + def use_pso_lockout_settings(self, creds): ++ + # create a PSO with the lockout settings the test cases normally expect ++ # ++ # Some test cases sleep() for self.account_lockout_duration + pso = PasswordSettings("lockout-PSO", self.ldb, lockout_attempts=3, +- lockout_duration=3) ++ lockout_duration=self.account_lockout_duration) + self.addCleanup(self.ldb.delete, pso.dn) + +- # the test cases should sleep() for the PSO's lockoutDuration/obsvWindow +- self.account_lockout_duration = 3 +- self.lockout_observation_window = 3 +- + userdn = "cn=%s,cn=users,%s" % (creds.get_username(), self.base_dn) + pso.apply_to(userdn) + +diff --git a/source4/dsdb/tests/python/password_lockout_base.py b/source4/dsdb/tests/python/password_lockout_base.py +index 4a320684702..9d82e088bb8 100644 +--- a/source4/dsdb/tests/python/password_lockout_base.py ++++ b/source4/dsdb/tests/python/password_lockout_base.py +@@ -323,8 +323,15 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + """) + + self.base_dn = self.ldb.domain_dn() +- self.account_lockout_duration = 3 +- self.lockout_observation_window = 3 ++ ++ # ++ # Some test cases sleep() for self.account_lockout_duration ++ # so allow it to be controlled via the subclass ++ # ++ if not hasattr(self, 'account_lockout_duration'): ++ self.account_lockout_duration = 3 ++ if not hasattr(self, 'lockout_observation_window'): ++ self.lockout_observation_window = 3 + self.update_lockout_settings(threshold=3, + duration=self.account_lockout_duration, + observation_window=self.lockout_observation_window) +-- +2.17.1 + diff --git a/CVE-2018-16857-2.patch b/CVE-2018-16857-2.patch new file mode 100644 index 0000000..856562b --- /dev/null +++ b/CVE-2018-16857-2.patch @@ -0,0 +1,31 @@ +From 31198d39a76474d55c3d391e04d76758ee115d8e Mon Sep 17 00:00:00 2001 +From: Joe Guo +Date: Mon, 30 Jul 2018 18:21:29 +1200 +Subject: [PATCH 10/17] CVE-2018-16857 PEP8: fix E305: expected 2 blank lines + after class or function definition, found 1 + +Signed-off-by: Joe Guo +Reviewed-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +Partial backport of commit 115f2a71b88 (only password_lockout.py +change) as a dependency for: +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13683 +--- + source4/dsdb/tests/python/password_lockout.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/source4/dsdb/tests/python/password_lockout.py b/source4/dsdb/tests/python/password_lockout.py +index e817e656a2a..d8710866f39 100755 +--- a/source4/dsdb/tests/python/password_lockout.py ++++ b/source4/dsdb/tests/python/password_lockout.py +@@ -1400,6 +1400,7 @@ userPassword: """ + userpass + """ + self._test_samr_password_change(self.lockout1ntlm_creds, + other_creds=self.lockout2ntlm_creds) + ++ + host_url = "ldap://%s" % host + + TestProgram(module=__name__, opts=subunitopts) +-- +2.17.1 diff --git a/CVE-2018-16857-3.patch b/CVE-2018-16857-3.patch new file mode 100644 index 0000000..8f95ee9 --- /dev/null +++ b/CVE-2018-16857-3.patch @@ -0,0 +1,366 @@ +From 4d0fd1a421ad4a3ca19ed954ee91fcc36413b017 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Sun, 2 Sep 2018 18:03:06 +1200 +Subject: [PATCH 11/17] CVE-2018-16857 selftest: Split up password_lockout into + tests with and without a call to sleep() + +This means we can have a long observation window for many of the tests and +so make them much more reliable. Many of these cause frustrating flapping +failures in our CI systems. + +Signed-off-by: Andrew Bartlett +Reviewed-by: Gary Lockyer + +Autobuild-User(master): Andrew Bartlett +Autobuild-Date(master): Mon Sep 3 06:14:55 CEST 2018 on sn-devel-144 + +(cherry picked from commit 74357bf347348d3a8b7483c58e5250e98f7e8810) +Backported as a dependency for: +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13683 +--- + source4/dsdb/tests/python/password_lockout.py | 299 +++++++++--------- + 1 file changed, 157 insertions(+), 142 deletions(-) + +diff --git a/source4/dsdb/tests/python/password_lockout.py b/source4/dsdb/tests/python/password_lockout.py +index d8710866f39..0022dee21ba 100755 +--- a/source4/dsdb/tests/python/password_lockout.py ++++ b/source4/dsdb/tests/python/password_lockout.py +@@ -88,6 +88,42 @@ class PasswordTests(password_lockout_base.BasePasswordTestCase): + self.lockout2ntlm_ldb = self._readd_user(self.lockout2ntlm_creds, + lockOutObservationWindow=self.lockout_observation_window) + ++ ++ def use_pso_lockout_settings(self, creds): ++ ++ # create a PSO with the lockout settings the test cases normally expect ++ # ++ # Some test cases sleep() for self.account_lockout_duration ++ pso = PasswordSettings("lockout-PSO", self.ldb, lockout_attempts=3, ++ lockout_duration=self.account_lockout_duration) ++ self.addCleanup(self.ldb.delete, pso.dn) ++ ++ userdn = "cn=%s,cn=users,%s" % (creds.get_username(), self.base_dn) ++ pso.apply_to(userdn) ++ ++ # update the global lockout settings to be wildly different to what ++ # the test cases normally expect ++ self.update_lockout_settings(threshold=10, duration=600, ++ observation_window=600) ++ ++ def _reset_samr(self, res): ++ ++ # Now reset the lockout, by removing ACB_AUTOLOCK (which removes the lock, despite being a generated attribute) ++ samr_user = self._open_samr_user(res) ++ acb_info = self.samr.QueryUserInfo(samr_user, 16) ++ acb_info.acct_flags &= ~samr.ACB_AUTOLOCK ++ self.samr.SetUserInfo(samr_user, 16, acb_info) ++ self.samr.Close(samr_user) ++ ++ ++class PasswordTestsWithoutSleep(PasswordTests): ++ def setUp(self): ++ # The tests in this class do not sleep, so we can have a ++ # longer window and not flap on slower hosts ++ self.account_lockout_duration = 30 ++ self.lockout_observation_window = 30 ++ super(PasswordTestsWithoutSleep, self).setUp() ++ + def _reset_ldap_lockoutTime(self, res): + self.ldb.modify_ldif(""" + dn: """ + str(res[0].dn) + """ +@@ -615,22 +651,130 @@ userPassword: thatsAcomplPASS2XYZ + "samr", + initial_lastlogon_relation='greater') + +- def use_pso_lockout_settings(self, creds): ++ def test_multiple_logon_krb5(self): ++ self._test_multiple_logon(self.lockout1krb5_creds) + +- # create a PSO with the lockout settings the test cases normally expect +- # +- # Some test cases sleep() for self.account_lockout_duration +- pso = PasswordSettings("lockout-PSO", self.ldb, lockout_attempts=3, +- lockout_duration=self.account_lockout_duration) +- self.addCleanup(self.ldb.delete, pso.dn) ++ def test_multiple_logon_ntlm(self): ++ self._test_multiple_logon(self.lockout1ntlm_creds) + +- userdn = "cn=%s,cn=users,%s" % (creds.get_username(), self.base_dn) +- pso.apply_to(userdn) ++ def _test_samr_password_change(self, creds, other_creds, lockout_threshold=3): ++ """Tests user lockout by using bad password in SAMR password_change""" + +- # update the global lockout settings to be wildly different to what +- # the test cases normally expect +- self.update_lockout_settings(threshold=10, duration=600, +- observation_window=600) ++ # create a connection for SAMR using another user's credentials ++ lp = self.get_loadparm() ++ net = Net(other_creds, lp, server=self.host) ++ ++ # work out the initial account values for this user ++ username = creds.get_username() ++ userdn = "cn=%s,cn=users,%s" % (username, self.base_dn) ++ res = self._check_account(userdn, ++ badPwdCount=0, ++ badPasswordTime=("greater", 0), ++ badPwdCountOnly=True) ++ badPasswordTime = int(res[0]["badPasswordTime"][0]) ++ logonCount = int(res[0]["logonCount"][0]) ++ lastLogon = int(res[0]["lastLogon"][0]) ++ lastLogonTimestamp = int(res[0]["lastLogonTimestamp"][0]) ++ ++ # prove we can change the user password (using the correct password) ++ new_password = "thatsAcomplPASS2" ++ net.change_password(newpassword=new_password.encode('utf-8'), ++ username=username, ++ oldpassword=creds.get_password()) ++ creds.set_password(new_password) ++ ++ # try entering 'x' many bad passwords in a row to lock the user out ++ new_password = "thatsAcomplPASS3" ++ for i in range(lockout_threshold): ++ badPwdCount = i + 1 ++ try: ++ print("Trying bad password, attempt #%u" % badPwdCount) ++ net.change_password(newpassword=new_password.encode('utf-8'), ++ username=creds.get_username(), ++ oldpassword="bad-password") ++ self.fail("Invalid SAMR change_password accepted") ++ except NTSTATUSError as e: ++ enum = ctypes.c_uint32(e[0]).value ++ self.assertEquals(enum, ntstatus.NT_STATUS_WRONG_PASSWORD) ++ ++ # check the status of the account is updated after each bad attempt ++ account_flags = 0 ++ lockoutTime = None ++ if badPwdCount >= lockout_threshold: ++ account_flags = dsdb.UF_LOCKOUT ++ lockoutTime = ("greater", badPasswordTime) ++ ++ res = self._check_account(userdn, ++ badPwdCount=badPwdCount, ++ badPasswordTime=("greater", badPasswordTime), ++ logonCount=logonCount, ++ lastLogon=lastLogon, ++ lastLogonTimestamp=lastLogonTimestamp, ++ lockoutTime=lockoutTime, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, ++ msDSUserAccountControlComputed=account_flags) ++ badPasswordTime = int(res[0]["badPasswordTime"][0]) ++ ++ # the user is now locked out ++ lockoutTime = int(res[0]["lockoutTime"][0]) ++ ++ # check the user remains locked out regardless of whether they use a ++ # good or a bad password now ++ for password in (creds.get_password(), "bad-password"): ++ try: ++ print("Trying password %s" % password) ++ net.change_password(newpassword=new_password.encode('utf-8'), ++ username=creds.get_username(), ++ oldpassword=password) ++ self.fail("Invalid SAMR change_password accepted") ++ except NTSTATUSError as e: ++ enum = ctypes.c_uint32(e[0]).value ++ self.assertEquals(enum, ntstatus.NT_STATUS_ACCOUNT_LOCKED_OUT) ++ ++ res = self._check_account(userdn, ++ badPwdCount=lockout_threshold, ++ badPasswordTime=badPasswordTime, ++ logonCount=logonCount, ++ lastLogon=lastLogon, ++ lastLogonTimestamp=lastLogonTimestamp, ++ lockoutTime=lockoutTime, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, ++ msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) ++ ++ # reset the user account lockout ++ self._reset_samr(res) ++ ++ # check bad password counts are reset ++ res = self._check_account(userdn, ++ badPwdCount=0, ++ badPasswordTime=badPasswordTime, ++ logonCount=logonCount, ++ lockoutTime=0, ++ lastLogon=lastLogon, ++ lastLogonTimestamp=lastLogonTimestamp, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, ++ msDSUserAccountControlComputed=0) ++ ++ # check we can change the user password successfully now ++ net.change_password(newpassword=new_password.encode('utf-8'), ++ username=username, ++ oldpassword=creds.get_password()) ++ creds.set_password(new_password) ++ ++ def test_samr_change_password(self): ++ self._test_samr_password_change(self.lockout1ntlm_creds, ++ other_creds=self.lockout2ntlm_creds) ++ ++ # same as above, but use a PSO to enforce the lockout ++ def test_pso_samr_change_password(self): ++ self.use_pso_lockout_settings(self.lockout1ntlm_creds) ++ self._test_samr_password_change(self.lockout1ntlm_creds, ++ other_creds=self.lockout2ntlm_creds) ++ ++ ++class PasswordTestsWithSleep(PasswordTests): ++ def setUp(self): ++ super(PasswordTestsWithSleep, self).setUp() + + def _test_unicodePwd_lockout_with_clear_change(self, creds, other_ldb, + initial_logoncount_relation=None): +@@ -1065,12 +1209,6 @@ unicodePwd:: """ + base64.b64encode(new_utf16).decode('utf8') + """ + self.use_pso_lockout_settings(self.lockout1ntlm_creds) + self._test_login_lockout(self.lockout1ntlm_creds) + +- def test_multiple_logon_krb5(self): +- self._test_multiple_logon(self.lockout1krb5_creds) +- +- def test_multiple_logon_ntlm(self): +- self._test_multiple_logon(self.lockout1ntlm_creds) +- + def _testing_add_user(self, creds, lockOutObservationWindow=0): + username = creds.get_username() + userpass = creds.get_password() +@@ -1251,15 +1389,6 @@ userPassword: """ + userpass + """ + msDSUserAccountControlComputed=0) + return ldb + +- def _reset_samr(self, res): +- +- # Now reset the lockout, by removing ACB_AUTOLOCK (which removes the lock, despite being a generated attribute) +- samr_user = self._open_samr_user(res) +- acb_info = self.samr.QueryUserInfo(samr_user, 16) +- acb_info.acct_flags &= ~samr.ACB_AUTOLOCK +- self.samr.SetUserInfo(samr_user, 16, acb_info) +- self.samr.Close(samr_user) +- + def test_lockout_observation_window(self): + lockout3krb5_creds = self.insta_creds(self.template_creds, + username="lockout3krb5", +@@ -1286,120 +1415,6 @@ userPassword: """ + userpass + """ + self._testing_add_user(lockout4ntlm_creds, + lockOutObservationWindow=self.lockout_observation_window) + +- def _test_samr_password_change(self, creds, other_creds, lockout_threshold=3): +- """Tests user lockout by using bad password in SAMR password_change""" +- +- # create a connection for SAMR using another user's credentials +- lp = self.get_loadparm() +- net = Net(other_creds, lp, server=self.host) +- +- # work out the initial account values for this user +- username = creds.get_username() +- userdn = "cn=%s,cn=users,%s" % (username, self.base_dn) +- res = self._check_account(userdn, +- badPwdCount=0, +- badPasswordTime=("greater", 0), +- badPwdCountOnly=True) +- badPasswordTime = int(res[0]["badPasswordTime"][0]) +- logonCount = int(res[0]["logonCount"][0]) +- lastLogon = int(res[0]["lastLogon"][0]) +- lastLogonTimestamp = int(res[0]["lastLogonTimestamp"][0]) +- +- # prove we can change the user password (using the correct password) +- new_password = "thatsAcomplPASS2" +- net.change_password(newpassword=new_password.encode('utf-8'), +- username=username, +- oldpassword=creds.get_password()) +- creds.set_password(new_password) +- +- # try entering 'x' many bad passwords in a row to lock the user out +- new_password = "thatsAcomplPASS3" +- for i in range(lockout_threshold): +- badPwdCount = i + 1 +- try: +- print("Trying bad password, attempt #%u" % badPwdCount) +- net.change_password(newpassword=new_password.encode('utf-8'), +- username=creds.get_username(), +- oldpassword="bad-password") +- self.fail("Invalid SAMR change_password accepted") +- except NTSTATUSError as e: +- enum = ctypes.c_uint32(e[0]).value +- self.assertEquals(enum, ntstatus.NT_STATUS_WRONG_PASSWORD) +- +- # check the status of the account is updated after each bad attempt +- account_flags = 0 +- lockoutTime = None +- if badPwdCount >= lockout_threshold: +- account_flags = dsdb.UF_LOCKOUT +- lockoutTime = ("greater", badPasswordTime) +- +- res = self._check_account(userdn, +- badPwdCount=badPwdCount, +- badPasswordTime=("greater", badPasswordTime), +- logonCount=logonCount, +- lastLogon=lastLogon, +- lastLogonTimestamp=lastLogonTimestamp, +- lockoutTime=lockoutTime, +- userAccountControl=dsdb.UF_NORMAL_ACCOUNT, +- msDSUserAccountControlComputed=account_flags) +- badPasswordTime = int(res[0]["badPasswordTime"][0]) +- +- # the user is now locked out +- lockoutTime = int(res[0]["lockoutTime"][0]) +- +- # check the user remains locked out regardless of whether they use a +- # good or a bad password now +- for password in (creds.get_password(), "bad-password"): +- try: +- print("Trying password %s" % password) +- net.change_password(newpassword=new_password.encode('utf-8'), +- username=creds.get_username(), +- oldpassword=password) +- self.fail("Invalid SAMR change_password accepted") +- except NTSTATUSError as e: +- enum = ctypes.c_uint32(e[0]).value +- self.assertEquals(enum, ntstatus.NT_STATUS_ACCOUNT_LOCKED_OUT) +- +- res = self._check_account(userdn, +- badPwdCount=lockout_threshold, +- badPasswordTime=badPasswordTime, +- logonCount=logonCount, +- lastLogon=lastLogon, +- lastLogonTimestamp=lastLogonTimestamp, +- lockoutTime=lockoutTime, +- userAccountControl=dsdb.UF_NORMAL_ACCOUNT, +- msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) +- +- # reset the user account lockout +- self._reset_samr(res) +- +- # check bad password counts are reset +- res = self._check_account(userdn, +- badPwdCount=0, +- badPasswordTime=badPasswordTime, +- logonCount=logonCount, +- lockoutTime=0, +- lastLogon=lastLogon, +- lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl=dsdb.UF_NORMAL_ACCOUNT, +- msDSUserAccountControlComputed=0) +- +- # check we can change the user password successfully now +- net.change_password(newpassword=new_password.encode('utf-8'), +- username=username, +- oldpassword=creds.get_password()) +- creds.set_password(new_password) +- +- def test_samr_change_password(self): +- self._test_samr_password_change(self.lockout1ntlm_creds, +- other_creds=self.lockout2ntlm_creds) +- +- # same as above, but use a PSO to enforce the lockout +- def test_pso_samr_change_password(self): +- self.use_pso_lockout_settings(self.lockout1ntlm_creds) +- self._test_samr_password_change(self.lockout1ntlm_creds, +- other_creds=self.lockout2ntlm_creds) +- + + host_url = "ldap://%s" % host + +-- +2.17.1 diff --git a/CVE-2018-16857-4.patch b/CVE-2018-16857-4.patch new file mode 100644 index 0000000..83f3b62 --- /dev/null +++ b/CVE-2018-16857-4.patch @@ -0,0 +1,183 @@ +From fe8e05a9ea8185325ff87ac73ef0106a85cd662a Mon Sep 17 00:00:00 2001 +From: Joe Guo +Date: Mon, 30 Jul 2018 18:15:34 +1200 +Subject: [PATCH 12/17] CVE-2018-16857 PEP8: fix E127: continuation line + over-indented for visual indent + +Signed-off-by: Joe Guo +Reviewed-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +Partial backport of commit bbb9f57603d (only password_lockout_base.py +change) as a dependency for: +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13683 +--- + .../tests/python/password_lockout_base.py | 36 +++++++++---------- + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/source4/dsdb/tests/python/password_lockout_base.py b/source4/dsdb/tests/python/password_lockout_base.py +index 9d82e088bb8..1b408c75166 100644 +--- a/source4/dsdb/tests/python/password_lockout_base.py ++++ b/source4/dsdb/tests/python/password_lockout_base.py +@@ -390,7 +390,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=("greater", 0), + lastLogonTimestamp=("greater", 0), + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + logonCount = int(res[0]["logonCount"][0]) +@@ -421,7 +421,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0, + msg='lastlogontimestamp with wrong password') + badPasswordTime = int(res[0]["badPasswordTime"][0]) +@@ -440,7 +440,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=('greater', lastLogon), + lastLogonTimestamp=lastLogonTimestamp, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0, + msg='LLTimestamp is updated to lastlogon') + +@@ -461,7 +461,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + +@@ -483,7 +483,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + +@@ -508,7 +508,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogonTimestamp=lastLogonTimestamp, + lockoutTime=("greater", badPasswordTime), + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + lockoutTime = int(res[0]["lockoutTime"][0]) +@@ -530,7 +530,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogonTimestamp=lastLogonTimestamp, + lockoutTime=lockoutTime, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) + + # The wrong password +@@ -550,7 +550,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogonTimestamp=lastLogonTimestamp, + lockoutTime=lockoutTime, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) + + # The correct password, but we are locked out +@@ -570,7 +570,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogonTimestamp=lastLogonTimestamp, + lockoutTime=lockoutTime, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) + + # wait for the lockout to end +@@ -585,7 +585,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + + # The correct password after letting the timeout expire +@@ -605,7 +605,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogonTimestamp=lastLogonTimestamp, + lockoutTime=0, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0, + msg="lastLogon is way off") + +@@ -629,7 +629,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + +@@ -650,7 +650,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + +@@ -664,7 +664,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + + # The wrong password +@@ -684,7 +684,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + +@@ -700,7 +700,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=("greater", lastLogon), + lastLogonTimestamp=lastLogonTimestamp, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + + def _test_multiple_logon(self, creds): +@@ -734,7 +734,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=("greater", 0), + lastLogonTimestamp=("greater", 0), + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + logonCount = int(res[0]["logonCount"][0]) +@@ -774,5 +774,5 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=(lastlogon_relation, lastLogon), + lastLogonTimestamp=lastLogonTimestamp, + userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) +-- +2.17.1 diff --git a/CVE-2018-16857-5.patch b/CVE-2018-16857-5.patch new file mode 100644 index 0000000..bcdd6bd --- /dev/null +++ b/CVE-2018-16857-5.patch @@ -0,0 +1,221 @@ +From 9cb6b4e9131afac71a39a2f6a3c142723cb6ca19 Mon Sep 17 00:00:00 2001 +From: Joe Guo +Date: Mon, 30 Jul 2018 18:19:21 +1200 +Subject: [PATCH 13/17] CVE-2018-16857 PEP8: fix E251: unexpected spaces around + keyword / parameter equals + +Signed-off-by: Joe Guo +Reviewed-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall + +Partial backport of commit 1ccc36b4010cd63 (only password_lockout_base.py +change) as a dependency for: +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13683 +--- + .../tests/python/password_lockout_base.py | 60 +++++++------------ + 1 file changed, 20 insertions(+), 40 deletions(-) + +diff --git a/source4/dsdb/tests/python/password_lockout_base.py b/source4/dsdb/tests/python/password_lockout_base.py +index 1b408c75166..48a74018624 100644 +--- a/source4/dsdb/tests/python/password_lockout_base.py ++++ b/source4/dsdb/tests/python/password_lockout_base.py +@@ -93,8 +93,7 @@ class BasePasswordTestCase(PasswordTestCase): + logonCount=0, + lastLogon=0, + lastLogonTimestamp=("absent", None), +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + + def _check_account(self, dn, +@@ -389,8 +388,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + logonCount=(logoncount_relation, 0), + lastLogon=("greater", 0), + lastLogonTimestamp=("greater", 0), +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + logonCount = int(res[0]["logonCount"][0]) +@@ -420,8 +418,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + logonCount=logonCount, + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0, + msg='lastlogontimestamp with wrong password') + badPasswordTime = int(res[0]["badPasswordTime"][0]) +@@ -439,8 +436,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + logonCount=(logoncount_relation, logonCount), + lastLogon=('greater', lastLogon), + lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0, + msg='LLTimestamp is updated to lastlogon') + +@@ -460,8 +456,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + logonCount=logonCount, + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + +@@ -482,8 +477,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + logonCount=logonCount, + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + +@@ -507,8 +501,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + lockoutTime=("greater", badPasswordTime), +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + lockoutTime = int(res[0]["lockoutTime"][0]) +@@ -529,8 +522,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + lockoutTime=lockoutTime, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) + + # The wrong password +@@ -549,8 +541,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + lockoutTime=lockoutTime, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) + + # The correct password, but we are locked out +@@ -569,8 +560,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + lockoutTime=lockoutTime, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) + + # wait for the lockout to end +@@ -584,8 +574,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lockoutTime=lockoutTime, + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + + # The correct password after letting the timeout expire +@@ -604,8 +593,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lastLogon=(lastlogon_relation, lastLogon), + lastLogonTimestamp=lastLogonTimestamp, + lockoutTime=0, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0, + msg="lastLogon is way off") + +@@ -628,8 +616,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lockoutTime=0, + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + +@@ -649,8 +636,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lockoutTime=0, + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + +@@ -663,8 +649,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lockoutTime=0, + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + + # The wrong password +@@ -683,8 +668,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lockoutTime=0, + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + +@@ -699,8 +683,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + lockoutTime=0, + lastLogon=("greater", lastLogon), + lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + + def _test_multiple_logon(self, creds): +@@ -733,8 +716,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + logonCount=(logoncount_relation, 0), + lastLogon=("greater", 0), + lastLogonTimestamp=("greater", 0), +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + logonCount = int(res[0]["logonCount"][0]) +@@ -754,8 +736,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + logonCount=(logoncount_relation, logonCount), + lastLogon=(lastlogon_relation, lastLogon), + lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0, + msg=("second logon, firstlogon was %s" % + firstLogon)) +@@ -773,6 +754,5 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + logonCount=(logoncount_relation, logonCount), + lastLogon=(lastlogon_relation, lastLogon), + lastLogonTimestamp=lastLogonTimestamp, +- userAccountControl= +- dsdb.UF_NORMAL_ACCOUNT, ++ userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) +-- +2.17.1 diff --git a/CVE-2018-16857-6.patch b/CVE-2018-16857-6.patch new file mode 100644 index 0000000..e74f4a2 --- /dev/null +++ b/CVE-2018-16857-6.patch @@ -0,0 +1,104 @@ +From ec9cc4ed5a05490297cde3fcaac50eeeaaca8469 Mon Sep 17 00:00:00 2001 +From: Tim Beale +Date: Tue, 13 Nov 2018 11:49:56 +1300 +Subject: [PATCH 14/17] CVE-2018-16857 tests: Sanity-check password lockout + works with default values + +Sanity-check that when we use the default lockOutObservationWindow that +user lockout actually works. + +The easiest way to do this is to reuse the _test_login_lockout() +test-case, but stop at the point where we wait for the lockout duration +to expire (because we don't want the test to wait 30 mins). + +This highlights a problem currently where the default values don't work. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13683 + +Signed-off-by: Tim Beale +Reviewed-by: Andrew Bartlett +--- + selftest/knownfail.d/password_lockout | 4 +++ + source4/dsdb/tests/python/password_lockout.py | 30 +++++++++++++++++++ + .../tests/python/password_lockout_base.py | 6 +++- + 3 files changed, 39 insertions(+), 1 deletion(-) + create mode 100644 selftest/knownfail.d/password_lockout + +diff --git a/selftest/knownfail.d/password_lockout b/selftest/knownfail.d/password_lockout +new file mode 100644 +index 00000000000..305bcbdef25 +--- /dev/null ++++ b/selftest/knownfail.d/password_lockout +@@ -0,0 +1,4 @@ ++samba4.ldap.password_lockout.python\(ad_dc_ntvfs\).__main__.PasswordTestsWithDefaults.test_pso_login_lockout_krb5\(ad_dc_ntvfs\) ++samba4.ldap.password_lockout.python\(ad_dc_ntvfs\).__main__.PasswordTestsWithDefaults.test_pso_login_lockout_ntlm\(ad_dc_ntvfs\) ++samba4.ldap.password_lockout.python\(ad_dc_ntvfs\).__main__.PasswordTestsWithDefaults.test_login_lockout_ntlm\(ad_dc_ntvfs\) ++samba4.ldap.password_lockout.python\(ad_dc_ntvfs\).__main__.PasswordTestsWithDefaults.test_login_lockout_krb5\(ad_dc_ntvfs\) +diff --git a/source4/dsdb/tests/python/password_lockout.py b/source4/dsdb/tests/python/password_lockout.py +index 0022dee21ba..b09a732e179 100755 +--- a/source4/dsdb/tests/python/password_lockout.py ++++ b/source4/dsdb/tests/python/password_lockout.py +@@ -1415,6 +1415,36 @@ userPassword: """ + userpass + """ + self._testing_add_user(lockout4ntlm_creds, + lockOutObservationWindow=self.lockout_observation_window) + ++class PasswordTestsWithDefaults(PasswordTests): ++ def setUp(self): ++ # The tests in this class do not sleep, so we can use the default ++ # timeout windows here ++ self.account_lockout_duration = 30 * 60 ++ self.lockout_observation_window = 30 * 60 ++ super(PasswordTestsWithDefaults, self).setUp() ++ ++ # sanity-check that user lockout works with the default settings (we just ++ # check the user is locked out - we don't wait for the lockout to expire) ++ def test_login_lockout_krb5(self): ++ self._test_login_lockout(self.lockout1krb5_creds, ++ wait_lockout_duration=False) ++ ++ def test_login_lockout_ntlm(self): ++ self._test_login_lockout(self.lockout1ntlm_creds, ++ wait_lockout_duration=False) ++ ++ # Repeat the login lockout tests using PSOs ++ def test_pso_login_lockout_krb5(self): ++ """Check the PSO lockout settings get applied to the user correctly""" ++ self.use_pso_lockout_settings(self.lockout1krb5_creds) ++ self._test_login_lockout(self.lockout1krb5_creds, ++ wait_lockout_duration=False) ++ ++ def test_pso_login_lockout_ntlm(self): ++ """Check the PSO lockout settings get applied to the user correctly""" ++ self.use_pso_lockout_settings(self.lockout1ntlm_creds) ++ self._test_login_lockout(self.lockout1ntlm_creds, ++ wait_lockout_duration=False) + + host_url = "ldap://%s" % host + +diff --git a/source4/dsdb/tests/python/password_lockout_base.py b/source4/dsdb/tests/python/password_lockout_base.py +index 48a74018624..e8ac46dcd97 100644 +--- a/source4/dsdb/tests/python/password_lockout_base.py ++++ b/source4/dsdb/tests/python/password_lockout_base.py +@@ -365,7 +365,7 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + def tearDown(self): + super(BasePasswordTestCase, self).tearDown() + +- def _test_login_lockout(self, creds): ++ def _test_login_lockout(self, creds, wait_lockout_duration=True): + username = creds.get_username() + userpass = creds.get_password() + userdn = "cn=%s,cn=users,%s" % (username, self.base_dn) +@@ -563,6 +563,10 @@ lockoutThreshold: """ + str(lockoutThreshold) + """ + userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) + ++ # if we're just checking the user gets locked out, we can stop here ++ if not wait_lockout_duration: ++ return ++ + # wait for the lockout to end + time.sleep(self.account_lockout_duration + 1) + print(self.account_lockout_duration + 1) +-- +2.17.1 + diff --git a/CVE-2018-16857-7.patch b/CVE-2018-16857-7.patch new file mode 100644 index 0000000..b153bba --- /dev/null +++ b/CVE-2018-16857-7.patch @@ -0,0 +1,58 @@ +From 4f86beeaf3408383385ee99a74520a805dd63c0f Mon Sep 17 00:00:00 2001 +From: Tim Beale +Date: Tue, 13 Nov 2018 12:24:16 +1300 +Subject: [PATCH 15/17] CVE-2018-16857 dsdb/util: Correctly treat + lockOutObservationWindow as 64-bit int + +Commit 442a38c918ae1666b35 refactored some code into a new +get_lockout_observation_window() function. However, in moving the code, +an ldb_msg_find_attr_as_int64() inadvertently got converted to a +ldb_msg_find_attr_as_int(). + +ldb_msg_find_attr_as_int() will only work for values up to -2147483648 +(about 3.5 minutes in MS timestamp form). Unfortunately, the automated +tests used a low enough timeout that they still worked, however, +password lockout would not work with the Samba default settings. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13683 + +Signed-off-by: Tim Beale +Reviewed-by: Andrew Bartlett +--- + selftest/knownfail.d/password_lockout | 2 -- + source4/dsdb/common/util.c | 10 +++++----- + 2 files changed, 5 insertions(+), 7 deletions(-) + +diff --git a/selftest/knownfail.d/password_lockout b/selftest/knownfail.d/password_lockout +index 305bcbdef25..a4e37a84c21 100644 +--- a/selftest/knownfail.d/password_lockout ++++ b/selftest/knownfail.d/password_lockout +@@ -1,4 +1,2 @@ + samba4.ldap.password_lockout.python\(ad_dc_ntvfs\).__main__.PasswordTestsWithDefaults.test_pso_login_lockout_krb5\(ad_dc_ntvfs\) + samba4.ldap.password_lockout.python\(ad_dc_ntvfs\).__main__.PasswordTestsWithDefaults.test_pso_login_lockout_ntlm\(ad_dc_ntvfs\) +-samba4.ldap.password_lockout.python\(ad_dc_ntvfs\).__main__.PasswordTestsWithDefaults.test_login_lockout_ntlm\(ad_dc_ntvfs\) +-samba4.ldap.password_lockout.python\(ad_dc_ntvfs\).__main__.PasswordTestsWithDefaults.test_login_lockout_krb5\(ad_dc_ntvfs\) +diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c +index 193fa2ae653..438a29e1773 100644 +--- a/source4/dsdb/common/util.c ++++ b/source4/dsdb/common/util.c +@@ -5400,12 +5400,12 @@ static int64_t get_lockout_observation_window(struct ldb_message *domain_msg, + struct ldb_message *pso_msg) + { + if (pso_msg != NULL) { +- return ldb_msg_find_attr_as_int(pso_msg, +- "msDS-LockoutObservationWindow", +- 0); ++ return ldb_msg_find_attr_as_int64(pso_msg, ++ "msDS-LockoutObservationWindow", ++ 0); + } else { +- return ldb_msg_find_attr_as_int(domain_msg, +- "lockOutObservationWindow", 0); ++ return ldb_msg_find_attr_as_int64(domain_msg, ++ "lockOutObservationWindow", 0); + } + } + +-- +2.17.1 diff --git a/CVE-2018-16857-8.patch b/CVE-2018-16857-8.patch new file mode 100644 index 0000000..045c0d9 --- /dev/null +++ b/CVE-2018-16857-8.patch @@ -0,0 +1,47 @@ +From d12b02c78842786969557b9be7c953e9594d90dd Mon Sep 17 00:00:00 2001 +From: Tim Beale +Date: Tue, 13 Nov 2018 13:19:04 +1300 +Subject: [PATCH 16/17] CVE-2018-16857 dsdb/util: Fix lockOutObservationWindow + for PSOs + +Fix a remaining place where we were trying to read the +msDS-LockoutObservationWindow as an int instead of an int64. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13683 + +Signed-off-by: Tim Beale +Reviewed-by: Andrew Bartlett +--- + selftest/knownfail.d/password_lockout | 2 -- + source4/dsdb/common/util.c | 6 +++--- + 2 files changed, 3 insertions(+), 5 deletions(-) + delete mode 100644 selftest/knownfail.d/password_lockout + +diff --git a/selftest/knownfail.d/password_lockout b/selftest/knownfail.d/password_lockout +deleted file mode 100644 +index a4e37a84c21..00000000000 +--- a/selftest/knownfail.d/password_lockout ++++ /dev/null +@@ -1,2 +0,0 @@ +-samba4.ldap.password_lockout.python\(ad_dc_ntvfs\).__main__.PasswordTestsWithDefaults.test_pso_login_lockout_krb5\(ad_dc_ntvfs\) +-samba4.ldap.password_lockout.python\(ad_dc_ntvfs\).__main__.PasswordTestsWithDefaults.test_pso_login_lockout_ntlm\(ad_dc_ntvfs\) +diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c +index 438a29e1773..8d863f85a29 100644 +--- a/source4/dsdb/common/util.c ++++ b/source4/dsdb/common/util.c +@@ -5361,9 +5361,9 @@ int samdb_result_effective_badPwdCount(struct ldb_context *sam_ldb, + + if (res != NULL) { + lockOutObservationWindow = +- ldb_msg_find_attr_as_int(res->msgs[0], +- "msDS-LockoutObservationWindow", +- 0); ++ ldb_msg_find_attr_as_int64(res->msgs[0], ++ "msDS-LockoutObservationWindow", ++ 0); + talloc_free(res); + } else { + +-- +2.17.1 + diff --git a/CVE-2018-16857-9.patch b/CVE-2018-16857-9.patch new file mode 100644 index 0000000..71df94a --- /dev/null +++ b/CVE-2018-16857-9.patch @@ -0,0 +1,59 @@ +From 60b2cd50f4d0554cc5ca8c53b2d1fa89e56a6d06 Mon Sep 17 00:00:00 2001 +From: Tim Beale +Date: Tue, 13 Nov 2018 13:22:41 +1300 +Subject: [PATCH 17/17] CVE-2018-16857 dsdb/util: Add better default + lockOutObservationWindow + +Clearly the lockOutObservationWindow value is important, and using a +default value of zero doesn't work very well. + +This patch adds a better default value (the domain default setting of 30 +minutes). + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13683 + +Signed-off-by: Tim Beale +Reviewed-by: Andrew Bartlett +--- + source4/dsdb/common/util.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c +index 8d863f85a29..18f700370a3 100644 +--- a/source4/dsdb/common/util.c ++++ b/source4/dsdb/common/util.c +@@ -56,6 +56,9 @@ + */ + #include "dsdb/samdb/ldb_modules/util.h" + ++/* default is 30 minutes: -1e7 * 30 * 60 */ ++#define DEFAULT_OBSERVATION_WINDOW -18000000000 ++ + /* + search the sam for the specified attributes in a specific domain, filter on + objectSid being in domain_sid. +@@ -5363,7 +5366,7 @@ int samdb_result_effective_badPwdCount(struct ldb_context *sam_ldb, + lockOutObservationWindow = + ldb_msg_find_attr_as_int64(res->msgs[0], + "msDS-LockoutObservationWindow", +- 0); ++ DEFAULT_OBSERVATION_WINDOW); + talloc_free(res); + } else { + +@@ -5402,10 +5405,11 @@ static int64_t get_lockout_observation_window(struct ldb_message *domain_msg, + if (pso_msg != NULL) { + return ldb_msg_find_attr_as_int64(pso_msg, + "msDS-LockoutObservationWindow", +- 0); ++ DEFAULT_OBSERVATION_WINDOW); + } else { + return ldb_msg_find_attr_as_int64(domain_msg, +- "lockOutObservationWindow", 0); ++ "lockOutObservationWindow", ++ DEFAULT_OBSERVATION_WINDOW); + } + } + +-- +2.17.1 diff --git a/CVE-2018-16860.patch b/CVE-2018-16860.patch new file mode 100644 index 0000000..5efdc9c --- /dev/null +++ b/CVE-2018-16860.patch @@ -0,0 +1,36 @@ +From 43958af1d50f0185e21e6cd74110c455ee8996af Mon Sep 17 00:00:00 2001 +From: Isaac Boukris +Date: Wed, 30 Jan 2019 23:49:07 +0200 +Subject: [PATCH] CVE-2018-16860 Heimdal KDC: Reject PA-S4U2Self with unkeyed + checksum + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=13685 + +Signed-off-by: Isaac Boukris +Reviewed-by: Andrew Bartlett +Signed-off-by: Andrew Bartlett + +Autobuild-User(master): Karolin Seeger +Autobuild-Date(master): Tue May 14 11:45:13 UTC 2019 on sn-devel-184 +--- + source4/heimdal/kdc/krb5tgs.c | 7 + + 1 files changed, 7 insertions(+), 0 deletions(-) + +diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c +index a888788bb6f..ff7d93138c0 100644 +--- a/source4/heimdal/kdc/krb5tgs.c ++++ b/source4/heimdal/kdc/krb5tgs.c +@@ -1925,6 +1925,13 @@ tgs_build_reply(krb5_context context, + goto out; + } + ++ if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) { ++ free_PA_S4U2Self(&self); ++ kdc_log(context, config, 0, "Reject PA-S4U2Self with unkeyed checksum"); ++ ret = KRB5KRB_AP_ERR_INAPP_CKSUM; ++ goto out; ++ } ++ + ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack); + if (ret) + goto out; diff --git a/CVE-2019-10197-1.patch b/CVE-2019-10197-1.patch new file mode 100644 index 0000000..e7d38f4 --- /dev/null +++ b/CVE-2019-10197-1.patch @@ -0,0 +1,75 @@ +From 5e94fe726e9af81374c697ce603b3728ccaaebf3 Mon Sep 17 00:00:00 2001 +From: Jeremy Allison +Date: Fri, 12 Jul 2019 12:10:35 -0700 +Subject: [PATCH 1/6] CVE-2019-10197: smbd: separate out impersonation debug + info into a new function. + +Will be called on elsewhere on successful impersonation. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14035 + +Signed-off-by: Jeremy Allison +Reviewed-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher +--- + source3/smbd/uid.c | 37 +++++++++++++++++++++++-------------- + 1 file changed, 23 insertions(+), 14 deletions(-) + +diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c +index a4bcb747d37e..ce8e8d92131c 100644 +--- a/source3/smbd/uid.c ++++ b/source3/smbd/uid.c +@@ -279,6 +279,28 @@ static bool check_user_ok(connection_struct *conn, + return(True); + } + ++static void print_impersonation_info(connection_struct *conn) ++{ ++ struct smb_filename *cwdfname = NULL; ++ ++ if (!CHECK_DEBUGLVL(DBGLVL_INFO)) { ++ return; ++ } ++ ++ cwdfname = vfs_GetWd(talloc_tos(), conn); ++ if (cwdfname == NULL) { ++ return; ++ } ++ ++ DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n", ++ (int)getuid(), ++ (int)geteuid(), ++ (int)getgid(), ++ (int)getegid(), ++ cwdfname->base_name); ++ TALLOC_FREE(cwdfname); ++} ++ + /**************************************************************************** + Become the user of a connection number without changing the security context + stack, but modify the current_user entries. +@@ -415,20 +437,7 @@ static bool change_to_user_internal(connection_struct *conn, + current_user.done_chdir = true; + } + +- if (CHECK_DEBUGLVL(DBGLVL_INFO)) { +- struct smb_filename *cwdfname = vfs_GetWd(talloc_tos(), conn); +- if (cwdfname == NULL) { +- return false; +- } +- DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n", +- (int)getuid(), +- (int)geteuid(), +- (int)getgid(), +- (int)getegid(), +- cwdfname->base_name); +- TALLOC_FREE(cwdfname); +- } +- ++ print_impersonation_info(conn); + return true; + } + +-- +2.17.1 + diff --git a/CVE-2019-10197-2.patch b/CVE-2019-10197-2.patch new file mode 100644 index 0000000..e7ed51e --- /dev/null +++ b/CVE-2019-10197-2.patch @@ -0,0 +1,36 @@ +From b4cd0dcbc38ae61cfb075e5f659384df889e99f7 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 11 Jul 2019 17:01:29 +0200 +Subject: [PATCH 2/6] CVE-2019-10197: smbd: make sure that + change_to_user_internal() always resets current_user.done_chdir + +We should not leave current_user.done_chdir as true if we didn't call +chdir_current_service() with success. + +This caused problems in when calling vfs_ChDir() in pop_conn_ctx() when +chdir_current_service() worked once on one share but later failed on another +share. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14035 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Ralph Boehme +--- + source3/smbd/uid.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c +index ce8e8d92131c..77a81f602988 100644 +--- a/source3/smbd/uid.c ++++ b/source3/smbd/uid.c +@@ -427,6 +427,7 @@ static bool change_to_user_internal(connection_struct *conn, + current_user.conn = conn; + current_user.vuid = vuid; + current_user.need_chdir = conn->tcon_done; ++ current_user.done_chdir = false; + + if (current_user.need_chdir) { + ok = chdir_current_service(conn); +-- +2.17.1 + diff --git a/CVE-2019-10197-3.patch b/CVE-2019-10197-3.patch new file mode 100644 index 0000000..f142118 --- /dev/null +++ b/CVE-2019-10197-3.patch @@ -0,0 +1,30 @@ +From b1496ce793129302c9959ebc6330219c6a3143f0 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 18 Jun 2019 14:04:08 +0200 +Subject: [PATCH 3/6] CVE-2019-10197: smbd: make sure we reset + current_user.{need,done}_chdir in become_root() + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14035 + +Signed-off-by: Stefan Metzmacher +--- + source3/smbd/uid.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c +index 77a81f602988..50868ba8572a 100644 +--- a/source3/smbd/uid.c ++++ b/source3/smbd/uid.c +@@ -624,6 +624,9 @@ void smbd_become_root(void) + } + push_conn_ctx(); + set_root_sec_ctx(); ++ ++ current_user.need_chdir = false; ++ current_user.done_chdir = false; + } + + /* Unbecome the root user */ +-- +2.17.1 + diff --git a/CVE-2019-10197-4.patch b/CVE-2019-10197-4.patch new file mode 100644 index 0000000..3389e59 --- /dev/null +++ b/CVE-2019-10197-4.patch @@ -0,0 +1,49 @@ +From 03a0719d6d5c1a81b44bc3cedc76563a1eb04491 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 30 Jul 2019 17:16:59 +0200 +Subject: [PATCH 4/6] CVE-2019-10197: selftest: make fsrvp_share its own + independent subdirectory + +The next patch will otherwise break the fsrvp related tests. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14035 + +Signed-off-by: Stefan Metzmacher +--- + selftest/target/Samba3.pm | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm +index 9d88253c9fe7..f7eb314138a0 100755 +--- a/selftest/target/Samba3.pm ++++ b/selftest/target/Samba3.pm +@@ -1540,6 +1540,9 @@ sub provision($$$$$$$$$) + my $widelinks_linkdir="$shrdir/widelinks_foo"; + push(@dirs,$widelinks_linkdir); + ++ my $fsrvp_shrdir="$shrdir/fsrvp"; ++ push(@dirs,$fsrvp_shrdir); ++ + my $shadow_tstdir="$shrdir/shadow"; + push(@dirs,$shadow_tstdir); + my $shadow_mntdir="$shadow_tstdir/mount"; +@@ -2083,14 +2086,14 @@ sub provision($$$$$$$$$) + guest ok = yes + + [fsrvp_share] +- path = $shrdir ++ path = $fsrvp_shrdir + comment = fake shapshots using rsync + vfs objects = shell_snap shadow_copy2 + shell_snap:check path command = $fake_snap_pl --check + shell_snap:create command = $fake_snap_pl --create + shell_snap:delete command = $fake_snap_pl --delete + # a relative path here fails, the snapshot dir is no longer found +- shadow:snapdir = $shrdir/.snapshots ++ shadow:snapdir = $fsrvp_shrdir/.snapshots + + [shadow1] + path = $shadow_shrdir +-- +2.17.1 + diff --git a/CVE-2019-10197-5.patch b/CVE-2019-10197-5.patch new file mode 100644 index 0000000..b5d9ec3 --- /dev/null +++ b/CVE-2019-10197-5.patch @@ -0,0 +1,111 @@ +From 409447f3258b87745a2248570278b1c6da8991f4 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 16 Jul 2019 15:40:38 +0200 +Subject: [PATCH 5/6] CVE-2019-10197: test_smbclient_s3.sh: add regression test + for the no permission on share root problem + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14035 + +Signed-off-by: Stefan Metzmacher +--- + selftest/knownfail.d/CVE-2019-10197 | 1 + + selftest/target/Samba3.pm | 12 +++++++++ + source3/script/tests/test_smbclient_s3.sh | 30 +++++++++++++++++++++++ + 3 files changed, 43 insertions(+) + create mode 100644 selftest/knownfail.d/CVE-2019-10197 + +diff --git a/selftest/knownfail.d/CVE-2019-10197 b/selftest/knownfail.d/CVE-2019-10197 +new file mode 100644 +index 000000000000..f7056bbf3ad4 +--- /dev/null ++++ b/selftest/knownfail.d/CVE-2019-10197 +@@ -0,0 +1 @@ ++^samba3.blackbox.smbclient_s3.*.noperm.share.regression +diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm +index f7eb314138a0..2f491441815f 100755 +--- a/selftest/target/Samba3.pm ++++ b/selftest/target/Samba3.pm +@@ -1516,6 +1516,9 @@ sub provision($$$$$$$$$) + my $ro_shrdir="$shrdir/root-tmp"; + push(@dirs,$ro_shrdir); + ++ my $noperm_shrdir="$shrdir/noperm-tmp"; ++ push(@dirs,$noperm_shrdir); ++ + my $msdfs_shrdir="$shrdir/msdfsshare"; + push(@dirs,$msdfs_shrdir); + +@@ -1586,6 +1589,11 @@ sub provision($$$$$$$$$) + chmod 0755, $piddir; + + ++ ## ++ ## Create a directory without permissions to enter ++ ## ++ chmod 0000, $noperm_shrdir; ++ + ## + ## create ro and msdfs share layout + ## +@@ -1902,6 +1910,10 @@ sub provision($$$$$$$$$) + [ro-tmp] + path = $ro_shrdir + guest ok = yes ++[noperm] ++ path = $noperm_shrdir ++ wide links = yes ++ guest ok = yes + [write-list-tmp] + path = $shrdir + read only = yes +diff --git a/source3/script/tests/test_smbclient_s3.sh b/source3/script/tests/test_smbclient_s3.sh +index bf033ccd2fbf..0bae1d78fac9 100755 +--- a/source3/script/tests/test_smbclient_s3.sh ++++ b/source3/script/tests/test_smbclient_s3.sh +@@ -1329,6 +1329,32 @@ EOF + fi + } + ++# ++# Regression test for CVE-2019-10197 ++# we should always get ACCESS_DENIED ++# ++test_noperm_share_regression() ++{ ++ cmd='$SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/noperm -I $SERVER_IP $LOCAL_ADDARGS -c "ls;ls" 2>&1' ++ eval echo "$cmd" ++ out=`eval $cmd` ++ ret=$? ++ if [ $ret -eq 0 ] ; then ++ echo "$out" ++ echo "failed accessing no perm share should not work" ++ return 1 ++ fi ++ ++ num=`echo "$out" | grep 'NT_STATUS_ACCESS_DENIED' | wc -l` ++ if [ "$num" -ne "2" ] ; then ++ echo "$out" ++ echo "failed num[$num] - two NT_STATUS_ACCESS_DENIED lines expected" ++ return 1 ++ fi ++ ++ return 0 ++} ++ + # Test smbclient deltree command + test_deltree() + { +@@ -1857,6 +1883,10 @@ testit "follow local symlinks" \ + test_local_symlinks || \ + failed=`expr $failed + 1` + ++testit "noperm share regression" \ ++ test_noperm_share_regression || \ ++ failed=`expr $failed + 1` ++ + testit "smbclient deltree command" \ + test_deltree || \ + failed=`expr $failed + 1` +-- +2.17.1 + diff --git a/CVE-2019-10197-6.patch b/CVE-2019-10197-6.patch new file mode 100644 index 0000000..5e7baec --- /dev/null +++ b/CVE-2019-10197-6.patch @@ -0,0 +1,87 @@ +From 501e034aa5b6ba50bf14e41c59674fbbc28a2e9c Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 11 Jul 2019 17:02:15 +0200 +Subject: [PATCH 6/6] CVE-2019-10197: smbd: split change_to_user_impersonate() + out of change_to_user_internal() + +This makes sure we always call chdir_current_service() even +when we still impersonated the user. Which is important +in order to run the SMB* request within the correct working directory +and only if the user has permissions to enter that directory. + +It makes sure we always update conn->lastused_count +in chdir_current_service() for each request. + +Note that vfs_ChDir() (called from chdir_current_service()) +maintains its own cache and avoids calling SMB_VFS_CHDIR() +if possible. + +It means we still avoid syscalls if we get a multiple requests +for the same session/tcon tuple. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14035 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Ralph Boehme +--- + selftest/knownfail.d/CVE-2019-10197 | 1 - + source3/smbd/uid.c | 21 +++++++++++++++++---- + 2 files changed, 17 insertions(+), 5 deletions(-) + delete mode 100644 selftest/knownfail.d/CVE-2019-10197 + +diff --git a/selftest/knownfail.d/CVE-2019-10197 b/selftest/knownfail.d/CVE-2019-10197 +deleted file mode 100644 +index f7056bbf3ad4..000000000000 +--- a/selftest/knownfail.d/CVE-2019-10197 ++++ /dev/null +@@ -1 +0,0 @@ +-^samba3.blackbox.smbclient_s3.*.noperm.share.regression +diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c +index 50868ba8572a..5c39baade5cf 100644 +--- a/source3/smbd/uid.c ++++ b/source3/smbd/uid.c +@@ -306,9 +306,9 @@ static void print_impersonation_info(connection_struct *conn) + stack, but modify the current_user entries. + ****************************************************************************/ + +-static bool change_to_user_internal(connection_struct *conn, +- const struct auth_session_info *session_info, +- uint64_t vuid) ++static bool change_to_user_impersonate(connection_struct *conn, ++ const struct auth_session_info *session_info, ++ uint64_t vuid) + { + int snum; + gid_t gid; +@@ -321,7 +321,6 @@ static bool change_to_user_internal(connection_struct *conn, + + if ((current_user.conn == conn) && + (current_user.vuid == vuid) && +- (current_user.need_chdir == conn->tcon_done) && + (current_user.ut.uid == session_info->unix_token->uid)) + { + DBG_INFO("Skipping user change - already user\n"); +@@ -426,6 +425,20 @@ static bool change_to_user_internal(connection_struct *conn, + + current_user.conn = conn; + current_user.vuid = vuid; ++ return true; ++} ++ ++static bool change_to_user_internal(connection_struct *conn, ++ const struct auth_session_info *session_info, ++ uint64_t vuid) ++{ ++ bool ok; ++ ++ ok = change_to_user_impersonate(conn, session_info, vuid); ++ if (!ok) { ++ return false; ++ } ++ + current_user.need_chdir = conn->tcon_done; + current_user.done_chdir = false; + +-- +2.17.1 + diff --git a/CVE-2019-14861.patch b/CVE-2019-14861.patch new file mode 100644 index 0000000..1c3ce86 --- /dev/null +++ b/CVE-2019-14861.patch @@ -0,0 +1,390 @@ +From 9501741466ba2c0740ffc703c5d242d6b41510e8 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Tue, 29 Oct 2019 17:25:28 +1300 +Subject: [PATCH 1/9] CVE-2019-14861: s4-rpc/dnsserver: Confirm sort behaviour + in dcesrv_DnssrvEnumRecords + +The sort behaviour for child records is not correct in Samba so +we add a flapping entry. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14138 + +Signed-off-by: Andrew Bartlett +--- + python/samba/tests/dcerpc/dnsserver.py | 101 +++++++++++++++++++++++++ + selftest/flapping.d/dnsserver | 2 + + 2 files changed, 103 insertions(+) + create mode 100644 selftest/flapping.d/dnsserver + +diff --git a/python/samba/tests/dcerpc/dnsserver.py b/python/samba/tests/dcerpc/dnsserver.py +index 7264a290ef2..14ce308e38f 100644 +--- a/python/samba/tests/dcerpc/dnsserver.py ++++ b/python/samba/tests/dcerpc/dnsserver.py +@@ -156,6 +156,107 @@ class DnsserverTests(RpcInterfaceTestCase): + None) + super(DnsserverTests, self).tearDown() + ++ def test_enum_is_sorted(self): ++ """ ++ Confirm the zone is sorted ++ """ ++ ++ record_str = "192.168.50.50" ++ record_type_str = "A" ++ self.add_record(self.custom_zone, "atestrecord-1", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-2", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-3", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-4", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-0", record_type_str, record_str) ++ ++ # This becomes an extra A on the zone itself by server-side magic ++ self.add_record(self.custom_zone, self.custom_zone, record_type_str, record_str) ++ ++ _, result = self.conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN, ++ 0, ++ self.server, ++ self.custom_zone, ++ "@", ++ None, ++ self.record_type_int(record_type_str), ++ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA, ++ None, ++ None) ++ ++ self.assertEqual(len(result.rec), 6) ++ self.assertEqual(result.rec[0].dnsNodeName.str, "") ++ self.assertEqual(result.rec[1].dnsNodeName.str, "atestrecord-0") ++ self.assertEqual(result.rec[2].dnsNodeName.str, "atestrecord-1") ++ self.assertEqual(result.rec[3].dnsNodeName.str, "atestrecord-2") ++ self.assertEqual(result.rec[4].dnsNodeName.str, "atestrecord-3") ++ self.assertEqual(result.rec[5].dnsNodeName.str, "atestrecord-4") ++ ++ def test_enum_is_sorted_children_prefix_first(self): ++ """ ++ Confirm the zone returns the selected prefix first but no more ++ as Samba is flappy for the full sort ++ """ ++ ++ record_str = "192.168.50.50" ++ record_type_str = "A" ++ self.add_record(self.custom_zone, "atestrecord-1.a.b", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-2.a.b", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-3.a.b", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-4.a.b", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-0.a.b", record_type_str, record_str) ++ ++ # Not expected to be returned ++ self.add_record(self.custom_zone, "atestrecord-0.b.b", record_type_str, record_str) ++ ++ _, result = self.conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN, ++ 0, ++ self.server, ++ self.custom_zone, ++ "a.b", ++ None, ++ self.record_type_int(record_type_str), ++ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA, ++ None, ++ None) ++ ++ self.assertEqual(len(result.rec), 6) ++ self.assertEqual(result.rec[0].dnsNodeName.str, "") ++ ++ def test_enum_is_sorted_children(self): ++ """ ++ Confirm the zone is sorted ++ """ ++ ++ record_str = "192.168.50.50" ++ record_type_str = "A" ++ self.add_record(self.custom_zone, "atestrecord-1.a.b", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-2.a.b", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-3.a.b", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-4.a.b", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-0.a.b", record_type_str, record_str) ++ ++ # Not expected to be returned ++ self.add_record(self.custom_zone, "atestrecord-0.b.b", record_type_str, record_str) ++ ++ _, result = self.conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN, ++ 0, ++ self.server, ++ self.custom_zone, ++ "a.b", ++ None, ++ self.record_type_int(record_type_str), ++ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA, ++ None, ++ None) ++ ++ self.assertEqual(len(result.rec), 6) ++ self.assertEqual(result.rec[0].dnsNodeName.str, "") ++ self.assertEqual(result.rec[1].dnsNodeName.str, "atestrecord-0") ++ self.assertEqual(result.rec[2].dnsNodeName.str, "atestrecord-1") ++ self.assertEqual(result.rec[3].dnsNodeName.str, "atestrecord-2") ++ self.assertEqual(result.rec[4].dnsNodeName.str, "atestrecord-3") ++ self.assertEqual(result.rec[5].dnsNodeName.str, "atestrecord-4") ++ + # This test fails against Samba (but passes against Windows), + # because Samba does not return the record when we enum records. + # Records can be given DNS_RANK_NONE when the zone they are in +diff --git a/selftest/flapping.d/dnsserver b/selftest/flapping.d/dnsserver +new file mode 100644 +index 00000000000..9b33e8522a3 +--- /dev/null ++++ b/selftest/flapping.d/dnsserver +@@ -0,0 +1,2 @@ ++# This is not stable in samba due to a bug ++^samba.tests.dcerpc.dnsserver.samba.tests.dcerpc.dnsserver.DnsserverTests.test_enum_is_sorted_children +\ No newline at end of file +-- +2.17.1 + + +From 51fa9a6a805e4221120847ee9dcab6796021175a Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Mon, 21 Oct 2019 12:12:10 +1300 +Subject: [PATCH 2/9] CVE-2019-14861: s4-rpc_server: Remove special case for @ + in dns_build_tree() + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14138 + +Signed-off-by: Andrew Bartlett +--- + source4/rpc_server/dnsserver/dnsdata.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/source4/rpc_server/dnsserver/dnsdata.c b/source4/rpc_server/dnsserver/dnsdata.c +index 59e29f029a6..f991f4042e3 100644 +--- a/source4/rpc_server/dnsserver/dnsdata.c ++++ b/source4/rpc_server/dnsserver/dnsdata.c +@@ -795,10 +795,11 @@ struct dns_tree *dns_build_tree(TALLOC_CTX *mem_ctx, const char *name, struct ld + for (i=0; icount; i++) { + ptr = ldb_msg_find_attr_as_string(res->msgs[i], "name", NULL); + +- if (strcmp(ptr, "@") == 0) { +- base->data = res->msgs[i]; +- continue; +- } else if (strcasecmp(ptr, name) == 0) { ++ /* ++ * This might be the sub-domain in the zone being ++ * requested, or @ for the root of the zone ++ */ ++ if (strcasecmp(ptr, name) == 0) { + base->data = res->msgs[i]; + continue; + } +-- +2.17.1 + + +From 16405fecc403517574915a49de5f4abcaa964e21 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Tue, 29 Oct 2019 14:15:36 +1300 +Subject: [PATCH 3/9] CVE-2019-14861: s4-rpc/dnsserver: Avoid crash in + ldb_qsort() via dcesrv_DnssrvEnumRecords) + +dns_name_compare() had logic to put @ and the top record in the tree being +enumerated first, but if a domain had both then this would break the +older qsort() implementation in ldb_qsort() and cause a read of memory +before the base pointer. + +By removing this special case (not required as the base pointer +is already seperatly located, no matter were it is in the +returned records) the crash is avoided. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14138 + +Signed-off-by: Andrew Bartlett +--- + .../rpc_server/dnsserver/dcerpc_dnsserver.c | 21 ++++++++++++------- + source4/rpc_server/dnsserver/dnsdata.c | 19 ++--------------- + source4/rpc_server/dnsserver/dnsserver.h | 4 ++-- + 3 files changed, 17 insertions(+), 27 deletions(-) + +diff --git a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c +index 353754f9261..c0bf3425dae 100644 +--- a/source4/rpc_server/dnsserver/dcerpc_dnsserver.c ++++ b/source4/rpc_server/dnsserver/dcerpc_dnsserver.c +@@ -1733,6 +1733,7 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, + struct DNS_RPC_RECORDS_ARRAY *recs; + char **add_names = NULL; + char *rname; ++ const char *preference_name = NULL; + int add_count = 0; + int i, ret, len; + WERROR status; +@@ -1749,6 +1750,7 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, + ret = ldb_search(dsstate->samdb, tmp_ctx, &res, z->zone_dn, + LDB_SCOPE_ONELEVEL, attrs, + "(&(objectClass=dnsNode)(!(dNSTombstoned=TRUE)))"); ++ preference_name = "@"; + } else { + char *encoded_name + = ldb_binary_encode_string(tmp_ctx, name); +@@ -1756,6 +1758,7 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, + LDB_SCOPE_ONELEVEL, attrs, + "(&(objectClass=dnsNode)(|(name=%s)(name=*.%s))(!(dNSTombstoned=TRUE)))", + encoded_name, encoded_name); ++ preference_name = name; + } + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); +@@ -1769,16 +1772,18 @@ static WERROR dnsserver_enumerate_records(struct dnsserver_state *dsstate, + recs = talloc_zero(mem_ctx, struct DNS_RPC_RECORDS_ARRAY); + W_ERROR_HAVE_NO_MEMORY_AND_FREE(recs, tmp_ctx); + +- /* Sort the names, so that the first record is the parent record */ +- ldb_qsort(res->msgs, res->count, sizeof(struct ldb_message *), name, +- (ldb_qsort_cmp_fn_t)dns_name_compare); ++ /* ++ * Sort the names, so that the records are in order by the child ++ * component below "name". ++ * ++ * A full tree sort is not required, so we pass in "name" so ++ * we know which level to sort, as only direct children are ++ * eventually returned ++ */ ++ LDB_TYPESAFE_QSORT(res->msgs, res->count, name, dns_name_compare); + + /* Build a tree of name components from dns name */ +- if (strcasecmp(name, z->name) == 0) { +- tree = dns_build_tree(tmp_ctx, "@", res); +- } else { +- tree = dns_build_tree(tmp_ctx, name, res); +- } ++ tree = dns_build_tree(tmp_ctx, preference_name, res); + W_ERROR_HAVE_NO_MEMORY_AND_FREE(tree, tmp_ctx); + + /* Find the parent record in the tree */ +diff --git a/source4/rpc_server/dnsserver/dnsdata.c b/source4/rpc_server/dnsserver/dnsdata.c +index f991f4042e3..acdb87752f8 100644 +--- a/source4/rpc_server/dnsserver/dnsdata.c ++++ b/source4/rpc_server/dnsserver/dnsdata.c +@@ -1052,8 +1052,8 @@ WERROR dns_fill_records_array(TALLOC_CTX *mem_ctx, + } + + +-int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2, +- char *search_name) ++int dns_name_compare(struct ldb_message * const *m1, struct ldb_message * const *m2, ++ const char *search_name) + { + const char *name1, *name2; + const char *ptr1, *ptr2; +@@ -1064,21 +1064,6 @@ int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m + return 0; + } + +- /* '@' record and the search_name record gets preference */ +- if (name1[0] == '@') { +- return -1; +- } +- if (search_name && strcasecmp(name1, search_name) == 0) { +- return -1; +- } +- +- if (name2[0] == '@') { +- return 1; +- } +- if (search_name && strcasecmp(name2, search_name) == 0) { +- return 1; +- } +- + /* Compare the last components of names. + * If search_name is not NULL, compare the second last components of names */ + ptr1 = strrchr(name1, '.'); +diff --git a/source4/rpc_server/dnsserver/dnsserver.h b/source4/rpc_server/dnsserver/dnsserver.h +index 93f1d72f2ef..690ab87ed10 100644 +--- a/source4/rpc_server/dnsserver/dnsserver.h ++++ b/source4/rpc_server/dnsserver/dnsserver.h +@@ -188,8 +188,8 @@ struct DNS_ADDR_ARRAY *dns_addr_array_copy(TALLOC_CTX *mem_ctx, struct DNS_ADDR_ + int dns_split_name_components(TALLOC_CTX *mem_ctx, const char *name, char ***components); + char *dns_split_node_name(TALLOC_CTX *mem_ctx, const char *node_name, const char *zone_name); + +-int dns_name_compare(const struct ldb_message **m1, const struct ldb_message **m2, +- char *search_name); ++int dns_name_compare(struct ldb_message * const *m1, struct ldb_message * const *m2, ++ const char *search_name); + bool dns_record_match(struct dnsp_DnssrvRpcRecord *rec1, struct dnsp_DnssrvRpcRecord *rec2); + + void dnsp_to_dns_copy(TALLOC_CTX *mem_ctx, struct dnsp_DnssrvRpcRecord *dnsp, +-- +2.17.1 + + +From 90073f0abc495c4b5bd05322b71667c534ee9dd8 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Wed, 30 Oct 2019 11:50:57 +1300 +Subject: [PATCH 4/9] CVE-2019-14861: Test to demonstrate the bug + +This test does not fail every time, but when it does it casues a segfault which +takes out the rpc_server master process, as this hosts the dnsserver pipe. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14138 + +Signed-off-by: Andrew Bartlett +--- + python/samba/tests/dcerpc/dnsserver.py | 47 ++++++++++++++++++++++++++ + 1 file changed, 47 insertions(+) + +diff --git a/python/samba/tests/dcerpc/dnsserver.py b/python/samba/tests/dcerpc/dnsserver.py +index 14ce308e38f..a9b8a4ace91 100644 +--- a/python/samba/tests/dcerpc/dnsserver.py ++++ b/python/samba/tests/dcerpc/dnsserver.py +@@ -191,6 +191,53 @@ class DnsserverTests(RpcInterfaceTestCase): + self.assertEqual(result.rec[4].dnsNodeName.str, "atestrecord-3") + self.assertEqual(result.rec[5].dnsNodeName.str, "atestrecord-4") + ++ def test_enum_is_sorted_with_zone_dup(self): ++ """ ++ Confirm the zone is sorted ++ """ ++ ++ record_str = "192.168.50.50" ++ record_type_str = "A" ++ self.add_record(self.custom_zone, "atestrecord-1", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-2", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-3", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-4", record_type_str, record_str) ++ self.add_record(self.custom_zone, "atestrecord-0", record_type_str, record_str) ++ ++ # This triggers a bug in old Samba ++ self.add_record(self.custom_zone, self.custom_zone + "1", record_type_str, record_str) ++ ++ dn, record = self.get_record_from_db(self.custom_zone, self.custom_zone + "1") ++ ++ new_dn = ldb.Dn(self.samdb, str(dn)) ++ new_dn.set_component(0, "dc", self.custom_zone) ++ self.samdb.rename(dn, new_dn) ++ ++ _, result = self.conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN, ++ 0, ++ self.server, ++ self.custom_zone, ++ "@", ++ None, ++ self.record_type_int(record_type_str), ++ dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA, ++ None, ++ None) ++ ++ self.assertEqual(len(result.rec), 7) ++ self.assertEqual(result.rec[0].dnsNodeName.str, "") ++ self.assertEqual(result.rec[1].dnsNodeName.str, "atestrecord-0") ++ self.assertEqual(result.rec[2].dnsNodeName.str, "atestrecord-1") ++ self.assertEqual(result.rec[3].dnsNodeName.str, "atestrecord-2") ++ self.assertEqual(result.rec[4].dnsNodeName.str, "atestrecord-3") ++ self.assertEqual(result.rec[5].dnsNodeName.str, "atestrecord-4") ++ ++ # Windows doesn't reload the zone fast enough, but doesn't ++ # have the bug anyway, it will sort last on both names (where ++ # it should) ++ if result.rec[6].dnsNodeName.str != (self.custom_zone + "1"): ++ self.assertEqual(result.rec[6].dnsNodeName.str, self.custom_zone) ++ + def test_enum_is_sorted_children_prefix_first(self): + """ + Confirm the zone returns the selected prefix first but no more +-- +2.17.1 diff --git a/CVE-2019-14870.patch b/CVE-2019-14870.patch new file mode 100644 index 0000000..f05c4e4 --- /dev/null +++ b/CVE-2019-14870.patch @@ -0,0 +1,285 @@ +From 5249cad8b435d162584f010f492568d6f4526662 Mon Sep 17 00:00:00 2001 +From: Isaac Boukris +Date: Wed, 30 Oct 2019 15:59:16 +0100 +Subject: [PATCH 7/9] CVE-2019-14870: heimdal: add S4U test for + delegation_not_allowed + +Signed-off-by: Isaac Boukris +--- + selftest/knownfail.d/heimdal_not_delegated | 1 + + source4/selftest/tests.py | 1 + + testprogs/blackbox/test_s4u_heimdal.sh | 73 ++++++++++++++++++++++ + 3 files changed, 75 insertions(+) + create mode 100644 selftest/knownfail.d/heimdal_not_delegated + create mode 100755 testprogs/blackbox/test_s4u_heimdal.sh + +diff --git a/selftest/knownfail.d/heimdal_not_delegated b/selftest/knownfail.d/heimdal_not_delegated +new file mode 100644 +index 00000000000..bfc382a3fc2 +--- /dev/null ++++ b/selftest/knownfail.d/heimdal_not_delegated +@@ -0,0 +1 @@ ++^samba4.blackbox.krb5.s4u +diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py +index 9c3c77f1c56..2ec0bee923b 100755 +--- a/source4/selftest/tests.py ++++ b/source4/selftest/tests.py +@@ -425,6 +425,7 @@ if have_heimdal_support: + plantestsuite("samba4.blackbox.kinit_trust(fl2003dc:local)", "fl2003dc:local", [os.path.join(bbdir, "test_kinit_trusts_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_SERVER', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', '$PREFIX', "external", "arcfour-hmac-md5"]) + plantestsuite("samba4.blackbox.export.keytab(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_export_keytab_heimdal.sh"), '$SERVER', '$USERNAME', '$REALM', '$DOMAIN', "$PREFIX", smbclient4]) + plantestsuite("samba4.blackbox.kpasswd(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_kpasswd_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', "$PREFIX/ad_dc_ntvfs"]) ++ plantestsuite("samba4.blackbox.krb5.s4u", "fl2008r2dc:local", [os.path.join(bbdir, "test_s4u_heimdal.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', configuration]) + else: + plantestsuite("samba4.blackbox.kinit(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_kinit_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', smbclient4, configuration]) + plantestsuite("samba4.blackbox.kinit(fl2000dc:local)", "fl2000dc:local", [os.path.join(bbdir, "test_kinit_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$PREFIX', smbclient4, configuration]) +diff --git a/testprogs/blackbox/test_s4u_heimdal.sh b/testprogs/blackbox/test_s4u_heimdal.sh +new file mode 100755 +index 00000000000..0e12c7ec096 +--- /dev/null ++++ b/testprogs/blackbox/test_s4u_heimdal.sh +@@ -0,0 +1,73 @@ ++#!/bin/sh ++ ++if [ $# -lt 5 ]; then ++cat < $PREFIX/tmppassfile ++testit "kinit with password" $samba4kinit -f --password-file=$PREFIX/tmppassfile $impersonator || failed=`expr $failed + 1` ++ ++testit "test S4U2Self with normal user" $samba4kgetcred --out-cache=$ocache --forwardable --impersonate=${USERNAME} $impersonator || failed=`expr $failed + 1` ++testit "test S4U2Proxy with normal user" $samba4kgetcred --out-cache=$ocache --delegation-credential-cache=${ocache} $target || failed=`expr $failed + 1` ++ ++testit "test S4U2Self with sensitive user" $samba4kgetcred --out-cache=$ocache --forwardable --impersonate=$princ $impersonator || failed=`expr $failed + 1` ++testit_expect_failure "test S4U2Proxy with sensitive user" $samba4kgetcred --out-cache=$ocache --delegation-credential-cache=${ocache} $target || failed=`expr $failed + 1` ++ ++rm -f $ocache ++testit "unset not-delegated flag" $samba_tool user sensitive $princ off || failed=`expr $failed + 1` ++ ++testit "test S4U2Self after unsetting ND flag" $samba4kgetcred --out-cache=$ocache --forwardable --impersonate=$princ $impersonator || failed=`expr $failed + 1` ++testit "test S4U2Proxy after unsetting ND flag" $samba4kgetcred --out-cache=$ocache --delegation-credential-cache=${ocache} $target || failed=`expr $failed + 1` ++ ++ ++rm -f $ocache $PREFIX/tmpccache tmppassfile ++exit $failed +-- +2.17.1 + + +From d0d4954b9b4643678b6f465959dd69de0faafd07 Mon Sep 17 00:00:00 2001 +From: Isaac Boukris +Date: Mon, 28 Oct 2019 02:54:09 +0200 +Subject: [PATCH 8/9] CVE-2019-14870: heimdal: enforce delegation_not_allowed + in S4U2Self + +Signed-off-by: Isaac Boukris +--- + selftest/knownfail.d/heimdal_not_delegated | 1 - + source4/heimdal/kdc/krb5tgs.c | 58 ++++++++++++++-------- + 2 files changed, 36 insertions(+), 23 deletions(-) + delete mode 100644 selftest/knownfail.d/heimdal_not_delegated + +diff --git a/selftest/knownfail.d/heimdal_not_delegated b/selftest/knownfail.d/heimdal_not_delegated +deleted file mode 100644 +index bfc382a3fc2..00000000000 +--- a/selftest/knownfail.d/heimdal_not_delegated ++++ /dev/null +@@ -1 +0,0 @@ +-^samba4.blackbox.krb5.s4u +diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c +index ff7d93138c0..ee3ac3d8f53 100644 +--- a/source4/heimdal/kdc/krb5tgs.c ++++ b/source4/heimdal/kdc/krb5tgs.c +@@ -1975,30 +1975,42 @@ server_lookup: + if (ret) + goto out; + ++ ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags, ++ NULL, &s4u2self_impersonated_clientdb, ++ &s4u2self_impersonated_client); ++ if (ret) { ++ const char *msg; ++ ++ /* ++ * If the client belongs to the same realm as our krbtgt, it ++ * should exist in the local database. ++ * ++ */ ++ ++ if (ret == HDB_ERR_NOENTRY) ++ ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; ++ msg = krb5_get_error_message(context, ret); ++ kdc_log(context, config, 1, ++ "S2U4Self principal to impersonate %s not found in database: %s", ++ tpn, msg); ++ krb5_free_error_message(context, msg); ++ goto out; ++ } ++ ++ /* Ignore pw_end attributes (as Windows does), ++ * since S4U2Self is not password authentication. */ ++ free(s4u2self_impersonated_client->entry.pw_end); ++ s4u2self_impersonated_client->entry.pw_end = NULL; ++ ++ ret = kdc_check_flags(context, config, s4u2self_impersonated_client, tpn, ++ NULL, NULL, FALSE); ++ if (ret) ++ goto out; ++ + /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */ + if(rspac.data) { + krb5_pac p = NULL; + krb5_data_free(&rspac); +- ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags, +- NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client); +- if (ret) { +- const char *msg; +- +- /* +- * If the client belongs to the same realm as our krbtgt, it +- * should exist in the local database. +- * +- */ +- +- if (ret == HDB_ERR_NOENTRY) +- ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; +- msg = krb5_get_error_message(context, ret); +- kdc_log(context, config, 1, +- "S2U4Self principal to impersonate %s not found in database: %s", +- tpn, msg); +- krb5_free_error_message(context, msg); +- goto out; +- } + ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, &p); + if (ret) { + kdc_log(context, config, 0, "PAC generation failed for -- %s", +@@ -2034,10 +2046,12 @@ server_lookup: + + /* + * If the service isn't trusted for authentication to +- * delegation, remove the forward flag. ++ * delegation or if the impersonate client is disallowed ++ * forwardable, remove the forwardable flag. + */ + +- if (client->entry.flags.trusted_for_delegation) { ++ if (client->entry.flags.trusted_for_delegation && ++ s4u2self_impersonated_client->entry.flags.forwardable) { + str = "[forwardable]"; + } else { + b->kdc_options.forwardable = 0; +-- +2.17.1 + + +From 277ab21fcf31bf60458410994e188d9c236963a3 Mon Sep 17 00:00:00 2001 +From: Isaac Boukris +Date: Thu, 21 Nov 2019 11:12:48 +0100 +Subject: [PATCH 9/9] CVE-2019-14870: mit-kdc: enforce delegation_not_allowed + flag + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14187 + +Signed-off-by: Isaac Boukris +--- + source4/kdc/mit_samba.c | 5 +++++ + source4/kdc/sdb_to_kdb.c | 17 ++++++----------- + 2 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/source4/kdc/mit_samba.c b/source4/kdc/mit_samba.c +index eacca0903ec..06e680b60e2 100644 +--- a/source4/kdc/mit_samba.c ++++ b/source4/kdc/mit_samba.c +@@ -304,6 +304,11 @@ fetch_referral_principal: + + sdb_free_entry(&sentry); + ++ if ((kflags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) == 0) { ++ kentry->attributes &= ~KRB5_KDB_DISALLOW_FORWARDABLE; ++ kentry->attributes &= ~KRB5_KDB_DISALLOW_PROXIABLE; ++ } ++ + done: + krb5_free_principal(ctx->context, referral_principal); + referral_principal = NULL; +diff --git a/source4/kdc/sdb_to_kdb.c b/source4/kdc/sdb_to_kdb.c +index 74d882738f8..b7253ade122 100644 +--- a/source4/kdc/sdb_to_kdb.c ++++ b/source4/kdc/sdb_to_kdb.c +@@ -36,18 +36,13 @@ static int SDBFlags_to_kflags(const struct SDBFlags *s, + if (s->initial) { + *k |= KRB5_KDB_DISALLOW_TGT_BASED; + } +- /* +- * Do not set any disallow rules for forwardable, proxiable, +- * renewable, postdate and server. +- * +- * The KDC will take care setting the flags based on the incoming +- * ticket. +- */ +- if (s->forwardable) { +- ; ++ /* The forwardable and proxiable flags are set according to client and ++ * server attributes. */ ++ if (!s->forwardable) { ++ *k |= KRB5_KDB_DISALLOW_FORWARDABLE; + } +- if (s->proxiable) { +- ; ++ if (!s->proxiable) { ++ *k |= KRB5_KDB_DISALLOW_PROXIABLE; + } + if (s->renewable) { + ; +-- +2.17.1 + diff --git a/samba.spec b/samba.spec index 4b5d0a7..c5265c9 100644 --- a/samba.spec +++ b/samba.spec @@ -50,7 +50,7 @@ Name: samba Version: 4.9.1 -Release: 4 +Release: 7 Summary: A suite for Linux to interoperate with Windows License: GPLv3+ and LGPLv3+ URL: http://www.samba.org/ @@ -80,6 +80,41 @@ Patch6011: CVE-2018-16841-1.patch Patch6012: CVE-2018-16841-2.patch Patch6013: CVE-2019-12435-1.patch Patch6014: CVE-2019-12435-2.patch +Patch6015: CVE-2018-16852-1.patch +Patch6016: CVE-2018-16852-2.patch +Patch6017: CVE-2018-16852-3.patch +Patch6018: CVE-2018-16857-1.patch +Patch6019: CVE-2018-16857-2.patch +Patch6020: CVE-2018-16857-3.patch +Patch6021: CVE-2018-16857-4.patch +Patch6022: CVE-2018-16857-5.patch +Patch6023: CVE-2018-16857-6.patch +Patch6024: CVE-2018-16857-7.patch +Patch6025: CVE-2018-16857-8.patch +Patch6026: CVE-2018-16857-9.patch +Patch6027: CVE-2019-10197-1.patch +Patch6028: CVE-2019-10197-2.patch +Patch6029: CVE-2019-10197-3.patch +Patch6030: CVE-2019-10197-4.patch +Patch6031: CVE-2019-10197-5.patch +Patch6032: CVE-2019-10197-6.patch +Patch6033: 0001-CVE-2019-14847.patch +Patch6034: 0002-CVE-2019-14847.patch +Patch6035: 0003-CVE-2019-14847.patch +Patch6036: 0001-CVE-2019-14833.patch +Patch6037: 0002-CVE-2019-14833.patch +Patch6038: 0001-CVE-2019-10218.patch +Patch6039: 0002-CVE-2019-10218.patch +Patch6040: 0001-CVE-2019-3824.patch +Patch6041: 0002-CVE-2019-3824.patch +Patch6042: 0003-CVE-2019-3824.patch +Patch6043: 0004-CVE-2019-3824.patch +Patch6044: 0005-CVE-2019-3824.patch +Patch6045: 0006-CVE-2019-3824.patch +Patch6046: 0007-CVE-2019-3824.patch +Patch6047: CVE-2019-14861.patch +Patch6048: CVE-2019-14870.patch +Patch6049: CVE-2018-16860.patch BuildRequires: avahi-devel cups-devel dbus-devel docbook-style-xsl e2fsprogs-devel gawk gnupg2 gpgme-devel BuildRequires: jansson-devel krb5-devel >= %{required_mit_krb5} libacl-devel libaio-devel libarchive-devel @@ -580,29 +615,34 @@ then exit -1 fi -touch %{buildroot}%{_libexecdir}/samba/cups_backend_smb +pushd %{buildroot} +touch .%{_libexecdir}/samba/cups_backend_smb -install -dm755 %{buildroot}%{_sysconfdir}/logrotate.d -install -m644 %{SOURCE3} %{buildroot}%{_sysconfdir}/logrotate.d/samba +install -dm755 .%{_sysconfdir}/logrotate.d +install -m644 %{SOURCE3} .%{_sysconfdir}/logrotate.d/samba -install -m644 %{SOURCE4} %{buildroot}%{_sysconfdir}/samba/smb.conf -install -m644 %{SOURCE5} %{buildroot}%{_sysconfdir}/samba/smb.conf.example +install -m644 %{SOURCE4} .%{_sysconfdir}/samba/smb.conf +install -m644 %{SOURCE5} .%{_sysconfdir}/samba/smb.conf.example -install -dm755 %{buildroot}%{_sysconfdir}/security -install -m644 %{SOURCE6} %{buildroot}%{_sysconfdir}/security/pam_winbind.conf +install -dm755 .%{_sysconfdir}/security +install -m644 %{SOURCE6} .%{_sysconfdir}/security/pam_winbind.conf -install -dm755 %{buildroot}%{_sysconfdir}/pam.d -install -m644 %{SOURCE7} %{buildroot}%{_sysconfdir}/pam.d/samba +install -dm755 .%{_sysconfdir}/pam.d +install -m644 %{SOURCE7} .%{_sysconfdir}/pam.d/samba -echo 127.0.0.1 localhost > %{buildroot}%{_sysconfdir}/samba/lmhosts +echo 127.0.0.1 localhost > .%{_sysconfdir}/samba/lmhosts -install -dm755 %{buildroot}%{_sysconfdir}/openldap/schema -install -m644 examples/LDAP/samba.schema %{buildroot}%{_sysconfdir}/openldap/schema/samba.schema +install -dm755 .%{_sysconfdir}/openldap/schema +install -m644 %{_builddir}/%{name}-%{version}/examples/LDAP/samba.schema \ + %{buildroot}%{_sysconfdir}/openldap/schema/samba.schema -install -m744 packaging/printing/smbprint %{buildroot}%{_bindir}/smbprint +install -m744 %{_builddir}/%{name}-%{version}/packaging/printing/smbprint \ + %{buildroot}%{_bindir}/smbprint install -dm755 %{buildroot}%{_tmpfilesdir} -install -m644 packaging/systemd/samba.conf.tmp %{buildroot}%{_tmpfilesdir}/samba.conf +install -m644 %{_builddir}/%{name}-%{version}/packaging/systemd/samba.conf.tmp \ + %{buildroot}%{_tmpfilesdir}/samba.conf +popd echo "d /run/samba 755 root root" >> %{buildroot}%{_tmpfilesdir}/samba.conf %if %with_clustering_support @@ -915,9 +955,9 @@ fi %{_libdir}/%{name}/libsmbpasswdparser-samba4.so %{_libdir}/%{name}/libxattr-tdb-samba4.so %{_bindir}/smbstatus -%{_sbindir}/eventlogadm -%{_sbindir}/nmbd %{_sbindir}/smbd +%{_sbindir}/nmbd +%{_sbindir}/eventlogadm %if %{with_dc} %{_libdir}/samba/vfs/dfs_samba4.so %{_libdir}/samba/libdfs-server-ad-samba4.so @@ -998,6 +1038,7 @@ fi %{_libdir}/libsmbldap.so.* %{_libdir}/libtevent-util.so.* %{_libdir}/libdcerpc.so.* + %{_bindir}/cifsdd %{_bindir}/dbwrap_tool %{_bindir}/findsmb @@ -1013,6 +1054,7 @@ fi %exclude %{_bindir}/smbpasswd %exclude %{_bindir}/smbstatus %exclude %{_bindir}/smbtorture + %dir %{_libexecdir}/samba %ghost %{_libexecdir}/samba/cups_backend_smb @@ -1113,8 +1155,8 @@ fi %dir /var/lib/samba/lock %attr(755,root,root) %dir %{_sysconfdir}/samba %config(noreplace) %{_sysconfdir}/samba/smb.conf -%{_sysconfdir}/samba/smb.conf.example %config(noreplace) %{_sysconfdir}/samba/lmhosts +%{_sysconfdir}/samba/smb.conf.example %config(noreplace) %{_sysconfdir}/sysconfig/samba %{_libdir}/samba/libpopt-samba3-samba4.so %if %{with_intel_aes_accel} @@ -2383,14 +2425,13 @@ fi %doc ctdb/README %doc ctdb/doc/examples %config(noreplace, missingok) %{_sysconfdir}/sysconfig/ctdb - %dir %{_sysconfdir}/ctdb -%config(noreplace) %{_sysconfdir}/ctdb/ctdb.conf %config(noreplace) %{_sysconfdir}/ctdb/*.sh +%config(noreplace) %{_sysconfdir}/ctdb/ctdb.conf %{_sysconfdir}/ctdb/functions -%{_sysconfdir}/ctdb/nfs-linux-kernel-callout %{_sysconfdir}/ctdb/statd-callout +%{_sysconfdir}/ctdb/nfs-linux-kernel-callout %config %{_sysconfdir}/sudoers.d/ctdb %dir %{_sysconfdir}/ctdb/events @@ -2399,40 +2440,22 @@ fi %dir %{_sysconfdir}/ctdb/nfs-checks.d %{_sysconfdir}/ctdb/nfs-checks.d/README -%config(noreplace) %{_sysconfdir}/ctdb/nfs-checks.d/00.portmapper.check -%config(noreplace) %{_sysconfdir}/ctdb/nfs-checks.d/10.status.check -%config(noreplace) %{_sysconfdir}/ctdb/nfs-checks.d/20.nfs.check -%config(noreplace) %{_sysconfdir}/ctdb/nfs-checks.d/30.nlockmgr.check -%config(noreplace) %{_sysconfdir}/ctdb/nfs-checks.d/40.mountd.check -%config(noreplace) %{_sysconfdir}/ctdb/nfs-checks.d/50.rquotad.check +%config(noreplace) %{_sysconfdir}/ctdb/nfs-checks.d/*.check +%{_bindir}/ctdb +%{_bindir}/ctdb_diagnostics +%{_bindir}/ltdbtool +%{_bindir}/onnode +%{_bindir}/ping_pong %{_sbindir}/ctdbd %{_sbindir}/ctdbd_wrapper -%{_bindir}/ctdb -%{_bindir}/ping_pong -%{_bindir}/ltdbtool -%{_bindir}/ctdb_diagnostics -%{_bindir}/onnode %dir %{_libexecdir}/ctdb -%{_libexecdir}/ctdb/ctdb-config -%{_libexecdir}/ctdb/ctdb-event -%{_libexecdir}/ctdb/ctdb-eventd -%{_libexecdir}/ctdb/ctdb_killtcp -%{_libexecdir}/ctdb/ctdb_lock_helper -%{_libexecdir}/ctdb/ctdb_lvs -%{_libexecdir}/ctdb/ctdb_mutex_fcntl_helper -%{_libexecdir}/ctdb/ctdb_natgw -%{_libexecdir}/ctdb/ctdb-path -%{_libexecdir}/ctdb/ctdb_recovery_helper -%{_libexecdir}/ctdb/ctdb_takeover_helper +%{_libexecdir}/ctdb/ctdb* %{_libexecdir}/ctdb/smnotify %dir %{_localstatedir}/lib/ctdb/ - - %{_tmpfilesdir}/ctdb.conf - %{_unitdir}/ctdb.service %dir %{_datadir}/ctdb @@ -2463,56 +2486,9 @@ fi %dir %{_libexecdir}/ctdb %dir %{_libexecdir}/ctdb/tests -%{_libexecdir}/ctdb/tests/cmdline_test -%{_libexecdir}/ctdb/tests/comm_client_test -%{_libexecdir}/ctdb/tests/comm_server_test -%{_libexecdir}/ctdb/tests/comm_test -%{_libexecdir}/ctdb/tests/conf_test -%{_libexecdir}/ctdb/tests/ctdb_packet_parse -%{_libexecdir}/ctdb/tests/ctdb_takeover_tests -%{_libexecdir}/ctdb/tests/db_hash_test -%{_libexecdir}/ctdb/tests/dummy_client -%{_libexecdir}/ctdb/tests/errcode -%{_libexecdir}/ctdb/tests/event_protocol_test -%{_libexecdir}/ctdb/tests/event_script_test -%{_libexecdir}/ctdb/tests/fake_ctdbd -%{_libexecdir}/ctdb/tests/fetch_loop -%{_libexecdir}/ctdb/tests/fetch_loop_key -%{_libexecdir}/ctdb/tests/fetch_readonly -%{_libexecdir}/ctdb/tests/fetch_readonly_loop -%{_libexecdir}/ctdb/tests/fetch_ring -%{_libexecdir}/ctdb/tests/g_lock_loop -%{_libexecdir}/ctdb/tests/hash_count_test -%{_libexecdir}/ctdb/tests/line_test -%{_libexecdir}/ctdb/tests/lock_tdb -%{_libexecdir}/ctdb/tests/message_ring -%{_libexecdir}/ctdb/tests/pidfile_test -%{_libexecdir}/ctdb/tests/pkt_read_test -%{_libexecdir}/ctdb/tests/pkt_write_test -%{_libexecdir}/ctdb/tests/porting_tests -%{_libexecdir}/ctdb/tests/protocol_basic_test -%{_libexecdir}/ctdb/tests/protocol_ctdb_compat_test -%{_libexecdir}/ctdb/tests/protocol_ctdb_test -%{_libexecdir}/ctdb/tests/protocol_types_compat_test -%{_libexecdir}/ctdb/tests/protocol_types_test -%{_libexecdir}/ctdb/tests/protocol_util_test -%{_libexecdir}/ctdb/tests/rb_test -%{_libexecdir}/ctdb/tests/reqid_test -%{_libexecdir}/ctdb/tests/run_event_test -%{_libexecdir}/ctdb/tests/run_proc_test -%{_libexecdir}/ctdb/tests/sigcode -%{_libexecdir}/ctdb/tests/sock_daemon_test -%{_libexecdir}/ctdb/tests/sock_io_test -%{_libexecdir}/ctdb/tests/srvid_test -%{_libexecdir}/ctdb/tests/test_mutex_raw -%{_libexecdir}/ctdb/tests/transaction_loop -%{_libexecdir}/ctdb/tests/tunnel_cmd -%{_libexecdir}/ctdb/tests/tunnel_test -%{_libexecdir}/ctdb/tests/update_record -%{_libexecdir}/ctdb/tests/update_record_persistent +%{_libexecdir}/ctdb/tests/* %dir %{_datadir}/ctdb/tests - %dir %{_datadir}/ctdb/tests/complex %{_datadir}/ctdb/tests/complex/* %exclude %{_datadir}/ctdb/tests/complex/scripts @@ -3246,11 +3222,29 @@ fi %{_mandir}/man8/smbpasswd.8* %changelog +* Sat Dec 21 2019 openEuler Buildteam - 4.9.1-7 +- Type:bugfix +- Id:NA +- SUG:NA +- DESC:fix CVE + +* Thu Dec 19 2019 openEuler Buildteam - 4.9.1-6 +- Type:bugfix +- Id:NA +- SUG:NA +- DESC:modify the changelog message + +* Tue Dec 3 2019 openEuler Buildteam - 4.9.1-5 +- Type: NA +- ID: NA +- SUG: NA +- DESC: optimize the spec file + * Thu Nov 21 2019 openEuler Buildteam - 4.9.1-4 - Type: enhancement - ID: NA - SUG: NA -- DESC:modify spec file to solve fossid +- DESC:modify spec file * Mon Sep 23 2019 huzhiyu - 4.9.1-3 - Package init